STM8开发记录二:UART RX空闲中断和DMA操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xqw19891201/article/details/83864678

一、用STM8L的时候,没能在同时读取Rx中断和IDLE中断标志,最后用DMA取数据,见 (三、DMA实现数据拷贝):

       1.1 uart配置

void UsartConfig(void)
{
//	USART_DeInit(USART1);

	/* Enable USART clock */  
	CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);

	/* USART pin remap */
	SYSCFG_REMAPPinConfig(REMAP_Pin_USART1TxRxPortA, ENABLE);

	/* Configure USART Tx as alternate function push-pull  (software pull up)*/
	GPIO_ExternalPullUpConfig(USART1_Tx_PORT, USART1_Tx_Pin, ENABLE);

	/* Configure USART Rx as alternate function push-pull  (software pull up)*/
	GPIO_ExternalPullUpConfig(USART1_Rx_PORT, USART1_Rx_Pin, ENABLE);

	/* USART configuration */
	USART_Init(USART1, BAUDRATE, USART_WordLength_8b, USART_StopBits_1,
	        								USART_Parity_No, USART_Mode_Rx_and_TX);


	/* Enable the USART Receive interrupt: this interrupt is generated when the USART*/
	USART_ITConfig(USART1 , USART_IT_RXNE, ENABLE);		
	USART_ITConfig(USART1 , USART_IT_IDLE , ENABLE);		//空闲中断


	//配置ITC 中断管理
	ITC_SetSoftwarePriority(USART1_RX_IRQn, ITC_PriorityLevel_3);

	//start UART
	USART_Cmd(USART1 , ENABLE);							//打开串口

	//解决第一个数据发送失败的问题	
	USART_ClearFlag(USART3 , USART_FLAG_TC);
//    	USART_ClearFlag(USART3 , USART_FLAG_IDLE);
}

       1.2 中断处理, 不能判断IDLE中断:如发送 AA01数据后,不能进入IDLE中断。

             但是只开IDLE中断,发送完毕会进入IDLE中断。

                /* Enable the USART Receive interrupt: this interrupt is generated when the USART*/
                //USART_ITConfig(USART1 , USART_IT_RXNE, ENABLE);        
                USART_ITConfig(USART1 , USART_IT_IDLE , ENABLE);        //空闲中断

INTERRUPT_HANDLER(USART1_RX_TIM5_CC_IRQHandler, 28)
{
	/* In order to detect unexpected events during development,
	 it is recommended to set a breakpoint on the following instruction.
	*/	
	static U8 BytesPos = 0;
	static U8 MessagePos = 0;
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)		//RX interrupt
	{
		UartApiVar.RXBuffer[MessagePos][BytesPos] = USART_ReceiveData8(USART1);  
		printflog("MessagePos = %d, BytesPos = %d\n\r", MessagePos, BytesPos);
		printflog("data_0 = %d\n\r", UartApiVar.RXBuffer[MessagePos][BytesPos]);
		BytesPos++;
	}
	else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)	//IDLE interrupt
	{	
		USART1->SR;//先读SR
		USART1->DR;//再读DR	
		printflog("MessagePos = %d, BytesPos = %d\n\r", MessagePos, BytesPos);
		printflog("data_1 = %d\n\r", UartApiVar.RXBuffer[MessagePos][0]);
		if((BytesPos < COMM_IF_UART_RX_BUFFER_LENGTH) && 
								(UartApiVar.RXBuffer[MessagePos][0] == 0xAA))
		{
			if(MessagePos < COMM_IF_UART_RX_MSG_NUM)
			{
				MessagePos++;	
			}
			else
			{
				MessagePos = 0;	
			}
		}
		BytesPos = 0;
	}
}

二、用STM32的时候,可以同时判断Rx中断和IDLE中断:

       2.1 uart配置:

void USART3Conf(u32 baudRate, u32 nvicPre, u32 nvicSub)
{
	USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); //使能USART1
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);	//GPIOA时钟
	
	//USART3_TX   GPIOB.10
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.10

	//USART3_RX	  GPIOB.11初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PB11
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOA.10 

//  //Usart3 NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=nvicPre ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = nvicSub;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器


	//USART3 Configure	
	USART_InitStructure.USART_BaudRate = baudRate;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	//USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART3 , &USART_InitStructure);
	
	//USART3_INT Configure
	USART_ITConfig(USART3 , USART_IT_RXNE, ENABLE);		
  	USART_ITConfig(USART3 , USART_IT_IDLE , ENABLE);		//空闲中断
	USART_Cmd(USART3 , ENABLE);//打开串口
	USART_ClearFlag(USART3 , USART_FLAG_TC);//解决第一个数据发送失败的问题
}

       2.2中断处理:

void USART3_IRQHandler(void)
{
	static u8 i = 0;
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
	{
		UsartBuf[i] = (u8)USART_ReceiveData(USART3);
		i++;
		/* deliver rx byte */
	}
	else if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)
	{	
		USART3->SR;//先读SR
		USART3->DR;//再读DR	

		if(UsartBuf[i -1] == 0x0A)
		{
			UsartBuf[UART_DATA_LEN -2] = i;		
			UsartBuf[UART_DATA_LEN -1] = UART_DATA_END_CODE;
		}
		i = 0;
	}

	if(USART_GetITStatus(USART3, USART_IT_TXE) != RESET)
	{   
		
	}	
}

三、鉴于STM8L没有能让RX和IDLE中断标志同时置位,故采用DMA实现数据拷贝。

       3.1DMA配置:

/**********************************************************************/
//Description:		DmaConfig()														  
//Parameters:    	//0x5231, 为UART数据寄存器地址:USART1_BASE = 0x5230                  												  
//Return:   																  
//Date:           	quanwu.xu  
/**********************************************************************/
void DmaConfig(void)
{
	CLK_PeripheralClockConfig(CLK_Peripheral_DMA1, ENABLE);//打开时钟,很重要	
	/* Deinitialize DMA channels */	
	DMA_GlobalDeInit(); 
	DMA_DeInit(DMA1_Channel1);
	DMA_DeInit(DMA1_Channel2);
	/* DMA channel Rx of USART Configuration */    //该函数主要要配置好接受的数组,以及USART的数据寄存器地址,数组大小,以及DMA模式
	DMA_Init(DMA1_Channel2, (uint16_t)UartApiVar.RxBuffer, UART_DR_ADDRESS,  
	COMM_IF_UART_RX_BUFFER_LENGTH,  DMA_DIR_PeripheralToMemory, DMA_Mode_Normal, 
	DMA_MemoryIncMode_Inc, DMA_Priority_High, DMA_MemoryDataSize_Byte); 

	/* DMA channel Tx of USART Configuration */    //该函数主要配置发送数组,以及USART的数据寄存器地址,数组大小,以及DMA模式
	DMA_Init(DMA1_Channel1, (uint16_t)UartApiVar.TxBuffer, UART_DR_ADDRESS, 
	COMM_IF_UART_TX_BUFFER_LENGTH,  DMA_DIR_MemoryToPeripheral, DMA_Mode_Normal, 
	DMA_MemoryIncMode_Inc, DMA_Priority_Low, DMA_MemoryDataSize_Byte);

	/* Enable the USART Tx/Rx DMA requests */
	USART_DMACmd(USART1, USART_DMAReq_TX, ENABLE);
	USART_DMACmd(USART1, USART_DMAReq_RX, ENABLE); 

	/* Global DMA Enable */
	DMA_GlobalCmd(ENABLE); 

	/* Enable the USART Tx DMA channel */
	DMA_Cmd(DMA1_Channel1, ENABLE);

	/* Enable the USART Rx DMA channel */
	DMA_Cmd(DMA1_Channel2, ENABLE); 
}

       3.2UART配置,只使能IDLE中断

/**********************************************************************/
//Description:		UsartConfig()														  
//Parameters:      												  
//Return:   																  
//Date:           	zhengrong.peng  
/**********************************************************************/
void UsartConfig(void)
{
	USART_DeInit(USART1);

	/* Enable USART clock */  
	CLK_PeripheralClockConfig(CLK_Peripheral_USART1, ENABLE);

	/* USART pin remap */
	SYSCFG_REMAPPinConfig(REMAP_Pin_USART1TxRxPortA, ENABLE);

	/* Configure USART Tx as alternate function push-pull  (software pull up)*/
	GPIO_ExternalPullUpConfig(USART1_Tx_PORT, USART1_Tx_Pin, ENABLE);

	/* Configure USART Rx as alternate function push-pull  (software pull up)*/
	GPIO_ExternalPullUpConfig(USART1_Rx_PORT, USART1_Rx_Pin, ENABLE);

	/* USART configuration */
	USART_Init(USART1, BAUDRATE, USART_WordLength_8b, USART_StopBits_1,
	        								USART_Parity_No, USART_Mode_Rx_and_TX);


	/* Enable the USART Receive interrupt: this interrupt is generated when the USART*/
	//USART_ITConfig(USART1 , USART_IT_RXNE, ENABLE);		
	USART_ITConfig(USART1 , USART_IT_IDLE , ENABLE);		//空闲中断


	//配置ITC 中断管理
	ITC_SetSoftwarePriority(USART1_RX_IRQn, ITC_PriorityLevel_3);

	//start UART
	USART_Cmd(USART1 , ENABLE);							//打开串口

	//解决第一个数据发送失败的问题	
	USART_ClearFlag(USART3 , USART_FLAG_TC);
}

       3.3 UART IDLE中断处理函数

 extern void* Memcpy(void* pDest, void* pSrc, U8 Len); 
INTERRUPT_HANDLER(USART1_RX_TIM5_CC_IRQHandler, 28)
{
	/* In order to detect unexpected events during development,
	 it is recommended to set a breakpoint on the following instruction.
	*/	
	static U8 MessagePos = 0;
	U8 DataLen = 0;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)		//RX interrupt
	{
		
	}
       else if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)	//IDLE interrupt
	{	
		USART1->SR;//先读SR
		USART1->DR;//再读DR	
		DataLen = COMM_IF_UART_RX_BUFFER_LENGTH - 
										DMA_GetCurrDataCounter(DMA1_Channel2);

		if(DataLen < COMM_IF_UART_RX_BUFFER_LENGTH)
		{
			printflog("RxBuffer[0]=%x\n\r", UartApiVar.RxBuffer[0]);	
			Memcpy((void*)&UartApiVar.RxMessage[MessagePos], 
											 (void*)&UartApiVar.RxBuffer, DataLen);
			
			if(++MessagePos == COMM_IF_UART_RX_MSG_NUM)
			{
				MessagePos = 0;
			}
			SystemApiVar.UartWakeupFlag = 1;
		}
		
		DMA_Cmd(DMA1_Channel2, DISABLE);
		DMA_SetCurrDataCounter(DMA1_Channel2, COMM_IF_UART_RX_BUFFER_LENGTH);
		DMA_Cmd(DMA1_Channel2, ENABLE);		
	}	  	
}

     3.4 其他相关定义和函数

/*****************************************************************************/
//uart.h
#define UART_DR_ADDRESS        ((uint16_t)0x5231)		//UART寄存器地址

/*! UART RX Buffer size */
#ifndef COMM_IF_UART_RX_BUFFER
#define COMM_IF_UART_RX_MSG_NUM	    		4
#define COMM_IF_UART_RX_BUFFER_LENGTH	16u
#endif

/*! UART TX Buffer size */
#ifndef COMM_IF_UART_TX_BUFFER
#define COMM_IF_UART_TX_MSG_NUM    		4
#define COMM_IF_UART_TX_BUFFER_LENGTH	16u
#endif

typedef struct _UartApi
{
	U8  RxBuffer[COMM_IF_UART_RX_BUFFER_LENGTH];
	U8  RxMessage[COMM_IF_UART_RX_MSG_NUM][COMM_IF_UART_RX_BUFFER_LENGTH];
	U8  TxBuffer[COMM_IF_UART_RX_BUFFER_LENGTH];	
	U8  TxMessage[COMM_IF_UART_TX_MSG_NUM][COMM_IF_UART_TX_BUFFER_LENGTH];
}UartApi;

/*****************************************************************************/
//定义全局变量
SystemApi SystemApiVar;


/*****************************************************************************/
//Mempcy函数原型

/**********************************************************************/
//Description:	Memcpy()															  
//Parameters:                        												  
//Return:   																  
//Date:           quanwu.xu  
/**********************************************************************/
void* Memcpy(void* pDest, const void* pSrc, U8 Len)
{
	char* Des = (char*)pDest;
	char* Src = (char*)pSrc;
	
	if (Des == NULL ||Src == NULL)
	{
		return NULL;
	}

	while(Len--)
	{
		*Des++ = *Src++;    // *(char *)pDest++ = *(char *)pSrc++ , IAR编译异常
	}

	return pDest;
}

猜你喜欢

转载自blog.csdn.net/xqw19891201/article/details/83864678
今日推荐