基于HAL库的STM32串口中断接收16进制数据

最近,要弄Lora组网,采集温湿度通过网关和ESP8266数据上传服务器,Lora的库采用hal编写,因此要改用Hal库编写程序。ESP8266的串口中断是基于标准库编写的,因此,要把标准库的转为Hal库。
  参考了网上的一些文献。
  Hal库的串口函数共有3类:阻塞式、中断、DMA,中断函数后缀带IT,DMA后缀带DMA。

阻塞式
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
中断
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
DMA
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

其中,阻塞式具有会超时的变量,例如,发送5个字节,如果一个字节发送需要5ms(假设),如果超时设置为20ms,那么只能发送4给字节,后续的字节就不发送了,通信就不正常了,而且是阻塞式的发送,只有发送完成了,才能执行后续的代码。所以通常只能用于数据量比较少的地方。
通常可以把时间设置的长一些。例如0xffff,1000,10000等!

HAL_UART_Receive_IT和HAL_UART_Transmit_DMA两个函数,而且发送完成有中断的功能。

  找了一个正点原子的模板。
  (1)定义变量 
   #define RXBUFFERSIZE 1
   #define USART_REC_LEN 200

   uint8_t Count=0;  //定义计数变量,接收数据的数量
   uint8_t aRxBuffer[RXBUFFERSIZE];//HAL库使用的串口接收缓冲
   UART_HandleTypeDef UART1_Handler; //UART句柄
   uint8_t USART1_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.

这几个变量在.h文件中,添加extern 再定义一次,方便在其他函数中使用头文件。
(2)串口通信参数设定

//bound:波特率
void uart_init(u32 bound)
{	
	//UART 初始化设置
	UART1_Handler.Instance=USART1;					    //USART1
	UART1_Handler.Init.BaudRate=bound;				    //波特率
	UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;   //字长为8位数据格式
	UART1_Handler.Init.StopBits=UART_STOPBITS_1;	    //一个停止位
	UART1_Handler.Init.Parity=UART_PARITY_NONE;		    //无奇偶校验位
	UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控
	UART1_Handler.Init.Mode=UART_MODE_TX_RX;		    //收发模式
	HAL_UART_Init(&UART1_Handler);					    //HAL_UART_Init()会使能UART1
	
  HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, 1);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量

}

(3)初始化IO 串口1 ,选择串口1

void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    //GPIO端口设置
	GPIO_InitTypeDef GPIO_Initure;
	
	if(huart->Instance==USART1)//如果是串口1,进行串口1 MSP初始化
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
		__HAL_RCC_USART1_CLK_ENABLE();			//使能USART1时钟
		__HAL_RCC_AFIO_CLK_ENABLE();
	
		GPIO_Initure.Pin=GPIO_PIN_9;			//PA9
		GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
		GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
		GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA9

		GPIO_Initure.Pin=GPIO_PIN_10;			//PA10
		GPIO_Initure.Mode=GPIO_MODE_AF_INPUT;	//模式要设置为复用输入模式!	
    GPIO_Initure.Pull = GPIO_NOPULL;
		HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化PA10
		
//#if EN_USART1_RX
		HAL_NVIC_EnableIRQ(USART1_IRQn);				//使能USART1中断通道
		HAL_NVIC_SetPriority(USART1_IRQn,3,3);			//抢占优先级3,子优先级3
//#endif	
	}
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)

{


if(huart->Instance==USART1)

{
//	GPIO_InitTypeDef GPIO_Initure;

//DEBUG_USART_RCC_CLK_DISABLE();
		__HAL_RCC_USART1_CLK_DISABLE();			//使不能USART1时钟

/**USART1 GPIO Configuration    
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

		HAL_NVIC_DisableIRQ(USART1_IRQn);

}

else if(huart->Instance==USART2)

 {

		__HAL_RCC_USART2_CLK_DISABLE();			//使不能USART1时钟

    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);

		HAL_NVIC_DisableIRQ(USART2_IRQn);

 }

}

(4)重写串口接收中断回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef*UartHandle)
{
	if(huart->Instance==USART1)//如果是串口1
	{
		Count++;
	  USART1_RX_BUF[Count-1]=aRxBuffer[0];	
      if(aRxBuffer[0]==0x02)    //一帧数据的最后一个字节,接收结束标志位,定协议的时候,可以定义字尾
      
     {
        printf("Count=%d\r\n",Count); 
        for(int i=0;i<Count;i++){
        printf("USART1_RX_BUF[%d] = 0x%x\r\n",i,USART1_RX_BUF[i]); 
				}
		HAL_UART_Transmit(&UART1_Handler, (uint8_t*)USART1_RX_BUF,8,100); //接收完了,再发送出去
        memset(USART1_RX_BUF,0,sizeof(USART1_RX_BUF));  //清空缓存数组
        Count=0;  //清空接收长度
      }	
 	  HAL_UART_Receive_IT(&UART1_Handler,(uint8_t *)aRxBuffer,1);//接收完了一帧数据,再打开
	//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
  	}
  	if(huart->Instance==USART2)//如果是串口1
	{
	……
	}
}

(5)串口1中断服务程序

void USART1_IRQHandler(void)                	
{ 
	u32 timeout=0;
#if SYSTEM_SUPPORT_OS	 	//使用OS
	OSIntEnter();    
#endif
	//	u8 Res;

	HAL_UART_IRQHandler(&UART1_Handler);	//调用HAL库中断处理公用函数
	
#if SYSTEM_SUPPORT_OS	 	//使用OS
	OSIntExit();  											 
#endif
} 

主函数

采集了DHT12的温湿度。
extern float  Temprature,Humi;//定义温湿度变量 ,此变量为全局变量

int main(void)
{
    int i;
    char temp[10] = {0};
    char humi[10] = {0};
    u8 len;	
    u16 times=0;
u8 UART_BUF[14] = "you press K  !";
u8 key;
    
    HAL_Init();                    	 	//初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72M
    delay_init(72);               		//初始化延时函数
    uart_init(115200);					//初始化串口
    LED_Init();							//初始化LED	
    KEY_Init();							//初始化按键
    OLED_Init();
    sensor_iic_init();

    //	 OLED_ShowString(0,0,"GoodLuck",24); 
    
    for(i=0;i<8;i++)
    {
        OLED_ShowFontHZ(16*i,0,i,16,1);
    }		
    
    OLED_ShowString(0,24, "Temp:",16);
    OLED_ShowString(85,24,"^C",16); 
    OLED_ShowString(0,40,"Humi:",16);  
    OLED_ShowString(85,40,"%RH",16); 
    OLED_Refresh_Gram();
    while(1)
    {
        key = KEY_Scan(0);
//			  printf("Press key: %d",key);
        switch(key)
        {
        case KEY1_PRES: UART_BUF[11] = '1';  
					     break;
        case KEY2_PRES: UART_BUF[11] = '2'; break;
            //     case KEY3_PRES: UART_BUF[11] = '3'; break;
            //     case KEY4_PRES: UART_BUF[11] = '4';  break;
        default: break;    
        }    
        if(key)
        {
            LED0=!LED0;
					  printf("return value is %d! \r\n",key);
            HAL_UART_Transmit(&UART1_Handler,UART_BUF,14,0xffff);   
            
        }
    
        sensor_read();
        
        sprintf(temp, "%0.1f", Temprature); //输出:" 3.142"
        sprintf(humi, "%0.1f", Humi); //输出:" 3.142"	
        
        OLED_ShowString(48,24,temp,16); 
        OLED_ShowString(48,40,humi,16); 
        
        OLED_Refresh_Gram();
        
        delay_ms(2000);   
        
    }
}

参考了这个https://www.cnblogs.com/xingboy/p/12457154.html。
但这个里边,

RxBuff[0]=0;// 这句不应该存在,如果有这一句,收到的第一个被0替代了。
    UHAL_UART_Receive_IT(&huart1, (uint8_t *)RxBuff, 1); //每接收一个数据,就打开一次串口中断接收,否则只会接收一个数据就停止接收

此外,这个程序还有一个问题,就是定协议的时候,就得定义字尾了!如果想常规定义如 55 AA ……,由于字尾不定,所以,不好判断什么时候完事了。只能把……,AA 55 放在数据帧最后。
因此可以考虑结合IDLE进行程序编写,这样就可以按55 AA……定义数据帧了。

下一步可以修改ESP8266连接的串口2的中断程序了。

下载地址:https://download.csdn.net/download/petertang1975/86481973

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值