STM32基础知识:串口通信-轮询方式

描述

串口通信-轮询方式

1 串口通信概述

1.1 计算机通信的基本概念

计算机通信: 将计算机技术和通信技术相结合,完成计算机与外部设备或计算机与计算机之间的信息交换。按照数据传输方式的不同,可以分为串行通信和并行通信两类。

寄存器

串行通信: 数据逐位传输,传输线少,长距离传输时成本低,但数据的传输控制较复杂。按照实现数据同步的方式,可以分为同步串行和异步串行两种。

  • 同步串行通信: 数据传输以数据块(一组字符)为单位,在一个数据块内,字符与字符间无间隔,收发双方依靠独立的时钟线进行信号的同步。
    寄存器
  • 异步串行通信: 数据传输以单个字符为单位,字符和字符之间的间隙任意,字符内部每一位持续的时间相同。收发双方没有专门的时钟信号,而是依靠事先约定的字符格式和通信速率来完成通信适用于大批量的数据传输。
    寄存器

并行通信: 多位数据同时传输,传输控制简单,传输速度快,但是在长距离传输时硬件成本较高。

1.2 异步串行通信

异步通信的两个关键点是字符格式波特率 ,字符格式决定了数据的传输形式,波特率决定了字符中每一位数据的持续时间。

字符格式

寄存器

❑ 1 位起始位,规定为低电平;
❑ 5~8 位数据位,即要传送的有效信息;
❑ 1 位奇偶校验位;
❑ 1~2 位停止位,规定为高电平。

常用字符格式:1位起始位,8位数据位,无奇偶校验,1位停止位

寄存器

传输时低位在前,高位在后,上图发送数据为0xE9。

通信速率

波特率:每秒钟传送二进制数码的位数,以bit/s(bps)为单位。

常用的波特率有:9600、19200、38400、57600和115200;

波特率为115200,表示每秒传输115200位,且每一位数据在数据线上持续时间为Tbit= 1/115200 ≈ 8.68us

异步串行通信的数据接收过程

寄存器

接收过程的本质是数据采样,假设接收端的采样时钟是波特率的16倍。

① 接收过程由起始位的下降沿启动;
② 接收端等待8个时钟周期,以便建立一个接近比特周期中间的采样点;
③ 接收端等待16个时钟周期,使其进入第一个数据位周期的中点;
④ 第一个数据位被采样并存储在接收寄存器中;
⑤ 串口模块在采样第二个数据位之前等待另外16个时钟周期;
⑥ 重复此过程,直到所有数据位都被采样和存储;
⑦ 由停止位的上升沿使数据线返回到空闲状态。

串口通信的数据传输方向

寄存器

错误校验方式

  • 奇偶校验:奇校验表示数据中“1”的个数与校验位“1”的个数之和为奇数;偶校验表示数据中“1”的个数与校验位“1”的个数之和为偶数。
  • 代码和校验:发送方将所发数据块求和,产生一个字节的校验字符附加到数据块末尾。接收方采用同样方式进行检测。
  • 循环冗余校验:通过某种数学运算实现有效信息与校验位之间的循环校验,常用于磁盘信息的传输、存储区的完整性校验等。

2 STM32串口通信

2.1 串口收发单元

寄存器

串口收发单元主要利用数据寄存器DR,发送引脚TX,接收引脚RX,以及三个通信状态位TXE、TC和RXNE来完成数据的接收和发送。

  • TXE:发送数据寄存器空标志。当TDR寄存器的内容已经传送到发送移位寄存器 时,该位由硬件置1。如果串口控制寄存器CR1中的TXEIE位为1,将会触发发送数据寄存器空中断。注意:当TXE置1时,数据有可能还在发送。
  • TC:发送完成标志。当发送移位寄存器的内容发送完成,同时TDR寄存器也为 空时,该位由硬件置1,表示本次数据传输已经完成。如果串口控制寄存器CR1中的TCIE位为1,将会触发发送完成中断。注意:当TC置1时,数据才是真正地发送完成。
  • RXNE:接收数据寄存器不为空标志。当移位寄存器的内容已经传送到接收数据寄存器RDR时,该位由硬件置1。如果串口控制寄存器CR1中的RXNEIE位为1,将会触发接收数据寄存器不为空中断。

数据寄存器DR在硬件上分为TDR和RDR两个寄存器,通过数据的流向进行区分,在结构设计上采用了双缓冲结构;

发送时,数据通过数据总线送入TDR寄存器,然后传送到发送移位寄存器完成数据转换,从并行数据转为串行数据,最后通过TX引脚发送;

接收时,数据通过RX引脚逐位送入接收移位寄存器,8位数据接收完成后,送入RDR寄存器,供用户读取。

USB转TTL串口模块

寄存器

2.2 串口的数据类型定义

①外设句柄的定义:

HAL库在结构上,对每个外设抽象成了一个称为ppp_HandleTypeDef的结构体,其中ppp就是每个外设的名字。所有的函数都是工作在ppp_HandleTypeDef指针之下。

例如,使用USART2时,可以定义USART初始化结构体变量(全局变量)huart2

UART_HandleTypeDef huart2;

huart2就被称为串口的句柄,它被贯穿整个USART收发的流程。

②外设句柄数据类型的组成:

寄存器

寄存器

③串口初始化数据类型:

寄存器

成员变量WordLength的取值范围

宏常量定义含义
UART_WORDLENGTH_8B数据位长度为8位
UART_WORDLENGTH_9B数据位长度为9位

成员变量StopBits的取值范围

宏常量定义含义
UART_STOPBITS_1停止位长度为1位
UART_STOPBITS_2停止位长度为2位

成员变量Parity的取值范围

宏常量定义含义
UART_PARITY_NONE无奇偶校验
UART_PARITY_EVEN偶校验
UART_PARITY_ODD奇校验

成员变量Mode的取值范围

宏常量定义含义
UART_MODE_RX串口仅处于接收模式,只能接收数据,不能发送数据
UART_MODE_TX串口仅处于发送模式,只能发送数据,不能接收数据
UART_MODE_TX_RX串口处于接收和发送模式,可以同时收发数据

成员变量HwFlowCtI的取值范围

宏常量定义含义
UART_HWCONTROL_NONE无硬件流控
UART_HWCONTROL_RTS使能“请求发送(RTS)”引脚
UART_HWCONTROL_CTS使能“允许发送(CTS)”引脚
UART_HWCONTROL_RTS_CTS使能“请求发送(RTS)”和“允许发送(CTS)引脚

成员变量OverSampling的取值范围

宏常量定义含义
UART_OVERSAMPLING_16采样频率是信号传输频率的16倍
UART_OVERSAMPLING_8采样频率是信号传输频率的8倍

2.3 外设初始化设计思想

寄存器

①串口初始化过程:

寄存器

抽象—串口初始化函数MX_USART2_UART_Init 将与MCU无关的通信参数存入句柄结构 + 使用HAL_UART_Init执行串口初始化操作,将句柄参数写入寄存器。

HAL_UART_Init 干了哪些事?

  • 调用 HAL_UART_MspInit
  • 修改状态忙
  • 配置寄存器
  • 清除标志位

寄存器

承载—与MCU相关的初始化函数HAL_UART_MspInit :时钟初始化 + 引脚初始化

寄存器

3 串口通信方式

  • 轮询方式:CPU不断检测串口的状态标志来判断数据收发的情况。特点:程序设计简单,但CPU在检测标志位期间,无法执行其他任务,CPU利用率较低。
  • 中断方式:使能中断后,接收一字节数据或发送一字节后申请中断,在ISR中完成后续处理。在数据收发期间,CPU可以执行其他任务,CPU利用率较高。
  • DMA方式:初始化时设置相关参数,启动DMA传输后,数据传输过程不需要CPU的干预。传输完成后,再产生DMA中断,由CPU进行后续处理。传输效率最高。

4 轮询方式的串口通信 ##

  1. 串口初始化函数:HAL_UART_Init

    函数原型HAL StatusTypeDef HAL_UART_Init (UART_HandleTypeDef *huart)
    功能描述按照串口句柄中指定的参数初始化串口
    入口参数huart:串口句柄的地址
    返回值HAL状态值:HAL_OK表示初始化成功,HAL_ERROR表示初始化失败
    注意事项1.该函数将调用与MCU相关的初始化函数HAL_UART_Msplnit完成时钟、引脚和中断等底层硬件的初始化操作2.该函数由CubeMX自动生成
  2. 接口函数:HAL_UART_Transmit

    函数原型HAL_StatusTypeDef HAL_UART_Transmit(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout)
    功能描述在轮询方式下发送一定数量的数据
    入口参数1huart:串口句柄的地址
    入口参数pData:待发送数据的首地址
    入口参数3Size:待发送数据的个数
    入口参数4Timeout:超时等待时间, 以ms为单位, HAL MAX DELAY表示无限等待
    返回值HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用;HAL_TIMEOUT表示发送超时
    注意事项1.该函数连续发送数据,发送过程中通过判断TXE标志来发送下一个数据,通过判断TC标志来结束数据的发送2.如果在等待时间内没有完成发送,则不再发送,返回超时标志3.该函数由用户调用
  3. 接口函数:HAL_UART_Receive

    函数原型HAL_StatusTypeDef HAL_UART_Receive(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout)
    功能描述在轮询方式下接收一定数量的数据
    入口参数1huart:串口句柄的地址
    入口参数pData:存放数据的首地址
    入口参数3Size:待接收数据的个数
    入口参数4Timeout:超时等待时间, 以ms为单位, HAL MAX DELAY表示无限等待
    返回值HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用;HAL_TIMEOUT表示发送超时
    注意事项1.该函数连续接收数据,接收过程中通过判断RXNE标志来发送下一个数据2.如果在等待时间内没有完成接收,则不再接收,返回超时标志3.该函数由用户调用

5 任务实践1

在PC上利用串口调试助手发送数据到MCU,MCU调用scanf函数读取数据,然后调用printf函数发送应答信息到PC。

  1. 串口外设配置
    寄存器

    • 异步模式,无硬件流控
    • 设置通信参数:波特率115200,8位数据位,无奇偶校验,1位停止位,使能接收和发送,16倍过采样(CubeMX默认配置)
  2. 在Keil中勾选Use MicroLIB
    寄存器

  3. 编写代码
    printf和scanf重定向

    /* USER CODE BEGIN Includes */
    #include < stdio.h >
    /* USER CODE END Includes */
    
    int fputc (int ch, FILE *f)
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
        return ch;
    }
    int fgetc(FILE *f)
    {
        uint8_t ch = 0;
        HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
        return ch;
    }
    /* USER CODE END 4 */
    

    用户应用代码——猜数游戏

    /* USER CODE BEGIN 3 */
        printf("Please guess a number between 0 to 9n");
        if (scanf("%d", &guess_num) == 1)
        {
          if (guess_num == ans)
          {
            printf("You are right! It's %dn", ans);
          }
          else
          {
            printf("You are wrong! It is not %dn", guess_num);
          }
        }
      }
      /* USER CODE END 3 */
    

    实验现象

    寄存器

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分