HAL库学习之串口通信_帧头帧尾

目录

一、串口通讯协议简介

一、物理层

1.电平标准

 二、协议层

 1.波特率

2.通讯的启示和停止信号

3.数据校验

三、STM32的串口简介

四、软件实现

1.通过图形化软件CubeMX配置

2.程序实现 

        (1)使用阻塞模式,发送数据

        (2)使用中断模式,接收数据

一、串口通讯协议简介

        串口通讯 (Serial Communication) 是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此
大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试
信息。
        在计算机科学里,大部分复杂的问题都可以通过分层来简化。如芯片被分为内核层和片上外设;
STM32HAL 库则是在寄存器与用户代码之间的软件层。对于通讯协议,我们也以分层的方式来
理解,最基本的是把它分为物理层和协议层。物理层规定通讯系统中具有机械、电子功能部分的
特性,确保原始数据在物理媒体的传输。协议层主要规定通讯逻辑,统一收发双方的数据打包、
解包标准。简单来说物理层规定我们用嘴巴还是用肢体来交流,协议层则规定我们用中文还是英
文来交流。

一、物理层

        串口通讯的物理层有很多标准及变种,我们主要讲解 RS-232 标准, RS-232 标准主要规定了信号 的用途、通讯接口以及信号的电平标准。 使用 RS-232 标准的串口设备间常见的通讯结构见
        在上面的通讯方式中,两个通讯设备的“DB9 接口”之间通过串口信号线建立起连接,串口信号
线中使用“ RS-232 标准”传输数据信号。由于 RS-232 电平标准的信号不能直接被控制器直接识
别,所以这些信号会经过一个“电平转换芯片”转换成控制器能识别的“ TTL 标准”的电平信号,
才能实现通讯。

1.电平标准

根据通讯使用的电平标准不同,串口通讯可分为 TTL 标准及 RS-232 标准,见表 。
表中 为TTL 电平标准与 RS232 电平标准
                              

 二、协议层

        串口通讯的数据包由发送设备通过自身的 TXD 接口传输到接收设备的 RXD 接口。在串口通讯 的协议层中,规定了数据包的内容,它由启始位、主体数据、校验位以及停止位组成,通讯双方的数据包格式要约定一致才能正常收发数据,其组成见图

 1.波特率

        本文章中主要讲解的是串口异步通讯,异步通讯中由于没有时钟信号 ,所以两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信 号进行解码,图 中用虚线分开的每一格就是代表一个码元。常见的波特率为 4800 9600 、 115200 等。

2.通讯的启示和停止信号

        串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑 0 的数据位表示,而数据包的停止信号可由 0.5、1、1.5 或 2 个逻辑 1 的数据位表示,只要双方约定
一致即可。

3.数据校验

        在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输 数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验 (odd) 、偶校验
(even) 0 校验 (space) 1 校验 (mark) 以及无校验 (noparity)。
        奇校验要求有效数据和校验位中“1”的个数为奇数,比如一个 8 位长的有效数据为 01101001 ,此时总共有 4 个“1”,为达到奇校验效果,校验位为“1”,最后传输的数据将是 8 位的有效数据 加上 1 位的校验位总共 9 位。
        
        偶校验与奇校验要求刚好相反,要求帧数据和校验位中“1”的个数为偶数,比如数据帧: 11001010 , 此时数据帧“1”的个数为 4 个,所以偶校验位为“0”。
        
        0 校验是不管有效数据中的内容是什么,校验位总为“0”,1 校验是校验位总为“1”。

三、STM32的串口简介

        在STM32中,串口分USART和UART两种,USART与UART其中最简单的区别是USART有两种通信模式(异步和同步),而UART通信只有异步模式。
        简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。
在STM32中一共有五个串口,如下:

四、软件实现

1.通过图形化软件CubeMX配置

        下面通过配置USART1作为演示,使用的是C8T6最小系统板。

       

   

2.程序实现 

        本次使用到的函数:阻塞模式下的发送函数(HAL_UART_Transmit())中断模式下的接收函数(HAL_UART_Receive_IT())

     

        (1)使用阻塞模式,发送数据

int main(void)
{
  /* USER CODE BEGIN 1 */
    uint8_t Data[] = "HELLO WORLD !\n";
  /* USER CODE END 1 */


  /* USER CODE BEGIN 2 */
  
   //参数1:使用的串口,2:要发送的数据,3:数据大小,4:发送的超时时间
    HAL_UART_Transmit(&huart1,Data,sizeof(Data),1000);
    
  /* USER CODE END 2 */


}

   编译下载程序可在串口助手中看到:

         在使用串口发送数据时,常用 printf() 语句进行发送。而在STM32中使用printf() 语句需要进行printf() 语句的重定向。代码如下:

        在 usart.h 文件中添加

/* USER CODE BEGIN Includes */
#include <stdio.h>

/* USER CODE END Includes */
 

         在 usart.c 文件中添加:

/* USER CODE BEGIN 0 */

int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

/* USER CODE END 0 */

         做完以上步骤后即可实现 printf() 语句的重定向

/* USER CODE BEGIN 2 */
  
   //参数1:使用的串口,2:要发送的数据,3:数据大小,4:发送的超时时间
    HAL_UART_Transmit(&huart1,Data,sizeof(Data),1000);
    
    printf("HELLO STM32 !\n");
    
  /* USER CODE END 2 */

        (2)使用中断模式,接收数据

1.在main函数中添加:

/* USER CODE BEGIN 2 */
  //参数说明, 1:使用的串口,2:接收数据的缓存区,3:接收数据的字节数
  HAL_UART_Receive_IT(&huart1,Rx_Data,3);

2. 调用中断回调函数,将接收到的数据发送出去

        

uint8_t Rx_Data[3];


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if(huart->Instance == USART1)
    {
        HAL_UART_Transmit(&huart1,Rx_Data,sizeof(Rx_Data),100);
        HAL_UART_Receive_IT(&huart1,Rx_Data,3);  //接收结束后需要重新调用该函数,

                                                                                        //不然只能接收一次
    }
}

实验现象如下:

//-----更新-----//

一、如何使用帧头帧尾,处理串口数据

在串口通信过程中,如果需要发送不同的数据表示不同的操作,这就需要对串口数据进行约束,也就是添加帧头帧尾,并且串口数据有时也会出错,不对串口数据进行有效处理,有可能产生误操作。当然想要接受到的串口数据正确性,也不止这一个办法,使用校验和也是其一。下面介绍的使用帧头帧尾是一种较为简单的方法。

废话不多说,直接上程序:

void USART3_IRQHandler(void)

{

    static uint8_t RxState = 0;

    static uint8_t pRxPacket = 0;

    if (USART_GetITStatus(USART3, USART_IT_RXNE) == SET)

    {

        uint8_t RxData = USART_ReceiveData(USART3);

       

        if (RxState == 0)

        {

            if (RxData == 0x2C)

            {

                RxState = 1;

                pRxPacket = 0;

            }

        }

        else if (RxState == 1)

        {

            Serial_Rx[pRxPacket] = RxData;

            pRxPacket ++;

            if (pRxPacket >= 3)

            {

                RxState = 2;

            }

        }

        else if (RxState == 2)

        {

            if (RxData == 0x5B)

            {

                RxState = 0;

                Serial_RxFlag = 1;

            }

        }

       

        USART_ClearITPendingBit(USART3, USART_IT_RXNE);

    }

}

帧头:0X2C

有效数据:date1、date2、date3

帧尾:0X5B

上述代码利用串口中断,每接收1字节串口数据,对其进行判断,当数据符合我们所设定的帧头时,接收后续到数据,接收完所要的数据后,再次判断帧尾也正确时,所接收到的串口数据就是我们想要的数据了。此代码还能再次优化,笔者在这里将这个留给各位读者,发挥自己到能力。代码不关乎平台,锻炼出写代码逻辑思维才是目的。

        当然,此办法很简单,所以适用的场景受限制,适用于已经知道接收数据的长度,发送的是什么数据。除此之外还有很多方法,其一就是利用串口空闲中断,它还可以对不定数据帧进行接收判断。(详见主页文章)

  • 22
    点赞
  • 84
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在使用HAL库进行串口接收处理时,处理是一种常见的方法,以确保接收到的数据是完整的数据。 首先,需要设置一个合适的,它们可以是一个特定的字节或者是一个特定的字节序列。的作用是标识一数据的开始和结束位置。 在接收数据时,可以使用一个缓冲区来逐个字节地接收数据,并进行判断。可以使用一个状态机来处理接收过程,状态机可以包含几个状态,如等待、接收数据、校验等等。 在等待的状态下,不断接收数据,并与进行比对,一旦匹配成功,就进入接收数据的状态。在接收数据的状态下,可以将接收到的数据依次存储到缓冲区中。 在接收数据过程中,可以增加一些校验,比如计算校验和或者使用CRC校验,来验证接收数据的完整性。 在接收完一数据后,可以比对来确定数据是否接收完整。如果正确,则处理接收到的完整数据;如果不正确,则丢弃该数据,并重新开始接收下一数据。 需要注意的是,在设计时,要保证其与实际数据不会出现冲突,以免造成误判或混淆。 总结起来,使用HAL库进行串口接收处理需要设置合适的,并使用状态机来处理接收过程,结合校验来保证接收到的数据完整性。这样可以更加可靠和灵活地进行串口通信

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值