STM32—串口通讯详解

STM32—串口通讯详解串口通讯目录物理层协议层 USART 简介代码讲解串口通讯 SerialCommun 是一种设备间非常常用的串行通讯方式 因为它简单便捷 因此大部分电子设备都支持该通讯方式 其通讯协议可分层为协议层和物理层 物理层规定通信协议中具有机械 电子功能的特性 从而确保原始数据在物理媒体的传播 协议层主要规定通讯逻辑 统一双方的数据打包 解包标准 通俗的讲物理层规定我们用嘴巴还是肢体交流 协

串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。

物理层

1.通讯结构
串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下:
在这里插入图片描述
在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。
2.电平标准
根据使用的电平标准不同,串口通讯可分为 RS-232标准 TTL标准,具体标准如下:
在这里插入图片描述
在电子电路中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。














协议层

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




2.波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、等。STM32中波特率的设置通过串口初始化结构体来实现。
3.起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
4.有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
5.数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校验(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。














USART简介

开发板与上位机的连接

开发板与上位机之间通过USB线连接,所以在上位机上要配置一个USB转串口 的驱动,以便把USB传输过来的电平转换为TTL电平,TTL电平才能与串口调试助手建立联系。一般使用CH341驱动作为win10下的USB转串口,驱动安装成功的情况下接入USB会在计算机的设备管理器的端口中发现串口:
在这里插入图片描述
(win7系统一般选择CH340作为USB转串口驱动。)




代码讲解:

固件库编程的一大好处就是我们可以根据固件库函数来学习外设的相关知识,而且固件库函数的编写都是建立在对底层寄存器操作上的,所以通过讲解代码可以更好理解串口通讯相关知识。

一.初始化结构体

typedef struct { uint32_t USART_BaudRate; // 波特率 uint16_t USART_WordLength; // 字长 uint16_t USART_StopBits; // 停止位 uint16_t USART_Parity; // 校验位 uint16_t USART_Mode; // USART 模式 uint16_t USART_HardwareFlowControl; // 硬件流控制 } USART_InitTypeDef; 

USART初始化结构体中的相应变量都对应着数据包中的相对内容。

二.NVIC配置中断优先级

我们在串口接收信息时采用了触发中断事件,所以要配置一下串口中断的优先级:

NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 嵌套向量中断控制器组选择 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 配置USART为中断源 */ NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ; /* 抢断优先级*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 子优先级 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 使能中断 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 初始化配置NVIC */ NVIC_Init(&NVIC_InitStructure); } 

三.USART配置函数讲解

USART配置函数的主要作用是打开串口与相应的GPIO引脚,配置好相应串口信息与GPIO引脚的工作模式,以便信息的传输与接收。

void DEBUG_USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /* 第一步:初始化GPIO */ // 打开串口GPIO的时钟 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE); // 将USART Tx的GPIO配置为推挽复用模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 将USART Rx的GPIO配置为浮空输入模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); /* 第二步:配置串口的初始化结构体 */ // 打开串口外设的时钟 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE); // 配置串口的工作参数 // 配置波特率 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; // 配置 针数据字长 USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 配置停止位 USART_InitStructure.USART_StopBits = USART_StopBits_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(DEBUG_USARTx, &USART_InitStructure); /*--------------------------------------------------------*/ // 串口中断优先级配置 NVIC_Configuration(); // 使能串口接收中断 USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE); /*--------------------------------------------------------*/ /* 第三步:使能串口 */ // 使能串口 USART_Cmd(DEBUG_USARTx, ENABLE); } 

第一步:打开了GPIO的时钟,设置发送和接收引脚的信息,将Tx(发送引脚)配置为推挽复用模式用来发送数据,Rx(接收引脚)配置为浮空输入模式用来接收数据。
第二步:首先打开USART1 的时钟,根据USART初始化结构体成员配置相关的信息,之后利用初始化函数将初始化结构体中的信息写入相应寄存器中,然后的话就是引用NVIC_Configuration()函数配置串口中断优先级,打开相应的串口接收中断,中断接收函数的参数如下:
在这里插入图片描述
第三步 :最后相当于打开总电源——使能串口






USART配置函数完成后代表,USART1 的接收和发送准备工作已经准备就绪,接下来就是,串口与上位机之间的信息传递了,信息的发送和接收都有相对于的函数。

四.传输数据的函数:

开发板与上位机之间的数据传输可以有多种方法,下面一一介绍:

1.发送一个字节

USART_SendData(pUSARTx,ch); 函数为基础建立的函数可以向上位机发送一个字节的数据,利用FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) 读取发送数据寄存器的状态来 等待发送寄存器将数据成功发送。

void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch) { /* 发送一个字节数据到USART */ USART_SendData(pUSARTx,ch); /* 等待发送数据寄存器为空 */ while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); } 
2.发送字符串

本质是利用上面的字节发送函数逐位发送字符串中的内容

void USART_SendString(USART_TypeDef * pUSARTx, char *str) { unsigned int k=0; while(*(str+k)!='\0') { USART_SendData(pUSARTx, *(str+k)); /* 等待发送数据寄存器为空 */ while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); k++; } while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET); /* TC:传输完成标志 */ } 
3.重定向printf函数发送字符串

关于重定向的知识之前总结过,链接:重定向知识。重定向后的printf()函数功能强大,具有向串口调试助手打印数据的功能,使用方法和c语言时一样,比如printf("欢迎来到小全全的串口实验\n");就可以将“欢迎来到小全全的串口实验”这句话发送到上位机中,而且换行符“\n”还具有换行作用。

/* 重定向printf函数 */ int fputc(int ch, FILE *f) { USART_SendData( DEBUG_USARTx, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); return ch; } 
4.重定向getchar函数接收字符

具体操作与重定向后的printf函数类似,比如可以通过如下代码向上位机发送已经接收到的数据

x=getchar(); printf("接收到的字符是:%c\n",x); 

重定义如下:

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数 int fgetc(FILE *f) { /* 等待串口输入数据 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(DEBUG_USARTx); } 

在使用此函数作为接收数据时记得关闭串口得接收中断!!!

5.通过中断接收

stm32f10x_it.c中编写USART1中断源相对应得中断函数,利用了固件库函数中的
USART_ReceiveData(DEBUG_USARTx);接收函数
USART_SendData(DEBUG_USARTx, x);发送函数
USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE);判断标志位函数






/* #define DEBUG_USART_IRQn USART1_IRQn #define DEBUG_USART_IRQHandler USART1_IRQHandler */ void DEBUG_USART_IRQHandler(void) { uint16_t x; /* 判断是否收到中断信号 */ if(USART_GetITStatus(DEBUG_USARTx, USART_IT_RXNE) == SET) { x = USART_ReceiveData(DEBUG_USARTx); USART_SendData(DEBUG_USARTx, x); } } 

结语

以固件库函数编程的思路讲解,未能顾及到众多寄存器的讲解,我认为进行固件库编程本身就是学习操作寄存器的过程,很多时候我们不需要知道如何操作寄存器,只要了解如何操作固件库函数即可。(吹爆固件库编程)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204300.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午8:35
下一篇 2026年3月19日 下午8:36


相关推荐

  • 矩阵外积与内积

    矩阵外积与内积一个行向量乘以一个列向量称作向量的内积,又叫作点积,结果是一个数;一个列向量乘以一个行向量称作向量的外积,外积是一种特殊的克罗内克积,结果是一个矩阵,假设和b分别是一个行向量和一个列向量,那么内积、外积分别记作和,,为了讨论方便,假设每个向量的长度为2。注意:外积在不同的地方定义方式不太一样,这里不详细讨论定义了内积和外积以后,我们讨论矩阵的乘法。矩

    2025年8月7日
    3
  • offsetWidth和clientWidth

    offsetWidth和clientWidth在項目

    2022年7月22日
    13
  • python之random库

    random库是用于产生并运用随机数的标准库1.random库函数(1)random.seed(a)设置随机种子数,可以是浮点数或整数,如果不设置的话,则random库默认以系统时间产生当作随

    2021年12月29日
    60
  • windows开启远程桌面命令

    windows开启远程桌面命令开启远程桌面命令 关闭远程桌面 设置远程桌面端口 默认开启 3389 检查默认端口状态非命令行打开方式 1 打开 控制面板 怎么开启远程桌面连接详细教程 2 点击 系统 怎么开启远程桌面连接详细教程 3 选择 远程设置 怎么开启远程桌面连接详细教程 4 点击 远程 勾选 允许远程协助连接这台计算机 和 允许远程连接到此计算机 点击 确定 怎么开启远程桌面连接详细教程 5 在任务栏搜索 远程桌面连接 并打开 怎么开启远程桌面连接详细教程 6 输入 ip 地址后点击 连接 即可

    2026年3月18日
    2
  • 离线地图的原理_matplotlib地图

    离线地图的原理_matplotlib地图侵权说明:如文章内容有侵权行为,请联系本人告知,本人会尽快删除修改,避免扩大影响。Bmap说明:Bmap由北京百度网讯科技有限公司提供技术支持为用户提供包括智能路线规划、智能导航(驾车、步行、骑行)、实时路况等出行相关服务的平台。本身并不提供离线功能,因为离线会导致“搜索周边”“搜索路线”“交通状况”等实时性数据要求的功能缺失。Bmap加载原理简图:离线地图…

    2025年6月13日
    4
  • java timestamp 转date_如何在Java中将TimeStamp转换为Date?

    java timestamp 转date_如何在Java中将TimeStamp转换为Date?问题在 java 中获取计数后如何将 timeStamp 转换为 date 我目前的代码如下 publicclassG publicintdat intcount 0 java sql Timestamptim newTimestamp System currentTimeM java sql Datedat

    2026年3月19日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号