一、串口的基本概念
- 【数据组成】串口的通讯协议由开始位,数据位,校验位,结束位构成。
- 【数据结构】一般以一个低电平作为一帧数据的起始,接着跟随 8 位或者 9 位数据位,之后为校验位,分为奇校验,偶校验和无校验,最后以一个先高后低的脉冲表示结束位,长度可以设置为 0.5,1,1.5 或 2 位长度。
- 【奇偶校验原理】统计发送数据中高电平即’1’的奇偶,将结果记录在奇偶校验位中发送给接收方,接收方收到奇偶校验位后和自己收到的数据进行对比,如果奇偶性一致就接受这帧数据,否则认为这帧数据出错。
如下图所示:一个 8 位数据位,1 位奇偶校验位,1 位结束位的串口数据帧。
上图的解释如下:
注意事项:
- 一般进行串口通讯时,收发双方要保证遵守同样的协议才能正确的完成收发,除了协议要一致之外,还有一个非常重要的要素要保持一致,那就是通讯的速率,即波特率。
- 波特率是指发送数据的速率,单位为波特每秒,一般串口常用的波特率有 115200,38400,9600 等。
- 串口的波特率和总线时钟周期(clock)成倒数关系,即总线时钟周期越短,单位时间内发送的码元数量越多,串口波特率就越高。
二、使用 STM32 标准库 实现任意长度数据的收发
示例程序功能说明:首先,通过串口一实现对任意长度数据的接收,接收到数据之后,将其存放到一个数组当中,方便后续调用;其次将STM32接收到的数据通过串口一发送出去。核心程序如下:(完整版程序详见文末链接)
// 串口发送部分核心代码如下:
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
// USART_SendData(USART1, 0x11);
// while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
while(1)
{
if(receive_flag == 1) //串口接收完成标志位
{
for(int i=0;i<8;i++)
{
USART_SendData(USART1, Receive_Data[i]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
receive_flag = 0; //一帧数据发送完毕之后,标志位置0
}
}
}
// 串口接收部分核心代码如下:
void USART1_IRQHandler(void)
{
static u8 Count=0; //定义计数静态变量
u8 Usart_Receive; //定义中间传递变量
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判断是否接收到数据
{
Usart_Receive = USART_ReceiveData(USART1); //读取数据
if(receive_flag == 0)
{
//串口数据填入数组
Receive_Data[Count]=Usart_Receive;
//确保数组第一个数据为FRAME_HEADER(帧头)
if(Usart_Receive == FRAME_HEADER||Count>0)
Count++;
else
Count=0;
if (Count == 8) //验证数据包的长度
{
Count=0; //为串口数据重新填入数组做准备
if(Receive_Data[7] == FRAME_TAIL) //验证数据包的帧尾
{
//接收到完整的一帧数据之后,在这里面进行处理
receive_flag = 1;
}
}
}
}
}
程序关键:
- 通过微小调整,可以实现任意长度数据的收发,方便使用;
- 串口接收鲁棒性高,采用校验帧头、帧尾以及数据长度的方式,确保接收数据的稳定性。
STM32 标准库 串口收发实验展示(实验中,帧头设置为0x01,帧尾设置为0x02,数据长度为8个字节)
【实验结论】如上图所示,发送端的数据,接收端会完好收到。下面进行干扰性测试:
【实验结论】如上图所示,在引入帧头、帧尾以及长度校验后,程序的抗干扰能力较强。
三、使用 STM32 HAL库 实现任意长度数据的收发
HAL库程序使用CUBE MX生成
// 串口发送部分核心代码如下:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
//__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
HAL_UART_Receive_IT(&huart1,(uint8_t *)Usart_Receive,1); //这句话极为重要
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(receive_flag == 1)
{
HAL_UART_Transmit(&huart1,Receive_Data,8,100);
receive_flag = 0;
}
}
/* USER CODE END 3 */
}
// 串口接收部分核心代码如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
static uint8_t Count=0; //定义计数静态变量
if(huart->Instance==USART1)
{
HAL_UART_Receive_IT(&huart1,(uint8_t *)Usart_Receive,1);
if(receive_flag == 0)
{
//串口数据填入数组
Receive_Data[Count]=Usart_Receive[0];
//确保数组第一个数据为FRAME_HEADER(帧头)
if(Usart_Receive[0] == FRAME_HEADER||Count>0)
Count++;
else
Count=0;
if (Count == 8) //验证数据包的长度
{
Count=0; //为串口数据重新填入数组做准备
if(Receive_Data[7] == FRAME_TAIL) //验证数据包的帧尾
{
//接收到完整的一帧数据之后,在这里面进行处理
receive_flag = 1;
}
}
}
}
}
STM32 HAL库 串口收发实验展示(实验中,帧头设置为0x01,帧尾设置为0x02,数据长度为8个字节)
四、相关程序及总结
1.上述代码已开源,开源链接:
https://e.coding.net/ehangtest01/stm32_explore/STM32_Explore.git文章来源:https://www.toymoban.com/news/detail-621339.html
文件夹内容如下:
2.不管是使用标准库还是HAL库,都需要对数据进行校验,这样才能保证数据传输的稳定性。文章来源地址https://www.toymoban.com/news/detail-621339.html
到了这里,关于【STM32通讯系列--串口通讯】使用标准库、HAL库实现任意长度数据的收发(包含帧头、帧尾校验,配套完整开源程序)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!