19、江科大stm32视频学习笔记——USART串口数据包

目录

一、发送HEX数据包

1、固定包长,含包头包尾(包尾不是必须的)

2、可变包长,含包头包尾 

二、接收HEX数据包

三、发送文本数据包

四、接收文本数据包

五、HEX数据包和文本数据包的比较

六、串口收发HEX数据包&串口收发文本数据包

1、串口发送HEX数据包

(1)Serial.c

(2)主函数中添加

(3)Serial.h

2、串口发送HEX数据包 

  (1) Serial.c 

(2)主函数显示发送数据

(3)主函数添加key

3、串口收发文本数据包

(1) Serial.c 

七、静态变量

一、发送HEX数据包

1、固定包长,含包头包尾(包尾不是必须的)

2、可变包长,含包头包尾 

 1、包头包围和数据载荷重复的问题,传输的数据本身是FF和FE,可能引起误判
解决:限制载荷数据的范围,限幅(例如只发送0~100)
          如果无法避免数据于包头包尾重复,则尽量使用固定长度的数据包
          增加包头包尾的数量,尽量是其呈现出载荷数据出现不了的状态
2、包头包尾并不是全部都需要的,例如可以只要一个包头
3、固定包长和可变包长的选择问题
(1)对HEX来说,若载荷出现和包头包尾重复的情况,最好选择固定包长,避免接受错误
(2)若不重复,可以选择可变包长
4、各种数据转化为数据流的问题
数据包都是一个字节一个字节组成的,若想发送16位整型数据、32位整型数据,float、double、甚至是结构体(其内部都是由一个字节一个字节组成的),只需要用一个uint8_t的指针指向它,把数据当作字节数组发送即可

二、接收HEX数据包

 每收到一个字节,函数都会进入一次中断,在中断函数中,可以拿到一个字节,但拿到字节之后,就得退出中断,故每拿到一个数据,都是一个独立的过程,而对数据包来说,有数据、包头、包尾三种状态,根据状态不同处理也不同

使用状态机收数据如上图

 三、发送文本数据包

四、接收文本数据包

五、HEX数据包和文本数据包的比较

(1)在hex数据包中,数据都是以原始的字节数据本身呈现的

(2)在文本数据包中,每个字节就经过一层编码和译码,最终表现出文本格式(文本背后还是一个字节的HEX数据) 

(3)hex数据包:传输直接、解析数据简单,适合一些模块发送原始的数据,比如一些使用串口通信的陀螺仪、温湿度传感器,但是灵活性不足、载荷容易和包头包尾重复

(4)文本数据包:数据直观易理解、灵活,适合一些输入指令进行人机交互,但解析效率低.

(5)发送100,hex直接发送一个字节100,而文本发送三个字节'1','0'.'0',收到之后还要把字符转换程数据,才能得到100。

六、串口收发HEX数据包&串口收发文本数据包

1、串口发送HEX数据包

(1)Serial.c

将uint8_t Serial_GetRxData(void)替换成void Serial_SendPacket(void)

uint8_t Serial_TxPacket[4];  

void Serial_SendPacket(void)
{
	Serial_SendByte(0xFF);
	Serial_SendArray(Serial_TxPacket, 4);
	Serial_SendByte(0xFE);
}

(2)主函数中添加

	Serial_TxPacket[0] = 0x01;
	Serial_TxPacket[1] = 0x02;
	Serial_TxPacket[2] = 0x03;
	Serial_TxPacket[3] = 0x04;
	
	Serial_SendPacket();

 将程序下载到开发板中,按下复位键盘,在串口调试助手中显示FF 01 02 03 04 FE

(3)Serial.h

extern uint8_t Serial_TxPacket[];

2、串口发送HEX数据包 

(1) Serial.c 

在接收中断函数中,需要用状态机来执行接收逻辑,接收数据包,然后把载荷数据存在RxPacket数组里

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == 0xFF)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			Serial_RxPacket[pRxPacket] = RxData;
			pRxPacket ++;
			if (pRxPacket >= 4)
			{
				RxState = 2;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == 0xFE)
			{
				RxState = 0;
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

(2)主函数显示发送数据

将单片机接收到的数据(即串口调试助手发送的数据)显示在OLED显示屏上

if (Serial_GetRxFlag() == 1)//接收到了数据包
		{
		    //接收到的数据放在第四行
			OLED_ShowHexNum(4, 1, Serial_RxPacket[0], 2);
			OLED_ShowHexNum(4, 4, Serial_RxPacket[1], 2);
			OLED_ShowHexNum(4, 7, Serial_RxPacket[2], 2);
			OLED_ShowHexNum(4, 10, Serial_RxPacket[3], 2);
		}

(3)主函数添加key

添加了key按键,将数据发送出去的数据显示在OLED,按一次健,发送数据都+1

		KeyNum = Key_GetNum();
		if (KeyNum == 1)
		{
			Serial_TxPacket[0] ++;
			Serial_TxPacket[1] ++;
			Serial_TxPacket[2] ++;
			Serial_TxPacket[3] ++;
			
			Serial_SendPacket();
			
			OLED_ShowHexNum(2, 1, Serial_TxPacket[0], 2);
			OLED_ShowHexNum(2, 4, Serial_TxPacket[1], 2);
			OLED_ShowHexNum(2, 7, Serial_TxPacket[2], 2);
			OLED_ShowHexNum(2, 10, Serial_TxPacket[3], 2);
		}

3、串口收发文本数据包

(1) Serial.c 

char Serial_RxPacket[100];

void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == '@' && Serial_RxFlag == 0)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			if (RxData == '\r')
			{
				RxState = 2;
			}
			else
			{
				Serial_RxPacket[pRxPacket] = RxData;
				pRxPacket ++;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == '\n')
			{
				RxState = 0;

把读取标志位然后立即清0的函数删掉,在主函数中,判断Serial_RxFlag == 1,表示接收到数据包,等操作完成之后,再清0,在中断函数中,只有Flag=0了,才会继续接收到下一个数据包。这样数据的读写就是严格分开,不会混淆,但是这样发送数据包的频率不能太快,否则会被丢弃。或者定义一个指令缓存区,把接受好的字符串放在这个指令缓存区进行排队

七、静态变量

函数进入只会初始化一次0,在函数退出后,数据仍然有效,与全局变量不同的是,静态变量只能在本函数使用。

  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值