STM32 HAL库串口收发数据

许多传感器的使用方法是:单片机给传感器发送一帧数据,然后传感器返回单片机一帧有用数据,所以串口的收发功能十分重要。

STM32cubeMX的配置

时钟和下载方式就不讲了
串口配置,因为要接收数据,所以通常打开串口中断
在这里插入图片描述
注意要选到模块需要的波特率,数据位,校验位,停止位,很多模块的波特率是9600,不是我们常用的115200不一样。
打开中断:
在这里插入图片描述
串口配置就这些

串口发送

发送函数:

HAL_UART_Transmit_IT(&huart1, (uint8_t *)CO2AskBuffer, sizeof(CO2AskBuffer));

其中第一个参数是串口号,第二个参数是要发送的数据起始地址,第三个是要发送的数据长度,一般都用sizeof函数专业一点。
把要发送的数据放在一个数组里:

uint8_t  CO2AskBuffer[9]={0xFF,0x01,0x03,0x02,0x00,0x00,0x00,0x00,0xFB};
串口接收

首先需要打开中断,通常是在单片机发送完指令后开中断:

uint8_t  RecieveBuffer[1]={0};//暂存接收到的字符
HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);

不定长接收:

uint8_t  CO2Buffer[12];//收到的数据存放处
uint8_t  RxLine=0; //记录接收数据长度
uint8_t errorBuffer[]="\r\nerror\r\n"; //错误提示
/**
 * @brief 不定长数据接收
 * @param  串口号
 * @retval void
 * @author smart_mode
 * @Time 2021年11月21日
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	UNUSED(huart);
	RxLine++;
	CO2Buffer[RxLine-1]=RecieveBuffer[0];
	if (RxLine>12) //根据自己的需要修改,当数据接收超多多少位就错了
	{
		RxLine=0;
		memset(CO2Buffer,0,sizeof(CO2Buffer)); 
		HAL_UART_Transmit_IT(&huart1, (uint8_t *)errorBuffer,sizeof(errorBuffer));
	}
	if (RecieveBuffer[0]==0x0A)  //数据最后一字节,根据实际情况修改
	{
		HAL_UART_Transmit_IT(&huart1, (uint8_t *)CO2Buffer,RxLine);  //如果接收到的数据都对,就将数据发送出去
		RxLine=0;	
	}

	RecieveBuffer[0]=0;
	HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);
	//一定记得再次打开中断
}
数据帧的检验和处理

我们可能需要判断传感器发送来的数据是否是正确的,也可能需要对数据帧的某几个字节做处理,这种情况可以用状态机的写法:

uint8_t  NH3Buffer[10]; //存放模块返回的数据 16进制
uint8_t  RxLine=0; //接收到的数据长度
uint8_t  RecieveBuffer[1]={0};//临时存放数据
uint8_t  gaozijie;  //有用数据高字节
uint8_t  dizijie;   //有用数低字节
uint16_t  NH3concentration;
double  NH3Dec;   //十进制的NH3浓度
uint8_t errorBuffer[]="\r\nerror\r\n";
extern uint8_t flag;
/**
 * @brief 接收回调:保存数据并处理
 * @param  串口号
 * @retval void
 * @author smart_mode
 * @Time 2021年11月21日
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	UNUSED(huart);
	RxLine++;  //接收到的数据加一
	NH3Buffer[RxLine-1]=RecieveBuffer[0];  //保存收到的正确数据
//判断帧头是否正确,只要某一位错了,就重新等待正确的第一位数据
	if (RxLine==1)
	{
		if(RecieveBuffer[0]==0xFF)
		{
			RxLine=1;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==2)
	{
		if(RecieveBuffer[0]==0x01)
		{
			RxLine=2;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==3)
	{
		if(RecieveBuffer[0]==0x07)
		{
			RxLine=3;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==4)
	{
		if(RecieveBuffer[0]==0x02)  //分辨率0.01
		{
			RxLine=4;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==5)
	{
		gaozijie=RecieveBuffer[0];  //保存有用数据高字节
	}
	else if(RxLine==6)
	{
		dizijie=RecieveBuffer[0];   //保存有用数据低字节
		//16进制转换10进制,并缩小100倍
		NH3Dec=gaozijie*256+dizijie*1;
		NH3Dec=NH3Dec*0.01;     
	}
	else if(RxLine==7)
	{
		if(RecieveBuffer[0]==0x00) 
		{
			RxLine=7;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==8)
	{
		if(RecieveBuffer[0]==0x00)  
		{
			RxLine=8;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==9)
	{
		if(RecieveBuffer[0]==0x00)  
		{
			RxLine=9;
		}
		else
		{
			RxLine=0;
		}	
	}
	else if(RxLine==10&flag==0)
	{
		printf("%.2f ppm",NH3Dec);  
		flag=1;
		RxLine=0;	
	}
	else 
	{
		flag=1;
		RxLine=0;	
	}
	
	RecieveBuffer[0]=0;
	HAL_UART_Receive_IT(&huart1, (uint8_t *)RecieveBuffer, 1);
}

接收到的数据存在buff数组里是一个字符串,有时候我们想把它赋给一个变量
把buff一位一位直接打印出来是ascii码,1对应49,2对应50这样
printf(“%d”,rx_data[0]) 这样输出是ascii码
转换代码:将字符串中的数字字符转换成十进制整数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	rx_data[rx_cnt] = rx_bit;
	rx_cnt=rx_cnt+1;
	if (rx_data[rx_cnt-1] == 0x0A  && rx_data[rx_cnt-2] == 0x0D)
	{
		printf("接收到的数据为:\r\n");
		HAL_UART_Transmit(&huart1, (uint8_t *)&rx_data, sizeof(rx_data),0xFFFF); 
		printf("\r\n");
		arr_set = 0;
		for(rx_cnt=0;rx_data[rx_cnt]!='\0';rx_cnt++)//循环条件:rx_data[rx_cnt]!='\0'
	  {if(rx_data[rx_cnt]>='0'&&rx_data[rx_cnt]<='9')//判断数字字符 
	    arr_set=arr_set*10+rx_data[rx_cnt]-'0'; //转换成数字
		}
	//number*10是进位,s[i]-'0'其中s[i]是字符型,'0'也是字符型,两个相减其实就是ASCII码相减,得到数字。
		printf("arr_set=%lu \r\n",arr_set);
		rx_cnt =0;
		memset(rx_data,0x00,sizeof(rx_data));
	}

	 HAL_UART_Receive_IT(&huart1, (uint8_t *)&rx_bit, 1);
}
**CO2和NH3和HCHO(二氧化碳和氨气和甲醛)的检测代码已上传我的资源,需要可自行下载**
PS 二氧化碳是环境中有的气体,比较容易检测。空气中的氨气几乎没有,得去卫生间这种地方收集,可以用排水集气法。甲醛可以去新装修的房子里收集,如果没有这个条件可以使用酒精棉,一些酒精棉里面有甲醛。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐