Appearance
《STM32实战快速入门》课程讲义
课程介绍
STM32F1单片机教程
此教程以动手为主,解决大伙学了半天单片机不知道干什么的问题。
本课程涉及的内容和知识以小项目为基本单元(暂规划如下)
/* 01. 电动车报警器 ====》 IO控制入门 */
/* 02. 感应开关盖垃圾桶 ====》 定时器,PWM开发,超声波 */
/* 03. 基于wifi的智能控制插座 =====》 串口开发,ESP8266模块AT控制指令学习,中断学习*/
/* 04. 基于蓝牙HC-05的智能控制插座 =====》 串口开发,蓝牙穿透*/
/* 05. 基于4G的智能控制插座 =====》 串口开发,蓝牙穿透*/
/* 06. 温湿度检测系统 ======》 DS18B20单线协议,如何看时序图,IIC协议液晶屏显示,SPI协议液晶显示*/
/* 07. 语音控制开关灯 ======》 语音模块二次开发 */
/* 08. 智能小车_远程控制/壁障/寻迹/数据采集等 ======》 综合性项目 */
- 课程要求:C语言熟练,如果C语言不好,可以学习良许老师录制的C语言课程。
不仅讲理论,而且更注重实践,在项目中学会理论,不知不觉学会玩转STM32!
资料下载及参考文章
1. 资料及源码下载
课程所有资料对学员完全公开,可以找助理领取。
资料目录架构如下:

2. 参考文章
2.1 本讲义
学习的过程一定要以本讲义为主,配合视频教程,将 STM32 的每个外设、常用模块、通讯协议全部啃下。
2.2 课程配套的参考文章

如何高效学习本课程
将所有视频全部看完,并且一定要动手实操,一定要动手实操,一定要动手实操!!!
光看不练将会造成眼高手低(貌似这个知识点见过,但想不起来,更不会写)。
1. 遇到问题如何解决?
- 多看几遍视频,勤思考,网上搜索相关帖子,培养独立思考能力;
- 半年班、年班、永久班以及其他包含答疑服务的学员,可在答疑群里向答疑老师提问;
- 问题解决之后,一定要做好笔记,保存解决方案,下次问题再出现可快速解决。
2. 代码没按预期运行怎么办?
- 首先解决接线问题,检查一下接线是否跟老师一样;
- 然后再将老师的代码烧录进去,看看代码是否正常运行;
- 使用代码比对工具,查看自己的代码与老师有何不同。
在学习阶段,有参考代码,可以使用代码比对工具快速排查问题所在。
而在工作中,没有参考代码,就要求自己具备独立解决问题的能力。随着学习进度的推进,代码量的积累,将形成自己的代码库,降低出 bug 的概率。我们不怕写 bug ,怕的是不懂解 bug 。问题解决得越多,自己解决问题的能力就变得越强。
代码比对工具推荐:
- beyond compare(收费)
- 在线文本比对:http://www.kuquidc.com/textDifference/
一、基础入门
1. 零基础快速上手STM32开发
1.1 前置准备
1.1.1 电脑配置要求
- 最好是 Windows 电脑
- CPU:i5 及以上
- 内存:16G 及以上
1.1.2 安装包及驱动
- MDK5 安装包
- 芯片固件包
- STM32CubeMX安装包
- CH340驱动
- ST-Link驱动
- 示例代码
1.1.3 硬件准备
- 上官二号
- ST-Link
- USB转TTL模块
- 杜邦线若干
1.2 安装MDK5
编程语言:C语言
需要安装的软件有两个:Keil5 和 STM32CubeMX
使用 Keil4 写 STM32 代码其实也是可以,但需要很复杂的配置,不建议新手操作。
比较推荐 Keil5 编写 STM32 ,只需要一些简单的设置就可以上手,对新手友好。
安装
安装包(不需要太新,本课程以 MDK324 为例,最新的 MDK327 有问题)
安装过程一路下一步即可(建议不要安装在 C 盘)
安装路径一定不要有中文或空格!!(重要)
Keil5 安装完之后,记得安装 F1 固件包
破姐
使用
- 编程与编译过程与 Keil4 完全一样
1.3 驱动安装
CH340驱动
ST-Link驱动
1.4 程序编译

第一个按钮: Translate 就是翻译当下修改过的文件,说明白点就是检查下有没有语法错误,并不会去链接库文件,也不会生成可执行文件。
第二个按钮: Build 就是编译当下修改过的文件,它包含了语法检查,链接动态库文件,生成可执行文件。
第三个按钮: Rebuild 重新编译整个工程,跟 Build 这个按钮实现的功能是一样的,但有所不同的是它编译的是整个工程的所有文件,耗时巨大。
在实际工作中,我们最经常使用的就是第二个按钮,另外两个用得不多,尤其是第一个。
1.5 程序下载
1.5.1 硬件接线

1.5.2 MDK配置
1.5.3 下载
1.5.4 注意事项
MDK一定要配置好;
设备的接线,只要有一根线没接对,就无法完成下载;
编译好程序;
板子一定要上电。
2. 初识单片机
2.1 什么是单片机
身边单片机案例:
- 共享单车
- 门禁系统
- 打卡机
- 快递柜
- 航空航天
- ……
单片机(Single-Chip Microcomputer)单片机微型计算机,是一种集成电路芯片,把具有数据处理能力的中央处理器 CPU、随机存储器 RAM、闪存 flash、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。

单片机特点:
- 体积小:<5mm*5mm
- 功耗低:mA级
- 集成度高:IO/TIM/AD/DA
- 使用方便:C/Debug
- 扩展灵活:IIC/SPI/FSMC
2.2 Cortex-M系列介绍
2.2.1 ARM公司与ST公司
ARM公司:只做内核设计和 IP 授权,不参与芯片设计。
ST公司:拿到 ARM 公司授权后,进行芯片设计。类似的公司还有华为、高通、NXP 等。
2.2.2 ARM内核系列
A 系列:Application缩写。高性能应用,比如:手机、电脑、电视等。
R 系列:Real-time缩写。实时性强,汽车电子、军工、无线基带等。
M 系列:Microcontroller缩写。超低功耗,工控、消费电子、家电、医疗器械等。
性能由高到低,时钟频率由高到低。
2.2.3 STM32命名规则
ST -- 意法半导体
M -- Microelectronics 微电子
32 -- 总线宽度

3. 数据手册相关
3.1 如何获取数据手册
ST官网:www.st.com


中文社区网:
https://www.stmcu.com.cn/Designresource/list/STM32F1/document/datasheet


其它途径获取:
- 万能的百度
- 淘宝详情页白嫖
3.2 如何阅读数据手册
芯片手册
参考手册
4. 嵌入式硬件基础
4.1 认识上官二号开发板
- 主控芯片:STM32F103C8T6
- 高速晶振:8M
- 低速晶振:32.768k
- LED:5 颗
- KEY:3 个
| 项目 | 介绍 |
|---|---|
| 内核 | Cortex-M3 |
| Flash | 64K x 8bit |
| SRAM | 20K x 8bit |
| GPIO | 37个GPIO,分别为PA0-PA15、PB0-PB15、PC13-PC15、PD0-PD1 |
| ADC | 2个12bit ADC合计12路通道,外部通道:PA0到PA7+PB0到PB1 内部通道: 温度传感器通道ADC_Channel_16和内部参考电压通道ADC_Channel_17 |
| 定时器/计数器 | 4个16bit定时器/计数器,分别为TIM1、TIM2、TIM3、TIM4,TIM1带死区插入,常用于产生PWM控制电机 |
| 看门狗定时器 | 2个看门狗定时器(独立看门狗IWDG、窗口看门狗WWDG) |
| 滴答定时器 | 1个24bit向下计数的滴答定时器systick |
| 工作电压、温度 | 2V~3.6V、-40°C~85°C |
| 通信接口 | 2 * IIC,2 * SPI,3 * USART,1 * CAN |
| 系统时钟 | 内部8MHz时钟HSI最高可倍频到64MHz,外部8MHZ时钟HSE最高可倍频到72MHZ |
4.2 STM32F103C8T6引脚分布
- 电源引脚
基本以字母 V 开头,比如 VDD/VSS、VDDA/VSSA、VREF+/VREF-、VBAT 等。
VDD/VSS:数字部分电源正/负引脚,为 STM32 供电。
VDDA/VSSA:模拟部分电源正/负引脚,为内部模拟部分供电。
VREF+/VREF-:为 ADC/DAC 提供参考电压,100 脚以上的型号才有这两个脚。
VBAT:RTC/后备区域供电引脚。
- 晶振引脚
一共两组:OSC_IN/OSC_OUT、OSC_IN32/OSC_OUT32。
OSC_IN/OSC/OUT:外部 HSE 晶振引脚(高速),用于给 STM32 提供高精度系统时钟。
OSC_IN32/OSC_OUT32:外部 LSE 晶振引脚(低速),用于给 STM32 内部 RTC 提供晶振。
内部晶振:HSI、LSI
- 复位引脚
只有一个:NRST
用于复位 STM32 ,低电平有效。
- 下载引脚
三种下载引脚。
第一种:JTAG

可仿真/调试,但占用引脚数较多;
第二种:SWD

可仿真/调试,占用引脚数较少,强烈建议!
第三种:串口
只能串口 1 ,其它串口不行!

只能下载程序,不可调试。
- BOOT引脚
BOOT0 及 BOOT1 ,启动选择引脚。
- GPIO引脚
以字母 P 开头的都是 GPIO 引脚。
4.3 STM32最小系统
单片机最小系统是指能够将单片机芯片运行所必需的最少的硬件电路集成在一起的系统。
它是一种基本的单片机应用系统,通常由主芯片,时钟电路,复位电路,电源电路,BOOT启动电路,程序下载电路,扩展接口组成,为单片机提供时钟信号、复位信号以及外设接口等必要功能。

STM32中的晶振是一个非常重要的组成部分,它为整个系统提供了一个稳定的时钟源。具体来说,晶振在STM32中的作用如下:
- 提供时钟信号:晶振是一个振荡器,它会产生连续的脉冲信号,这些信号的频率非常稳定。STM32微控制器中的CPU和其他外围设备需要一个稳定的时钟信号来协调它们的工作。因此,晶振为整个系统提供了一个可靠的时钟源,使得各个模块能够以相同的频率工作,从而保证系统的稳定性和准确性。
- 决定CPU的工作速度:晶振的频率决定了CPU的工作速度。频率越高,CPU的执行速度就越快;反之,频率越低,CPU的执行速度就越慢。因此,根据实际需求选择合适的晶振,可以确保系统在满足性能要求的同时,不会造成不必要的功耗浪费。
- 确保外围设备的正常工作:除了CPU之外,系统中还有很多其他的外围设备,如串口、定时器、ADC等。这些外围设备也需要时钟信号来进行工作。晶振提供的时钟信号可以确保这些外围设备正常、准确地工作。
- 解决电磁兼容性问题:一些外围设备在工作时可能会产生电磁干扰,这些干扰可能会影响系统的稳定性。而晶振产生的时钟信号是高度稳定的,因此使用晶振可以减少由于电磁干扰导致的系统误差或故障。
综上所述,晶振在STM32微控制器中起着非常重要的作用。它不仅为整个系统提供了一个稳定的时钟源,还决定了CPU的工作速度和外围设备的正常工作。因此,选择合适的晶振对于保证系统的稳定性和准确性至关重要。
4.4 电路基础知识
上拉、下拉电阻
电容、电阻、电感、三级管






4.5 如何查看原理图
时钟电路
复位电路
电源电路
BOOT启动电路
程序下载电路
扩展接口
5. 开发环境搭建
5.1 官方安装包/器件支持包获取
5.1.1 MDK5官方安装包获取
链接:https://www.keil.com/demo/eval/arm.htm#/DOWNLOAD
当前最新版本是 MDK539 ,但新版并不意味着最好,可能会有一些奇奇怪怪的问题,也可能不稳定。

5.1.2 官方器件包获取
什么是器件包呢?由于 ST 公司生产了非常多的芯片,每颗芯片所需要的支持文件都不一样,这些文件组合起来就是器件包。
但有这么多芯片,他们不可能把所有的器件包都集成在 MDK5 里,否则 MDK5 的安装包将变得超级无敌巨大,很占空间也没必要。比较好的解决方案就是你需要用到什么芯片,就安装对应的器件包就可以了。
器件包也是在官网上可以下载到,网址如下:


5.1.3 STM32CubeMX官方安装包获取
链接:https://www.st.com/content/st_com/zh/stm32cubemx.html

5.2 STM32CubeMX 的安装
作用
- 通过界面的方式,快速生成工程文件。
下载
安装
- 一路下一步,建议不要安装在C盘
配置
更新固件包位置(比较大,默认在C盘,可以更改到其它盘)
- help ---> update settings --> Firmware Repository
5.3 为什么要安装 CH340 驱动?



5.4 五种方法下载程序
6. MDK5配置及使用技巧
6.1 MDK5基本使用
6.2 MDK5的一些推荐配置
编辑器设置

代码提示及语法检测

快速定位函数或变量定义

6.3 MDK5的使用技巧
6.3.1 查找匹配花括号
control+e
6.3.2 Tab键的妙用
- 一次填充 4 个空格
- 代码段整体右移/左移
6.3.3 快速注释/取消注释
- 选中代码段 →

- 选中代码段 → Comment Selection
6.3.4 快速编辑一列
按住 Alt 选择一列编辑
6.3.5 快速打开头文件
右击,选择open document
6.3.6 快速拆分窗口
右击标签页,选择 new horizontal/vertical tab group
6.3.7 查找/替换功能

7. MDK5调试功能
8. C语言基础复习
8.1 数据类型
| 关键字 | 位数 | 表示范围 | stdint关键字 | ST关键字 |
|---|---|---|---|---|
| char | 8 | -128 ~ 127 | int8_t | s8 |
| unsigned char | 8 | 0 ~ 255 | uint8_t | u8 |
| short | 16 | -32768 ~ 32767 | int16_t | s16 |
| unsigned short | 16 | 0 ~ 65535 | uint16_t | u16 |
| int | 32 | -2147483648 ~ 2147483647 | int32_t | s32 |
| unsigned int | 32 | 0 ~ 4294967295 | uint32_t | u32 |
| long | 32 | -2147483648 ~ 2147483647 | ||
| unsigned long | 32 | 0 ~ 4294967295 | ||
| long long | 64 | -(2^64)/2 ~ (2^64)/2-1 | int64_t | |
| unsigned long long | 64 | 0 ~ (2^64)-1 | uint64_t | |
| float | 32 | -3.4e38 ~ 3.4e38 | ||
| double | 64 | -1.7e308 ~ 1.7e308 |
8.2 宏定义
在C语言中,宏定义是一种预处理指令,用于将一个标识符(宏名)替换为指定的字符串。这个过程称为“宏展开”或“宏替换”。宏定义是通过使用#define预处理命令来完成的。
宏定义主要有以下作用:
- 提升易读性:比如
#define HIGH 1 - 便于批量修改:比如
#define PIN 5
宏定义的一般形式如下:
c
#define 宏名 字符串其中,宏名是你给标识符起的名字,而字符串可以是常数、表达式、格式串等。在预处理阶段,对程序中所有出现的“宏名”,预处理器都会用宏定义中的字符串去替换,这称为“宏替换”或“宏展开”。
例如,下面的代码演示了如何使用宏定义来定义一个常量:
c
#define PI 3.14159在这个例子中,我们使用#define命令定义了一个名为PI的宏,并将其替换为字符串3.14159。在程序中,每次出现PI时,它都会被替换为3.14159。
除了简单的文本替换,C语言的宏定义还支持一些更复杂的操作,如算术运算和逻辑运算。例如:
c
#define AREA(x) (x * x)在这个例子中,我们定义了一个名为AREA的宏,它接受一个参数x,并返回x * x的结果。当程序中出现AREA(5)时,它会被替换为(5 * 5)。
需要注意的是,宏定义只进行简单的文本替换,而不进行计算或求值。这意味着,宏定义的代码不会被编译器执行或计算,而只是直接替换掉相应的文本。因此,在使用宏定义时需要小心避免出现副作用或错误的结果。
8.3 typedef
typedef是C语言中的一个关键字,用于为复杂的数据类型定义简单的别名。通过使用typedef,可以为现有的数据类型创建一个新的名称,这样可以使代码更加简洁、易读。
typedef可以用于为基本数据类型、结构体、联合体等定义别名。例如,可以定义一个名为SIZE的类型,该类型为unsigned int类型:
c
typedef unsigned int SIZE;之后,在代码中可以使用SIZE作为unsigned int类型的别名:
c
SIZE a = 10;
a = 20;typedef还可以用于简化指针类型的使用。例如,可以定义一个指向整数的指针类型:
c
typedef int* IntPtr;之后,可以使用IntPtr作为指向整数的指针类型的别名:
c
IntPtr p = malloc(sizeof(int));
*p = 10;需要注意的是,使用typedef定义的别名并不会改变原有的数据类型,而只是为该类型定义了一个新的名称。因此,在使用别名时,需要注意不要混淆原有的数据类型和别名。
typedef与宏定义区别:
- 宏定义新名字在左边,typedef在右边;
- 宏定义不需要分号,typedef需要分号;
- 宏定义一切都可以替换,而typedef只能替换数据类型;
- 宏定义只是无脑改名,而typedef会做检查;
8.4 条件编译
C语言中的条件编译是一种预处理指令,它允许根据某些条件决定是否编译某段代码。条件编译在编译时根据条件来选择性地包含或排除代码块,这对于调试、多平台支持、配置设置等场景非常有用。
C语言中的条件编译主要通过#if、#ifdef、#ifndef、#else、#elif和#endif等预处理指令来实现。这些指令可以在代码的任何位置使用,以根据特定的条件来控制代码的编译。
下面是一些条件编译的示例:
- #if:根据条件决定是否编译某段代码。
c
#if 表达式
// 如果表达式为真,则编译下面的代码
#endif- #ifdef:如果宏已经定义,则编译某段代码。
c
#ifdef 宏名
// 如果宏已经定义,则编译下面的代码
#endif- #ifndef:如果宏未定义,则编译某段代码。
c
#ifndef 宏名
// 如果宏未定义,则编译下面的代码
#endif- #else:在条件编译的其他指令之后使用,如果之前的条件不满足,则编译此处的代码。
c
#ifdef 宏名1
// 如果宏1已定义,则编译下面的代码
#else
// 如果宏1未定义,则编译此处的代码
#endif- #elif:用于多条件判断。类似于其他编程语言中的
else if。
c
#if 表达式1
// 如果表达式1为真,则编译下面的代码
#elif 表达式2
// 如果表达式1为假且表达式2为真,则编译下面的代码
#endif这些条件编译指令可以根据需要进行组合,以实现更复杂的条件判断和代码控制。需要注意的是,条件编译的判断是在预处理阶段进行的,因此它不会影响程序的运行时行为。
8.5 结构体
C语言中的结构体(struct)是一种用户自定义的数据类型,它是由若干基本数据类型集合组成的一种自定义数据类型,也叫聚合类型。结构体可以包含不同类型的数据成员,并且这些数据成员可以是相同、部分相同或完全不同的数据类型。
定义结构体的语法如下:
c
struct 结构体名 {
数据类型 成员名1;
数据类型 成员名2;
...
数据类型 成员名n;
};在定义结构体后,可以在程序中使用该结构体来声明变量,并为其分配内存空间。例如:
c
struct Student {
char gender;
int age;
float score;
};
struct Student stu1;在上面的例子中,我们定义了一个名为Student的结构体类型,它包含三个成员:gender、age和score。然后我们声明了一个名为stu1的结构体变量,并为其分配了内存空间。
结构体变量可以用于存储具有不同属性或特征的数据,例如学生的性别、年龄和成绩。结构体中的成员可以通过点运算符(.)来访问,例如stu1.name表示访问stu1变量的name成员。
此外,C语言还提供了结构体数组、结构体指针等用法,以便更灵活地处理和操作结构体数据。
8.6 枚举
C语言中的枚举(enum)是一种用户定义的数据类型,它允许你为一组整数值分配有意义的名字。枚举常用于为变量的可能值定义有意义的名称,或者为编译器的内部值分配用户定义的名称。
枚举的一般形式如下:
c
enum 枚举名 {
常量1, 常量2, ...
};其中,枚举名是你给枚举类型起的名字,而常量1、常量2等是该枚举类型的成员名。这些成员名在编译时会被赋予整数值,默认从0开始,每次递增1。
例如:
c
enum Color {
RED=0, GREEN, BLUE
};在这个例子中,我们定义了一个名为Color的枚举类型,它有三个成员:RED、GREEN和BLUE。这三个成员在编译时会被赋予整数值,分别是0、1和2。
枚举还可以用来限制变量取值范围。通过枚举,你可以为变量定义一组预定义的、有意义的值,从而确保变量的取值始终在预期的范围内。
例如,假设你正在编写一个关于星期几的程序,你可以使用枚举来定义一个星期中每天的值:
c
enum Weekday {
MONDAY=1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
};然后,你可以声明一个枚举类型的变量,并为其分配一个有效的星期几值:
c
enum Weekday today;
today = MONDAY; // 或者其他有效的枚举值通过这种方式,你可以确保today变量的取值始终在MONDAY到SUNDAY的范围内。如果尝试为today分配一个无效的值,编译器有可能会报错。
8.7 指针
C语言中的指针是一种特殊的变量,它存储了一个内存地址,这个地址可以是其他变量的地址,也可以是数组的元素、结构体、函数等类型的地址。通过指针,我们可以间接地访问和操作这些内存地址所指向的内容。
指针的定义和声明方式如下:
c
type* ptr;其中,type表示指针所指向的数据类型,ptr是变量名。例如,定义一个指向整数的指针:
c
int* p;指针的赋值可以通过取地址运算符&来实现,例如:
c
int a = 10;
p = &a; // p指向变量a的内存地址通过指针访问其所指向的内容需要使用解引用运算符*,例如:
c
int value = *p; // 获取p所指向的整数值除了基本的指针操作,C语言还提供了指针的算术运算和关系运算。例如,指针的加法可以用于遍历数组,指针的减法可以用于计算两个指针之间的距离。指针与整数之间的运算需要特别小心,因为可能导致内存访问越界等问题。
以下是一些C语言指针的例子:
- 定义并初始化指针:
c
int x = 10;
int *p = &x; // p指向变量x的地址- 通过指针访问变量:
c
int value = *p; // 获取p所指向的整数值,即x的值
*p = 20; // 修改p所指向的整数值,即x的值- 指针的算术运算:
c
int arr[5] = {1, 2, 3, 4, 5};
int *ptr = arr; // ptr指向数组的首地址
int i = 0;
for (i = 0; i < 5; i++) {
printf("%d ", *(ptr + i)); // 输出数组元素的值
}- 动态内存分配:
c
int *p = malloc(sizeof(int)); // 分配一个整数的内存空间,返回指向该空间的指针p
if (p != NULL) {
*p = 20; // 在该内存空间中存储整数值20
printf("%d\n", *p); // 输出20
free(p); // 释放内存空间
}这些例子展示了C语言中指针的基本用法和常见操作。通过指针,我们可以更加灵活地操作内存和实现复杂的数据结构。但同时也要注意指针的使用可能会导致内存泄漏、野指针等问题,需要谨慎处理。
9. STM32系统入门
9.1 F1系列内核和芯片系统架构

9.2 存储器映像
STM32 寻址范围:2^32 = 4 * 2^10 *2^10 K = 4 * 2^10 M = 4G
地址所访问的存储单元是按字节编址的。
0x0000 0000 ~ 0xFFFF FFFF
什么是存储器映射?
存储器本身不具有地址信息,给存储器分配地址的过程称为存储器映射。
例如:给小区 1000 户人家分配门牌号就叫存储器映射。
| 类型 | 起始地址 | 存储器 | 用途 |
|---|---|---|---|
| ROM | 0X0800 0000 | 程序存储器Flash | 存储C语言编译后的程序代码 |
| ROM | 0X1FFF F000 | 系统存储器 | 存储BootLoader,用于串口下载 |
| ROM | 0X1FFF F800 | 选项字节 | 存储一些独立于程序代码的配置参数 |
| RAM | 0X2000 0000 | 运行内存SRAM | 存储运行过程中的临时变量 |
| RAM | 0X4000 0000 | 外设寄存器 | 存储各个外设的配置参数 |
| RAM | 0XE000 0000 | 内核外设寄存器 | 存储内核各个外设的配置参数 |
ROM:只读存储器,非易失性,掉电不丢失的存储器(类似于硬盘);
RAM:随机存储器,易失性,掉电丢失的存储器(类似内存)。

9.3 寄存器映射
9.3.1 什么是寄存器

寄存器本质也是内存!!通过控制寄存器可以实现对外设工作的控制。
数据寄存器:高压锅的液晶显示屏;
控制寄存器:开关、食物类型、口感
状态寄存器:加热/升压/保压/减压
中断:饭煮熟了将嘀嘀响
9.3.2 寄存器映射
寄存器是特殊的存储器,给寄存器地址命名的过程,就叫作寄存器映射。
例如:门牌号 1208 -- 良许家,门牌号 1209 -- 老王家
寄存器地址:0x4001080C -- 寄存器名字:GPIOx_ODA

| 直接操作寄存器 | 寄存器映射再操作 |
|---|---|
| 门牌号1209 = 一斤大米两个鸡蛋 | 老王家 = 一斤大米两个鸡蛋 |
| *(unsined int *)(0x4001080C) = 0xFFFF | GPIOx_ODR = 0xFFFF |
9.3.3 如何进行外设地址映射?
总线基地址+外设相对于总结基地址偏移量+寄存器相对于外设基地址偏移量
例如:有个小区叫追西西,里面分成三个区:A 区、B 区、C 区,每区有 10 栋楼,每栋楼有 20 户人家。
相应每户人家门牌号类似于:A 区 5 栋 1209 户。
总线基地址:
| 总线 | 基地址 | 偏移量 |
|---|---|---|
| APB1 | 0X4000 0000 | 0 |
| APB2 | 0X4001 0000 | 0X1 0000 |
| AHB | 0X4001 8000 | 0X1 8000 |
外设 GPIO 基地址:
| 外设 | 基地址 | 偏移量 |
|---|---|---|
| GPIOA | 0X4001 0800 | 0X800 |
| GPIOB | 0X4001 0C00 | 0XC00 |
| GPIOC | 0X4001 1000 | 0X1000 |
| GPIOD | 0X4001 1400 | 0X1400 |
GPIOA 寄存器地址:
| 寄存器 | 地址 | 偏移量 |
|---|---|---|
| GPIOA_CRL | 0X4001 0800 | 0X00 |
| GPIOA_CRH | 0X4001 0804 | 0X04 |
| GPIOA_IDR | 0X4001 0808 | 0X08 |
| GPIOA_ODR | 0X4001 080C | 0X0C |
| GPIOA_BSRR | 0X4001 0810 | 0X10 |
| GPIOA_BRR | 0X4001 0814 | 0X14 |
| GPIOA_LCKR | 0X4001 0818 | 0X18 |
上代码!
10. 新建HAL版本工程模板
10.1 手把手教你创建模板工程

10.2 什么是CMSIS
ARM 是一个做芯片标准的公司,它负责的是芯片内核的架构设计,而TI、ST这样的公司,他们并不做标准,他们是芯片公司,他们是根据 ARM 公司提供的芯片内核标准设计自己的芯片。所以,任何一个做 Cortex M3 芯 片 ,他们的内核结构都是一样的,不同的是他们的存储器容量, 片上外设 IO 以及其他模块的区别。

ARM Cortex™ 微控制器软件接口标准(Cortex Microcontroller Software Interface Standard)是 Cortex-M 处理器系列的与供应商无关的硬件抽象层。使用CMSIS,可以为处理器和外设实现一致且简单的软件接口,从而简化软件的重用、缩短微控制器新开发人员的学习过程,并缩短新设备的上市时间。

10.3 标准库与 HAL 库
- 寄存器
寄存器众多,需要经常翻阅芯片手册,费时费力;
更大灵活性,可以随心所欲达到自己的目的;
深入理解单片机的运行原理,知其然更知其所以然。
- 标准库
将寄存器底层操作都封装起来,提供一整套接口(API)供开发者调用
每款芯片都编写了一份库文件,也就是工程文件里stm32F1xx…之类的;
配置结构体变量成员就可以修改外设的配置寄存器,从而选择不同的功能;
大大降低单片机开发难度,但是在不同芯片间不方便移植。
- HAL库(Hardware Abstraction Layer)
ST公司目前主力推的开发方式,新的芯片已经不再提供标准库;
为了实现在不同芯片之间移植代码;
为了兼容所有芯片,导致代码量庞大,执行效率低下。
10.4 两个宏的意义
- USE_HAL_DRIVER
- STM32F103xB
10.5 常见文件意义
- startup_stm32f102xb.s
启动文件,用于初始化硬件、设置堆栈和中断向量表,然后跳转到 C/C++ 的主程序入口点(main 函数)。
- stm32f1xx_it.c
中断服务例程文件,它包含了处理各种中断的 C 语言函数实现,例如定时器中断、外部中断等
- system_stm32f1xx.c
定义了系统初始化函数 SystemInit 和系统时钟更新函数SystemCoreClockUpdate
- sm32f1xx_hal.c
HAL库初始化、系统滴答、HAL库延时等相关函数
- stm32f1xx_hal_cortex.c
内核通用函数定义和声明,如NVIC、MPU、系统软复位、Systick等,其实主要是对core_cm3.h 文件的相关函数再次封装。
- stm32f1xx.h
是所有F1系列的顶层头文件,通过条件编译来包含某个芯片的头文件,定义通用的枚举类型,定义通用的宏定义
- stm32f103xb.h
包含:中断编号定义、外设寄存器结构体类型定义、寄存器映射、寄存器位定义、外设判定
- stm32f1xx_hal_conf.h
HAL库的用户配置文件,用于裁剪HAL库、配置晶振参数等
- stm32hxx_hal_def.h
包含HAL库通用的枚举类型数据和宏定义
- stm32f1xx_hal_ppp.c
某任意外设驱动源码,PPP表示任意外设
- stm32f1xx_hal_ppp_ex.c
主要是存放外设的扩展(特殊)功能的驱动源码,PPP表示任意外设
11. 细讲STM32启动
11.1 STM32启动流程
复位/上电
根据 BOOT0/BOOT1 确定程序从哪个存储位置执行
初始化 SP 及 PC 指针
将 0X08000000 位置的栈顶地址存放在 SP 指针中
将 0x08000004 位置存放的向量地址装入 PC 程序计数器
初始化系统时钟
初始化用户堆栈
进入main函数

11.2 map文件
map 文件是 MDK 编译代码后,产生的集程序、数据及IO空间的一种映射列表文件。简单来说就是包括了:各种.c文件、函数、符号等的地址、大小、引用关系等信息。
作用: 用于分析各 .c 文件占用 FLASH 和 RAM 的大小,方便优化代码。
map 文件大致可以分为五大部分,每部分的作用如下:
- 模块、段(入口)交叉引用(Section Cross References):描述了各文件之间函数的调用关系,有助于理解各个源文件如何相互关联。
- 移除未使用的模块(Removing Unused input sections from the image):描述了工程中未用到而被删除的冗余程序段,有助于优化代码,降低内存负担。
- 映射符号表(Image Symbol Table):描述了各符号(程序段、数据)在存储器中的地址、类型、大小等信息,对于理解程序的内存布局以及定位特定代码或数据段非常有用。
- 内存(映射)分布(Memory Map of the image):描述了各程序段(函数)在存储器中的地址及占用大小,有助于分析程序的内存占用情况。
- 映射组件大小(Image component sizes):给出了整个映像代码(.o)占用空间的汇总信息,包括代码、只读数据、已初始化读写数据、未初始化读写数据等的大小,有助于了解程序的总体内存使用情况。
MAP文件的这五部分提供了对程序内存布局、函数调用关系、以及各模块占用情况的全面分析,是STM32开发中重要的优化和调试工具。
map 文件相关的一些基本概念
段(section):描述映像文件的代码和数据块 RO:Read-Only的缩写,包括RO-data(只读数据)和RO-code(代码) RW:Read-Write的缩写,主要是RW-data,RW-data由程序初始化初始值 ZI:Zero-initialized的缩写,主要是ZI-data,由编译器初始化为0。 .text:与RO-code同义 .constdata:与RO-data同义 .bss:与ZI-data同义 .data:与RW-data同义
12. 时钟树
12.1 时钟树是什么?
- 什么是时钟?
时钟是由电路产生的具有周期性的脉冲信号,相当于单片机的心脏,给单片机提供一个统一的信号。
要想使用单片机的外设必须开启相应的时钟。
HSE = 高速外部时钟
HSI = 高速内部时钟
LSI = 低速内部时钟
LSE = 低速外部时钟
- 时钟树

12.2 系统时钟配置
二、GPIO
1. 什么是GPIO?
GPIO是通用输入输出端口(General-purpose input/output)的英文简写,是所有的微控制器必不可少的外设之一,可以由STM32直接驱动从而实现与外部设备通信、控制以及采集和捕获的功能。
GPIO口可配置为多种输入输出模式,如输入浮空、输入上拉、输入下拉、模拟输入、开漏输出、开漏复用功能、推挽式输出以及推挽式复用功能等。
STM32单片机的GPIO被分为很多组,每组最多有16个引脚,不同型号的 MCU 的GPIO个数是不同的。
引脚电平:0V~3.3V,部分引脚可容忍5V。
2. GPIO内部结构

3. GPIO工作模式
| 模式名称 | 类型 | 模式介绍 |
|---|---|---|
| 浮空输入 | 数字输入 | 浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的 |
| 上拉输入 | 数字输入 | IO口在无输入的情况下,保持高电平 |
| 下拉输入 | 数字输入 | IO口在无输入的情况下,保持低电平 |
| 模拟输入 | 模拟输入 | 输入信号不经施密特触发器直接接入,输入信号为模拟量而非数字量,其余输入方式输入数字量 |
| 开漏输出 | 数字输出 | 只能输出低电平 |
| 推挽输出 | 数字输出 | 可以输出高、低电平 |
| 复用开漏输出 | 数字输出 | 参考复用推挽 |
| 复用推挽输出 | 数字输出 | 此时 IO 受内部外设控制,比如定时器的 PWM,比如 SPI 的 MOSI ,MISO 等。 而普通的推挽输出,则 IO 受 ODR 控制 |
4. GPIO寄存器介绍
5. GPIO库函数介绍
模块:LED
LED是发光二极体(Light Emitting Diode, LED)的简称,也被称作发光二极管,正向通电点亮,反向通电不亮。

如何判断 LED 灯引脚极性?
- 引脚长的为正,短的为负
- 电极大的为负极,小的为正极
- 贴片LED灯有做记号的为负极
LED 灯常见接线方式:

小实验1:点亮一颗 LED 灯
实验目的
点炸亮 LED1 。
硬件清单
- 上官二号
- ST-Link
小实验2:流水灯
实验目的
间隔 500ms 轮流点亮 LED1 和 LED2。
硬件清单
- 上官二号
- ST-Link
模块:蜂鸣器
蜂鸣器实物图:

蜂鸣器驱动电路:

如何让蜂鸣器鸣响?将I/O引脚拉低即可。
模块工作电压:3.3V
有源蜂鸣器与无源蜂鸣器的区别:
有源蜂鸣器内部带有震荡源,只要给它通电,它就会发出声音,但是声音音调是单一的,频率是固定的。
无源蜂鸣器内部没有震荡源,需要用一定频率的方波(常见的频率范围在2K到5K之间)去驱动它才可以发声。由于可以通过不同频率的方波驱动,其声音频率是可控的,可以模拟出多种声音效果,甚至达到唱歌的效果。
小实验:让蜂鸣器响起来
实验目的
驱动蜂鸣器以 500ms 间隔鸣响。
硬件清单
- 上官二号
- ST-Link
- 蜂鸣器
模块:按键
按键实物图:

作用:按下导通,松手断开
按键抖动:
按键抖动是指在按键开关被按下或释放的瞬间,由于机械触点的弹性作用或电信号的短暂波动,导致开关状态不稳定,出现短暂的抖动现象。这种抖动现象会影响按键的识别和处理,可能导致按一次键而输入多次,影响设备的正常运行和用户的使用体验。

软件消抖:
通过延时跳过抖动的时间段,再判断IO输入电平。
小实验:按键控制LED灯
实验目的
按下 KEY1,翻转 LED1 状态;按下 KEY2 ,翻转 LED2 状态。
硬件清单
- 上官二号
- ST-Link
三、中断
1. 中断相关概念
1.1 什么是中断?
中断是单片机正在执行程序时,由于内部或外部事件的触发,打断当前程序,转而去处理这一事件,当处理完成后再回到原来被打断的地方继续执行原程序的过程。
在ARM体系结构中,中断通常由外设或外部输入产生,有时也可以由软件触发。中断是单片机系统处理紧急或突发事件的重要方式,如定时器溢出、按键输入、串口数据到达等。

1.2 中断的意义
中断的主要意义在于提高CPU的效率,而不会一直占用CPU,实现对突发事件的实时处理,以及实现程序的并行化和嵌入式系统进程之间的切换。相较于轮询方式(即按照一定的频率和周期不断地检测某些事件的发生),中断在处理一些偶然发生的事情时效率更高。
1.3 中断优先级
中断具有优先级高低之分,两个中断同时触发,则优先响应高优先级中断,再响应低优先级中断。
1.4 中断嵌套
如果一个高优先级的中断发生,它会立即打断当前正在处理的中断(如果其优先级较低),并首先处理这个高优先级的中断,这就是所谓的中断嵌套。

1.5 中断执行流程
当中断发生时,STM32的执行流程如下:首先,由外设发出中断请求;然后,处理器暂停当前执行的任务,保护现场(如将当前位置的PC地址压栈);接着,程序跳转到对应的中断服务程序(ISR)并执行;中断服务程序执行完毕后,恢复现场(如将栈顶的值送回PC);最后,处理器返回到被中断的位置,继续执行下一个指令。
2. STM32中断
2.1 STM32F103C8T6中断数量
STM32F103C8T6 支持的中断共有 70 个,其中包括 10 个内核中断和 60 个外部中断。外部中断包含 EXTI、TIM、USART、ADC、I2C、SPI 等等。

2.2 中断向量表
STM32的中断向量表是一个存储中断处理函数地址的数组,位于Flash区的起始位置。每个数组元素对应一个中断源,其地址指向相应的中断服务程序。当中断发生时,处理器会根据中断号查找向量表,然后跳转到对应的中断服务程序执行。
中断向量表的主要作用是解决中断函数地址不固定与中断必须跳转到固定地方执行程序之间的矛盾。由于编译器每次编译都会为中断函数随机分配地址,但硬件要求中断必须跳转到固定的位置,因此,中断向量表就作为这样一个固定的地址列表,其中包含了中断函数的地址以及跳转到这些地址的程序。当中断发生时,处理器会跳转到这个固定的中断向量表,然后根据其中的信息跳转到相应的中断处理函数,从而执行中断。

2.3 STM32中断框图


3. NVIC
3.1 NVIC介绍
NVIC,即Nested Vectored Interrupt Controller(嵌套向量中断控制器),是STM32中的中断控制器。它负责管理和协调处理器的中断请求,是STM32中处理异步事件的重要机制。
NVIC提供了灵活、高效、可扩展的中断处理机制,支持多级优先级、多向中断、嵌套向量中断等特性。当一个中断请求到达时,NVIC会确定其优先级并决定是否应该中断当前执行的程序,以便及时响应和处理该中断请求。这种设计有助于提高系统的响应速度和可靠性,特别是在需要处理大量中断请求的实时应用程序中。
NVIC 支持:256个中断(16内核+240外部),支持:256个优先级,允许裁剪。
3.2 NVIC工作原理

3.3 中断优先级基本概念
NVIC可以管理多个中断请求,并按优先级处理它们。在STM32中,中断优先级被划分为抢占式优先级和响应优先级,可以根据具体的应用需求进行配置。不同的优先级分组方式会影响中断的响应和处理顺序。
- 抢占优先级
如果一个中断的抢占优先级高于当前正在执行的中断,那么它可以打断当前中断,优先得到执行。数值越小,优先级越高。
- 响应优先级
如果两个中断同时到达,且它们的抢占优先级相同,那么响应优先级高的中断将首先得到响应。数值越小,优先级越高。
- 自然优先级
自然优先级是由硬件固定并预先设定的,用户无法更改。当抢占优先级和响应优先级都相同时,自然优先级将决定哪个中断先得到处理。
- 优先级执行顺序
当多个中断同时发生时,执行顺序首先由抢占优先级决定。如果抢占优先级相同,则进一步由响应优先级决定。如果响应优先级也相同,则最终由自然优先级决定。
在中断嵌套的情况下,高抢占优先级的中断可以打断低抢占优先级的中断,但高响应优先级的中断不能打断低响应优先级的中断(当它们具有相同的抢占优先级时)。
- 优先级分组
优先级寄存器 IPR 有 8 位,但实际只使用到高 4 位,用于决定抢占优先级、响应优先级的等级。
具体这 4 位如何切割?由又由 AIRCR 寄存器控制。
| 优先级分组 | AIRCR[10:8] | 抢占优先级 | 响应优先级 |
|---|---|---|---|
| 0 | 111 | 0位,取值为0 | 4位,取值为0~15 |
| 1 | 110 | 1位,取值为0~1 | 3位,取值为0~7 |
| 2 | 101 | 2位,取值为0~3 | 2位,取值为0~3 |
| 3 | 100 | 3位,取值为0~7 | 1位,取值为0~1 |
| 4 | 011 | 4位,取值为0~15 | 0位,取值为0 |
3.4 NVIC寄存器
| 寄存器名称 | 位数 | 寄存器个数 | 说明 |
|---|---|---|---|
| 中断使能寄存器(ISER) | 32 | 8 | 每个位控制一个中断 |
| 中断失能寄存器(ICER) | 32 | 8 | 每个位控制一个中断 |
| 应用程序中断及复位控制寄存器(AIRCR) | 32 | 1 | 位[10:8]控制优先级分组 |
| 中断优先级寄存器(IPR) | 8 | 240 | 8个位对应一个中断,而STM32只使用高4位 |
3.5 NVIC相关函数介绍
3.6 NVIC配置方法
设置中断分组 → 设置中断优先级 → 使能中断
设置中断分组一般在 HAL_Init 函数中进行。
4. EXTI
4.1 EXTI简介
EXTI 是 External Interrupt 的缩写,表示外部中断事件控制器。EXTI 可以监测指定 GPIO 口的电平信号变化,并在检测到指定条件时,向内核的中断控制器 NVIC 发出中断申请。NVIC 在裁决后,如果满足条件,会中断CPU的主程序,使 CPU 转而执行 EXTI 对应的中断服务程序。
EXTI 支持的触发方式:上升沿、下降沿、双边沿或软件触发。
EXTI 支持所有的 GPIO 口,但需要注意的是,相同的 Pin 不能同时触发中断。例如,PA0 和 PB0 不能同时被配置为中断源。
EXTI 提供了 16 个 GPIO_Pin 的中断线,以及额外的中断线如 PVD 输出、RTC 闹钟、USB 唤醒和以太网唤醒。
通过适当的配置,EXTI可以实现丰富多样的功能,如响应按键的按下、传感器的状态变化等外部事件。
4.2 中断/事件
中断会打断CPU当前正在执行的程序,转而去执行中断服务程序,待中断服务程序执行完毕后,CPU会返回到原来的程序执行点继续执行。
事件只是简单地表示某个动作或状态的变化,而不会打断CPU当前正在执行的程序。当事件发生时,它会根据配置来决定是否触发相应的中断。如果开放了对应的中断屏蔽位,事件就可以触发相应的中断,否则事件只会作为一个信号存在,不会被CPU处理。
4.3 EXTI基本结构

4.4 EXTI框图

4.5 EXTI寄存器
4.6 EXTI相关函数介绍
5. AFIO
5.1 AFIO简介
AFIO 是 Alternate Function Input/Output 的缩写,表示复用功能 IO,主要用于实现 I/O 端口的复用功能以及外部中断的控制。
STM32上有很多 I/ O口以及内置外设(如I2C、ADC、ISP、USART等)。为了节省引出管脚的数量,这些内置外设通常与 I/O 口共用管脚,即 I/O 管脚具有复用功能。例如,一个 GPIO 管脚除了可以作为普通的 I/O 端口外,还可以被复用为某个内置外设的功能引脚。
然而,为了优化64脚或100脚封装的外设数量,有时需要将一些复用功能重新映射到其他引脚上。这时,就可以使用AFIO的复用重映射功能。通过设置复用重映射和调试I/O配置寄存器(AFIO_MAPR),可以实现引脚的重新映射,使得复用功能不再映射到它们的原始分配上。
此外,AFIO 还用于控制外部中断,用来配置 EXTI 中断线 0~15 对应哪个具体 IO 口。
当需要使能外部中断线或进行外部中断线的映射时,通常需要开启AFIO的时钟。
5.2 AFIO与IO口对应关系


5.3 AFIO寄存器
5.4 AFIO相关函数介绍
6. EXTI配置流程

小实验:按键点灯(中断法)
实验目的
使用中断的方法,按下 KEY1 翻转 LED1 状态,而 LED2 一直保持 500ms 的频率闪烁。
注意:
按键驱动一般使用轮询法。
如果采用中断法,由于软件消抖需要在中断服务函数加入延时函数,这种做法一般是不被允许的。由于还未学到传感器模块及定时器,本实验暂时在中断服务函数中加入延时函数。硬件清单
- 上官二号
- ST-Link
模块:震动传感器
小实验:震动点灯
实验目的
使用中断的方法,振动传感器检测到振动时,LED1 点亮 2 秒,之后熄灭。
硬件清单
- 振动传感器
- 上官二号
- ST-Link
硬件接线
| STM32 | 振动传感器 |
|---|---|
| PA4 | DO |
| 3V3 | VCC |
| GND | GND |
模块:继电器
小实验:继电器定时开闭
实验目的
继电器 500ms 闭合,再 500ms 断开,如此循环。
硬件清单
- 继电器
- 上官二号
- ST-Link
硬件接线
| STM32 | 继电器 |
|---|---|
| PB7 | I/O |
| 3V3 | VCC |
| GND | GND |
模块:433M无线发送/接收模块
小实验:433M点灯实验
实验目的
按下遥控器 A 键,LED1 亮/灭;按下遥控器 B 键,LED2 亮/灭。
硬件清单
- 433M发送/接收模块
- 上官二号
- ST-Link
硬件接线
| STM32 | 433M |
|---|---|
| PB5 | D0 |
| PA12 | D1 |
| 5V | 5V |
| GND | GND |
模块:高功率喇叭
项目:电动车报警器
项目需求
点击遥控器 A 按键,系统进入警戒模式,一旦检测到震动(小偷偷车),则喇叭发出声响报警,吓退小偷。
点击遥控器 B 按键,系统退出警戒模式,再怎么摇晃系统都不会报警,否则系统一直发出尖叫,让车主尴尬。
硬件清单
振动传感器
继电器
高功率喇叭
433M无线接收发射模块
杜邦线
上官二号
ST-Link
硬件接线
| STM32 | 振动传感器 | 继电器 | 433M |
|---|---|---|---|
| PA4 | DO | ||
| PB7 | I/O | ||
| PB5 | D0 | ||
| PA12 | D1 | ||
| 3V3 | VCC | VCC | |
| 5V | 5V | ||
| GND | GND | GND | GND |
项目流程图

四、SysTick
1. SysTick介绍
1.1 什么是SysTick?
Systick,即滴答定时器,是内核中的一个特殊定时器,用于提供系统级的定时服务。该定时器是一个24位的递减计数器,具有自动重载值寄存器的功能。当计数器到达自动重载值时,它会自动重新加载并开始新的计数周期。
Systick定时器的主要功能包括实现简单的延时、生成定时中断以及进行精确定时和周期定时操作。此外,Systick定时器还可以被用于其他目的,例如作为操作系统的时基(如FreeRTOS),或者用于软件看门狗等系统调度操作。在STM32中,Systick通常以HCLK(AHB时钟)或HCLK/8作为运行时钟。
1.2 SysTick工作原理
在使用Systick定时器进行延时操作时,可以设定初值并使能后,每经过一个系统时钟周期,计数值就减1。当计数到0时,Systick计数器自动重装初值并继续计数,同时内部的COUNTFLAG标志会置位,触发中断(如果中断使能)。这样,可以在中断处理函数中实现特定的延时逻辑。


2. SysTick寄存器介绍
SysTick控制及状态寄存器(CTRL)
| 位段 | 名称 | 类型 | 复位值 | 描述 |
|---|---|---|---|---|
| 16 | COUNTFLAG | R | 0 | 如果在上次读取本寄存器后,SysTick已经数到了0,则该位为1。如果读取该位,该位自动清零 |
| 2 | CLKSOURCE | R/W | 0 | 0=外部时钟源(STCLK),ST公司将其应用为8分频 1=内核时钟(FCLK),ST公司将其应用为1分频 |
| 1 | TICKINT | R/W | 0 | 1=SysTick倒数到0时产生SysTick异常请求 0=数到0时无动作 |
| 0 | ENABLE | R/W | 0 | SysTick定时器的使能位 |
SysTick重装载数值寄存器(LOAD)
| 位段 | 名称 | 类型 | 复位值 | 描述 |
|---|---|---|---|---|
| 23:0 | RELOAD | R/W | 0 | 当倒数至零时,将被重装载的值 |
SysTick当前数值寄存器(VAL)
| 位段 | 名称 | 类型 | 复位值 | 描述 |
|---|---|---|---|---|
| 23:0 | CURRENT | R/W | 0 | 读取时返回当前倒计数的值,写它则使之清零,同时还会清除在SysTick控制及状态寄存器中的COUNTFLAG标志。 |
3. 手撸延时函数
4. 手撸带操作系统延时函数

小实验:SysTick模拟多线程
实验目的
使用SysTick模拟多线程,实现流水灯实验。
硬件清单
- 上官二号
- ST-Link
模块:红外传感器
小实验:红外点灯
实验目的
用手遮挡红外传感器,LED1 点亮 2 秒,之后熄灭。
硬件清单
- 红外传感器
- 上官二号
- ST-Link
硬件接线
| STM32 | 红外避障模块 |
|---|---|
| 5V | VCC |
| G | GND |
| B4 | OUT |
模块:LCD1602显示器
小实验:驱动LCD1602显示内容
实验目的
- 使用 LCD1602 显示一个字符;
- 使用 LCD1602 显示一个字符串。
硬件清单
- LCD1602
- 上官二号
- ST-Link
硬件接线
| STM32 | LCD1602 |
|---|---|
| GND | GND |
| 5V | VDD |
| GND | V0 |
| B1 | RS |
| B2 | RW |
| B10 | E |
| A0 | D0 |
| A1 | D1 |
| A2 | D2 |
| A3 | D3 |
| A4 | D4 |
| A5 | D5 |
| A6 | D6 |
| A7 | D7 |
| 3.3 | BLA |
| GND | BLK |
项目:智能排队控制系统
项目需求
- 红外传感器检测有人通过并计数;
- 计数值显示在LCD1602
- 允许通过时,LED1闪烁,蜂鸣器不响,继电器不闭合;
- 不允许通过时,LED2闪烁,蜂鸣器响,继电器闭合;
- 每次允许通过5个人,之后转为不允许通过,3秒后再转为允许通过
硬件清单
- 继电器(模拟匣机)
- 蜂鸣器
- 红外避障模块
- LCD1602
- 上官二号
- ST-Link
硬件接线
| STM32 | LCD1602 | 继电器 | 蜂鸣器 | 红外 |
|---|---|---|---|---|
| GND | GND | |||
| 5V | VDD | |||
| GND | V0 | |||
| B1 | RS | |||
| B2 | RW | |||
| B10 | E | |||
| A0 | D0 | |||
| A1 | D1 | |||
| A2 | D2 | |||
| A3 | D3 | |||
| A4 | D4 | |||
| A5 | D5 | |||
| A6 | D6 | |||
| A7 | D7 | |||
| 3.3 | BLA | VCC | VCC | VCC |
| GND | BLK | GND | GND | GND |
| B4 | OUT | |||
| B5 | I/O | |||
| B6 | IN |
项目框图

状态机
状态机(State Machine)是一种用于描述系统行为或功能行为的数学模型。它通常包含一组状态、一组转换条件以及动作执行。状态机通过在不同状态之间进行转换来模拟系统的行为。每个状态都代表系统的一个特定配置或情况,而转换规则则定义了从一个状态转换到另一个状态的条件和动作。
状态机广泛应用于多个领域,包括但不限于计算机科学、电子工程、通信、自动化和机器人技术等。在计算机科学中,状态机常用于描述软件系统的行为,特别是在硬件设计、编译器设计、网络协议以及用户界面交互等方面。
状态机的主要特点包括:
- 有限状态:状态机通常具有有限数量的状态。这些状态可以是有序的、离散的或层次化的。
- 转换条件:状态之间的转换是基于特定条件触发的。当满足某个条件时,状态机会从当前状态转换到下一个状态。
- 动作执行:在状态转换过程中,状态机可能会执行某些动作或操作。这些动作可以包括计算、数据更新、输出信号等。
- 确定性和非确定性:状态机可以是确定性的(每个条件唯一对应一个转换)或非确定性的(一个条件可能导致多个可能的转换)。
状态机的实现方式多种多样,可以使用编程语言中的条件语句、循环结构或专门的状态机库来实现。此外,硬件设计领域中的有限状态机(Finite State Machine, FSM)也是状态机的一种重要应用。

伪代码:
C
while(1)
{
if(state == 开心)
{
KTV();
撸串();
if(女朋友跟人跑了)
state = 郁闷;
}
else if(state == 郁闷)
{
抽烟();
嫩模();
if(交新女朋友了)
state = 开心;
else if(刷到良许直播)
state = 打鸡血;
}
else if(state == 打鸡血)
{
写bug();
改bug();
if(成功入行了)
state = 开心;
}
}
五、定时器
1. 定时器介绍
STM32F103C8T6微控制器内部集成了多种类型的定时器,这些定时器在嵌入式系统中扮演着重要角色,用于计时、延时、事件触发以及PWM波形生成、脉冲捕获等应用。下面是对STM32F103C8T6中几个定时器的简单介绍:
- TIM1:这是一个高级定时器,不仅具备基本的定时中断功能,还拥有内外时钟源选择、输入捕获、输出比较、编码器接口以及主从触发模式等多种功能。这使得TIM1能够适用于各种复杂的应用场景,为开发者提供强大的时间控制和信号处理能力。
- TIM2、TIM3和TIM4:这些是通用定时器,同样具有定时功能,但在功能上与高级定时器有所区别。通用定时器通常用于实现一些基本的定时任务,如LED闪烁、脉冲宽度测量等。
每个定时器都由一个16位计数器、预分频器和自动重装寄存器的时基单元组成。预分频器可以对时钟进行分频,计数器则对预分频后的时钟进行计数。当计数器的值达到设定值时,会触发中断,从而执行相应的定时任务。
2. 定时器工作原理
定时器的核心就是计数器。

3. 三种定时器介绍
| 类型 | 编号 | 总线 | 功能 |
|---|---|---|---|
| 高级定时器 | TIM1、TIM8 | APB2 | 拥有通用定时器全部功能,并额外具有重复计数器、死区生成、互补输出、刹车输入等功能 |
| 通用定时器 | TIM2、TIM3、TIM4、TIM5 | APB1 | 拥有基本定时器全部功能,并额外具有内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等功能 |
| 基本定时器 | TIM6、TIM7 | APB1 | 拥有定时中断、主模式触发DAC的功能 |
4. 定时器框图




5. 定时器计数模式


6. 定时器溢出时间计算

Tout:定时器溢出时间
Ft:定时器的时钟源频率
ARR:自动重装载寄存器的值
PSC:预分频器寄存器的值例如,要定时 500ms,则:PSC=7199,ARR=4999,Ft=72M
7. 定时器中断实验配置步骤

msp 函数是对 MCU 相关的硬件进行初始化设置,通常被设计用于处理特定硬件外设或功能的底层初始化工作
小实验1:定时器中断点灯
实验目的
使用定时器 2 进行中断点灯,500ms LED 灯翻转一次。
硬件清单
- 上官二号
- ST-Link
8. 输出比较原理
输出比较可以通过比较定时计数器的值 CNT 与设定的比较值 CCR,可以控制输出引脚的电平状态(置高或置低),从而实现生成一定频率和占空比的 PWM 波形。


9. PWM介绍
PWM波形(Pulse Width Modulation,脉冲宽度调制波形)是一种占空比可变的脉冲波形。这种调制方式通过改变脉冲的宽度来控制电路中的信号强度和频率。具体来说,PWM波形中的高电平持续时间和低电平持续时间可以根据需要进行调整,从而实现对模拟信号电平的数字编码。
PWM波形在各种领域都有广泛的应用,包括电源管理、电机控制、LED亮度调节等。此外,生成PWM波形的方法有多种,例如使用波形发生器、单片机或可编程逻辑器件等。


频率 = 1/Ts
占空比 = Ton / Ts
分辨率 = 占空比变化步距

10. 定时器输出PWM波配置步骤

小实验2:呼吸灯实验
实验目的
使用定时器 4 通道 3 生成 PWM 波控制 LED1 ,实现呼吸灯效果。
频率:2kHz,PSC=71,ARR=499
硬件清单
- 上官二号
- ST-Link
11. 输入捕获原理

12. 定时器输入捕获实验配置步骤

13. 测量按键按下时长思路


小实验3:测量按键按下时间
实验目的
使用定时器 2 通道 2 来捕获按键 2 按下时间,并通过串口打印。
计一个数的时间:1us,PSC=71,ARR=65535
下降沿捕获、输入通道 2 映射在 TI2 上、不分频、不滤波
硬件清单
- 上官二号
- ST-Link
- USB转TTL
14. 脉冲计数原理
15. 脉冲计数配置步骤

小实验4:脉冲计数实验
实验目的
将定时器 2 通道 2 输入的低电平脉冲作为定时器 2 的时钟,并通过串口打印脉冲数
PSC=0,ARR=65535
外部时钟模式1、触发选择、上升沿触发、不分频、不滤波
硬件清单
- 上官二号
- ST-Link
- USB转TTL
模块:超声波传感器
- 怎么让它发送波
Trig,给Trig端口至少10us的高电平
- 怎么知道它开始发了波
Echo引脚,由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波
Echo,由高电平跳转回低电平,表示波回来了
- 怎么算时间
Echo引脚维持高电平的时间
波发出去的那一下,开始启动定时器
波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离
距离 = 速度(343m/s) * 时间 / 2
模块:sg90舵机
项目:感应开关盖垃圾桶
项目需求
以下几个事件触发时,自动开盖,并伴随蜂鸣器短响一声,同时 LED 灯闪烁一下,2秒后自动关盖:
- 检测到有人靠近
- 检测到有震动
- 按下按键 KEY1
硬件清单
超声波传感器
震动传感器
蜂鸣器
舵机
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | 振动传感器 | 蜂鸣器 | 超声波传感器 | 舵机 |
|---|---|---|---|---|
| PA4 | DO | |||
| PA6 | I/O | |||
| PB5 | I/O | |||
| PB6 | Trig | |||
| PB7 | Echo | |||
| 3V3 | VCC | VCC | ||
| 5V | VCC | VCC | ||
| GND | GND | GND | GND | GND |
项目框图

六、独立看门狗
1. IWDG简介
独立看门狗(Independent Watchdog,通常缩写为IWDG)主要作用是主要用于检测外界电磁干扰,或硬件异常导致的程序跑飞问题。
- IWDG本质上是一个12位的递减计数器。当计数器的值从某个初始值开始递减,并一直减到0时,系统会产生一个复位信号(IWDG_RESET)。CPU在接收到这个复位信号后,会重新启动系统,以确保系统从可能的错误或死锁状态中恢复。
- 在计数器的值减到0之前,如果程序通过特定的“喂狗”操作(即重置计数器的值)来刷新计数器,那么就不会产生复位信号,系统将继续正常运行。这种“喂狗”操作通常是由程序在正常运行时定期执行的,以确保IWDG不会因计数器超时而产生复位信号。
- 它使用专用的低速时钟(LSI)作为时钟源,即使在主时钟发生故障时,IWDG仍然能够继续运行。IWDG可以在停止模式和待机模式下工作,确保在这些模式下系统仍然受到保护。
2. IWDG工作原理及框图


LSI 时钟频率并不精确,RC 频率会在 30kHz 到 60kHz 之间变化 ,F1 用 40kHz 进行计算即可。
3. IWDG寄存器及函数介绍
4. IWDG溢出时间计算

Tout:看门狗溢出时间
fIWDG:看门狗的时钟源频率
psc:看门狗预分频系数
rlr:看门狗重装载值
5. IWDG配置步骤

小实验:独立看门狗喂狗实验
实验目的
配置 IWDG 溢出时间为 1 秒左右,并验证未及时喂狗时系统将被复位。
硬件清单
- 上官二号
- ST-Link
- USB转TTL
七、窗口看门狗
1. WWDG简介
窗口看门狗用于监测单片机程序运行时效是否精准,主要检测软件异常,一般用于需要精准检测程序运行时间的场合。
窗口看门狗的本质是一个能产生系统复位信号和提前唤醒中断的6位计数器。
产生复位条件:
当递减计数器值从 0x40 减到 0x3F 时复位(即T6位跳变到0)
计数器的值大于 W[6:0] 值时喂狗会复位。
产生中断条件:
- 当递减计数器等于 0x40 时可产生提前唤醒中断 (EWI)。
在窗口期内重装载计数器的值,防止复位,也就是所谓的喂狗。
2. WWDG工作原理及框图


3. WWDG寄存器及函数介绍
4. WWDG溢出时间计算

5. WWDG配置步骤

小实验:窗口看门狗喂狗实验
实验目的
开启窗口看门狗,计数器值设置为 0X7F ,窗口值设置为 0X5F ,预分频系数为 8 。在 while 循环里喂狗,同时翻转 LED1 状态;在提前唤醒中断服务函数进行喂狗,同时翻转 LED2 状态。

硬件清单
- 上官二号
- ST-Link
- USB转TTL
独立看门狗与窗口看门狗区别
| 对比点 | 独立看门狗 | 窗口看门狗 |
|---|---|---|
| 时钟源 | 独立时钟,LSI (40KHz) ,不精确 | PCLK1(36MHz),精确 |
| 复位条件 | 递减计数到0 | 窗口期外喂狗或减到0x3F |
| 中断 | 无 | 计数值减到0x40可产生中断 |
| 递减计数器位数 | 12位(最大计数范围:4096~0) | 7位(最大计数范围:127~63) |
| 喂狗方式 | 写入键寄存器,重装固定值RLR | 直接写入计数器,写多少重装多少 |
| 应用场合 | 防止程序跑飞,死循环,死机 | 检测程序时效,防止软件异常 |
八、串口
1. 通信基础
1.1 串行通信与并行通信

1.2 全双工、半双工及单工通信

单工通信:数据只能沿一个方向传输
半双工通信:数据可以沿两个方向传输,但需要分时进行
全双工通信:数据可以同时进行双向传输
1.3 同步通信与异步通信
- 同步通信

- 异步通信

同步通信:发送和接收双方按照预定的时钟节拍进行数据的发送和接收,双方的操作严格同步。
异步通信:双方不需要严格的时钟同步,每个数据块之间通过特定的起始位和停止位进行分隔,接收方可以独立地识别每个数据块。
1.4 通信速率
通信速率是指在通信系统中单位时间内传输的信息量,是评估通信系统性能的重要指标之一。
- 比特率(Bit rate):
- 定义:比特率是指在通信线路(或系统)中单位时间(每秒)内传输的信息量,即每秒能传输的二进制位数。它用单位时间内传输的二进制代码的有效位(bit)数来表示,其单位为比特/秒(bit/s或bps)。
- 含义:比特率越高,表示单位时间内传送的数据量越大,信息传输的速率越快。它经常被用作连接速度、传输速度、信息传输速率和数字带宽容量的同义词。
- 波特率(Baud rate):
- 定义:在电子通信领域,波特率表示每秒传送的码元的个数,即单位时间内载波调制状态变化的次数。它用单位时间内载波调制状态改变次数来表示,其单位为波特(Baud)。
- 含义:波特率描述的是单位时间内调制信号的能力,它决定了在给定时间内可以通过通信通道发送多少个离散的信号单元(码元)。在数字通信中,码元是表示数字信息的最小单位。
- tips
比特率 = 波特率 * log2 M ,M表示每个码元承载的信息量
二进制系统中,波特率数值上等于比特率
2. 串口通信简介
串口,也称为串行接口或串行通信接口(通常指COM接口),是一种采用串行通信方式的扩展接口。它实现了数据一位一位地顺序传送,具有通信线路简单、成本低但传送速度慢的特点。只要一对传输线,串口就可以实现双向通信。
串口通信的接口类型包括TTL、CMOS、RS-232和RS-485等,它们分别代表了不同的电平标准。
- TTL电平
逻辑1:5V,逻辑0:0V
- CMOS电平
逻辑1:供电电压的最大值,逻辑0:0V
- RS-232电平
逻辑1:-3V~-15V,逻辑0:+3~+15V
- RS-485电平
采用差分信号,逻辑1:两线间的电压差为+(0.2~6)V,逻辑0:两线间的电压差为-(0.2~6)V


- 起始位(Start Bit):起始位为低电平时,告诉接收方数据传输即将开始,准备接收。在通信开始时,发送端首先会发送一个起始位,它是一个逻辑0(低电平)的信号,用于同步发送和接收设备之间的时钟。接收端在检测到起始位后,会开始准备接收后续的数据位。
- 有效数据位(Data Bits):数据位是由一系列二进制值组成,用于传输或接收实际的数据。数据位的数量决定了可以传输的不同二进制值的数量,常见的有5位、6位、7位、8位,LSB在前,MSB在后。数据位紧随起始位之后,包含了要传输的实际信息。
- 校验位(Parity Bit):校验位用于验证数据的完整性,以确保传输过程中没有出现错误。常见的校验位选项有None(无校验位)、Odd(奇校验位)和Even(偶校验位)。在发送数据时,校验位会根据数据位中1的个数进行计算,并加入到数据中一起传输。接收端则会根据校验位的值进行校验,以判断数据是否存在错误。
- 停止位(Stop Bit):停止位是一个逻辑高电平(1),用于指示数据传输的结束。当停止位出现时,接收端知道数据传输已经完成,并且可以开始处理接收到的数据。停止位位于数据位和校验位之后,它的作用是确保接收端有足够的时间来识别数据帧的结束,并为下一个数据帧的到来做好准备。
3. STM32的USART简介
Universal synchronous asynchronous receiver transmitter,通用同步异步收发器
Universal asynchronous receiver transmitter,通用异步收发器
- 全双工通信:USART支持全双工通信,即数据可以在两个方向上同时传输(A→B且B→A)。这使得USART能够满足许多需要双向通信的应用场景。
- 同步与异步传输:尽管USART的“S”代表同步,但在实际应用中,USART更常用于异步通信。然而,它也支持同步通信模式,只是这种模式通常用于兼容其他协议或特殊模式,并且两个USART设备不能通过同步模式进行直接通信。
- 波特率发生器:USART自带波特率发生器,最高可达4.5Mbits/s,可以根据需要配置不同的波特率。
- 硬件流控制:USART支持硬件流控制,通过特定的信号线(如RTS/CTS)实现数据的可靠传输。当接收端没有准备好接收数据时,可以通过RTS信号通知发送端暂停发送;当接收端准备好接收数据时,再通过CTS信号通知发送端恢复发送。
4. USART框图


5. UART寄存器及函数介绍
小实验1:通过串口发送/接收一个字符
实验目的
使用串口1发送/接收一个字符。
硬件清单
- 上官二号
- ST-Link
- USB转TTL
小实验2:串口接收不定长数据(接收中断)
小实验3:串口接收不定长数据(空闲中断)
模块:HC-08蓝牙
项目:蓝牙遥控插座
项目需求
手机通过蓝牙模块远程遥控风扇。
硬件清单
蓝牙模块
继电器
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | 蓝牙模块 | 继电器 |
|---|---|---|
| PA2 | RX | |
| PA3 | TX | |
| PB6 | I/O | |
| 3V3 | VCC | |
| 5V | VCC | |
| GND | GND | GND |
项目框图

模块:ESP8266
1. ESP8266作为设备
1.1 入网设置
- 设置工作模式
AT+CWMODE=1 //1. 是station(设备)模式 2.是AP(路由)模式 3.是双模
OK- 以设备模式接入家中路由器配置
AT+CWJAP="HuaweiAP-1ED0_Guest","gcc11111111" //指令
WIFI CONNECTED //结果
WIFI GOT IP //结果- 设置单路链接模式(透传只能使用此模式)
AT+CIPMUX=0
OK- 查询IP地址
AT+CIFSR //指令
+CIFSR:APIP,"192.168.4.1"
+CIFSR:APMAC,"4e:75:25:0d:ae:2f"
+CIFSR:STAIP,"192.168.0.148"
+CIFSR:STAMAC,"4c:75:25:0d:ae:2f"
OK1.2 连接到TCP Server
1.2.1 使用网络助手,设立TCP服务器

1.2.2 连接服务器
AT+CIPSTART="TCP","192.168.1.18",8080 //指令,注意双引号逗号都要半角(英文)输入
CONNECT //结果:成功
OK //结果:成功1.2.3 发送数据
AT+CIPSEND=4 // 设置即将发送数据的长度 (这里是4个字节)
>abcd // 看到大于号后,输入消息,abcd,不要带回车
Response :SEND OK //结果:成功
//注意,这种情况下,每次发送前都要先发送AT+CIPSEND=长度 的指令,再发数据!1.3 透传
上一节每次发送数据都要进行字符长度设定,如果设置成透传,就有点像蓝牙模块的玩法
在1.2.2之后
AT+CIPMODE=1 //开启透传模式
Response :OK
AT+CIPSEND //带回车
Response: > //这个时候随意发送接收数据咯退出透传模式
//在透传发送数据过程中,若识别到单独的⼀包数据 “+++”,则退出透传发送2. ESP8266作为服务器
USB转TTL插入电脑,TX--RX RX-TX VCC-3.3V GND-GND
查询IP地址:AT+CIFSR
//1 配置成AP模式
AT+CWMODE=2
Response :OK
//2 使能多链接
AT+CIPMUX=1
Response :OK
//3 建立TCPServer
AT+CIPSERVER=1 // default port = 333
Response :OK
//4 发送数据
AT+CIPSEND=0,4 // 发送4个字节在连接0通道上
>abcd //输入数据,不带回车
Response :SEND OK
//5 接收数据
+IPD, 0, n: xxxxxxxxxx //+IPD是固定字符串 0是通道,n是数据长度,xxx是数据
//断开连接
AT+CIPCLOSE=0
Response :0, CLOSED OK项目:Wi-Fi遥控风扇
项目需求
电脑通过esp8266模块远程遥控风扇。
硬件清单
esp8266模块
继电器
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | esp8266模块 | 继电器 |
|---|---|---|
| PA2 | RX | |
| PA3 | TX | |
| PB6 | I/O | |
| 3V3 | VCC | |
| 5V | VCC | |
| GND | GND | GND |
项目框图

模块:4G模块
1. 内网穿透
内网穿透的原理就像在内网和外网之间搭建了一座桥梁,使得外部网络可以穿过内网的障碍,直接访问内部的设备。


2. 花生壳配置



3. 4G模块配置
接线图:

相关参数:

上位机配置:
- 选择端口号(根据自己的端口选择)
- 选择波特率(默认115200)
- 打开串口
- 点击进入配置,上位机会自动发送AT指令进行配置
- 读取参数,此命令可以读取4g模块的详细信息,并打印带基本信息栏(这一步很重要,否则在第九步的时候会出现问题)
- 选择链路1
- 默认是连接亿佰特的服务器 这边我们需要修改成我们自己的,具体从花生壳获取(是一串域名,或者IP地址,他都支持,根据自己获取到的填写就可以)
- 输入从花生壳获取的端口号
- 点击保存配置(对应第五步,我们很多的配置需要获取到模块默认配置,保存时才会不改变)
- 点击重启(重启后默认进入透传模式,无需在做其他操作,直接链接到串口助手上即可发送与接收信息)

项目:4G遥控灯
项目需求
服务器通过4G模块远程遥控开关灯。
硬件清单
4G模块
继电器
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | 4G模块 |
|---|---|
| PA2 | RX |
| PA3 | TX |
| PB6 | |
| 3V3 | |
| 5V | VCC |
| GND | GND |
项目框图

九、DMA
1. DMA介绍
1.1 什么是DMA?
令人头秃的描述:
DMA(Direct Memory Access,直接存储器访问)提供在外设与内存、存储器和存储器之间的高速数据传输使用。它允许不同速度的硬件装置来沟通,而不需要依赖于CPU,在这个时间中,CPU对于内存的工作来说就无法使用。
简单描述:
就是一个数据搬运工!!
1.2 DMA的意义
代替 CPU 搬运数据,为 CPU 减负。
数据搬运的工作比较耗时间;
数据搬运工作时效要求高(有数据来就要搬走);
没啥技术含量(CPU 节约出来的时间可以处理更重要的事)。

1.3 搬运什么数据?
存储器、外设
这里的外设指的是spi、usart、iic、adc 等基于APB1 、APB2或AHB时钟的外设,而这里的存储器包括自身的闪存(flash)或者内存(SRAM)以及外设的存储设备都可以作为访问地源或者目的。
三种搬运方式:
- 存储器→存储器(例如:复制某特别大的数据buf)
- 存储器→外设 (例如:将某数据buf写入串口TDR寄存器)
- 外设→存储器 (例如:将串口RDR寄存器写入某数据buf)
存储器→存储器

存储器→外设

外设→存储器

2. DMA框图

3. DMA控制器
STM32F103 有 2 个 DMA 控制器,DMA1 有 7 个通道,DMA 2 有 5 个通道。
一个通道每次只能搬运一个外设的数据!! 如果同时有多个外设的 DMA 请求,则按照优先级进行响应。
STM32F103C8T6 只有 DMA1 !
DMA1有7个通道:

DMA2 有 5 个通道:

4. DMA优先级管理
优先级管理采用软件+硬件:
软件: 每个通道的优先级可以在DMA_CCRx寄存器中设置,有4个等级
最高级>高级>中级>低级
硬件: 如果2个请求,它们的软件优先级相同,则较低编号的通道比较高编号的通道有较高的优先权。
比如:如果软件优先级相同,通道2优先于通道4

5. DMA传输方式
DMA_Mode_Normal(正常模式)
一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
DMA_Mode_Circular(循环传输模式)
当传输结束时,硬件自动会将传输数据量寄存器进行重装,进行下一轮的数据传输。 也就是多次传输模式
6. 指针递增模式
外设和存储器指针在每次传输后可以自动向后递增或保持常量。当设置为增量模式时,下一个要传输的地址将是前一个地址加上增量值。


7. DMA数据对齐方式

8. DMA寄存器及库函数介绍
__HAL_RCC_DMA1_CLK_ENABLE(…)
HAL_DMA_Init(…)
HAL_DMA_Start(…)
__HAL_LINKDMA(…)
HAL_UART_Transmit_DMA(…)
HAL_UART_Receive_DMA(…)
__HAL_DMA_GET_FLAG(…)
__HAL_DMA_ENABLE(…)
__HAL_DMA_DISABLE(…)小实验1:DMA内存到内存数据搬运
实验目的
使用 DMA 将一个大数组的数据搬运到另一个位置。
硬件清单
- 上官二号
- ST-Link
- USB转TTL

小实验2:DMA内存到外设数据搬运
实验目的
使用 DMA 将一个大数组的数据通过串口 1 发送。
硬件清单
- 上官二号
- ST-Link
- USB转TTL

小实验3:DMA外设到内存数据搬运
实验目的
使用 DMA 接收串口 1 数据。
硬件清单
- 上官二号
- ST-Link
- USB转TTL

十、ADC
1. ADC介绍
1.1 什么是ADC?
全称:Analog-to-Digital Converter,指模拟/数字转换器。
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。

12 位 ADC 是一种逐次逼近型模拟数字转换器(0~4095)。它有多达 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。 ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
ADC 的输入时钟不得超过 14MHz,它是由 PCLK2 经分频产生。
STM32F103C8T6 ADC资源:ADC1、ADC2,10 个外部输入通道
1.2 ADC工作原理(逐次逼近型)

1.3 ADC特性参数
ADC的性能指标
- 量程:能测量的电压范围
- 分辨率:ADC能辨别的最小模拟量,通常以输出二进制数的位数表示,比如:8、10、12、16位等;位数越多,分辨率越高,一般来说分辨率越高,转化时间越长
- 转化时间(采样时间):从转换开始到获得稳定的数字量输出所需要的时间称为转换时间。转换时间越长,转换结果相对越准确,但是转换速度就越慢
ADC特性
- 12 位精度下转换速度可高达1MHZ
- 供电电压:VSSA :0V,VDDA :2.4V~3.6V
- ADC输入范围:VREF- ≤ VIN ≤ VREF+,0~3.3V
- ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中
2. ADC框图


3. ADC的一些细节
3.1 输入通道

总共 2 个 ADC(ADC1,ADC2),每个 ADC 有 18 个转换通道: 16 个外部通道、 2 个内部通道(温度传感器、内部参考电压)。

外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。
3.2 规则组/注入组


3.3 转换顺序
每个 ADC 规则通道只有一个数据寄存器,16个通道一起共用这个寄存器,所以需要指定规则转换通道的转换顺序。
规则通道中的转换顺序由三个寄存器控制:SQR1、SQR2、SQR3,它们都是32位寄存器。SQR寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx中写入相应的通道,这个通道就是第x个转换。

和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有一个JSQR寄存器来控制,控制关系如下:

注入序列的转换顺序是从JSQx[ 4 : 0 ](x=4-JL[1:0])开始。只有当JL=4的时候,注入通道的转换顺序才会按照JSQ1、JSQ2、JSQ3、JSQ4的顺序执行。
3.4 触发转换方法
通过向控制寄存器 ADC-CR2 的 ADON 位写 1 来开启 ADC ,再将 SWSTART 位置 1 ,启动规则通道转换
也可以通过外部事件(如定时器)进行转换。

3.5 转换时间
ADC 是挂载在 APB2 总线(PCLK2)上的,经过分频器得到 ADC 时钟(ADCCLK),最高 14 MHz。
转换时间=采样时间+12.5个周期
12.5个周期是固定的,一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us。
3.6 中断及事件
| 中断事件 | 事件标志 | 使能控制位 |
|---|---|---|
| 规则通道转换结束 | EOC | EOCIE |
| 注入通道转换结束 | JEOC | JEOCIE |
| 设置了模拟看门狗状态位 | AWD | AWDIE |
DMA请求(只适用于规则组)
规则组每个通道转换结束后,除了可以产生中断外,还可以产生DMA请求,我们利用DMA及时把转换好的数据传输到指定的内存里,防止数据被覆盖。
3.7 校准
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
通过设置ADC_CR2寄存器的CAL位启动校准。一旦校准结束, CAL位被硬件复位,可以开始正常转换。建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。
建议在每次上电后执行一次校准。
3.8 单次转换和连续转换
单次转换:只转换一次
连续转换:转换一次之后,立马进行下一次转换
3.9 扫描模式
关闭扫描模式:只转换ADC_SQRx或ADC_JSQR选中的第一个通道
打开扫描模式:扫描所有被ADC_SQRx或ADC_JSQR选中的所有通道
4. ADC寄存器及库函数介绍
小实验1:ADC单通道采集实验
实验目的
使用 ADC1 采集通道 1 的电压值,通道 1 连接光敏电阻传感器。
硬件清单
- 上官二号
- 光敏电阻传感器
- ST-Link
- USB转TTL

小实验2:ADC单通道采集实验+DMA读取
实验目的
使用 ADC1 采集通道 1 的电压值+DMA读取,通道 1 连接光敏电阻传感器。
硬件清单
- 上官二号
- 光敏电阻传感器
- ST-Link
- USB转TTL

小实验3:ADC多通道采集实验+DMA读取
实验目的
使用 ADC1 采集通道 0 ~3 的电压值+DMA读取,通道 1 连接光敏电阻传感器。
硬件清单
- 上官二号
- 光敏电阻传感器
- ST-Link
- USB转TTL
烟雾模块MQ-2
项目:吸烟室管控系统
项目需求
- 使用 mq-2 获取环境烟雾值,并显示在 LCD1602 上;
- 按键修改阈值,并显示在 LCD1602 上;
- 烟雾值超过阈值时,蜂鸣器长响,风扇打开;烟雾值小于阈值时,蜂鸣器不响,风扇关闭;
硬件清单
LCD1602
mq-2
蜂鸣器
继电器(模拟风扇)
按键
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | LCD1602 | MQ-2 | 蜂鸣器 | 风扇 | 按键1 | 按键2 |
|---|---|---|---|---|---|---|
| GND | GND | |||||
| 5V | VDD | |||||
| GND | V0 | |||||
| B1 | RS | |||||
| B2 | RW | |||||
| B10 | E | |||||
| A0 | D0 | |||||
| A1 | D1 | |||||
| A2 | D2 | |||||
| A3 | D3 | |||||
| A4 | D4 | |||||
| A5 | D5 | |||||
| A6 | D6 | |||||
| A7 | D7 | |||||
| 5V | BLA | VCC | ||||
| 3.3V | VCC | VCC | ||||
| B0 | AO | |||||
| B5 | IO | |||||
| B6 | IN | |||||
| B13 | IN | |||||
| B14 | IN | |||||
| GND | BLK | GND | GND | GND | GND | GND |
项目框图

十一、IIC
1. 串口通信缺点
- 串口通信通常需要至少三条线(TX、RX和GND),而 I2C 总线仅需要两条信号线(SDA和SCL);
- 串口通信仅支持一对一通信,而 I2C 总线支持多机通信,允许单个主机与多个从机设备进行通信;
- 串口通信通常无应答机制,而 I2C 必须有应答机制;
- 串口通讯一般是异步通信,而 I2C 使用同步传输方式,数据在时钟信号(SCL)的控制下传输。
2. IIC总线介绍
I2C总线,全称Inter-Integrated Circuit(互连集成电路),是一种由Philips(现NXP半导体)公司在1980年代初开发的同步 串行 半双工通信总线。

工作原理:
- 主从关系:主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。
- 数据传送:
- 如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送。
- 如果主机要接收从器件的数据,首先由主器件寻址从器件,然后主机接收从器件发送的数据,最后由主机终止接收过程。
- 时钟同步:SCL用于数据的时钟同步,确保主从设备之间的数据传输同步进行。
主要特点
- 硬件简单:I2C总线只需要一根数据线和一根时钟线两根线,总线接口已经集成在芯片内部,不需要特殊的接口电路。
- 多主机总线:I2C总线是一个真正的多主机总线,如果两个或多个主机同时初始化数据传输,可以通过冲突检测和仲裁防止数据破坏。
- 在线检测:I2C总线可以通过外部连线进行在线检测,便于系统故障诊断和调试。
- 数据传输与地址设定:数据传输和地址设定由软件设定,非常灵活。总线上的器件增加和删除不影响其他器件正常工作。
- 负载能力:由于线路中电容会影响总线传输速度,I2C总线的负载能力为400pF,因此可以估算出总线允许长度和所接器件数量。
应用领域
I2C总线广泛应用于各种设备和应用领域,例如传感器、存储器(如EEPROM)、显示屏、温度传感器、实时时钟(RTC)、扩展IO芯片等。
3. IIC总线时序
3.1 起始信号
- 起始信号由主设备发起,用于通知总线上的所有设备即将开始数据传输。
- 当SCL为高电平时,SDA由高电平变为低电平,产生一个下降沿,表示起始信号的开始。

3.2 停止信号
- 停止信号也由主设备发起,用于通知总线上的所有设备数据传输已经结束。
- 当SCL为高电平时,SDA由低电平变为高电平,产生一个上升沿,表示停止信号的开始。

3.3 应答信号
- 每当一个字节的数据传输完成后,接收方会向发送方发送一个应答信号(ACK)或非应答信号(NACK)。
- 应答信号在SCL的第9个时钟周期(当SCL为高电平时)发送。
- 如果SDA线为低电平,则表示ACK(有效应答),表示接收方已成功接收该字节。
- 如果SDA线为高电平,则表示NACK(非应答),通常表示接收方接收该字节没有成功。

3.4 读写时序
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

3.5 一次完整的I2C时序

模块:OLED显示屏
1. 0.96寸OLED屏幕介绍
0.96 寸 4P OLED 屏幕模块是一种显示屏模块,它包括一个 0.96 英寸的 OLED 显示屏和四个引脚。这种 OLED 屏幕模块通常用于嵌入式系统和小型电子设备中,可以显示文本、图像和其他类型的信息。由于其小尺寸和低功耗,也常用于智能手表、健康追踪器和其他便携式设备中。
0.96OLED 参数:
- 驱动芯片:SSD1306
- 分辨率:128 × 64
- 显示尺寸:0.96英寸
- 外形尺寸:27.5 × 27.8(mm)
- 玻璃尺寸:26.7 × 19.26 × 1.4(mm)
- 显示区域:21.74(W)× 10.864(mm)
- 视角:全视角
- 工作电压:3.3V ~ 5V
- 工作温度:-20℃ ~ 70℃
- 存储温度:-30℃ ~ 80℃
- 使用寿命:>=16000 小时
- 支持接口:I2C

0.96OLED 屏幕模块的优点有:
- 高对比度和高亮度:OLED 屏幕模块可以提供深黑色背景和明亮的字色,因此可以实现高对比度和高亮度的显示效果;
- 自发光:OLED 屏幕模块不需要背光灯,因此可以实现更薄、更轻的设计;
- 响应速度快:OLED 屏幕模块的响应速度非常快,可以实现流畅的动画和视频效果;
- 视角宽:OLED 屏幕模块的视角非常宽,即使从不同角度观察,图像和文字也能保持清晰。
0.96OLED 屏幕模块的缺点有:
- 显示寿命短:与 LCD 显示屏相比,OLED 的显示寿命相对较短,因为它的有机材料会随着时间的推移而逐渐失效;
- 显示面积小:0.96 寸 OLED 屏幕模块的显示面积相对较小,因此不适合用于需要大屏幕的应用。
2. 如何驱动OLED屏幕显示内容?

3. OLED通讯协议

4. SSD1306


5. GDDRAM

页地址模式:

水平地址模式:

垂直地址模式:

6. OLED命令

7. 如何取模

小实验:OLED实验
实验目的
驱动 OLED 屏幕,显示点、线、字符、字符串、汉字、图片等内容。
硬件清单
- OLED屏幕
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | OLED屏幕 |
|---|---|
| PB6 | SCL |
| PB7 | SDA |
| 3V3 | VCC |
| GND | GND |
十二、SPI
1. IIC与SPI对比
- IIC 是半双工通讯,无法同时收发信息;SPI 是全双工通讯,可以同时收发信息;
- IIC 通讯协议较复杂,而 SPI 通讯协议较简单;
- IIC 需要通过地址选择从机,而 SPI 只需一个引脚即可选中从机;
- IIC 通讯速率一般为 100kHz 左右,而 SPI 可以达到 50MHz ;
- IIC 需要的通讯线较少,而 SPI 需要较多。
2. SPI是什么?
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如 AT91RM9200 。
以上介绍来自360百科
3. SPI物理架构

SPI 总线包含 4 条通讯线,分别为 SS、SCK、MOSI、MISO。它们的作用介绍如下 :
(1) MISO – Master Input Slave Output,主设备数据输入,从设备数据输出 (2) MOSI – Master Output Slave Input,主设备数据输出,从设备数据输入 (3) SCK – Serial Clock,时钟信号,由主设备产生 (4) CS – Chip Select,片选信号,由主设备控制
STM32F1 系列芯片有 3 个SPI 接口。
4. SPI工作原理



5. SPI工作模式
时钟极性(CPOL):
没有数据传输时时钟线的空闲状态电平
0:SCK在空闲状态保持低电平 1:SCK在空闲状态保持高电平
时钟相位(CPHA):
时钟线在第几个时钟边沿采样数据
0:SCK的第一(奇数)边沿进行数据位采样,数据在第一个时钟边沿被锁存 1:SCK的第二(偶数)边沿进行数据位采样,数据在第二个时钟边沿被锁存
| SPI工作模式 | CPOL | CPHA | SCL空闲状态 | 采样边沿 | 采样时刻 |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 低电平 | 上升沿 | 奇数边沿 |
| 1 | 0 | 1 | 低电平 | 下降沿 | 偶数边沿 |
| 2 | 1 | 0 | 高电平 | 下降沿 | 奇数边沿 |
| 3 | 1 | 1 | 高电平 | 上升沿 | 偶数边沿 |
模式 0 和模式 3 最常用。
模式 0 时序图:

模式 3 时序图:

6. SPI寄存器及库函数介绍
模块:W25Q128
小实验:读写W25Q128实验
实验目的
读写W25Q128
硬件清单
- W25Q128
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | W25Q128 |
|---|---|
| PA4 | CS |
| PA5 | CLK |
| PA6 | DO |
| PA7 | DI |
| 3V3 | VCC |
| GND | GND |
模块:矩阵键盘
项目:智能门禁
项目需求
- 矩阵键盘输入密码,正确则开锁,错误则提示,三次错误蜂鸣器响3秒;
- 按下#号确认输入,按下*号修改密码;
- 密码保存在 W25Q128 里;
- OLED 屏幕显示信息。
硬件清单
矩阵键盘
OLED 屏幕
蜂鸣器
W25Q128
继电器
杜邦线
上官二号
ST-Link
USB转TTL
硬件接线
| STM32 | 矩阵键盘 | OLED屏幕 | 蜂鸣器 | W25Q128 | 继电器 |
|---|---|---|---|---|---|
| PB0 | R1 | ||||
| PB1 | R2 | ||||
| PB2 | R3 | ||||
| PB10 | R4 | ||||
| PB11 | C1 | ||||
| PB12 | C2 | ||||
| PB13 | C3 | ||||
| PB8 | SCL | ||||
| PB9 | SDA | ||||
| PC13 | I/O | ||||
| PA4 | CS | ||||
| PA5 | CLK | ||||
| PA6 | DO | ||||
| PA7 | DI | ||||
| PB7 | I/O | ||||
| 5V | VCC | ||||
| 3.3V | VCC | VCC | VCC | ||
| GND | GND | GND | GND | GND |
项目框图

十三、BKP(备份寄存器)
1. 什么是BKP?
备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。
此外, BKP控制寄存器用来管理侵入检测和RTC校准功能。
复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问:
- 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
- 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。
用户数据存储容量:
20字节(中容量和小容量)/ 84字节(大容量和互联型)
2. BKP框图

小实验:读写BKP
实验目的
读写BKP
硬件清单
- 上官二号
- ST-Link
- USB转TTL
十四、RTC
1. 什么是RTC?
实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。
复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问:
- 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
- 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。
32位的可编程计数器,可对应Unix时间戳的秒计数器。
Unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。20位的可编程预分频器,可适配不同频率的输入时钟。
可选择三种RTC时钟源:
- HSE时钟除以128(通常为8MHz/128)
- LSE振荡器时钟(通常为32.768KHz)
- LSI振荡器时钟(40KHz)
2. RTC框图


3. 寄存器及库函数
4. RTC驱动步骤
注意事项:
必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器
对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器

小实验1:读写RTC时间实验
小实验2:RTC闹钟实验
项目:实时时钟
项目需求
- OLED屏幕显示当前时间、日期、闹钟等信息;
- 正常模式下,按下 KEY1 ,进入时间设置模式,此时按下 KEY2 则可以循环跳转修改秒、分、时、日、月、年;
- 时间设置模式下,KEY3 增加数值,KEY4 减小数值,再次按下 KEY1 则退出时间设置模式,并保存修改后的时间;
- 正常模式下,按下 KEY2,进入闹钟设置模式,此时按下 KEY2 则可以循环跳转修改秒、分、时;
- 闹钟设置模式下,KEY3 增加数值,KEY4 减小数值,再次按下 KEY1 则退出闹钟设置模式,并保存修改后的闹钟;
- 到达闹钟时间后,蜂鸣器响起。按下 KEY3 或 KEY4 停止蜂鸣器。
硬件清单
- OLED 屏幕
- 蜂鸣器
- 按键(2个)
- 杜邦线
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | OLED屏幕 | 蜂鸣器 | KEY3 | KEY4 |
|---|---|---|---|---|
| PB8 | SCL | |||
| PB9 | SDA | |||
| PC13 | I/O | |||
| PA2 | I/O | |||
| PA3 | I/O | |||
| 5V | VCC | |||
| 3.3V | VCC | VCC | VCC | |
| GND | GND | GND | GND | GND |
项目框图



十五、低功耗
1. 什么是低功耗?
STM32的低功耗(low power mode)特性是其嵌入式处理器系列的一个重要优势,特别适用于需要长时间运行且功耗敏感的应用场景,如便携式设备、物联网设备、智能家居系统等。
在很多应用场合中都对电子设备的功耗要求非常苛刻,如某些传感器信息采集设备,仅靠小型的电池提供电源,要求工作长达数年之久,且期间不需要任何维护;由于智慧穿戴设备的小型化要求,电池体积不能太大导致容量也比较小,所以也很有必要从控制功耗入手,提高设备的续行时间。
2. STM32电源系统结构

3. 低功耗模式介绍
STM32具有运行、睡眠、停止和待机四种工作模式。
上电后默认是在运行模式,当内核不需要继续运行时,可以选择后面三种低功耗模式。

3.1 睡眠模式(sleep mode)
在睡眠模式下,CPU停止工作,但所有外设(如ADC、通信接口等)仍然运行,时钟继续运转。这适用于需要暂时关闭CPU但外围设备需要继续工作的场景。
模式特点:
- 对系统影响小,但是节能效果最差。
- 在睡眠模式下,所有的I/O引脚都保持它们在运行模式时的状态。
进入条件:
- 当系统控制寄存器中的SLEEPDEEP位被清除(通常为0),并且SLEEPONEXIT位根据需求设置时(如果设置为1,则在最低优先级中断处理程序退出时进入Sleep模式;如果为0,则执行WFI或WFE时立即进入)。
- 执行WFI(Wait For Interrupt)或WFE(Wait For Event)指令来进入。
唤醒条件:
- 任意一个中断都能将系统从Sleep模式唤醒。
- 如果执行WFE指令进入Sleep模式,则一旦发生唤醒事件时,MCU将唤醒。
3.2 停机模式(stop mode)
在停机模式下,CPU和核心外围设备的时钟会停止,但部分唤醒源(如外部中断和某些定时器)仍然运行。这适用于需要长时间等待外部事件唤醒的应用,如等待用户输入或外部信号。Stop模式实现了非常低的功耗,同时保留了SRAM和寄存器的内容。
模式特点:
- 节能效果好,程序不会复位。但恢复时间较长(比如震荡器需要重新起震等)。
- 在停机模式下,所有的I/O引脚都保持它们在运行模式时的状态。
- 退出停止模式,HSI RC振荡器被选为系统时钟
进入条件:
- 需要将SLEEPDEEP位设置为1以进入深度睡眠模式,然后通过设置电源控制/状态寄存器(PWR_CSR)中的PDDS位为0来选择进入Stop模式。
- 根据需求设置LPDS位(LPDS = 0:表示在深睡眠模式下,电压调节器保持开启状态;LPDS = 1:表示在深睡眠模式下,电压调节器进入低功耗模式。)。
- 执行WFI(Wait For Interrupt)或WFE(Wait For Event)指令来进入。
- 在进入Stop模式之前,通常需要关闭不必要的外设时钟,并保存需要保留的状态信息。
唤醒条件:
- Stop模式可以通过外部中断(如按键中断、USART接收中断等)唤醒。
- RTC闹钟事件、USB唤醒、以太网(ETH)唤醒等也可以作为唤醒源,但这些通常需要通过外部中断来触发。
3.3 待机模式(standby mode)
在该模式下,CPU、外围设备和时钟都被关闭,只保留唤醒逻辑和备份寄存器。这适用于不需要保留RAM内容且可以从复位状态恢复的设备,常见于需要极低功耗且稀疏唤醒的应用。Standby模式是STM32中功耗最低的模式之一。
模式特点:
- 节能效果最好,但程序会复位,只有少数条件唤醒。
- 在Standby模式下,大部分IO引脚处于高阻态,只有复位引脚、TAMPER引脚(如果配置为防侵入或校准输出)和WKUP引脚可用作唤醒源。
进入条件:
- Standby模式进入前,需要清除电源控制/状态寄存器(PWR_CSR)中的WUF位,以确保没有未处理的唤醒标志。
- 将SLEEPDEEP位设置为1以进入深度睡眠模式,并设置PDDS位为1来选择进入Standby模式。
- 执行WFI或WFE指令进入Standby模式。
唤醒条件:
- Standby模式可以通过WKUP引脚的上升沿唤醒。
- RTC闹钟事件也可以作为唤醒源。
- 独立看门狗(IWDG)复位和NRST引脚上的外部复位也可以唤醒STM32,但这通常用于系统复位而非低功耗唤醒。

4. 寄存器及库函数介绍
小实验:低功耗实验
实验目的
- 按下按键 2 ,进入低功耗模式(睡眠、停机、待机);
- 按下按键 1 ,退出低功耗模式;
- 正常模式下,LED1 闪烁;进入停机模式,LED2 长亮,退出停机模式则 LED2 熄灭。
硬件清单
- 上官二号
- ST-Link
- USB转TTL
十六、CAN
1. CAN简介
CAN协议,全称为Controller Area Network(控制器局域网络),是一种广泛应用的串行通信协议,最初由德国BOSCH公司开发,并已成为国际标准。
低速CAN(ISO11519)通信速率 10~125Kbps,总线长度可达 1000 米。
高速CAN(ISO11898)通信速率 125Kbps~1Mbps,总线长度 ≤40 米。
- 定义:CAN协议是一种基于差分信号的异步串行通信协议,采用双绞线作为传输介质,具有高性能、高可靠性和独特的设计特点。
- 特点:
- 多主控制:支持多主方式,即任何一个节点都可以在总线上发送数据,其他节点根据需要进行接收。当两个以上的节点同时开始发送数据时,会根据标识符(ID)决定优先级。
- 系统柔软性:与总线相连的单元没有类似于“地址”的信息,因此在总线上增加单元时,连接在总线上的其他单元的软硬件及应用层都不需要改变。
- 通信速度快、距离远:数据传输速率较高,标准速率为125kbps,扩展速率可达1Mbps,且通信距离远,最远可达10KM(速率低于5Kbps)。
- 错误检测与恢复:具有错误检测、错误通知和错误恢复功能,能够确保数据传输的可靠性。
- 故障封闭功能:能够判断出错误的类型,并将引起故障的单元从总线上隔离出去。
CAN协议因其高效、可靠的特点,被广泛应用于多个领域:
- 汽车领域:用于实现车辆中各个控制单元(ECU)之间的通信,如发动机控制、车身控制、传动系统控制等。
- 工业自动化:用于机器人、物流设备、生产线等各种设备之间的通信与控制。
- 航空航天:用于飞机中的各种子系统之间的数据通信,如飞行控制系统、引擎控制系统、仪表盘、通信系统等。
- 船舶领域:用于实现船舶各种设备的可靠通信,包括远程控制、安全监测、航程分析、巡回检测等系统。
- 智能家居:连接各种智能设备,如照明设备、空调系统、安防系统等,实现设备的互联互通。
- 智能医疗:连接医疗设备,如监护仪、呼吸机等,实现设备间的快速通信。
2. CAN物理层介绍
CAN网络通常由CAN控制器、CAN收发器和双绞线组成。
- CAN控制器:负责处理数据的收发和协议转换。
- CAN收发器:负责将控制器的数字信号转换为差分信号进行传输,同时也负责将总线上的差分信号转换为数字信号供控制器处理。
终端电阻
- 在高速CAN总线的两端分别连接一个电阻,称为终端电阻。终端电阻的主要作用是匹配总线阻抗,提高信号质量,减少回波反射。一般来说,终端电阻的阻值为120Ω。
2.1 总线拓扑图


2.2 电平标准
CAN使用差分信号进行数据传输,根据CAN_H和CAN_L上的电位差来判断总线电平。
- 显性电平表示逻辑 0 ,通常 CAN_H 和 CAN_L 有 2V 的压差;
- 隐性电平表示逻辑 1 ,通常 CAN_H 和 CAN_L 有 0V 的压差。
显性电平在通信中具有优先权,能够覆盖隐性电平,确保数据的正确传输。
隐性电平则作为总线的空闲或监听状态存在,等待有节点发送数据。

2.3 CAN控制器与收发器


3. CAN协议层介绍
3.1 CAN帧种类介绍
- 数据帧(Data Frame):数据帧是CAN总线上用于传输用户数据的帧,包括必要的帧头、标识符、控制位、数据长度代码、数据域、CRC校验码和应答域等部分,是CAN通信中最基本和最重要的帧类型。
- 遥控帧(Remote Frame):遥控帧用于向总线上的其他节点请求发送具有相同标识符的数据帧,它没有数据域,仅通过标识符来指定所需的数据。遥控帧的帧结构与数据帧相似,但缺少数据部分。
- 错误帧(Error Frame):当CAN总线上的任何节点检测到通信错误时,会发送错误帧来通知其他节点。错误帧包含错误标志和错误界定符,用于指示错误的存在和类型。
- 过载帧(Overload Frame):过载帧用于在连续的数据帧或远程帧之间提供额外的延时,以指示接收节点尚未准备好接收下一个帧。当接收节点因内部条件限制而无法立即接收数据时,会发送过载帧来请求发送节点暂停发送。
- 帧间隔(Interframe Space):帧间隔用于隔离数据帧与前面的帧,确保它们之间的时间间隔足够长,以避免总线上的冲突和数据丢失。帧间隔包括连续三个隐性位(间隔段)和可能存在的空闲段,用于将数据帧或远程帧与前面的帧分隔开来。
3.2 CAN数据帧介绍
数据帧由7段组成。数据帧又分为标准帧(CAN2.0A)和扩展帧(CAN2.0B),主要体现在仲裁段和控制段。
- 帧起始(Frame Start):
- 功能:表示数据帧的开始。
- 特点:由一个显性位(Dominant Bit)构成,此时CAN_H为高电平(如3.5V),CAN_L为低电平(如1.5V),二者之间的电位差形成信号。
- 仲裁段(Arbitration Field):
- 功能:确定发送优先级,并包含标识符(Identifier)用于唯一标识发送者和接收者之间的通信关系。
- 组成:
- 标准数据帧的仲裁场由11位ID和1位RTR位(远程发送请求位)组成。RTR位用于区分数据帧(显性电平)和遥控帧(隐性电平)。
- 扩展数据帧中,还包含SRR位(Substituted Remote Request,替代的远程请求)和IDE位(Identifier Extension,标识符扩展)。SRR位用于指示发送方是否发送了远程请求帧,IDE位用于指示标识符字段是否使用了扩展格式(29位)。
- 控制段(Control Field):
- 功能:包含数据长度代码(DLC),用于定义数据帧中数据域的长度。
- 特点:DLC占4位,其取值范围为0到8个字节,表示数据帧中包含的数据字节数。
- 数据段(Data Field):
- 功能:包含要传输的数据,是数据帧的主体部分。
- 特点:数据域的长度可以根据DLC字段的值从0到8个字节不等,数据从最高位(MSB)开始传输。
- CRC段(CRC Field):
- 功能:用于检测数据帧的传输错误。
- 特点:CRC(循环冗余校验)是一种通过对数据进行计算生成的校验码,发送方在发送数据帧时会根据数据计算出CRC值,并将其添加到数据帧的CRC段中。接收方在接收到数据帧后会重新计算CRC值,并与接收到的CRC值进行比较,以确认数据在传输过程中是否发生错误。
- 应答段(ACK Field):
- 功能:用来确认数据帧的正常接收。
- 组成:由ACK槽(ACK Slot)和ACK界定符两个位构成。当接收节点成功解析了数据帧并确认无误后,会在ACK槽中发送一个显性位作为应答信号。
- 帧结束(Frame End):
- 功能:表示数据帧的结束。
- 特点:由7个连续的隐性位构成,标志着数据帧的传输完成。

3.3 CAN位时序
CAN总线以“位同步”机制,实现对电平的正确采样。位数据都由四段组成:同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)和相位缓冲段2(PBS2),每段又由多个位时序Tq组成。

所谓采样点是读取总线电平,并将读到的电平作为位值的点。位置在 PBS1 结束处。

CAN总线通过时钟同步机制来确保各个节点在通信过程中保持同步。时钟同步机制包括硬同步和再同步两种:
- 硬同步:
- 硬同步只在帧的起始位(SOF)处进行。
- 当接收节点检测到帧起始位的下降沿时,会将其与自身的位时间进行对齐,从而实现同步。

再同步:
再同步在帧的后续数据位中进行。
如果接收节点检测到数据位的跳变沿不在自身的同步段内,则会通过延长或缩短相位缓冲段的时间来调整自身的位时间,以重新获得同步。
再同步时,PBS1和PBS2中增加或者减少的时间被称为“再同步补偿宽度(SJW)”,其范围:1~4 Tq。

3.4 CAN仲裁机制
CAN总线处于空闲状态,最先开始发送消息的单元获得发送权。
多个单元同时开始发送时,从仲裁段(报文ID)的第一位开始进行仲裁。仲裁原理如下:
- 标识符优先级:
- CAN总线中传输的数据帧的起始部分为数据的标识符(ID)。这个标识符不仅用于区分消息,还表示消息的优先级。在CAN 2.0标准中,标识符可以是11位或29位(对于扩展帧)。标识符的数值越小,优先级越高。
- 例如,在11位标识符的情况下,ID为0x000的消息具有最高优先级,而ID为0x7FF的消息具有最低优先级。
- 逐位仲裁:
- 当两个或两个以上的节点同时开始传送报文时,就会产生总线访问冲突。此时,各节点会按照标识符的位顺序逐位进行仲裁。
- 在仲裁过程中,每个节点都会将自己发送的电平与总线上的电平进行比较。如果电平相同,则节点继续发送下一位;如果电平不同,则优先级低的节点停止发送,而优先级高的节点继续发送。
- 这种仲裁方式是非破坏性的,即优先级低的节点在仲裁过程中不会破坏总线上已经存在的数据。
- 显性电平优先:
- 在CAN总线上,显性电平(逻辑0)的优先级高于隐性电平(逻辑1)。因此,在仲裁过程中,如果某个节点发送的是隐性电平,但检测到总线上存在显性电平,那么该节点就会知道有更高优先级的消息正在发送,并主动停止发送。
一旦仲裁结束,优先级最高的节点将获得总线控制权并开始传输数据。其他节点则成为接收节点并监听总线上的数据,并会自动检测总线空闲,在第一时间再次尝试发送。

4. STM32 CAN控制器介绍
4.1 CAN控制器介绍
STM32的bxCAN,即基本扩展CAN(Basic Extend CAN),是STM32微控制器系列中集成的CAN控制器模块。
- 协议支持:支持CAN协议2.0A和2.0B的主动模式。
- 高波特率:波特率最高可达1兆位/秒。
- 时间触发通信:支持时间触发通信功能,CAN的硬件内部定时器可以在TX/RX的帧起始位的采样点位置生成时间戳。
- 发送功能:
- 具有3个发送邮箱,发送报文的优先级特性可软件配置。
- 记录发送SOF(Start Of Frame,帧起始)时刻的时间。
- 接收功能:
- 具有3级深度的2个FIFO(First In First Out,先进先出队列),每个FIFO都可以存放3个完整的报文,完全由硬件管理。
- 共有14个位宽可变的过滤器组(部分STM32型号可能支持更多),由整个CAN共享,用于筛选有效报文。
- 记录接收SOF时刻的时间。
- 支持禁止自动重传模式。
4.1 CAN控制器模式
CAN控制器的工作模式有三种:初始化模式、正常模式和睡眠模式。
睡眠模式:在睡眠模式下,CAN控制器的时钟停止,以降低功耗。但软件仍然可以访问邮箱寄存器。
初始化模式:在初始化模式下,禁止报文的接收和发送,并且CANTX引脚输出隐性位(高电平)。此时,可以对CAN控制器的相关寄存器进行配置,如位时间特性(CAN_BTR)和控制(CAN_MCR)等。
正常模式:作为总线的正常节点,可以向总线发送或接收数据。

CAN控制器的测试模式有三种:静默模式、环回模式和环回静默模式,主要用于特定的测试或调试目的,以确保CAN控制器的功能正常。
1. 静默模式
特点:
- 在静默模式下,CAN控制器可以正常地接收数据帧和远程帧,但只能发出隐性位,而不能真正发送报文。
- 这意味着,虽然CAN控制器在尝试发送数据,但实际上它并没有在CAN总线上产生任何显性位,因此不会对总线上的其他节点产生影响。
应用场景:
- 静默模式通常用于分析CAN总线的活动,而不会对总线上的其他通信造成干扰。
- 开发人员可以使用此模式来观察总线上的数据流,而无需担心他们的测试设备会发送出不必要的报文。
2. 环回模式
特点:
- 在环回模式下,CAN控制器会把发送的报文当作接收的报文并保存(如果可以通过接收过滤)。
- 这意味着,当CAN控制器发送一个报文时,它会立即在自己的接收缓冲区中看到这个报文,就像它是从总线上接收到的一样。
应用场景:
- 环回模式通常用于自测试,以验证CAN控制器的发送和接收功能是否正常。
- 通过发送一个报文并检查它是否被正确接收,开发人员可以确保CAN控制器的硬件和固件都按预期工作。
3. 环回静默模式
特点:
- 环回静默模式结合了静默模式和环回模式的特点。
- 在该模式下,CANRX引脚与CAN总线断开,同时CANTX引脚被驱动到隐性位状态。
- 这意味着,虽然CAN控制器在尝试发送报文,但它实际上并没有在CAN总线上产生任何显性位,并且它会将发送的报文视为接收到的报文。
应用场景:
- 环回静默模式通常用于“热自测试”,即可以在不影响CANTX和CANRX所连接的整个CAN系统的情况下进行测试。
- 这种模式允许开发人员在不干扰总线上的其他通信的情况下,验证CAN控制器的发送和接收功能。

4.2 CAN控制器框图
CAN控制内核:包含各种控制/状态/配置寄存器,用于配置CAN控制器的模式、波特率等参数。
发送邮箱(Transmit Mailbox):用来缓存待发送的CAN报文。STM32等微控制器通常具有多个发送邮箱(如3个),以支持同时缓存多个报文。
接收FIFO(First In First Out):缓存接收到的有效CAN报文。CAN控制器通常具有多个接收FIFO(如2个),以提高接收效率。
接收过滤器(Receive Filter):筛选接收到的CAN报文,只将符合特定条件的报文保存到接收FIFO中。这有助于减少CPU的处理负担,提高系统的响应速度。

发送处理过程:

接收处理过程:

有效报文指的是(数据帧直到EOF段的最后一位都没有错误),且通过过滤器组对标识符过滤。
接收过滤器:
当总线上报文数据量很大时,总线上的设备会频繁获取报文,占用CPU。过滤器的存在,选择性接收有效报文,减轻系统负担。
STM32的CAN控制器支持配置过滤器组,每个过滤器组包含2个32位的寄存器CAN_FxR1和CAN_FxR2,用于存储要筛选的ID或掩码。对于STM32F103C8T6,如果只有一个CAN控制器,则可以配置14个过滤器组,对应的编号为0到13。
过滤器可以配置为不同的位宽,以适应不同长度的CAN ID。常见的位宽包括16位(用于标准帧)和32位(用于扩展帧)。
选择模式可设置屏蔽位模式或标识符列表模式,寄存器内容的功能就有所区别。屏蔽位模式,可以选择出一组符合条件的报文。寄存器内容功能相当于是否符合条件。标识符列表模式,可以选择出几个特定ID的报文。寄存器内容功能就是标识符本身。

4.3 CAN控制器位时序


设TS1=8、TS2=7、BRP=3,波特率 = 36000 / [( 9 + 8 + 1 ) * 4] = 500Kbps。
注意:通信双方波特率需要一致才能通信成功。
5. CAN寄存器及库函数介绍
6. CAN基本驱动流程

小实验:CAN收发实验
实验目的
- 使用回环模式实现自发自收;
- 两个CAN设备实现收发。
硬件清单
- TJA1050
- 上官二号
- ST-Link
- USB转TTL
硬件接线

十七、MQTT
https://q4p5s568ub.feishu.cn/docx/ECsSdCSGoooQvux7U1xcmGaLnNd?from=from_copylink
模块:DHT11温湿度传感器
项目:温湿度上传OneNET
项目需求
使用 ESP8266 连接 OneNET 云平台,并通过 MQTT 协议上传 DHT11 获取的温湿度值。
硬件清单
- ESP8266
- DHT11
- 杜邦线
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | ESP8266 | DHT11 |
|---|---|---|
| PA3 | TX | |
| PA2 | RX | |
| PA5 | I/O | |
| 3.3V | 3V3 | VCC |
| GND | GND | GND |
项目框图

项目:Wi-Fi天气预报
项目需求
使用 ESP8266 通过 HTTP 获取天气数据(心知天气),并显示在 OLED 屏幕上。
按键 1 :循环切换今天/明天/后天天气数据;
按键 2 :更新天气。
硬件清单
- ESP8266
- OLED
- 杜邦线
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | ESP8266 | OLED |
|---|---|---|
| PA3 | TX | |
| PA2 | RX | |
| PB8 | SCL | |
| PB9 | SDA | |
| 3.3V | 3V3 | VCC |
| GND | GND | GND |
项目框图

模块:光敏电阻传感器
项目:智能台灯
项目需求
- 红外传感器检测是否有人,有人的话实时检测距离,过近则报警;同时计时,超过固定时间则报警;
- 按键 1 切换工作模式:智能模式、按键模式、远程模式;
- 智能模式下,根据光照强度自动调整光照档位(低亮、中亮、高亮),没人则自动光灯;
- 按键模式下,按键 2 可以手动调整光照档位;
- 远程模式下,可以通过蓝牙控制光照档位、计时等;
- 按键 3 暂停/开始计时,按键 4 清零计时;
- OLED 显示各项数据/状态。
硬件清单
- 蓝牙模块
- 超声波传感器
- 红外传感器
- 光敏电阻传感器
- OLED
- 高功率LED灯
- 蜂鸣器
- KEY × 4
- 杜邦线
- 上官二号
- ST-Link
- USB转TTL
硬件接线
| STM32 | OLED | LED灯 | 蜂鸣器 | 蓝牙 | 超声波 | 红外 | 光敏电阻 | KEY1 | KEY2 | KEY3 | KEY4 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| PB6 | SCL | ||||||||||
| PB7 | SDA | ||||||||||
| PB0 | I/O | ||||||||||
| PB13 | I/O | ||||||||||
| PA3 | TX | ||||||||||
| PA2 | RX | ||||||||||
| PA11 | Trig | ||||||||||
| PA12 | Echo | ||||||||||
| PB12 | I/O | ||||||||||
| PA1 | I/O | ||||||||||
| PA4 | I/O | ||||||||||
| PA5 | I/O | ||||||||||
| PA6 | I/O | ||||||||||
| PA7 | I/O | ||||||||||
| 3.3V | VCC | VCC | VCC | VCC | |||||||
| 5V | VCC | VCC | VCC | ||||||||
| GND | GND | GND | GND | GND | GND | GND | GND | GND | GND | GND | GND |
项目框图

画板入门

项目:智能小车
1. 智能小车的组装


| STM32 | 电机驱动 |
|---|---|
| PB0 | A-1A |
| PB1 | A-1B |
| PB2 | B-1A |
| PB10 | B-1B |
2. 让小车动起来
3. 串口控制小车
4. 蓝牙控制小车
5. 小车点动控制
6. pwm调速小车
| STM32 | 电机驱动 |
|---|---|
| PA0 | A-1A |
| PB1 | A-1B |
| PA1 | B-1A |
| PB10 | B-1B |
7. 左右轮差速调速
电机驱动接线同小项目 6 。
9. 循迹小车
| STM32 | 电机驱动 | 循迹模块 |
|---|---|---|
| PB0 | A-1A | |
| PB1 | A-1B | |
| PB2 | B-1A | |
| PB10 | B-1B | |
| PB13 | DO(左) | |
| PB14 | DO(右) |
循迹+pwm调速接线同小项目 6 。
10. 跟随小车
| STM32 | 电机驱动 | 跟随模块 |
|---|---|---|
| PB0 | A-1A | |
| PB1 | A-1B | |
| PB2 | B-1A | |
| PB10 | B-1B | |
| PB5 | OUT(左) | |
| PB6 | OUT(右) |
11. 避障小车
| STM32 | 电机驱动 | 舵机 | 超声波 |
|---|---|---|---|
| PB0 | A-1A | ||
| PB1 | A-1B | ||
| PB2 | B-1A | ||
| PB10 | B-1B | ||
| PA6 | 橙线 | ||
| PA12 | Trig | ||
| PA11 | Echo |
12. 测速小车
| STM32 | 电机驱动 | 测速模块 | OLED |
|---|---|---|---|
| PB0 | A-1A | ||
| PB1 | A-1B | ||
| PB2 | B-1A | ||
| PB10 | B-1B | ||
| PB12 | OUT | ||
| PB8 | SCL | ||
| PB9 | SDA | ||
| 3.3V | VCC | VCC | VCC |
| GND | GND | GND | GND |
注意:测速模块、蓝牙模块、OLED模块,都需要接到 3.3V 电源!
13. 语音控制小车
| STM32 | 电机驱动 | OLED | 循迹模块 | 跟随模块 | 舵机 | 超声波 | SU-03T |
|---|---|---|---|---|---|---|---|
| PB0 | A-1A | ||||||
| PB1 | A-1B | ||||||
| PB2 | B-1A | ||||||
| PB10 | B-1B | ||||||
| PB6 | SCL | ||||||
| PB7 | SDA | ||||||
| PB13 | DO(左) | ||||||
| PB14 | DO(右) | ||||||
| PB5 | OUT(左) | ||||||
| PB6 | OUT(右) | ||||||
| PA6 | 橙线 | ||||||
| PA12 | Trig | ||||||
| PA11 | Echo | ||||||
| PA0 | A25 | ||||||
| PA1 | A26 | ||||||
| PA2 | A27 |
模块:寻迹模块
模块:测速模块
模块:L9110电机控制模块
模块:SU-03T
项目:智能家居
项目需求
- 支持模拟多线程功能;
- 支持门禁功能;
- 支持燃气报警功能;
- 支持环境数据上传 OneNET 功能;
- 支持蓝牙、语音控制客厅/卧室灯;

硬件清单
- 矩阵键盘
- OLED
- 蜂鸣器
- W25Q128
- 继电器
- 烟雾传感器
- DHT11
- 光敏电阻传感器
- SU-03T
- 蓝牙模块
- 杜邦线
- 上官二号
- ST-Link
- USB转TTL
硬件接线

项目框图

项目:PID平衡小车(选修)
项目需求
- 实现小车自平衡
- 实现手机蓝牙控制小车
项目框架

MPU6050简介
MPU6050 是一款 六轴姿态传感器,能够测量芯片自身在 X、Y、Z 三个轴向上的加速度和角速度参数。通过对这些数据进行融合处理,可以进一步计算出设备的姿态角,从而精确感知设备的倾斜和旋转状态。这种能力使 MPU6050 成为许多需要检测自身姿态的应用场景中的核心元件,如平衡车、飞行器、机器人控制等。
1. 陀螺仪和加速度计
先给小伙伴们解释一下陀螺仪和加速度计的用途。这里就以 MPU6050 的三轴(X轴、Y轴和Z轴)为例。
- 陀螺仪:陀螺仪可以测量物体绕着三个轴旋转的速度,也称为角速度。角速度是指物体每秒钟绕轴旋转的角度。通过陀螺仪的数据,你可以知道设备是在左右旋转、上下颠倒还是前后倾斜。所以它能知道你在怎么转。
- 加速度计:加速度计可以测量物体在三个轴上的线性加速度。这里的加速度不仅仅指的是物体加速时的情况,还包括重力加速度。因此,即使静止不动的物体也会有一个加速度计读数,这个读数反映了重力的方向。通过分析加速度计的数据,可以判断出设备的大致朝向和是否在移动。所以它能知道你在怎么动。
2. MPU6050型号介绍
MPU6050 是由 InvenSense 公司生产的全球首款整合性六轴运动处理模块。六轴是指 MPU6050 集成了三轴陀螺仪和一个三轴加速度计,可以实时输出三轴的角度和速度信息。具体如下图。

旋转的方向按右手法则定义,即右手大拇指指向轴向,四指弯曲的方向即为绕该轴旋转的方向。 X 轴角度(滚转角 Roll)即为绕 X 轴旋转方向的角度, Y 轴角度(俯仰角 Pitch)即为绕 Y 轴旋转方向的角度, Z 轴角度(偏航角 Yaw)即为绕 Z 轴旋转方向的角度, 三者合称姿态角/欧拉角(Euler angles)。
除此之外,MPU6050 还集成了一个温度传感器,可以输出温度信息。
我们购买时,会分两种排针,直针和弯针,决定了 MPU6050 不同的放置方向,大家根据项目需求,结合上下两张图选择就好了。

3. MPU6050参数及引脚介绍
MPU6050参数:
- 工作电压:DC 3V ~ 5V
- 通信方式:标准IIC通信协议
- 芯片内置:16bit AD 转换器,16 位数据输出
- 陀螺仪范围:±250、500、1000、2000°/s
- 加速度范围:±2、±4、±8、±16g
- 精度:±2℃(-55°C ~ +125°C),±0.5℃(-10°C ~ +85°C)
- PCB 板尺寸:21mm × 16mm

接线如下:
| MPU6050 | 说明 |
|---|---|
| VCC | 电源正极 |
| GND | 电源地 |
| SCL | IIC 的时钟线 |
| SDA | IIC 的数据线 |
| XDA | 外接 IIC 设备的数据线 |
| XCL | 外接 IIC 设备的时钟线 |
| AD0 | 控制 IIC 从属地址,接地时,地址为 0x68;接 VCC 时,地址为 0x69 |
| INT | 中断数字输出 |
通过对 MPU6050 的引脚介绍我们可以知道,MPU6050 可以外接一个 IIC 设备,通常可以外接一个三轴的磁力计来实现完整的九轴输出。
4. MPU6050系统框图
MPU6050 对陀螺仪和加速度计分别用了三个16位的 ADC,将其测量的模拟量转化为可输出的数字量,并保存到寄存器中供用户读取。

定时器编码器模式
1. 编码器接口简介
在STM32的定时器编码器模式下,定时器的计数器(CNT)会根据接收到的编码器信号自动增加或减少。
具体来说,当编码器旋转时,相位A和相位B的脉冲信号会被送到定时器的输入捕获通道(通常是通道1和通道2)。
这些脉冲信号之间的相位差(通常为90度)用于确定旋转的方向。
根据编码器旋转产生的正交信号脉冲,定时器的计数器会自动增加或减少,从而指示编码器的位置、旋转方向和旋转速度。
每个高级定时器和通用定时器都拥有1个编码器接口。
2. 编码器如何判断正反转

3. 编码器框图


4. 编码器计数方向

电机驱动


小车直立行走任务分解
我们要求车模在直立的状态下以两个轮子在地面上随意行走,相比四轮着地状态,车模控制任务更为复杂。为了能够方便找到解决问题的办法,首先将复杂的问题分解成简单的问题进行讨论。
从控制角度来看,车模作为一个控制对象,它的控制输入量是两个电机的转动速度。车模运动控制任务可以分解成以下三个基本控制任务:
(1) 控制车模平衡:通过控制两个电机正反向运动保持车模直立平衡状态;
(2) 控制车模速度:通过调节车模的倾角来实现车模速度控制,实际上最后还是演变成通过控制电机的转速来实现车轮速度的控制。
(3) 控制车模方向:通过控制两个电机之间的转动差速实现车模转向控制。

控制车模平衡的直观经验来自于人们日常生活经验。一般的人通过简单练习就可以让一个直木棒在手指尖上保持直立。这需要两个条件:一个是托着木棒的手掌可以移动;另一个是眼睛可以观察到木棒的倾斜角度和倾斜趋势(角速度)。通过手掌移动抵消木棒的倾斜角度和趋势,从而保持木棒的直立。这两个条件缺一不可,实际上就是控制中的负反馈机制。

PID控制理论
所谓PID算法,是一种在工程应用领域被使用最为广泛的反馈调节方法,通过PID算法中比例、积分、微分三个部分的作用,达到使系统稳定的效果。
(1)比例调节:反应系统的基本(当前)偏差 e(t),系数大,可以加快调节,减小误差,但过大的比例使系统稳定性下降,甚至造成系统不稳定;
(2)积分调节:反应系统的累计偏差,使系统消除稳态误差,提高无差度,因为有误差,积分调节就进行,直至无误差;
(3)微分调节:反映系统偏差信号的变化率 e(t)-e(t-1),具有预见性,能预见偏差变化的趋势,产生超前的控制作用,在偏差还没有形成之前,已被微分调节作用消除,因此可以改善系统的动态性能。但是微分对噪声干扰有放大作用,加强微分对系统抗干扰不利。
注:积分和微分都不能单独起作用,必须与比例控制配合。


根据直立小车平衡任务分解:
- 直立环
- 速度环
- 方向环
直立环
车模平衡控制也是通过负反馈来实现的,与上面保持木棒直立比较则相对简单。因为车模有两个轮子着地,车体只会在轮子滚动的方向上发生倾斜。控制轮子转动,抵消在一个维度上倾斜的趋势便可以保持车体平衡了。

平衡小车直立环的调试过程包括确定平衡小车的机械中值、确定kp值的极性(也就是正负号)和大小、kd值的极性和大小等步骤。
1、确定平衡小车的机械中值:
把平衡小车放在地面上,绕电机轴旋转平衡小车,记录能让小车接近平衡的角度,一般都在0°附近的。
2、估算kp值的大小与极性(令kd=0)
首先我们估计kp的取值范围。我们的PWM设置的是7200代表占空比100%,再考虑避免电机的死区,我们直立环返回的PWM在7000左右的时候电机就会满载。
假如我们设定kp值为700,那么平衡小车在±10°的时候就会满转。根据我们的感性认识,这显然太大了,那我们就可以估计kp值在0~700之间。
首先大概我们给一个值kp=-200,我们可以观察到,小车往哪边倒,电机会往那边加速让小车到下,就是一个我们不愿看到的正反馈的效果。说明kp值的极性反了,接下来我们设定kp=200,这个时候可以看到平衡小车有直立的趋势,虽然响应太慢,但是,我们可以确定kp值是正的。具体的数据接下来再仔细调试。
3、确定kp值的大小(令kd=0)
设定kp=100,这个时候我们可以看到,小车虽然有平衡的趋势,但是显然响应有点慢了。
设定kp=250,这个时候我们可以看到,小车虽然有平衡的趋势,而且响应有所加快,总体感觉良好。
设定kp=500,这个时候我们可以看到,小车的响应明显加快,而且来回推动小车的时候,会有一定幅度的低频抖动。说明这个时候kp值已经足够大了,需要增加微分控制削弱p控制,抑制低频抖动。
经过总体比较: 我们选择参数为kp = 315;
4、确定kd值的极性与大小(令kp=0)
我们得到的MPU6050输出的陀螺仪的原始数据,通过观察数据,我们发现最大值不会超过4位数,再根据7000代表占空比100%,所以我们估算kd值应该在0~2之间。
我们先设定kd=-0.5,当我们拿起小车旋转的时候,车轮会反向转动,并没有能够实现跟随效果。这说明了kd的极性反了。
接下来,我们设定kd=0.5,这个时候我们可以看到,当我们旋转小车的时候,车轮会同向以相同的速度跟随转动,这说明我们实现了角速度闭环,至此,我们可以确定kd的极性是正的。
具体的数据接下来再仔细调试。最终我们选择kd = 1.1;
速度环
- 为什么需要速度环?
假设车模在上面直立控制调节下已经能够保持平衡了,但是由于安装误差,传感器实际测量的角度与车模角度有偏差,因此车模实际不是保持与地面垂直,而是存在一个倾角。在重力的作用下,车模就会朝倾斜的方向加速前进。如果没有速度调节是难以维持0速度的。

- 确定Kp的范围
积分项由偏差的积分得到,所以积分控制和比例控制的极性相同的,而根据工程经验,在不同的系统中,PID 参数相互之间会有一定的比例关系。在我们的平衡小车速度控制系统里面,一般我们可以把ki 值设置为
ki = kp/200
我们发现两路编码器相加最大值在160左右,而由经验可知,一般平衡小车行驶的最快速度不会超过电机最大速度的40%,再根据PWM = 7000时,在加上电机死区、占空比接近100%,我们可以大概估算
kp 最大值=7000/(160*40%)=109.37
- 确定kp值的极性(关闭直立环)
当我们旋转其中一个小车轮胎的时候,两个轮胎会往相同的方向加速,直至电机的最大速度,这是典型的正反馈效果,也是我们期望看到的。
- 确定Kp值(打开直立环)
- 设定kp=-30,ki=kp/200这个时候我们可以看到,小车的速度控制比较弱,很难让速度恒定。
- 设定kp=-50,ki=kp/200这个时候我们可以看到,小车的速度控制的响应有所加快,静止抖动可接受。
- 设定kp=-70,ki=kp/200这个时候我们可以看到,小车虽然回正力度增大了,而且响应更加快了,但是稍微加入一点的干扰都会让小车大幅度摆动,抗干扰能力明显不足,所以这组参数不可取。
