STM32快速入门(串口传输之USART)
STM32快速入门(串口传输之USART)
前言
USART串口传输能实现信息在设备之间的点对点传输,支持单工、半双工、全全双工,一般是有三个引脚:TX、RX、SW_RX(共地)。不需要一根线来同步时钟。最大优点是可以和电脑通信,实现程序调试的功能。
导航
图248 USART框图:

图片引自STM32 F1XX系列的中文参考手册。
USART发送和接收的实现细节
第一部分
首先,对于图248的1号矩形框部分。该部分负责数据的发送和接收。(类似人体的四肢
截取了中文手册有关USART的一幅时序图,如下:

首先解释一下空闲帧和断开帧:
从图中可以看到,空闲帧包括了停止位。而断开帧是10位低电平,后跟停止位(当m=0时);或者11位低电平,后跟停止位(m=1时)。不可能传输更长的断开帧(长度大于10或者11位)。
发送流程:
-  引脚处于空闲状态时,一般是高电平状态。发送使能位被使能: USART_CR1.TE[3]位被置为1。
-  (由用户)数据写到发送数据寄存器。在写之前,用户会等待 USART_SR.TXE[7]被硬件置位,只有该位被置为才说明发送数据寄存器为空,此时写入数据就是安全的,不会造成覆盖的问题。
-  (以下步骤都是由硬件完成)将发送数据寄存器的内容移到发送移位寄存器,同时将 USART_SR.TXE[7]置位。以示发送数据寄存器为空。
-  发送一个起始位。(低电平) 
-  从最低位开始,左移位将发送移位寄存器的值按位发送到TX引脚(对发送方)。 
-  如果用户使能了 USART_CR1.PCE[10],会根据USART_CR1.PS[9]发送一个校验位。
-  最后,根据 USART_CR2.STOP[13:12]的配置发送若干个停止位。(高电平)
-  将状态寄存器 USART_SR.TC[6]置位,表示数据的一帧发送完成。
接收流程:
-  接收使能位被使能: USART_CR1.RE[2]。
-  (以下未特别说明,都是由硬件完成)从RX引脚(对接收方)检测到起始位,接收移位寄存器准备接收数据。 
-  接收移位寄存器从最高位开始,左移位依次按位从RX引脚(对接收方)接收数据。 
-  接收到停止位。 
-  如果使能了校验位的话,根据配置进行数据校验。 
-  校验合格的话,就将接收移位寄存器的值移到接收数据寄存器。 
-  将 USART_SR.RXNE[5]置位,表示接收数据寄存器非空,提醒用户接收到数据了。
-  (由用户)读取接收数据寄存器的数据。 
注意:
-  虽然用户可以操作的寄存器只有一个USART_DR,但是实际上发送和接收数据寄存器在硬件上是各自一个!这样的设计也是双缓冲的实践。 
-  在发送和接收数据之前,用户必须统一设置两端的波特率、校验方式、停止位的数量、字长。否则这四项数据不一致,一定会造成传输错误,导致传输无法进行。其原因从上面的传输流程很容易推断。 
有关状态寄存器的位的解释如下:


上面对过载错误位做了一个特写。这是因为我再编码的过程中遇到的一个BUG。排查了半天,原因是当RXNEIE接收中断位使能时,发送方的ORE标志位和RXNE标志位的置位都会触发RXNE事件的中断,当中断处理函数在处理完毕后,只复位RXNE标志,而不管ORE,后续还是会不断的产生中断。所以根据手册(手册其实是有误的),我们需要先读USART_SR,在读USART_DR将ORE标志位清除。(注意!库函数Clear类函数不能清楚ORE位!),这里放一张中断请求对应的事件表:

第二部分
对于图248的2号矩形框部分。该部分负责接收和发送的控制,(类似人体大脑。
图中可以看到有很多的控制器、控制寄存器、标志寄存器等。我们可以设置相应的寄存器从而控制收发来实现一些功能。具体寄存器的功能可以参考中文手册,这里不过多赘述。
第三部分
对于图248的3号矩形框部分。该部分负责控制接收和发送的时钟。接收和发送的时钟也称之为波特率,通过波特率,通信双方就能协调其收发的频率(类似人体心脏。
从图248的3号矩形框部分,可知,发送和接受器时钟是相等的。而时钟最开始是来自F_PCLK,送和接受器的时钟是对F_PCLK进行了一个 (16 * USARTDIV) 分频,USARTDIV是一个可调的定点小数。


这里解释一下中文手册里面“如何从USART_BRR寄存器值得到USARTDIV”的示例一。 最开始看到这个例子我也是很懵的,什么是定点小数?这是怎么用整数来表示小数的?为什么 <Fraction (USARTDIV) = 12/16 = 0.75> 这里要除以16?原理是这样的:
USART_BRR寄存器里面按定点小数的方式存放USARTDIV的值。只使用了16位,高12位存放小数的整数部分,低4位存放的是小数部分。整数部分很好说,直接存放进去就好了。而小数部分呢,因为小数部分一定是小于1的,所以,它根据低4位所能代表的值,将1划分成了2^4份,也就是16份,每一份占1/16,所以我们要将小数部分表示成4位整数就将小数乘以16并向上取整即可。溢出的话就向整数部分进一。反之,要从4位整数还原小数,就用4位整数乘以1/16。
中文手册总结了一个公式:
波特率 = F_PCLK / (16 * USARTDIV)
通信必须维持相同的波特率。双方各自通过调节USARTDIV,就可以在不同环境下将双方但的波特率调成一样的。
此外,还应该说明的是,公式中,有一个乘以 1 / 16 的操作,这么做的目的是发送接收控制器里面有一个比波特率大16倍的采样频率。采样频率起到很好的滤波效果,它会对每一位进行16次采样。采样对于起始位的探测非常的精妙。并且,对于数据位,中间的8、9、10次采样会起到决定性作用。
起始位探测:

首先,我们称对第3、5、7次的采样为第一阶段采样,对第8、9、10次的采样为第二阶段采样。
-  如果该序列不完整,那么接收端将退出起始位侦测并回到空闲状态(不设置标志位)等待下降沿。 
-  两个阶段检测的全是0,则确认收到起始位,这时设置RXNE标志位,如果RXNEIE=1,则产生中断。 
-  如果两阶段中3个采样点上仅有2个是0,那么起始位仍然是有效的,但是会设置NE噪声标志位。如果不能满足这个条件,则中止起始位的侦测过程,接收器会回到空闲状态(不设置标志位)。 
-  如果两个阶段只有一个阶段中3个采样点上仅有2个是’0’,那么起始位仍然是有效的,但是会设置NE噪声标志位。 
数据位噪声探测:

对数据位的采样只有一个阶段采样有效,即8、9、10次采样。
上方图片的下面的表格已经规定了采样的值和有效性的映射。读者可以好好的品味一下。
最后,注意因为定点数表示小数是有精度的,所以波特率的计算是存在误差的,具体误差可以查阅中文手册。此外通过中文手册可知F_PCLK有两种情况:
-  PCLK1用于USART2、3、4、5。 
-  PCLK2用于USART1 
USART发送和接收的配置步骤
USART的配置步骤比较简单。
-  通信双方确定好波特率、停止位数、校验方式、字长。 
-  通过 USART_SR.RXNE[5]产生的中断(接收数据寄存器非空),去异步接收数据。
-  通过直接读写USART_DR寄存器可以实现数据的接收和发送。 
-  需要的话,可以等待 USART_SR.TC[6]被硬件置位,来确保发送完成。
-  处理中断后,一定要注意彻底清除中断相应的标志位!防止中断假触发! 
USART发送和接收的代码
我的开发板硬件连接图如下,所以本实验使用USART1进行串口通信。

并且,将PA9、PA10分别配置成推挽复用输出、浮空输入或带上拉输入。


代码如下:
int fputc(int ch,FILE *p) {//函数默认的,在使用printf函数时自动调用USART_SendData(USART1,(u8)ch);	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);return ch;
}void LunarNVICInit(){NVIC_InitTypeDef NVIC_Cfg;// 配置系统中断分组NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// CPU上开启USART的中断NVIC_Cfg.NVIC_IRQChannel = USART1_IRQn;NVIC_Cfg.NVIC_IRQChannelCmd = ENABLE;NVIC_Cfg.NVIC_IRQChannelPreemptionPriority = 2;NVIC_Cfg.NVIC_IRQChannelSubPriority = 2;NVIC_Init(&NVIC_Cfg);}void LunarInitUSART1() {GPIO_InitTypeDef GPIOA9_Cfg, GPIOA10_Cfg;USART_InitTypeDef USART1_Cfg;// PARCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);// 初始化GPIOA9为复用 (发送GPIOA9_Cfg.GPIO_Mode = GPIO_Mode_AF_PP;GPIOA9_Cfg.GPIO_Pin = GPIO_Pin_9;GPIOA9_Cfg.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIOA9_Cfg);// 初始化GPIOA10为复用 (接收GPIOA10_Cfg.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIOA10_Cfg.GPIO_Pin = GPIO_Pin_10;GPIO_Init(GPIOA, &GPIOA10_Cfg);// USART1RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);USART1_Cfg.USART_BaudRate = 115200;USART1_Cfg.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;USART1_Cfg.USART_Parity = USART_Parity_No;USART1_Cfg.USART_StopBits = USART_StopBits_1;USART1_Cfg.USART_WordLength = USART_WordLength_8b;USART1_Cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Init(USART1, &USART1_Cfg);// 接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 打开usartUSART_Cmd(USART1, ENABLE);
}// 中断处理程序
void USART1_IRQHandler(void) {if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {	// 接收数据中断uint16_t data = USART_ReceiveData(USART1);USART_SendData(USART1, data);while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);USART_ClearFlag(USART1, USART_FLAG_TXE);} else {// 其他中断不做处理}// 顺序去读SR和DR清楚ORE位if (USART_GetFlagStatus(USART1, USART_FLAG_ORE) != RESET){USART_ReceiveData(USART1);// USART_ClearFlag(USART1, USART_FLAG_ORE); // 函数USART_ClearFlag清楚不了USART_FLAG_ORE!!!}
}int main() {// 初始化usartLunarInitUSART1();LunarNVICInit();printf("stm32 启动\n");while(1) {}return 0;}
实验结果就是上位机通过给串口发送字符串,上位机接收框出现回显的效果。
本章完结
相关文章:
 
STM32快速入门(串口传输之USART)
STM32快速入门(串口传输之USART) 前言 USART串口传输能实现信息在设备之间的点对点传输,支持单工、半双工、全全双工,一般是有三个引脚:TX、RX、SW_RX(共地)。不需要一根线来同步时钟。最大优…...
什么是网络安全和网络隐私?
什么是网络安全?这个是我最感兴趣的话题,网络安全说白了就是在网络上的安全,跟现实中一样,现实中为了家里的安全,我们会给家门上锁,会装监控,农村的话可能还会养一条狗,只有我们让别人进我们家,别人才能进来,对于计算机来说也是一样的,我们会设置账户的密码,会设置防火墙,会安…...
 
树莓派变小路由器放出热点wifi
环境 树莓派4Bubuntu20 作用 树莓派放出wifi后,笔记本电脑连接树莓派的wifi,并且ip配置在一个网段,就可以互相通信(笔记本放出wifi,树莓派连接效果一样),这样的好处是树莓派只要一上电就会自…...
 
数据猎手:使用Java和Apache HttpComponents库下载Facebook图像
引言 在信息驱动的时代,互联网上的数据成为了无可比拟的宝藏。本文旨在探讨如何通过利用Java和Apache HttpComponents库,从全球最大的社交网络平台Facebook上获取图像数据。 作为全球最大的社交网络平台,Facebook聚集了数以亿计的用户&#…...
uniapp——阻止冒泡
点击事件阻止冒泡 click.stop"onSubmit"其他类型,比如视频: 最后加了一个 click.stop <view class"videoBox" v-if"item.video_url"><video :src"i.image(item.video_url)" :controls"true&quo…...
 
Jmeter性能测试(四)
一、遇到问题解决思路 1、检查请求头是否正确 2、检查请求参数是否正确 3、检查鉴权信息是否正确 4、检查变量作用域 5、检查数据提取是否正确(正则/json提取器) 二、请求头检查 1、在Http信息头管理器查看 2、注意这里的变量作用域是全局的 三、请求参数检查 1、在查看结…...
从零开始精通RTSP之传输ADPCM等音频流
概述 在上一篇文章中,我们详细介绍了使用RTP传输AAC音频流的打包方法。除了AAC编码算法外,常用的音频编码算法还有ADPCM、G711A、G711U、G726等。接下来,我们继续介绍RTP传输ADPCM等音频流的打包方法。 封装方法 RTP封装ADPCM等音频数据时&am…...
 
box-decoration-break 使用介绍
box-decoration-break属性的使用 一、定义 box-decoration-break是CSS片段模块(CSS Fragmentation Module Level 3)中的一个属性,主要用于指定背景(background)、内边距(padding)、边框&#…...
 
技术分享 | 京东商品API接口|京东零售数据可视化平台产品实践与思考
导读 本次分享题目为京东零售数据可视化平台产品实践与思考。 主要包括以下四个部分: 1.京东API接口介绍 2. 平台产品能力介绍 3. 业务赋能案例分享 01 京东API接口介绍 02 平台产品能力介绍 1. 产品矩阵 数据可视化产品是一种利用数据分析和可视化技术&…...
 
OpenHarmony鸿蒙蓝牙BLE调试app
OpenHarmony蓝牙模块提供了ble的功能,本篇提供一个简单的app供测试时使用。代码使用API10,对应4.0Release版本固件。 1.开启BLE 开启BLE前,先在设置界面中打开蓝牙开关。 openBle()函数负责打开ble扫描,并打印扫描结果。主要代…...
 
HackMyVM-VivifyTech
目录 信息收集 arp nmap nikto whatweb WEB web信息收集 wpscan feroxbuster hydra 提权 系统信息收集 横向渗透 git提权 get root 信息收集 arp ┌──(root㉿0x00)-[~/HackMyVM] └─# arp-scan -l Interface: eth0, type: EN10MB, MAC: 08:00:27:9d:6d:7b, …...
将unity中相机位置保存为json 文件或者 发送给后端
将unity中相机位置保存保存到服务器 ///相机的位置public Transform cameraTransform;void Start(){// SaveCameraPosition("sd");// ("{\"name\":\"sd\",\"position\":\"(0.00, 5.00, -12.00)\",\"rotation\&qu…...
vue2-表单组件封装
创建组件 components/test/index.vue <template><el-form :model"formData">// <!-- 具名插槽 --><slot name"header" /><el-form-itemv-for"(item, index) in formItem":key"index":label"item.la…...
 
智能家居4 -- 添加接收消息的初步处理
这一模块的思路和前面的语言控制模块很相似,差别只是调用TCP 去控制 废话少说,放码过来 增添/修改代码 receive_interface.c #include <pthread.h> #include <mqueue.h> #include <string.h> #include <errno.h> #include <…...
 
Python selenium
1.搭建环境 1.安装: pip install msedge-selenium-tools 不要使用pip install selenium,我的电脑上没法运行 2.下载驱动 Microsoft Edge WebDriver |Microsoft Edge 开发人员 edge浏览器点设置---关于即可找到版本号,一定要下载对应版…...
Python内置函数next()详解
Python的next()函数是一个内置函数,用于从迭代器中获取下一个元素。如果迭代器耗尽,则抛出StopIteration异常。 函数定义 next()函数的基本语法如下: next(iterator[, default])iterator:一个迭代器对象。default:可…...
 
初识指针(1)<C语言>
前言 指针是C语言中比较难的一部分,大部分同学对于此部分容易产生“畏难情结”,但是学习好这部分对C语言的深入很大的帮助,所以此篇主要以讲解指针基础为主。 指针概念 变量创建的本质就是在内存中申请空间,找到这个变量就需要地址…...
uniapp使用vconsole调试 兼容App
前言:引入vconsole发现uniapp打出来的包里,看不到vconsole,uniapp开发的h5需要使用vconsole真机调试,如果直接在main.ts引入,打包后整个项目会页面空白,经实验在单个页面引入可解决,以下是解决方…...
 
论文笔记模版
1. 摘要 1.1 背景 1.2 挑战 1.3 提出新方法 1.4 贡献 2. 引言 2.1 背景(引出问题) ①介绍大背景: ② 应用场景: ③ 介绍主题: 2.2 引出挑战 一般用图表来展现出我们的挑战(直观,解决什…...
 
docker-本地私有仓库、harbor私有仓库部署与管理
一、本地私有仓库: 1、本地私有仓库简介: docker本地仓库,存放镜像,本地的机器上传和下载,pull/push。 使用私有仓库有许多优点: 节省网络带宽,针对于每个镜像不用每个人都去中央仓库上面去下…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
 
【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
 
转转集团旗下首家二手多品类循环仓店“超级转转”开业
6月9日,国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解,“超级…...
 
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
 
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
 
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
OpenLayers 分屏对比(地图联动)
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能,和卷帘图层不一样的是,分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...
 
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
 
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
