STM32串口通信详细解答


数据帧结构


在这里插入图片描述
帧头:数据传输的开始标志,一般是判断两次,如果两次都判断正确再继续接受数据,如果判断错误则重新开始接受数据
字节长度:数据字节长度,除去帧头帧尾和校验位
数据:
功能码:
校验位:所有数据的总和,0XAA+0XAA+0X20+0X01+0X00=0X57
在这里插入图片描述
确定是要发送什么数据,比如要点灯,功能码就表示灯
功能内容:功能码所需要执行/接收的数据
在这里插入图片描述
在这里插入图片描述
通信协议测试代码
自己写的通信协议测试代码,通过串口调试助手发送数据给stm32(串口1)这段代码里没有校验位和数据长度,如果帧头帧尾接收正确,就数据接收正确,开始处理数据,检测校验和只是固定传输某些数据,对于可变数据的传输不检查校验和,检查帧头帧尾就可以。

#define E_START                 0       //准备状态
#define E_OK                    1       //成功
#define E_FRAME_HEADER_ERROR    2       //帧头错误
#define E_FRAME_RTAIL_ERROR     3       //帧尾错误
#define LINE_LEN                4     //数据长度  0--3
#define HEAD_FRAME       				0xD8
#define BACK_FRAME 					0xEE
uint8_t   temp_buff[LINE_LEN];            //主机用于接收数据的BUFF
uint8_t   uart_flag;                      //接收数据标志位
uint8_t   data_n;
void get_slave_data(uint8_t data)  //只管帧头帧尾的数据是否正确,帧尾数据正确之后再处理中间数据
{
    static uint8_t uart_num = 0;
    temp_buff[uart_num++] = data;  
		if(uart_num==1) //接收到的第一个数据  0xD8						
		{
			if(HEAD_FRAME != temp_buff[0])   //帧头错误
				{   		
						RED_ON;					
						uart_flag = E_FRAME_HEADER_ERROR;
					  uart_num=0;//数据位清零
				}				
		}
		else if(uart_num==2)  //接收到的第二个数据
		{
		    	
		}
		else if(uart_num==3)  //接收到的第三个数据
		{
			
		}
		else if(uart_num==4) //接收到的第四个数据 帧尾0xEE
		{ 
			 if(BACK_FRAME==temp_buff[LINE_LEN-1])  //如果帧尾正确
			 {
				 GREEN_ON;
				 uart_flag = E_OK;   //接收标志成功
				 data_n=temp_buff[2]-1;
			 }
			 else  //接收失败
			 {
				 uart_flag = E_FRAME_RTAIL_ERROR;	//帧尾错误	
			 }
			 uart_num=0;
		 }	 
		USART_SendData(DEBUG_USARTx, uart_flag);
}		
 
//数据处理
void data_process(void)
{
		if(uart_flag ==E_OK) //数据接收成功
		{
				if(data_n==2)
				{	
					GREEN_ON;
				}
				else if(data_n==1)
				{
					RED_ON;
				}
			  else BLUE_ON;
	  }
}


// 串口中断服务函数
extern uint8_t  uart_flag; 
extern uint8_t   data_n;
#define E_START              0       //准备状态
#define E_OK                 1       //成功
voidUSART1_IRQHandler(void)
{
  uint8_t ucTemp;
	if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
	{		
		ucTemp = USART_ReceiveData(DEBUG_USARTx);//获取串口数据
//		USART_SendData(DEBUG_USART1x,ucTemp); 
	  get_slave_data(ucTemp);//将每一个串口的数据存入temp_buff中,判断帧头帧尾
	  data_process();   
	}	 
}

串口通信编程要点
1:上位机发送数据时要勾选hex显示,或者是以16进制发送,以16进制接收
因为底层的数据都是以字节流模式传输,数据会被分解成一个一个字节,一个字节是8位,如果选择ASCII传输,那么接收端收到的就是ASCII码,
选择ASCII发送就代表你要发送的是字符串,这时候程序就会一位一位地读,比如你写了1234,在字节流中传递的就是1234对应的ASCII码,31,32,33,34(十六进制的)。比较而言,在Hex发送模式下,写了1234,会被发送的就是12,34,如果是01020304那就是01,02,03,04。这个时候,你写ab就会发送相应的ASCII码61,62,其他字符同理。
选择Hex发送就代表你要发送的内容是纯数字,由程序完成String到Int再到Byte的转化。
所以你应该保证每个你要发送的数都是两位的,如果是7就应该写07,因为程序会每两位每两位地读。如果你选择了Hex发送,而输入的又是字符,比如你写了ab,那么就会被程序读为16进制的AB。这就是不同的概念了,无论你选择什么方式显示都不能得到原来的ab了。
2:配置串口,配置串口的io口的初始化,以及串口的初始化,以及嵌套串口中断NVIC
3: 串口中断处理函数:
在这里插入图片描述
先将收到的数据用一个变量来接收,之后在串口数据处理函数中用一个buf缓存数组来接收处理数据,判断帧尾uart_flag = E_OK必须加,要不然uart_flag
会出错误,一直执行在uart_num ==1 里面
在这里插入图片描述当接收标志位为正确时开始解析数据:
在这里插入图片描述
串口通信从机数据发送:
1:初始化串口
2:将数据封装处理,如果数据时16位的需要分开处理,将高低八位分别发送,接收端合并
3: 通过串口将数据发送出去,
在这里插入图片描述
数据处理:
在这里插入图片描述
stm32f4串口数据接收解析代码:
1:串口初始化配置

void UART1_Init(uint32_t BaudRate)
{ 
   GPIO_InitTypeDef    GPIO_InitStructure;
	 USART_InitTypeDef    USART_InitStructure;
	 NVIC_InitTypeDef    NVIC_InitStructure;
	
	 //开启io口对应时钟
	 RCC_AHB1PeriphClockCmd(UART1_CLK , ENABLE);
	  
	 //开启串口对应时钟
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

	
	 //外围设备的特殊功能
	 GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	 GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
	 //TX RX-- 复用推挽输出
	 GPIO_InitStructure.GPIO_Pin = UART1_PIN_TX | UART1_PIN_RX;
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	 GPIO_Init(UART1_PORT,&GPIO_InitStructure);

	 USART_InitStructure.USART_BaudRate =  BaudRate;
	 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	 USART_InitStructure.USART_StopBits =  USART_StopBits_1;
	 USART_InitStructure.USART_BaudRate =  BaudRate;
	 USART_InitStructure.USART_Parity = USART_Parity_No;
	 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;  //收发一体
	 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	 USART_Init(USART1, &USART_InitStructure);

	 
	 USART_ITConfig(USART1, USART_IT_RXNE,ENABLE); //串口接收中断开启
	
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
	 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
	 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	 NVIC_Init(&NVIC_InitStructure);
	 USART_Cmd(USART1,ENABLE);
}

2:串口接收中断:
在这里插入图片描述
3:串口数据效验

void data_test(int rxdata)
{
  	static int  count = 0;
    TmpData[count++] = rxdata; //数据存入数组
  	if(count == 1) //帧头
		{
				if(TmpData[0] == 0x01) 
				{
						LED0_ON;
					  flag_num = 1;
					  BEEN_OFF;
				}	
				else 
				{
				    BEEN_ON;
				  	flag_num = 0;
				   	count = 0; //重新开始接收
				}
		}
		 if(count == 4) //帧尾
		{
			 flag_num = 4; // 这里必须加!!!!!!!!!!!!!!!!!
			
		    if(TmpData[3] == 0x07) //数据
				{
					 LED3_ON;
					 flag_num == 4;
				}
				else 
				{
				     flag_num = 0;
				   	 count = 0; //重新开始接收
					   BEEN_ON;
				}
				count = 0;
		}
}

4:串口数据处理:
在这里插入图片描述
串口数据发送数据类型问题:
串口数据是一个字节一个字节发送接收的,每一数据帧包含起始位,功能字,数据位,奇偶校验位,停止位。串口数据的发送是一个字节一个字节发送的,也就是串口每次只能发送和接收八位数据,那么如果要发送一些十六进制的数据就需要位操作来实现数据的发送以及合并。
以发送一个十六位数为例:
Data = 65530 这个数据是16位的数据(FFFA),就要拆成两部分发送
Low_Data = Data & 0xFF 取出低八位 Low_Data = FA
High_D = Data >> 8 将数据右移八位,高8位移到低8位 High_D = FF
Low_Data和High_D 都调用数据发送函数发送出去
数据接收
High_D = High_D << 8 将高位数据重新移到高位 FF00
Data_temp = High_D | Low_Data 数据重新合并 FFFA

数据拆分发送
在这里插入图片描述
数据接收合并
在这里插入图片描述
在这里插入图片描述
一些数据发送函数的解读:
数据的发送和接收都离不开USART的DR寄存器,这个寄存器由两个寄存器组成,包含了数据的发送与接收,兼具读和写两个功能
数据发送 USARTx->DR = (Data & (uint16_t)0x01FF);
数据接收 (uint16_t)(USARTx->DR & (uint16_t)0x01FF);

数据是以字节的形式在硬件流中传输 一个字节是8bit
发送一个字节:
在这里插入图片描述
接收一个字节:
在这里插入图片描述
所有的数据发送函数的扩充都是在这两个函数的基础上改进的
发送一个字节封装函数,与标准库功能参数一样。
在这里插入图片描述发送8位的数组,按字节循环发送
在这里插入图片描述
发送字符串,和数组发送类似,按字节循环发送
在这里插入图片描述
发送一个16位数,分别取出高低八位,分别发送
在这里插入图片描述

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!我可以为您解答关于MicroPython ESP32和STM32之间串口通信的问题。 要实现ESP32和STM32串口通信,您可以按照以下步骤进行操作: 1. 首先,确保您的ESP32和STM32设备上都已经安装了MicroPython固件。 2. 在ESP32上,您可以使用UART模块来设置串口通信。首先,导入UART模块: ```python from machine import UART ``` 3. 然后,通过实例化UART类来创建一个串口对象。您需要指定串口的引脚和波特率等参数。例如,假设您使用的是ESP32的UART2引脚和波特率为9600: ```python uart = UART(2, baudrate=9600) ``` 4. 接下来,您可以使用串口对象的`write()`方法向STM32发送数据: ```python uart.write('Hello STM32!') ``` 5. 在STM32上,您需要编写相应的代码来接收ESP32发送的数据。具体的代码取决于您使用的STM32开发板和编程环境。一般来说,您可以使用STM32的UART库来配置和接收数据。例如,使用STM32Cube HAL库: ```c #include "stm32f4xx_hal.h" UART_HandleTypeDef huart2; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { // 处理接收到的数据 // ... } int main(void) { // 初始化STM32串口 HAL_UART_MspInit(&huart2); // 开启接收中断 HAL_UART_Receive_IT(&huart2, rx_data, 1); while (1) { // 主循环代码 // ... } } ``` 请注意,上述代码仅为示例,具体的实现细节可能因您的硬件和需求而异。 希望这些信息对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值