• STM32F103 串口通信Uart、Usart基础+代码练习


    STM32F103 Uart和Usart(串口通信)

    一、串行通信的通信方式

    1. 同步通信:带时钟同步信号传输,有一根线是同步时钟。例如SPI(全双功)、IIC(半双工)通信接口
    2. 异步通信:不带时钟同步信号,必须约定好波特率。例如UART(全双功)

    二、STM32的串口通信接口

    USART:通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)可以灵活地与外部设备进行全双工数据交换。USART 支持使用 DMA,可实现高速数据通信

    UART:通用异步收发器(Universal Asynchronous Receiver and Transmitter)。是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。

    USART功能框图

    在这里插入图片描述

    功能引脚:

    1. TX:发送数据输出引脚。
    2. RX:接收数据输入引脚。
    3. SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
    4. nRTS:请求以发送(Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高电平。该引脚只适用于硬件流控制。
    5. nCTS:清除以发送(Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
    6. SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。

    三、STM32F10x系列包含3个USART和2个UART

    1. USART1 和时钟来源于 APB2 总线时钟,其最大频率为 72MHz。
    2. 其他四个的时钟来源于 APB1 总线时钟,其最大频率为 36MHz,UART 只是异步传输功能,所以没有 SCLK、nCTS 和 nRTS 功能引脚。

    四、常用串口相关寄存器

    1.USART_SR状态寄存器:里面一些相关位可以用来判断是否发送接收完成等。

    2.USART_DR数据寄存器:通过读写这个寄存器来发送接收数据

    1. USART 数据寄存器(USART_DR)只有低 9 位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。

    2. USART_DR 包含了已发送的数据或者接收到的数,USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。

    3. TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收
      时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

    4. USART_BRR波特率寄存器:

      波特率指数据信号对载波的调制速率,它用单位时间内载波调制状态改变次数来表示,单位为波特。比特率指单位时间内传输的比特数,单位 bit/s(bps)。对于 USART 波特率与比特率相等,以后不区分这两个概念。波特率越大,传输速率越快

    5. USART 的发送器和接收器使用相同的波特率。

      波特率计算公式:

    在这里插入图片描述

    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

    五、USART 初始化结构体详解

    初始化结构体定义在 stm32f10x_usart.h 文件中,初始化库函数定义在 stm32f10x_usart.c 文件中,编程时我们可以结合这两个文件内注释使用。

    USART 初始化结构体(异步)

    1 typedef struct {
    2 uint32_t USART_BaudRate; // 波特率
    3 uint16_t USART_WordLength; // 字长
    4 uint16_t USART_StopBits; // 停止位
    5 uint16_t USART_Parity; // 校验位
    6 uint16_t USART_Mode; // USART 模式
    7 uint16_t USART_HardwareFlowControl; // 硬件流控制
    8 } USART_InitTypeDef;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. USART_BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。标准库函数会根据设定值计算得到 USARTDIV 值,从而设置 USART_BRR 寄存器值。
    2. USART_WordLength:数据帧字长,可选 8 位或 9 位。它设定 USART_CR1 寄存器的 M 位的值。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位
    3. USART_StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,它设定USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。
    4. USART_Parity :奇偶校验控制选择 ,可 选 USART_Parity_No( 无校验 ) 、USART_Parity_Even( 偶校验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) , 它 设 定USART_CR1 寄存器的 PCE 位和 PS 位的值。
    5. USART_Mode:USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位
    6. USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,
      可选有⑴使能 RTS、⑵使能 CTS、⑶同时使能 RTS 和 CTS、⑷不使能硬件流。

    USART 时钟初始化结构体(同步情况)

    当使用同步模式时需要配置 SCLK 引脚输出脉冲的属性,标准库使用一个时钟初始化结构体 USART_ClockInitTypeDef 来设置,该结构体内容也只有在同步模式才需要设置

    USART 时钟初始化结构体

    1 typedef struct {
    2 uint16_t USART_Clock; // 时钟使能控制
    3 uint16_t USART_CPOL; // 时钟极性
    4 uint16_t USART_CPHA; // 时钟相位
    5 uint16_t USART_LastBit; // 最尾位时钟脉冲
    6 } USART_ClockInitTypeDef;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. USART_Clock:同步模式下 SCLK 引脚上时钟输出使能控制,可选禁止时钟输出(USART_Clock_Disable)或开启时钟输出(USART_Clock_Enable);如果使用同步模式发送,一般都需要开启时钟。它设定 USART_CR2 寄存器的 CLKEN 位的值。

    2. USART_CPOL:同步模式下 SCLK 引脚上输出时钟极性设置,可设置在空闲时SCLK 引脚为低电平(USART_CPOL_Low)或高电平(USART_CPOL_High)。它设定USART_CR2 寄存器的 CPOL 位的值。

    3. USART_CPHA:同步模式下 SCLK 引脚上输出时钟相位设置,可设置在时钟第一个变化沿捕获数据(USART_CPHA_1Edge)或在时钟第二个变化沿捕获数据。它设定USART_CR2 寄存器的 CPHA 位的值。USART_CPHA 与 USART_CPOL 配合使用可以获得多种模式时钟关系。

    4. USART_LastBit:选择在发送最后一个数据位的时候时钟脉冲是否在 SCLK 引脚输出 ,可以是不输出脉冲(USART_LastBit_Disable) ,输出脉冲(USART_LastBit_Enable)。它设定 USART_CR2 寄存器的LBCL 位的值。

    5. 下面是必要配置

      //使能串口
      void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
      //使能相关中断
      void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
      //发送数据串口
      void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
      //从串口接收数据
      uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
      //获取状态标志位
      FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
      //清除状态标志位
      void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);
      //获取中断状态标志位
      ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
      //清除中断状态标志位
      void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    六、USART 实现开发板与电脑通信

    要用到一个 USB 转USART 的 IC,我们选择 CH340G 芯片来实现这个功能,CH340G是一个USB总线的转接芯片,实现 USB 转
    USART、USB 转 lrDA 红外或者 USB 转打印机接口,我们使用其 USB 转 USART 功能。

    将 CH340G 的 TXD 引脚与 USART1 的 RX 引脚连接,CH340G 的 RXD 引脚与USART1 的 TX 引脚连接。CH340G 芯片集成在开发板上,其地线(GND)已与控制器的GND 连通。

    USB 转串口硬件设计

    在这里插入图片描述

    编程分析:

    1. 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
    2. 初始化 GPIO,并将 GPIO 复用到 USART 上;
    3. 配置 USART 参数;
    4. 配置中断控制器并使能 USART 接收中断;
    5. 使能 USART;
    6. 在 USART 接收中断服务函数实现数据接收和发送。

    串口配置步骤:

    1. 串口时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);

    2. 串口复位(无需求可以不写)
      USART_DeInit();

    3. GPIO模式设置
      对GPIO口输入输出的设置

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输入(相应引脚)

      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输出(相应引脚)

    4. 串口初始化设置

      USART_Init(USART1, &USART_InitStructure);

    5. 开启中断并且初始化NVIC

      NVIC_Init();

      USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    6. 使能串口

      USART_Cmd(USART1, ENABLE);

    7. 编写中断处理函数

      void USART1_IRQHandler(void)

    8. 串口数据收发

      void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);

      uint16_t USART_ReceiveData(USART_TypeDef* USARTx);

    9. 串口传输状态获取

      ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);

      void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

    代码分析

    1. GPIO 和 USART 宏定义

      1 /**
      2 * 串口宏定义,不同的串口挂载的总线和 IO 不一样,移植时需要修改这几个宏
      3 */
      4 
      5 // 串口 1-USART1
      6 #define DEBUG_USARTx USART1
      7 #define DEBUG_USART_CLK RCC_APB2Periph_USART1
      8 #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
      9 #define DEBUG_USART_BAUDRATE 115200
      10 
      11 // USART GPIO 引脚宏定义
      12 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
      13 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
      14 
      15 #define DEBUG_USART_TX_GPIO_PORT GPIOA
      16 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
      17 #define DEBUG_USART_RX_GPIO_PORT GPIOA
      18 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
      19 
      20 #define DEBUG_USART_IRQ USART1_IRQn
      21 #define DEBUG_USART_IRQHandler USART1_IRQHandler
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

      开发板中的 CH340G 的收发引脚默认通过跳帽连接到USART1,如果想使用其他串口,可以把 CH340G 跟 USART1 直接的连接跳帽拔掉,然后再把其他串口的 IO 用杜邦线接到 CH340G 的收发引脚即可.

      用 USART1,设定波特率为 115200,选定 USART 的 GPIO 为 PA9 和 PA10

    2. 嵌套向量中断控制器 NVIC 配置

      1 static void NVIC_Configuration(void)
      2 {
      3 NVIC_InitTypeDef NVIC_InitStructure;
      4 
      5 /* 嵌套向量中断控制器组选择 */
      6 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
      7 
      8 /* 配置 USART 为中断源 */
      9 NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
      10 /* 抢断优先级为 1 */
      11 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
      12 /* 子优先级为 1 */
      13 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
      14 /* 使能中断 */
      15 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
      16 /* 初始化配置 NVIC */
      17 NVIC_Init(&NVIC_InitStructure);
      18 }
      19
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
    3. USART 初始化配置

      1 void USART_Config(void)
      2 {
      3 GPIO_InitTypeDef GPIO_InitStructure;
      4 USART_InitTypeDef USART_InitStructure;
      5 
      6 // 打开串口 GPIO 的时钟
      7 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
      8 
      9 // 打开串口外设的时钟
      10 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
      11 
      12 // 将 USART Tx 的 GPIO 配置为推挽复用模式
      13 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
      14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
      15 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      16 GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
      17 
      18 // 将 USART Rx 的 GPIO 配置为浮空输入模式
      19 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
      20 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
      21 GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
      22 
      23 // 配置串口的工作参数
      24 // 配置波特率
      25 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
      26 // 配置 针数据字长
      27 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
      28 // 配置停止位
      29 USART_InitStructure.USART_StopBits = USART_StopBits_1;
      30 // 配置校验位
      31 USART_InitStructure.USART_Parity = USART_Parity_No ;
      32 // 配置硬件流控制
      33 USART_InitStructure.USART_HardwareFlowControl =
      34 USART_HardwareFlowControl_None;
      35 // 配置工作模式,收发一起
      36 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
      37 // 完成串口的初始化配置
      38 USART_Init(DEBUG_USARTx, &USART_InitStructure);
      39 
      40 // 串口中断优先级配置
      41 NVIC_Configuration();
      42 
      43 // 使能串口接收中断
      44 USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
      45 
      46 // 使能串口
      47 USART_Cmd(DEBUG_USARTx, ENABLE);
      48 }
      
      • 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

      程序用到 USART 接收中断,需要配置 NVIC,这里调用 NVIC_Configuration 函数完成配置。配置完 NVIC 之后调用 USART_ITConfig 函数使能 USART 接收中断。

    4. 字符发送

      1 /***************** 发送一个字符 **********************/
      2 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
      3 {
      4 /* 发送一个字节数据到 USART */
      5 USART_SendData(pUSARTx,ch);
      6 
      7 /* 等待发送数据寄存器为空 */
      8 while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
      9 }
      10 
      11 /***************** 发送字符串 **********************/
      12 void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
      13 {
      14 unsigned int k=0;
      15 do {
      16 Usart_SendByte( pUSARTx, *(str + k) );
      17 k++;
      18 } while (*(str + k)!='\0');
      19 
      20 /* 等待发送完成 */
      21 while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
      22 }
      23 }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23

      通过使用 USART_GetFlagStatus 函数来获取 USART事件标志来实现发送完成功能等待,它接收两个参数,一个是 USART,一个是事件标志。

    5. USART 中断服务函数

      1 void DEBUG_USART_IRQHandler(void)
      2 {
      3 uint8_t ucTemp;
      4 if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET) {
      5 ucTemp = USART_ReceiveData( DEBUG_USARTx );
      6 USART_SendData(USARTx,ucTemp);
      7 }
      8 
      9 }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9

      USART_GetITStatus 函数与 USART_GetFlagStatus 函数类似用
      来获取标志位状态,但 USART_GetITStatus 函数是专门用来获取中断事件标志的,并返回该标志位状态。

    6. 主函数

      1 int main(void)
      2 {
      3 /*初始化 USART 配置模式为 115200 8-N-1,中断接收*/
      4 USART_Config();
      5 
      6 Usart_SendString( DEBUG_USARTx,"这是一个串口中断接收回显实验\n");
      7
      8 while (1) {
      9 
      10 }
      11 }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      要调用 USART_Config 函数完成 USART 初始化配置,包括 GPIO 配置,USART 配置,接收中断使能等等信息

  • 相关阅读:
    Design patterns--策略模式
    zookeeper + kafka消息队列
    字符集详解
    随想录一刷Day51——动态规划
    代码随想录算法训练营第四十一天 | 01背包问题 二维
    redis desktop manager 0.9.3 免费版
    云原生应用的未来:无服务器计算的崭露头角
    全链路性能测试:Nginx 负载均衡的性能分析和调优
    【深入浅出向】从自信息到熵、从相对熵到交叉熵,nn.CrossEntropyLoss, 交叉熵损失函数与softmax,多标签分类
    Hadoop3.0大数据处理学习3(MapReduce原理分析、日志归集、序列化机制、Yarn资源调度器)
  • 原文地址:https://blog.csdn.net/weixin_46068274/article/details/127578869