0%

9-4串口收发HEX数据包&串口收发文本数据包

HEX数据包

HEX数据包
固定包长,含包头包尾:每个数据包的长度固定不变,前面是包头,后面是包尾
可变包头,含包头包尾:每个数据包的长度可以不一样,前面是包头,后面是包尾

固定包头这里规定,每组4个字节,在这4个字节之前,加上定义的包头0xFF,后面加上定义的包尾0xFE

另外,还可以不要包尾,只使用一个包头FF,接收到包头FF后,开始接收,收够4个字节之后,置标志位,一个数据包接收完成。

如果传输的数据本身就是FF和FE怎么办呢?

限制载荷数据的范围,在发送时进行限幅;
或者使用固定长度的数据包,可以通过包头包尾对其数据,哪个数据是包头,哪个数据是包尾,哪个数据是载荷数据,在接收载荷数据时,不会判断这个数据是否为包头或包尾;
或者增加包头包尾的数量,让它尽量呈现出载荷数据出现不了的状态

如果载荷不会和包头包尾重复,可以选择可变包长

数据长度可以任意改变,因为包头和包尾都是唯一的,出现包头,就接收,出现包尾,就停止接收。

文本数据包

文本数据包
在文本数据包中,数据经过了一次编码和译码,表现出来的文本格式。
由于数据译码成了字符形式,就可以有大量的字符作为包头和包尾,可以有效避免载荷和包头包尾重复的问题。

HEX数据包接收

HEX数据包接收
对于数据包来说,接收具有前后的关联性,包头->数据->包尾,对于这三种状态,需要不同的处理逻辑,即状态机
对于接收数据,可以定义为三个状态。等待包头,然后接收数据,最后等待包尾,每个状态用一个变量来标志一下。

文本数据包接收

文本数据包接收

串口收发HEX数据包

Serial.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

uint8_t Serial_TxPacket[4];//发数组
uint8_t Serial_RxPacket[4];//收数组
uint8_t Serial_RxFlag;//收到标志位



void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开启USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的时钟

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//引脚模式,TX是USART外设控制的输出脚,选择复用推挽输出;RX引脚是USART外设控制的输入脚,选择输入模式,一般RX配置为浮空输入或者上拉输入。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//RX配置为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;//波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送模式
USART_InitStructure.USART_Parity = USART_Parity_No;//校验位,选择不需要校验
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长,由于前面没有选择校验,这里选8位
USART_Init(USART1,&USART_InitStructure);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启RXNE标志位到NVIC的输出
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART1,ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );//获取标志位,发送寄存器空标志位,避免产生数据覆盖的问题

}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i=0;i<Length;i++)
{
Serial_SendByte(Array[i]);
}
}

void Serial_SendString(char *String)
{
uint8_t i;
for ( i = 0; String[i] != '\0'; i++ )
{
Serial_SendByte(String[i]);
}
}

uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}


void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for ( i = 0; i<Length; i++ )
{
Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
}
}

int fputc(int ch, FILE *f)//printf 输出到串口
{
Serial_SendByte(ch);
return ch;
}

void Serial_Printf(char *format, ... )
{
char String[100];
va_list arg;
va_start(arg,format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}

void Serial_SendPacket(void)//发送数据包
{
Serial_SendByte(0xFF);//发送包头
Serial_SendArray(Serial_TxPacket,4);//发送数据包内容
Serial_SendByte(0xFE);//发送包尾
}

uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}

void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t PRxPacket = 0;
if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)
{
//三种状态
uint8_t RxData = USART_ReceiveData(USART1);//获取当前接收到的数据
if(RxState == 0)
{
if(RxData == 0xFF)//接收到包头
{
RxState = 1;//进入下一步,开始接收有效载荷
}
}
else if(RxState == 1)
{
Serial_RxPacket[PRxPacket] = RxData;//接收一个数据
PRxPacket++;//存的位置自增
if(PRxPacket >= 4)//4组数据全部记录完
{
RxState = 2;//进入下一步,等待包尾
PRxPacket = 0;//记录的位置清0,为下一次准备
}
}
else if(RxState == 2)
{
if(RxData == 0xFE)//接收到包尾
{
RxState = 0;//回到最初状态,一个数据包接收完成
Serial_RxFlag = 1;//接收完成标志位置1
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "Key.h"

uint8_t KeyNum;

int main(void)
{
OLED_Init();
KEY_Init();
Serial_Init();

OLED_ShowString(1,1,"TxPacket:");
OLED_ShowString(3,1,"RxPacket:");
//给数组一个初值
Serial_TxPacket[0] = 0x01;
Serial_TxPacket[1] = 0x02;
Serial_TxPacket[2] = 0x03;
Serial_TxPacket[3] = 0x04;

while (1)
{

KeyNum = Key_GetNum();
if (KeyNum == 1)//按钮按下
{
Serial_TxPacket[0] ++;//发数组的值自增1
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);
}
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);
}
}
}

串口收发文本数据包

Serial.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>

char Serial_RxPacket[100];
uint8_t Serial_RxFlag;



void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开启USART1的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启GPIOA的时钟

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//引脚模式,TX是USART外设控制的输出脚,选择复用推挽输出;RX引脚是USART外设控制的输入脚,选择输入模式,一般RX配置为浮空输入或者上拉输入。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//RX配置为浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600;//波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//发送模式
USART_InitStructure.USART_Parity = USART_Parity_No;//校验位,选择不需要校验
USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长,由于前面没有选择校验,这里选8位
USART_Init(USART1,&USART_InitStructure);

USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//开启RXNE标志位到NVIC的输出
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);

USART_Cmd(USART1,ENABLE);
}

void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART1, Byte);
while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );//获取标志位,发送寄存器空标志位,避免产生数据覆盖的问题

}

void Serial_SendArray(uint8_t *Array, uint16_t Length)
{
uint16_t i;
for (i=0;i<Length;i++)
{
Serial_SendByte(Array[i]);
}
}

void Serial_SendString(char *String)
{
uint8_t i;
for ( i = 0; String[i] != '\0'; i++ )
{
Serial_SendByte(String[i]);
}
}

uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}


void Serial_SendNumber(uint32_t Number, uint8_t Length)
{
uint8_t i;
for ( i = 0; i<Length; i++ )
{
Serial_SendByte(Number / Serial_Pow(10,Length - i - 1) % 10 + '0');
}
}

int fputc(int ch, FILE *f)//printf 输出到串口
{
Serial_SendByte(ch);
return ch;
}

void Serial_Printf(char *format, ... )
{
char String[100];
va_list arg;
va_start(arg,format);
vsprintf(String, format, arg);
va_end(arg);
Serial_SendString(String);
}




void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;
static uint8_t PRxPacket = 0;
if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)
{
//三种状态
uint8_t RxData = USART_ReceiveData(USART1);//获取当前接收到的数据
if(RxState == 0)
{
if(RxData == '@' && Serial_RxFlag == 0)//接收到包头
{
RxState = 1;//进入下一步,开始接收有效载荷
PRxPacket = 0;//计数器清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;//回到最初状态,一个数据包接收完成
Serial_RxPacket[PRxPacket] = '\0';
Serial_RxFlag = 1;//接收完成标志位置1
}
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include <string.h>

int main(void)
{
OLED_Init();
LED_Init();
Serial_Init();

OLED_ShowString(1,1,"TxPacket:");
OLED_ShowString(3,1,"RxPacket:");



while (1)
{
if(Serial_RxFlag==1)
{
OLED_ShowString(4,1," ");
OLED_ShowString(4,1,Serial_RxPacket);

if(strcmp(Serial_RxPacket,"LED_ON") == 0)
{
LED1_ON();
Serial_SendString("LED_ON_OK");
OLED_ShowString(4,1," ");
OLED_ShowString(4,1,"LED_ON_OK");
}
else if(strcmp(Serial_RxPacket,"LED_OFF") == 0)
{
LED1_OFF();
Serial_SendString("LED_OFF_OK");
OLED_ShowString(4,1," ");
OLED_ShowString(4,1,"LED_OFF_OK");
}
else
{
Serial_SendString("ERROR");
OLED_ShowString(4,1," ");
OLED_ShowString(4,1,"ERROR");
}
Serial_RxFlag = 0;
}
}
}