STM32 USART串口通信

一、介绍

通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。

二、硬件连接

  1. 串口之间的接线方式
  2. TTL与RS232的电平标准
  3. STM32 USART框图

三、通信协议

  1. 数据包
    串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

  2. 波特率
    由于异步通信中没有时钟信号,所以接收双方要约定好波特率,常见的波特率有4800、9600、115200等。

  3. 起始和停止信号
    数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。

  4. 有效数据
    有效数据规定了主题数据的长度,一般为8或9位。

  5. 数据校验
    在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。

4、STM32 USART的寄存器

  1. STM32 USART的配置的寄存器,库函数中的结构体积是基于寄存器进行封装的,还没学会怎么看寄存器的小伙伴可以看我之前的笔记
寄存器 偏移 复位值 描述
USART_SR 0x00 0x00C0 状态寄存器
USART_DR 0x04 不确定 数据寄存器
USART_BRR 0x08 0x0000 波特比率寄存器
USART_CR1 0x0C 0x0000 控制寄存器1
USART_CR2 0x10 0x0000 控制寄存器2
USART_CR3 0x14 0x0000 控制寄存器3
USART_GTPR 0x18 0x0000 保护时间和预分频寄存器
  1. 寄存器的地址映象

四、代码分析

  1. 配置串口的结构体
typedef struct
{
uint32_t USART_BaudRate; // 波特率设置
uint16_t USART_WordLength; //数据位数设置
uint16_t USART_StopBits; //停止位设置
uint16_t USART_Parity; //是否奇偶校验
uint16_t USART_Mode; //接收与发送都使能
uint16_t USART_HardwareFlowControl; //硬件流控制模式设置
} USART_InitTypeDef;
  1. 中断配置结构体
typedef struct
{
uint8_t NVIC_IRQChannel; // 配置USART为中断源
uint8_t NVIC_IRQChannelPreemptionPriority; // 抢断优先级
uint8_t NVIC_IRQChannelSubPriority; // 子优先级
FunctionalState NVIC_IRQChannelCmd; // 使能中断
} NVIC_InitTypeDef;
  1. 配置USART 的 IO引脚
    将Tx配置为复用推挽输出,将Rx配置为浮空输入
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
  1. 配置USART 的工作模式配置
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校验:无
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式设置:没有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收与发送都使能
  1. 将Rx读取配置为中断读取模式
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 配置USART为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断
NVIC_Init(&NVIC_InitStructure); // 初始化配置NVIC
}
  1. 中断函数使用
    当串口接收到数据后此中断函数会被调用,调用次函数后,会将接收到的信息有通过串口发送获取。这里的中断函数名已经在启动文件中已经定义好了的,建议不做更改。

    注意:有的小伙伴编写好程序后,发现串口无法收到发送的信息,可能是这里的中断函数名写错了。
void USART1_IRQHandler(void)
{
uint16_t res;
/* 判断是否收到中断信号 */
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
res = USART_ReceiveData(USART1);
USART_SendData(USART1, res);
}
//USART_SendData(USART1,(uint16_t)0xAC);
}

五、程序源码

  1. usart1.c文件
/***************************************
* 文件名 :usart1.c
* 描述 :配置USART1
* 实验平台:MINI STM32开发板 基于STM32F103C8T6
* 硬件连接:------------------------
* | PA9 - USART1(Tx) |
* | PA10 - USART1(Rx) |
* ------------------------
**********************************************************************************/
#include "usart1.h"
#include <stdarg.h>
#include "misc.h"
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置NVIC中断分组2:2位抢占优先级,2位响应优先级
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 配置USART为中断源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 抢断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断
NVIC_Init(&NVIC_InitStructure); // 初始化配置NVIC
}
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率设置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校验:无
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式设置:没有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收与发送都使能
USART_Init(USART1, &USART_InitStructure); //初始化USART1
USART_Cmd(USART1, ENABLE);// USART1使能
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 开启串口接受中断
NVIC_Configuration();// 串口中断优先级配置
}
void USART1_IRQHandler(void)
{
uint16_t res;
/* 判断是否收到中断信号 */
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
res = USART_ReceiveData(USART1);
USART_SendData(USART1, res);
}
//USART_SendData(USART1,(uint16_t)0xAC);
}
  1. main.c文件
#include "stm32f10x.h"
#include "usart1.h"
int main(void)
{
SystemInit(); //配置系统时钟为 72M
USART1_Config(); //USART1 配置
while (1)
{
}
}

五、编译运行

  1. 编译

  2. 运行

六、常见问题

程序下载后运行后发送数据无反馈。
解决办法:

  1. 检查中断函数名是否正确。
  2. 将STM32的引脚设置为运行模式,有不知道的怎么设置为运行模式的小伙伴可以参考STM32零基础入门教程
posted @   浇筑菜鸟  阅读(1336)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示