当前位置: 首页 > article >正文

STM32F103_LL库+寄存器学习笔记06 - 梳理串口与串行发送“Hello,World“

导言


USART是嵌入式非常重要的通讯方式,它的功能强大、灵活性高且用途广泛。只停留在HAL库层面上用USART只能算是入门,要加深对USART的理解,必须从寄存器层面入手。接下来,先从最简单的USART串行发送开始。

另外,在接下来的几个章节里,我会逐步地完成一个能在实际产品上使用,可靠的、健壮的串口收发的驱动程序。 比如,为了实现高效地收发程序,肯定要用DMA。然后配合DMA的传输过半中断、传输完成中断来实现高效的串口数据发送与接收。比如,时刻监控USART的健康状态,及时发现通讯异常,解决问题。比如,增加超时通讯机制,进一步提高系统的稳定性等等。
如果你只停留在USART串行发送 + USART接收中断的实践上,那么你真的很有必要再重新梳理一遍怎样完成一个高效且稳定的串口收发程序。废话不多说,开始。

效果如下所示:
每隔1是发送一条字符串"Hello,Wrold.\r\n"。
在这里插入图片描述
项目地址:https://github.com/q164129345/MCU_Develop/tree/main/stm32f103_ll_library06_usart

一、CubeMX


在这里插入图片描述
在这里插入图片描述

二、代码(LL库)


2.1、main.c

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.1.1、MX_USART1_UART_Init()

在这里插入图片描述

2.1.1.1、USART1_TX(PA9)

在这里插入图片描述
复习一下GPIO的寄存器CRL/CRH,如下:
在这里插入图片描述

2.1.1.2、USART1_RX(PA10)

在这里插入图片描述
复习一下GPIO的寄存器CRL/CRH,如下:
在这里插入图片描述

2.1.1.3、为什么USART模式下,PA9与PA10要这样设置GPIO???

在这里插入图片描述
如上所示,《STM32F1参考手册》章节8.1.11看到,当GPIO用在USART功能时,TX引脚需要设置推挽复用输出,RX引脚需要设置浮空输入或者带上拉输入。
在这里插入图片描述
如上所示,从这张表里看到另外一个很常用的通讯方式CAN总线,TX引脚也是设置推挽复用输出,RX引脚也是设置浮空输入或者带上拉输入。

2.1.1.4、USART1

在这里插入图片描述

三、寄存器梳理


3.1、发送器

在这里插入图片描述
《STM32F1参考手册》的章节25.3.2-发送器一定要多看几遍,总的来说:

  1. 将要发送的字节放入USART_DR寄存器之前,一定要等待USART_SR的位TXE = 1。代码如下:
void USART1_SendChar_Reg(uint8_t c) {  // 等待TXE置位(发送缓冲区空)  while (!(USART1->SR & (1 << 7)));  // 写入数据到DR  USART1->DR = c;  
}
  1. USART_TXE是发送的”第一级缓冲“状态,表示数据从USART_DR到移位寄存器的转移完成,并不意味着数据已经完全发送出去。如下图所示:
    在这里插入图片描述
  2. USART_TC才是代表数据完成发送出去,TC = 1时,表明硬件发送通道完全空闲。比如在低功耗场景中,通过TC = 1的判断,进入低功耗模式。
  3. 在单字节发送流程里,TXE会先置1,TC后置1。用户写入USART_DR->TXE清零。接着,数据转移到移位寄存器->TXE置1,此时可以写入新数据。最后,移位寄存器逐位发送数据->发送完成,TC置1。

3.2、时钟RCC_APB2ENR

在这里插入图片描述
启动外设之前,先启动对应的外设时钟。 如上所示,寄存器RCC_APB2ENR的位14-USART1EN是USART的时钟,置1相当于开启USART时钟。

RCC->APB2ENR |= (0x01UL << 14UL); // 使能USART1时钟(位14)
RCC->APB2ENR |= (0x01UL << 2UL);  // 使能GPIOA(打开该时钟是因为USART1的TX、RX使用PA9与PA10

3.2、GPIO_CRH

在这里插入图片描述
如上所示,PA9是USART1_TX,PA10是USART1_RX。

// PA9,复用功能推挽输出模式
GPIOA->CRH &= ~(0xFUL << 4UL); // 清除CNF9与MODE9
GPIOA->CRH |= (0xAUL << 4UL);  // 复用功能推挽输出模式(CNF9 = 10,MODE9 = 11),最大速度50MHz// PA10,浮空输入模式
GPIOA->CRH &= ~(0xFUL << 8UL); // 清除CNF10与MODE10
GPIOA->CRH |= (0x4UL << 8UL);  // 浮空输入模式(CNF10 = 01,MODE10 = 00)

3.3、USART1

3.3.1、USART_BRR

在这里插入图片描述
摘自《STM32F1参考手册》章节25.3.4,波特率(BBR) = fck / 16 * USARTDIV。

计算过程:

  1. SystemClock设置72M,APB2没有分频,所以USART1的fck = 72MHz。
  2. BBR = fck / (16 * BaudRate) = 72000000 / (16 * 115200) = 39.0625。 整数部分39,小数部分0.0625 * 16 = 1。
  3. 写入USART1->BBR = 0x271(39 << 4 | 1)。 如下所示,39 << 4UL的目的是设置DIV_Mantissa,最后|1是设置DIV_Fraction。
    在这里插入图片描述

3.3.2、配置数据帧格式 - USART_CR1与USART_CR2

一般情况下UART通讯的数据帧格式是:8位数据 + 1位停止位 + 无奇偶校验。
在这里插入图片描述
在这里插入图片描述
如上所示,USART_CR1的M(字长)置0与PCE(校验控制使能)置0。

USART1->CR1 &= ~(0x01UL << 12UL); // 位M清0,数据一共8位
USART1->CF1 &= ~(0x01UL << 10UL); // 位PCE清0,禁止校验控制

在这里插入图片描述
如上所示,USART_CR2的段STOP置0。

USART1->CR2 &= ~(0x3UL << 12UL); // 位12、13置0,1个停止位

3.3.3、配置传输方向 - USART_CR1

在这里插入图片描述
在这里插入图片描述
如上所示,USART_CR1的TE与RE都置1。

USART1->CR1 |= (1UL << 3UL); // 使能发送
USART1->CR1 |= (1UL << 2UL); // 使能接收

3.3.4、禁用硬件流控 - USART_CR3

在这里插入图片描述
如上所示,USART_CR3的RTSE置0。

USART->CR3 &= ~(0x01UL << 8UL); // RTSE = 0,禁用硬件控流

3.3.6、清除无关模式位 - USART_CR2与USART_CR3

在这里插入图片描述
如上所示:

  • 禁止CK引脚输出时钟。
  • 禁止LIN模式。
    在这里插入图片描述
    如上所示:
  • 不使能红外模式。
  • 不选择半双工模式。
  • 禁止智能卡模式。
// (6) 配置异步模式 (清除无关模式位)
USART1->CR2 &= ~(1UL << 14);      // LINEN 位 = 0, 禁用 LIN 模式
USART1->CR2 &= ~(1UL << 11);      // CLKEN 位 = 0, 禁用时钟输出
USART1->CR3 &= ~(1UL << 5);       // SCEN 位 = 0, 禁用智能卡模式
USART1->CR3 &= ~(1UL << 1);       // IREN 位 = 0, 禁用 IrDA 模式
USART1->CR3 &= ~(1UL << 3);       // HDSEL 位 = 0, 禁用半双工

3.3.7、启用USART

在这里插入图片描述
如上所示,USART_CR1的UE置1,让USART模块使能。

USART1->CR1 |= (1UL << 13UL); // USART模块使能

四、代码(寄存器方式)


4.1、main.c

在这里插入图片描述
如上所示,函数USART1_Configure(void)用于初始化外设USART1。

  1. 错误修复: 第80行代码,改为GPIOA->CRH |= (0x09UL << 4UL)才对,速度10MHz的话,MODE9 = 01。所以应该是1001 = 0x09。

在这里插入图片描述
如上所示,函数USART1_SendString(const char \*str)用于串行发送字符串。
在这里插入图片描述
如上所示,在main()的while(1)里每隔1S执行一次函数USART1_SendString()发送字符串"Hello,World.\r\n"
在这里插入图片描述
如上所示,代码编译成功。
在这里插入图片描述

五、细节补充


5.1、为什么要清除无关模式位?

《3.3.6-清除无关模式位 - USART_CR2与USART_CR3》讲到怎样清除无关模式位,都是将某些位清0。实际上从《STM32F1参考手册》了解到,这些位(比如位14-LINEN)在系统初始化的时候默认就是0的。为什么我的代码还要再一次清0呢?多此一举吗?

首先,ST的LL库代码也会显式清除这些位。MX_USART1_UART_Init()函数里的LL_USART_ConfigAsyncMode(),它的内容如下:
在这里插入图片描述
既然LL库也会这样做,肯定有原因的。我的理解是:

  • 之前的状态可能非复位值:
    如果 USART 之前被其他程序或中断配置过(例如在 Bootloader 或其他初始化代码中),这些位可能被设置为 1。因此,即使复位值是 0,显式清除可以确保当前状态明确为禁用状态,避免遗留问题。
  • 代码可读性和可维护性:
    显式清除这些位(即使默认是 0)可以增强代码的可读性,让读者清楚地知道这些功能被故意禁用,而不是依赖复位值。这种做法在嵌入式开发中很常见,属于“防御性编程”。

5.2、为什么外设USART的校验功能一般都是关闭?

  1. 硬件奇偶校验的局限性
    • 只能检测单比特错误:硬件奇偶校验仅能检测数据传输中的单个比特错误,无法检测或纠正多比特错误。对于高可靠性应用(如工业通信、航空航天),这种检测能力不足。
    • 性能开销:启用硬件奇偶校验会增加通信帧长度(例如 8 位数据 + 1 位校验 + 1 停止位 = 10 位),从而降低有效数据吞吐量,尤其在高速通信中影响较大。
    • 复杂性增加:硬件奇偶校验需要发送端和接收端严格匹配配置(奇/偶、数据长度等),否则会导致错误(PE 标志),增加调试难度。
  2. 软件校验的灵活性
    • 更强大的错误检测:软件可以实现更复杂的校验算法,如 CRC-8、CRC-16、CRC-32,甚至自定义校验和。这些方法能检测多比特错误并提供更高的可靠性。
    • 协议层整合:在通信协议(如 Modbus、CAN、I2C)中,通常已经定义了标准校验机制(如 Modbus 的 LRC 或 CRC),硬件奇偶校验可能重复或冲突,不如直接在协议层实现。
    • 可扩展性:软件校验可以根据需要动态调整(如改变校验算法或长度),而硬件奇偶校验固定在硬件层面,缺乏灵活性。
  3. 工程实践的习惯
    • 简单性优先:在低成本或简单应用中(如串口调试、传感器通信),开发者往往选择关闭硬件奇偶校验,简化配置(使用 8-N-1 格式:8 位数据、无校验、1 停止位),并通过软件实现必要校验。
    • 兼容性:许多设备和工具(如串口调试助手)默认使用无校验配置,启用硬件奇偶校验可能导致不兼容。

5.3、USART1默认是PA9、PA19,怎样复用到PB6、PB7?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如上所示,从寄存器AFIO_MAPR的bit2-USART1_REMAP可以设置USART1所使用的引脚。代码例子如下:
在这里插入图片描述

相关文章:

STM32F103_LL库+寄存器学习笔记06 - 梳理串口与串行发送“Hello,World“

导言 USART是嵌入式非常重要的通讯方式&#xff0c;它的功能强大、灵活性高且用途广泛。只停留在HAL库层面上用USART只能算是入门&#xff0c;要加深对USART的理解&#xff0c;必须从寄存器层面入手。接下来&#xff0c;先从最简单的USART串行发送开始。 另外&#xff0c;在接…...

硬件基础--14_电功率

电功率 电功率:指电流在单位时间内做的功(表示用电器消耗电能快慢的一个物理量)。 单位:瓦特(W)&#xff0c;简称瓦。 公式:PUI(U为电压&#xff0c;单位为V&#xff0c;i为电流&#xff0c;单位为A&#xff0c;P为电功率&#xff0c;单位为W)。 单位换算:进位为1000&#xff…...

【C#语言】C#文件操作实战:动态路径处理与安全写入

文章目录 ⭐前言⭐一、场景痛点⭐二、完整实现代码⭐三、关键技术解析&#x1f31f;1、动态路径处理&#x1f31f;2、智能目录创建&#x1f31f;3、安全的文件写入 ⭐四、进阶扩展方案&#x1f31f;1、用户自定义路径选择&#x1f31f;2、异常处理增强&#x1f31f;3、异步写入…...

Vue.js 完全指南:从入门到精通

1. Vue.js 简介 1.1 什么是 Vue.js? Vue.js(通常简称为 Vue)是一个用于构建用户界面的渐进式 JavaScript 框架。所谓"渐进式",意味着 Vue 的设计是由浅入深的,你可以根据自己的需求选择使用它的一部分或全部功能。 Vue 最初由尤雨溪(Evan You)在 2014 年创…...

在Git仓库的Readme上增加目录页

一般在编写Readme时想要增加像文章那样的目录&#xff0c;方便快速跳转&#xff0c;但是Markdown语法并没有提供这样的方法&#xff0c;但是可以通过超链接结合锚点的方式来实现&#xff0c;如下图是我之前一个项目里写的Readme&#xff1a; 例如有下面几个Readme内容&#xff…...

C# SolidWorks 二次开发 -各种菜单命令增加方式

今天给大家讲一讲solidworks中各种菜单界面&#xff0c;如下图&#xff0c;大概有13处&#xff0c;也许还不完整哈。 1.CommandManager选项卡2.下拉选项卡3.菜单栏4.下级菜单5.浮动工具栏6.快捷方式工具栏7.FeatureManager工具栏区域8.MontionManager区域 ModelView?9.任务窗…...

分布式架构-Spring技术如何能实现分布式事务

在Spring技术栈中实现分布式事务&#xff0c;可通过多种成熟方案实现跨服务或跨数据库的事务一致性管理。以下是主要实现方式及技术要点&#xff1a; 一、基于Seata框架的AT模式 ‌核心组件‌ ‌TC (Transaction Coordinator)‌&#xff1a;全局事务协调器&#xff08;独立部署…...

【RocketMQRocketMQ Dashbord】Springboot整合RocketMQ

【RocketMQ&&RocketMQ Dashbord】Springboot整合RocketMQ 【一】Mac安装RocketMQ和RocketMQ Dashbord【1】安装RocketMQ&#xff08;1&#xff09;下载&#xff08;2&#xff09;修改 JVM 参数&#xff08;3&#xff09;启动测试&#xff08;4&#xff09;关闭测试&…...

vue 3 深度指南:从基础到全栈开发实践

目录 一、环境搭建与项目初始化 1. 前置依赖安装 2. 项目初始化与结构解析 二、核心概念与语法深度解析 1. MVVM 模式与响应式原理 2. 模板语法与指令进阶 3. 组件化开发 三、进阶开发与全栈集成 1. 路由管理&#xff08;Vue Router&#xff09; 2. 状态管理&#xf…...

《白帽子讲 Web 安全》之跨站请求伪造

引言 在数字化时代&#xff0c;网络已深度融入人们生活的方方面面&#xff0c;Web 应用如雨后春笋般蓬勃发展&#xff0c;为人们提供着便捷高效的服务。然而&#xff0c;繁荣的背后却潜藏着诸多安全隐患&#xff0c;跨站请求伪造&#xff08;CSRF&#xff09;便是其中极为隐蔽…...

K8S学习之基础五十:k8s中pod时区问题并通过kibana查看日志

k8s中pod默认时区不是中国的&#xff0c;挂载一个时区可以解决 vi pod.yaml apiVersion: v1 kind: Pod metadata:name: counter spec:containers:- name: countimage: 172.16.80.140/busybox/busybox:latestimagePullPolicy: IfNotPresentargs: [/bin/sh,-c,i0;while true;do …...

nginx代理前端请求

一&#xff0c;项目配置 我在 ip 为 192.168.31.177 的机器上使用 vue3 开发前端项目&#xff0c;项目中使用 axios 调用后端接口。 这是 axios 的配置&#xff1a; import axios from axios;const request axios.create({baseURL: http://192.168.31.177:8001,// 设置请求…...

LibVLC —— 《基于Qt的LibVLC专业开发技术》视频教程

🔔 LibVLC/VLC 相关技术、疑难杂症文章合集(掌握后可自封大侠 ⓿_⓿)(记得收藏,持续更新中…) 《基于Qt的LibVLC专业开发技术》课程视频,(CSDN课程主页、51CTO课程主页) 适合具有一些C++/Qt编程基础,想要进一步提高或涉足音视频行业的。本课程分7章节,共计35小节。…...

Android生态大变革,谷歌调整开源政策,核心开发不再公开

“开源”这个词曾经是Android的护城河&#xff0c;如今却成了谷歌的烫手山芋。最近谷歌宣布调整Android的开源政策&#xff0c;核心开发将全面转向私有分支。翻译成人话就是&#xff1a;以后Android的核心更新&#xff0c;不再公开共享了。 这操作不就是开源变节吗&#xff0c;…...

Android Gradle 插件问题:The option ‘android.useDeprecatedNdk‘ is deprecated.

问题与处理策略 问题描述 在 Android 项目中&#xff0c;报如下警告 The option android.useDeprecatedNdk is deprecated. The current default is false. It has been removed from the current version of the Android Gradle plugin. NdkCompile is no longer supported…...

【web应用安全】关于web应用安全的几个主要问题的思考

文章目录 防重放攻击1. **Token机制&#xff08;一次性令牌&#xff09;**2. **时间戳 超时验证**3. **Nonce&#xff08;一次性随机数&#xff09;**4. **请求签名&#xff08;如HMAC&#xff09;**5. **HTTPS 安全Cookie**6. **幂等性设计****综合防御策略建议****注意事项…...

Git 基础入门:从概念到实践的版本控制指南

一、Git 核心概念解析 1. 仓库&#xff08;Repository&#xff09; Git 的核心存储单元&#xff0c;包含项目所有文件及其完整历史记录。分为本地仓库&#xff08;开发者本地副本&#xff09;和远程仓库&#xff08;如 GitHub、GitLab 等云端存储&#xff09;&#xff0c;支持…...

银行分布式新核心的部署架构(两地三中心)

银行的核心系统对可用性和性能要求均非常严苛&#xff0c;所以一般都采用两地三中心部署模式。 其中&#xff1a; 同城两个主数据中心各自部署一套热备&#xff0c;平时两个中心同时在线提供服务&#xff0c;进行负载均衡假如其中一个数据中心出现异常&#xff0c;则由另外一个…...

Spring 及 Spring Boot 条件化注解(15个)完整列表及示例

Spring 及 Spring Boot 条件化注解完整列表及示例 1. 所有条件化注解列表 Spring 和 Spring Boot 提供了以下条件化注解&#xff08;共 15 个&#xff09;&#xff0c;用于在配置类或方法上实现条件化注册 Bean 或配置&#xff1a; 注解名称作用来源框架Conditional自定义条件…...

MantisBT在Windows10上安装部署详细步骤

MantisBT 是一款基于 Web 的开源缺陷跟踪系统&#xff0c;以下是在 Windows 10 上安装部署 MantisBT 的详细步骤&#xff1a; 1. 安装必要的环境 MantisBT 是一个基于 PHP 的 Web 应用程序&#xff0c;因此需要安装 Web 服务器&#xff08;如 Apache&#xff09;、PHP 和数据…...

9.4分漏洞!Next.js Middleware鉴权绕过漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;Next.js 存在一个授权绕过漏洞&#xff0c;编号为 CVE-2025-29927。攻击者可能通过发送精心构造的 x-middleware-subrequest 请求头绕过中间件安全控制&#xff0c;从而在未授权的情况下访问受保护…...

处理json,将接口返回的数据转成list<T>,和几个时间处理方法的工具类

接口或者其他方式返回json格式&#xff0c;也可以直接处理里边只有list的json数据 //第一种json格式&#xff0c;包含分页信息 {"code": 200,"msg": null,"data": {"records": [{"风速": "0.0","电流"…...

OpenCV图像拼接(5)图像拼接模块的用于创建权重图函数createWeightMap()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::createWeightMap 是 OpenCV 库中用于图像拼接模块的一个函数&#xff0c;主要用于创建权重图。这个权重图在图像拼接过程中扮演着重…...

linux 运行脚本命令区别

文章目录 chmod 赋予权限运行sh script.sh适用场景 bash script.shsource 或 . 脚本 chmod 赋予权限运行 chmod x script.sh # 赋予执行权限 ./script.sh # 直接执行创建新的子进程&#xff0c;不会影响当前 shell 的环境变量。#!&#xff08;Shebang&#xff09; 指…...

【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置

噩梦终结&#xff1a;Flutter 配安卓、鸿蒙、iOS 真机调试环境 问题背景 很多开发者在配置 Flutter 项目环境时遇到困难&#xff0c;尤其是在处理 Android、鸿蒙和 iOS 真机调试环境时。卓伊凡最近接手了一个项目&#xff0c;发现很多“专业程序员”在环境搭建上花费了大量时…...

C++11QT复习 (六)

类型转换函数和类域 **Day6-3 类型转换函数和类域****1. 类型转换函数&#xff08;Type Conversion Functions&#xff09;****1.1 概述****1.2 代码示例****1.3 关键优化** **2. 类域&#xff08;Class Scope&#xff09;****2.1 作用域 vs 可见域****2.2 代码示例****2.3 关键…...

区块链技术在投票系统中的应用:安全、透明与去中心化

区块链技术在投票系统中的应用:安全、透明与去中心化 【引言】 近年来,电子投票系统因其便捷性受到广泛关注,但随之而来的安全问题也屡见不鲜,如选票篡改、重复投票、数据泄露等。如何确保投票的公平性、透明度和安全性? 区块链技术或许是解决方案之一! 区块链的 去中…...

CTF类题目复现总结-[MRCTF2020]ezmisc 1

一、题目地址 https://buuoj.cn/challenges#[MRCTF2020]ezmisc二、复现步骤 1、下载附件&#xff0c;得到一张图片&#xff1b; 2、利用010 Editor打开图片&#xff0c;提示CRC值校验错误&#xff0c;flag.png应该是宽和高被修改了&#xff0c;导致flag被隐藏掉&#xff1b;…...

MetInfo6.0.0目录遍历漏洞原理分析

所需进行代码审计的文件路径&#xff1a; C:\phpStudy\WWW\MetInfo6.0.0\include\thumb.php C:\phpStudy\WWW\MetInfo6.0.0\app\system\entrance.php C:\phpStudy\WWW\MetInfo6.0.0\app\system\include\class\load.class.php C:\phpStudy\WWW\MetInfo6.0.0\app\system\include…...

linux打包前端vue,后端springboot项目

第一步先对整个项目进行通过maven进行clean在进行compile 第二步直接进行打包package和install都可以 第三部把对应的jar放到服务器上 把jar包放到服务器上某个地址下&#xff0c;然后cd到这个目录下&#xff0c;然后执行命令 nohup java -jar ruoyi-admin.jar > springbo…...