核心心法:如何阅读手册中的寄存器表格?

notion image

STM32F1系列下的不同产品子系列

  • 基础/增强型STM32F10X_LD / _MD / _HD。这是最常用的分类,根据Flash容量大小划分-。STM32F103C8T6 就属于这个类别,对应 STM32F10X_MD
  • 互联型STM32F10X_CL (Connectivity Line)。指集成了更丰富外设(如以太网、USB OTG)的STM32F105/107系列。
  • 超值型STM32F10X_LD_VL / _MD_VL / _HD_VL (Value Line)。专指性价比高、成本敏感的STM32F100系列。

频率和秒的知识点

notion image
notion image
notion image

格式化输出符号

C语言常用转义字符

  • 转义字符以\开头,用来表示无法直接输入 / 显示的特殊字符,或解决\"这类符号的冲突问题。
转义字符
ASCII 码(十进制 / 十六进制)
功能说明
串口 / 终端常见场景
\0
0 / 0x00
字符串结束标志
C 语言中char[]的终止符,while(*str != '\0')就是靠它判断字符串结束
\n
10 / 0x0A
换行(Line Feed)
光标移到下一行,但不回到行首
\r
13 / 0x0D
回车(Carriage Return)
光标回到当前行的行首,但不换行
\r\n
13+10 / 0x0D 0x0A
Windows 标准换行
同时实现「回到行首 + 换行」,串口助手里按回车就会发送这两个字节
\t
9 / 0x09
水平制表符(Tab)
光标跳到下一个 Tab 位置,用来对齐文本
\b
8 / 0x08
退格(Backspace)
光标回退一格,删除前一个字符
\f
12 / 0x0C
换页(Form Feed)
在 Windows 超级终端 / 串口助手发送\f(即0x0C)可实现清屏
\\
92 / 0x5C
反斜杠本身
因为\是转义起始符,要输出单个\必须写两个\\
\'
39 / 0x27
单引号
解决 C 语言中'作为字符边界的冲突
\"
34 / 0x22
双引号
解决 C 语言中"作为字符串边界的冲突
\ddd
8 进制表示的字符
用 1-3 位 8 进制数表示 ASCII 字符
比如\012等价于\n(8 进制 12 = 十进制 10)
\xhh
16 进制表示的字符
用 1-2 位 16 进制数表示 ASCII 字符
比如\x0A等价于\n\x0D等价于\r

ANSI 终端控制码(彩色文本 + 格式控制)

  • NSI 控制码以\033[(即ESC[\033是 ESC 的 8 进制表示)开头,用来控制终端的文本颜色、格式,支持大部分串口助手(如 DYS 串口助手、Xshell、PuTTY)

(1)基础格式控制码

开启码
对应关闭码
功能说明
杜洋串口助手 V1 支持情况
备注
0
无(全局重置)
恢复所有默认设置(黑底白字,关闭所有格式)
✅ 完美支持
最常用!所有格式输出后必须加这个,否则后续文字都会带格式
1
22
高亮 / 加粗显示
✅ 完美支持
最常用!让文字更醒目,调试信息必备
2
22
暗淡 / 低亮度显示
❌ 不支持
绝大多数串口助手都不支持
3
23
斜体显示
❌ 不支持
只有 Xshell、SecureCRT 等专业终端支持
4
24
下划线
✅ 完美支持
可以用来标记重要标题
5
25
慢速闪烁(<150 次 / 分钟)
⚠️ 部分支持
杜洋串口助手会显示为高亮,不会真的闪烁
6
25
快速闪烁(>150 次 / 分钟)
❌ 不支持
几乎没有终端支持
7
27
反白显示(前景色和背景色互换)
✅ 完美支持
用来突出显示警告信息
8
28
隐藏 / 不可见
❌ 不支持
杜洋串口助手会显示为黑色文字
9
29
删除线 / 划除线
❌ 不支持
只有现代终端支持

(2)前景 / 背景颜色对照表

(2.1)基础8色(所有终端通用)

前景色代码
背景色代码
颜色名称
效果
30
40
黑色
深黑色
31
41
红色
深红色
32
42
绿色
深绿色
33
43
黄色
深黄色(偏棕)
34
44
蓝色
深蓝色
35
45
紫红色
深紫色
36
46
青蓝色
深青色
37
47
白色
浅灰色(标准白色)

(2.2)16 色(绝大多数串口助手支持,推荐使用)

  • 在基础 8 色的基础上,增加了高亮版本,通过在颜色代码前加1;(高亮属性)实现,颜色更鲜艳、更清晰
前景色代码
背景色代码
颜色名称
效果
30
40
黑色
深黑色
90
100
亮黑色
深灰色
31
41
红色
深红色
91
101
亮红色
鲜红色
32
42
绿色
深绿色
92
102
亮绿色
鲜绿色
33
43
黄色
深黄色
93
103
亮黄色
纯黄色
34
44
蓝色
深蓝色
94
104
亮蓝色
天蓝色
35
45
紫红色
深紫色
95
105
亮紫红色
洋红色
36
46
青蓝色
深青色
96
106
亮青蓝色
天青色
37
47
白色
浅灰色
97
107
亮白色
纯白色
  • 示例(STM32):

(2.3)256 色(部分高级串口助手支持)

  • 支持 Xshell、SecureCRT、MobaXterm 等专业终端
  • 格式:
    • 前景色:38;5;颜色编号
    • 背景色:48;5;颜色编号
  • 颜色编号范围:0~255,分为 3 个区域:
    • 0~15:对应上面的 16 色
    • 16~231:216 种 RGB 颜色(6×6×6 色板)
    • 232~255:24 级灰度(从黑到白)
  • 示例:

(2.4)24 位真彩色(仅专业终端支持)

  • 支持 Xshell 7+、SecureCRT 9+、Windows Terminal 等现代终端,绝大多数串口助手不支持
  • 格式:
    • 前景色:38;2;R;G;B
    • 背景色:48;2;R;G;B
  • 其中 R、G、B 的范围是0~255
  • 示例:

(3)控制码格式与示例

  • 格式:\033[<格式>;<背景>;<前景>m,用\033[0m结束控制序列
  • 示例 1:黑底绿色高亮文字
  • \033[1;40;32m:开启高亮、黑背景、绿前景
  • \033[0m:恢复默认格式,避免后续文本也带颜色
  • 示例 2:红色闪烁文字
  • 示例 3:带背景的蓝色文字

存储器映像

notion image
 
notion image

STM32F103xx增强型模块框图(后续设置SYSCLK、AHB、APB1、APB2等都需要查看这幅图)

notion image

时钟树(后续设置SYSCLK、AHB、APB1、APB2等都需要查看这幅图)

notion image

单片机内部电路常见的四种模式

51单片机识别模式方式

notion image

双向模式

notion image
notion image
notion image

开漏模式

notion image

推挽模式

notion image
notion image
notion image
  • 上方MOS管:PMOS管,下方MOS管:NMOS管
notion image
左边NMOS管:高电平导通
右边PMOS管:低电平导通

浮空模式

notion image

一、四种方法实现的LED闪灯程序文件分析

main.c文件代码:

1.1 RCC_Configuration(void)

sys.c文件部分代码:

① 宏观目的

notion image

② 编写者视角🚀

notion image
notion image

③ RCC时钟是什么?为什么要从HSI设置为HSE+PLL?为什么需要外设时钟?

notion image
notion image
notion image
notion image
【代码解释】:

ErrorStatus HSEStartUpStatus

  • 出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 含义:定义状态变量
  • 我写这行的想法:定义一个叫 HSEStartUpStatus 的变量,它的类型是 ErrorStatus。我查到 ErrorStatus 只有两个值:SUCCESS 和 ERROR。我用它来存“等待外部晶振”的结果:成功了还是失败了。
  • stm32f10x.h文件中ErrorStatus类型的定义代码:

RCC_DeInit( )

  • 编写这行代码之前,芯片的时钟系统被人动过什么手脚(可能别的代码改过、或者系统从某个异常状态恢复)。我不能冒险在一个不确定的状态上直接配置,万一某个寄存器里还残留着上次的“半吊子”设置,我的配置加上去可能就乱了。所以我的第一件事是:全部清零,重新来过
  • 含义:恢复出厂时钟设置
  • 设计意图:这是一个“回到原点”的操作。它不假定任何硬件状态,强制把时钟系统拨回最原始的上电默认值。这样我后续的配置就是从一张白纸开始,不会出现“旧配置残留导致异常”的棘手Bug。
  • 我写这行的想法:先把时钟系统“恢复出厂设置”。为什么第一件事要做这个?因为我不知道之前系统被谁动过、处于什么状态。直接配置可能出乱子。所以我调用 RCC_DeInit,它帮我把所有时钟寄存器拨回到上电默认值(系统切回内部8MHz时钟,关掉外部晶振和PLL)。
notion image
  • 出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
  • stm32f10x_rcc.c文件中RCC_DeInit函数代码:
★(1)RCC->CR |= 0x01
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
  • 其中与0x01或运算,代表将HSION置为1,其余不变(在或运算中,0代表位的值不变,1代表将改位置为1)
notion image
notion image
  • 至于CR寄存器的其他位为什么不清零?
名称
类型
复位值
描述
0
HSION
控制位
1
内部高速时钟使能。复位后默认
1
HSIRDY
状态位
?
硬件自动管理。HSI稳定后由硬件置1。
7:3
HSITRIM
控制位
16
HSI频率微调,默认值16对应8MHz。
15:8
HSICAL
校准值
?
这是芯片出厂时校准好的,保证HSI频率精准的。你要是改了它,8MHz就不准了,千万别改
16
HSEON
控制位
0
外部高速时钟使能。复位后默认【当系统已经安全切回HSI,才能关闭;意思是先设置CFGR寄存器】
17
HSERDY
状态位
0
硬件自动管理。HSE稳定后由硬件置1。
18
HSEBYP
控制位
0
外部时钟旁路选择。【当系统已经安全切回HSI,才能关闭;意思是先设置CFGR寄存器】
19
CSSON
控制位
0
时钟安全系统使能。【当系统已经安全切回HSI,才能关闭;意思是先设置CFGR寄存器】
24
PLLON
控制位
0
PLL使能。复位后默认【当系统已经安全切回HSI,才能关闭;意思是先设置CFGR寄存器】
25
PLLRDY
状态位
0
硬件自动管理。PLL锁定后由硬件置1。
★(2)RCC->CFGR &= (uint32_t)0xF8FF000
  • 因为使用的是STM32F103C8T6芯片,所以是非互联型,因此条件判断为不是STM32F10X_CL。
  • 根据这行代码,表示位0~15位清零,24~26位清零,其余位不变(在与运算中,0代表位的值清零,1代表不变)
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
notion image
notion image
notion image
notion image
★(3)RCC->CR &= (uint32_t)0xFEF6FFFF
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
  • 根据这行代码,表示第16、19、24位清零,其余不变
notion image
notion image
notion image
notion image
★(4)RCC->CR &= (uint32_t)0xFFFBFFFF
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
  • 这行代码表示第18位清零,其余不变(旁路模式是用来接外部方波时钟的,我们用的是晶振,所以这个模式必须关掉。)
notion image
notion image
 
★(5)RCC->CFGR &= (uint32_t)0xFF80FFFF
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
  • 这行代码表示第16~22位清零,其余不变
notion image
notion image
notion image
notion image
★(6)最后的条件编译
  • 有关参考手册内容,在本小节后面部分有图片显示
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
  • 参考手册第85~86页
互联型:
notion image
  • 参考手册第63~65页
非互联型:
notion image
  • 参考手册第88~89页
互联型:
notion image
notion image
  • 参考手册第101~102页
互联型:
notion image
notion image
 

RCC_HSEConfig(RCC_HSE_ON)

  • 设计意图:函数先把“开关”和“旁路”都关干净,然后再按需要打开。这是一种“先复位再设置”的模式,保证任何情况调这个函数都是安全可预期的。
  • 我写这行的想法:现在要打开8MHz外部晶振了。RCC_HSE_ON 是一个宏,值是 0x00010000。我调用 RCC_HSEConfig 函数,它里面会把这个值写到硬件寄存器里。
notion image
  • 参数RCC_HSE_ON的值为((uint32_t)0x00010000)【0000 0000 0000 0001 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CR(时钟控制寄存器)- - - 与参数有关
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
notion image
notion image
  • RCC_HSEConfig(RCC_HSE_ON)这个函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)RCC_CR &= CR_HSEON_ResetRCC_CR &= CR_HSEBYP_Reset
  • CR_HSEON_Reset的值为((uint32_t)0xFFFEFFFF),CR_HSEBYP_Reset的值为((uint32_t)0xFFFBFFFF),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CR(时钟控制寄存器)- - - 与代码语句有关
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
notion image
notion image
notion image
  • 含义:前者表示将HSEON这个16位进行清零操作,后者表示将HSEBYP这个18位进行清零操作,其余位不变(与运算,1表示不变,0表示清零

HSEStartUpStatus = RCC_WaitForHSEStartUp( )

  • HSEStartUpStatus这个变量的类型在第一行有说明(ErrorStatus,有两值:ERROR(0)、SUCCESS(1))
  • RCC_WaitForHSEStartUp( )的作用(大白话):打开外部高速时钟(HSE)的开关之后,等着它“起床”,直到它彻底稳定,或者等了太久没反应就报错。
  • 设计意图:等待一个外部硬件事件,必须带超时机制。如果晶振坏了或者虚焊了,程序总不能在这里死循环一万年。等1280次还没好,就返回 ERROR,让上层代码决策(比如降级用内部时钟跑,或者报错)。
  • 我写这行的想法:通电只是开始,晶振需要时间“抖稳”。在手册第60页查到 HSERDY 位(第17位),它会在晶振稳定后被硬件自动置1。我调用 RCC_WaitForHSEStartUp 函数,它会反复去查这个位,并把结果(成功或超时失败)存到 HSEStartUpStatus 里。
notion image
  • 出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY)
  • HSEStatus是FlagStatus类型的变量,有两值:RESET(0)、SET(1)
  • HSEStatus的值是随硬件而变化的
  • 参数RCC_FLAG_HSERDY的值为((uint8_t)0x31),出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CR(时钟控制寄存器)- - - 与参数有关
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
notion image
notion image
notion image
RCC_BDCR(备份域控制寄存器)- - - 与参数有关
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image
RCC_CSR(控制/状态寄存器)- - - 与参数有关
  • RCC_CSR控制/状态寄存器在参考手册第75~76页有定义
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
RCC_GetFlagStatus(RCC_FLAG_HSERDY)是一个被调用函数
  • 整体作用:看时钟是否达到稳定的状态
  • 出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(2)while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET))
  • HSE_STARTUP_TIMEOUT出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义) - - - ✿ 固体库文件
  • 首先判断计数StartUpCounter是否不等于1280,其次判断目标位的状态HSEStatus是否等于RESET(0);
  • 因为这个是要判定时钟是否稳定,所以要进行的退出循环状态
  • 那么如何退出循坏,要满足三个条件情况:一种是要计数值等于1280但HSEStatus等于RESET(0),一种是计数值等于1280且HSEStatus不等于RESET(0),一种是计数值不等于1280但HSEStatus不等于RESET(0)
  • 其中第一个条件情况是代表时钟还没有稳定,二三条件代表时钟稳定

if(HSEStartUpStatus == SUCCESS){ /*省略*/ }

  • 我写这行的想法:如果外部晶振启动成功了,才进行后面的倍频和切换操作。因为外部晶振是PLL的输入源,它没稳定,后面一切免谈。
  • 含义:如果HSEStartUpStatus是否为SUCCESS(1),则执行下面条件判断内部语句

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMUl_9)

  • 设计意图:采用“读-改-写”模式,只修改需要改变的位,不影响其他无关位。同时必须先关闭 PLL 才能修改配置,前面的 RCC_DeInit 已经确保 PLL 是关闭的。
  • 我写这行的想法:晶振好了,现在设置倍频器PLL。我要告诉PLL两件事:
(1)输入源:用外部晶振(RCC_PLLSource_HSE_Div1 = 0x00010000)。
(2)倍频系数:乘9倍(RCC_PLLMul_9 = 0x001C0000)。
notion image
  • 第一个参数RCC_PLLSource_HSE_Div1的值为((uint32_t)0x00010000)【000 0000 0000 0001 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与参数有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
  • 第二个参数RCC_PLLMul_9的值为((uint32_t)0x001C0000)【0000 0000 0001 1100 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与参数有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • RCC_PLLConfig函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= CFGR_PLL_Mask
  • CFGR_PLL_Mask的值为((uint32_t)0xFFC0FFFF),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
notion image
  • 这行代码表示需要对RCC_CFGR(时钟配置寄存器)进行PLL设置,则需要对目标位(即第16~21位进行清零操作)

RCC_HCLKConfig(RCC_SYSCLK_Div1)

  • 设计意图:AHB 是系统主总线,连接 CPU、内存、DMA 等核心部件,设为不分频以获得最高吞吐性能。
  • 我写这行的想法:设完PLL参数,现在设AHB总线(主血管)的速度。RCC_SYSCLK_Div1 = 0x00000000,意思是“不分频”。等会儿系统时钟是多少,AHB总线就跑多少。
notion image
  • 参数RCC_SYSCLK_Div1的值为((uint32_t)0x00000000)【0000 0000 0000 0000 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与参数有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • RCC_HCLKConfig函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= CFGR_HPRE_Reset_Mask
  • CFGR_HPRE_Reset_Mask的值为((uint32_t)0xFFFFFF0F),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • 这条语句表示对CRR_CFGR(时钟配置寄存器)进行第4~7位的清零操作

RCC_PCLK1Config(RCC_HCLK_Div2)和RCC_PCLK2Config(RCC_HCLK_Div1)

  • 设计意图前者:APB1 总线连接定时器、串口、I2C 等外设,手册规定其最高频率为 36MHz。当 HCLK 跑 72MHz 时,必须至少 2 分频才能保证这些外设不会超频损坏。后者:APB2 连接 GPIO、USART1、SPI1 等高速外设,支持 72MHz 全速运行,所以不分频。
  • 我写这两行的想法前者:设低速外设总线APB1的速度。RCC_HCLK_Div2 = 0x00000400,意思是“2分频”。等会儿AHB跑72MHz,APB1就跑36MHz。手册上查到APB1最高只能跑36MHz,所以必须分频。后者:设高速外设总线APB2的速度。它也能跑72MHz,所以不用分频。RCC_HCLK_Div1 = 0x00000000
notion image
notion image
  • 参数RCC_HCLK_Div2的值为((uint32_t)0x00000400)【0000 0000 0000 0000 0000 0100 0000 0000】,参数RCC_HCLK_Div1的值为((uint32_t)0x00000000)【0000 0000 0000 0000 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与参数有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
  • RCC_PCLK1Config函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= CFGR_PPRE1_Reset_Mask
  • CFGR_PPRE1_Reset_Mask的值为((uint32_t)0xFFFFF8FF),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • 这条语句表示对CRR_CFGR(时钟配置寄存器)进行第8~10位的清零操作
  • RCC_PCLK2Config函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= CFGR_PPRE2_Reset_Mask
  • CFGR_PPRE2_Reset_Mask的值为((uint32_t)0xFFFFC7FF),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • 这条语句表示对CRR_CFGR(时钟配置寄存器)进行第11~13位的清零操作

FLASH_SetLatency(FLASH_Latency_2)

  • 设计意图:当系统时钟超过 48MHz 时,Flash 存储器的读取速度跟不上 CPU 的取指速度。手册规定 48MHz~72MHz 必须使用 2 个等待周期。这一步如果不做,CPU 可能读到错误的指令,系统立即崩溃。
  • 我写这行的想法:CPU跑72MHz太快了,FLASH存储器跟不上。我在手册上查到,频率超过48MHz时必须设置2个等待周期。FLASH_Latency_2 = 0x00000002
notion image
为什么要设置FLASH?
  • 把单片机理解成一个工厂:
    • CPU:是工厂里手脚麻利的工人。
    • 系统时钟频率 (72MHz):是工人的干活速度。频率越高,他取指令和执行指令的节奏就越快。
    • Flash 存储器:是存放所有程序指令的仓库。
    • Flash 等待周期:是工人到达仓库后,喊“管理员,把下一条指令给我!”,然后站在原地等待的时间。
  • 核心矛盾来了:工人(CPU)的干活速度是可以调快的(超频到72MHz)。但是,仓库管理员(Flash控制电路)从货架上拿东西的物理速度是有上限的,他没法无限快。
    • 在默认8MHz低速时,工人慢悠悠去仓库,管理员能轻松在他下次来之前把货备好。
    • 当我们突然把工人的节奏加到72MHz,他跑去仓库催货的频率瞬间提高了9倍。管理员动作再快也跟不上了。如果工人不等管理员拿货就走,那他拿走的就是一个错误的空箱子,工厂(程序)就要出大乱子(跑飞或死机)。
  • 设置Flash等待周期,就是告诉工人:“兄弟,你以后跑快了,到仓库提货时,必须原地多等我2个周期(这就是 FLASH_Latency_2 的含义),确保我把正确的货交给你才能走。”
  • 参数FLASH_Latency_2的值为((uint32_t)0x00000002)【0000 0000 0000 0000 0000 0000 0000 0010】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_flash.h(外设固体库头文件- - - ✿ 固体库文件
FLASH_ACR(闪存访问控制寄存器)- - - 与参数有关
  • FLASH_ACR闪存访问控制寄存器在STM32F10xxx闪存编程手册第15页有定义
notion image
notion image
  • FLASH_SetLatency函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= ACR_LATENCY_Mask
  • ACR_LATENCY_Mask的值为((uint32_t)0x00000038),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_ACR(闪存访问控制寄存器)- - - 与代码语句有关
  • FLASH_ACR闪存访问控制寄存器在STM32F10xxx闪存编程手册第15页有定义
notion image
notion image
  • 这条语句表示对FLASH_ACR(闪存访问控制寄存器)进行第0~2位的清零操作

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable)

  • 设计意图:预取缓冲是硬件加速功能。开启后,Flash 控制器会在 CPU 读取指令的同时预读后面的指令放进缓冲区。当 CPU 需要下一条指令时可以直接从缓冲区取,减少等待时间。这能显著补偿等待周期带来的性能损失,让程序在 72MHz 下也能接近“零等待”执行。
  • 我写这行的想法:打开FLASH的“预取缓冲”功能。这能让FLASH在读当前指令时,偷偷把后面几条指令也读进来,CPU就不用等了,能大大提速。
notion image
  • 参数FLASH_PrefetchBuffer_Enable的值为((uint32_t)0x00000010)【0000 0000 0000 0000 0000 0000 0001 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_flash.h(外设固体库头文件- - - ✿ 固体库文件
FLASH_ACR(闪存访问控制寄存器)- - - 与参数有关
  • FLASH_ACR闪存访问控制寄存器在STM32F10xxx闪存编程手册第15页有定义
notion image
notion image
  • FLASH_PrefetchBufferCmd函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
★(1)FLASH->ACR &= ACR_PRFTBE_Mask
  • ACR_PRFTBE_Mask的值为((uint32_t)0xFFFFFFEF),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_ACR(闪存访问控制寄存器)- - - 与参数有关
  • FLASH_ACR闪存访问控制寄存器在STM32F10xxx闪存编程手册第15页有定义
notion image
notion image
  • 这条语句表示对FLASH_ACR(闪存访问控制寄存器)进行第4位的清零操作

RCC_PLLCmd(ENABLE)

  • 设计意图:PLL 参数已设好,总线已配好,Flash 已调优,现在可以按下“启动键”。位带操作比“读-改-写”更快、更安全,避免了中断干扰的风险。
  • 我写这行的想法:现在PLL的参数设好了,系统总线的分频也设好了,FLASH的等待周期也调好了。万事俱备,可以“点火”启动PLL了!ENABLE 的值是 1
    • notion image
  • 参数ENABLE为枚举类型FunctionalState,值为1,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • RCC_PLLCmd函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)*(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState
  • CR_PLLON_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
    • notion image
      notion image
  • CR_PLLON_BB的值为0x42420060,它的值的计算分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算步骤:(外设RCC的起始地址为0x4002 1000 ~ 0x4002 13FF)
notion image
notion image
notion image
notion image
notion image
  • *(__IO uint32_t *) CR_PLLON_BB 两个* 号的含义
notion image
notion image
notion image
notion image
notion image

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

  • 设计意图:PLL 启动后,内部电路需要时间将频率“锁定”到目标值。这个时间是不确定的(取决于环境和电路),必须用死循环等待硬件给出“就绪”信号。不等待就直接切换时钟,系统必然崩溃。
  • 我写这行的想法:PLL启动后需要时间稳定,不能立刻切换过去。在手册里找到 PLLRDY 位(第25位),它会在PLL稳定后被硬件置1。RCC_FLAG_PLLRDY = 0x39 就是指向这一位的暗号。我就在这死等,直到 RCC_GetFlagStatus 告诉我它好了。
    • notion image
  • 参数RCC_FLAG_PLLRDY的值为((uint8_t)0x39)【0011 1001,(1,25)】,代表RCC_CR(时钟控制寄存器)的第26位PLLRDY(PLL时钟就绪标志);这个第25位是有硬件设置的,所以主要是看上一步代码是否成功设置第24位PLLON(PLL使能)为1;
    • notion image
      notion image
  • RCC_GetFlagStatus(RCC_FLAG_PLLRDY)这个函数在之前的“HSEStartUpStatus = RCC_WaitForHSEStartUp( )”的“★(1)HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY) ”有详细解释,可往上面翻一番;
  • 这行代码其实就是让你判断第25位PLLRDY(PLL时钟就绪标志)是否设置为1了,设置成功,就借宿循坏,进入下一步代码;

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK)

  • 设计意图:SW 位是系统时钟的“选择开关”。将开关拨到 PLL 档,硬件就会开始切换过程,但并不是瞬间完成。
  • 我写这行的想法:PLL稳定了,现在把系统时钟从HSI(内部8MHz)切换到PLL(72MHz)。RCC_SYSCLKSource_PLLCLK = 0x00000002
    • notion image
  • 参数RCC_SYSCLKSource_PLLCLK的值为((uint32_t)0x00000002)【0000 0000 0000 0000 0000 0000 0000 0010】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
  • 函数RCC_SYSCLKConfig出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
★(1)tmpreg &= CFGR_SW_Mask
  • CFGR_SW_Mask的值为((uint32_t)0xFFFFFFFC),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • 这条语句表示对CRR_CFGR(时钟配置寄存器)进行第0~1位的清零操作

while(RCC_GetSYSCLKSource() != 0x08)

  • 设计意图:SW 是我们要的目标,SWS 是硬件切换完成的回执。手册明确指出,必须检查 SWS 位来确认切换真正完成。时钟源切换不是原子操作,需要数个时钟周期。如果不等待,CPU 可能在时钟切换的“震荡期”执行指令,后果不可预测。
  • 我写这行的想法:虽然我写了“请切换到PLL”的命令,但硬件切换需要几个时钟周期。RCC_GetSYSCLKSource 函数会去读 CFGR 寄存器里的 SWS 位(状态位)。当 SWS 位变成 10(二进制)时,整个寄存器的对应值是 0x08。我就死等,直到确认硬件真的切换完成了。
    • notion image
  • RCC_GetSYSCLKSource( )函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
  • CFGR_SWS_Mask的值为((uint32_t)0x0000000C),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
  • RCC->CFGR & CFGR_SWS_Mask这条语句表示对CRR_CFGR(时钟配置寄存器)进行第2~3位的清零操作

RCC_APB2PeriphClockCmd(两个参数)

  • 设计意图:芯片为了省电,外设时钟默认关上。你不开,GPIO 和串口就没法工作。这行代码就是“我明确告诉你,这些水管我要用,请给它们通水”。
  • 我写这行的想法:时钟系统搞定了,现在“打开水龙头”,给外设供血。我把要用的外设(串口1、GPIO A/B/C/D/E)的位用 | 运算合在一起,打包发给 RCC_APB2PeriphClockCmd 函数。这些外设都挂在APB2总线上,所以我要去 APB2ENR 寄存器里把对应的位置1。
    • notion image
  • 第一个参数为外设的相关变量,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_APB2ENR(APB2外设时钟使能寄存器)
  • APB2外设时钟使能寄存器RCC_APB2ENR在参考手册第70~71页有定义,英文版第112~114页有定义(其中TIM15~17,参考手册和英文版都没有找到对应定义处)
notion image
notion image
notion image
notion image
notion image
 
  • 第二个参数ENABLE为枚举类型FunctionalState,值为1;DISABLE,值为0;出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 函数RCC_APB2PeriphClockCmd出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件

RCC_APB1PeriphClockCmd(两个参数)

  • 设计意图:芯片为了省电,外设时钟默认关上。你不开,GPIO 和串口就没法工作。这行代码就是“我明确告诉你,这些水管我要用,请给它们通水”。
  • 第一个参数为外设的相关变量,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_APB1ENR(APB1外设时钟使能寄存器)
  • APB1外设时钟使能寄存器RCC_APB1ENR在参考手册第71~73页有定义,英文版第115~117页有定义(其中CAN2(第26位)和CEC(第30位),参考手册和英文版都没有找到对应定义处)
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
 
 
  • 第二个参数ENABLE为枚举类型FunctionalState,值为1;DISABLE,值为0;出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 函数RCC_APB1PeriphClockCmd,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件

1.2 LED_Init(void)

led.c文件代码

GPIO_InitTypeDef GPIO_InitStructure

  • 含义:创建GPIO_InitTypeDef的变量
  • GPIO_InitTypeDef这个类型,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE)

  • 含义:在外设时钟使能寄存器RCC_APB2ENR,打开所需要的GPIOA、GPIOB、GPIOC三个外设IO端口的位的开关
  • 1.1 RCC_Configuration(void)RCC_APB2PeriphClockCmd(两个参数)有说明其详细代码和作用

GPIO_InitStructure.GPIO_Pin = LED1 | LED2

  • 含义:引脚设置为LED1和LED2,即第0个和第1个引脚,GPIO_InitStructure.GPIO_Pin = 0x0003
  • LED1和LED2出自led.h文件
#define LED1 PBout(0)#define LED2 PBout(1)
  • 含义:定义LED1为PBout(0)【值为0x42218180,代表对ODR寄存器的第0位0DR0进行修改读取的虚拟地址(位段)】,定义LED2为PBout(1)【值为0x42218184,代表对ODR寄存器的第1位0DR1进行修改读取的虚拟地址(位段)】
  • “位段”出自参考手册第29~30页有定义
notion image
notion image
  • PBout(0或1)出自sys.h文件
GPIOA/B/C/D/E/F/G_BASE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 例子中的PBout(1):
POut(0):
#define LEDPORT GPIOB
  • 含义:定义LEDPORT为GPIOB,其中GPIOB的十六进制值代表在寄存器的起地址0x40010C00
  • GPIO端口B在寄存器的起始地址:0x4001 0C00 ~ 0x4001 0FFF
  • GPIOB,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • GPIO_TypeDef,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
notion image
  • GPIOA/B/C/D/E/F/G_BASE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算下来:(GPIOA~G计算出来的十六进制为该外设在存储器映像中寄存器的开始地址,即基地址)
#define LED1 GPIO_Pin_0#define LED2 GPIO_Pin_1
  • 含义:定义LED1为GPIO_Pin_0【0x0001,表示第0个引脚被选中】,定义LED2为GPIO_Pin_1【0x0002,表示第1个引脚被选中】
  • GPIO_Pin_0或1,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件
 

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP

  • 含义:将GPIO的工作模式设置为推挽输出(0x10)
  • GPIO_Mode_Out_PP为推挽输出(0x10),出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件
端口配置高寄存器(GPIOx_CRH)
  • GPIOx_CRH在参考手册第106页参考手册第114页有定义
notion image
notion image
notion image

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz

  • 含义:将GPIO的速度设置为50MHz
  • GPIO_Speed_50MHz为2,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件

GPIO_Init(LEDPORT, &GPIO_InitStructure)

  • 含义:调用GPIO_Init函数,其目的在于将前几行设置的值写入对应外设的寄存器中
  • 第一个参数在之前的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LEDPORT GPIOB ”有说明,即为GPIOB的基地址(0x0x40010C00),GPIO端口B在寄存器的起始地址:0x4001 0C00 ~ 0x4001 0FFF。LEDPORT(即 GPIOB)本质上是一个指向地址 0x40010C00 的结构体指针
  • 第二个参数则为之前说明的GPIO_InitStructure变量(内部根据前几行代码设置的值:0x0003(引脚0和1)、0x10(推挽输出)、2(50MHz)),GPIO_InitStructure表示结构体本身,而&GPIO_InitStructure表示指向这个结构体的地址,因为函数内部要拿到结构体的地址,才能对其本身进行修改
  • GPIO_Init函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件
端口配置低寄存器(GPIOx_CRL)
  • GPIOx_CRL端口配置低寄存器在参考手册第113页有定义
notion image
端口配置高寄存器(GPIOx_CRH)
  • GPIOx_CRH端口配置高寄存器在参考手册第114页有定义
notion image
端口输出数据寄存器(GPIOx_ODR)
  • GPIOx_ODR端口输出数据寄存器在参考手册第115页有定义
notion image
端口位设置/清除寄存器(GPIOx_BSRR)
  • GPIOx_BSRR端口位设置/清除寄存器在参考手册第115页有定义
notion image
端口位清除寄存器(GPIOx_BRR)
  • GPIOx_BRR端口位清除寄存器在参考手册第115~116页有定义
notion image
notion image

1.3 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(1或0或1-GPIO_ReadOutputDataBit(LEDPORT,LED1)))

  • 含义:BitAction(1)为高电平,BitAction(0)为低电平
  • 第一个参数在之前的“1.2 LED_Init(void)”的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LEDPORT GPIOB ”有说明,即为GPIOB的基地址(0x0x40010C00),GPIO端口B在寄存器的起始地址:0x4001 0C00 ~ 0x4001 0FFF。LEDPORT(即 GPIOB)本质上是一个指向地址 0x40010C00 的结构体指针
  • 第二个参数LED1在之前的“1.2 LED_Init(void)”的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LED1 GPIO_Pin_0#define LED2 GPIO_Pin_1 ”有说明,即(uint16_t)0x0001
  • 第三个参数(BitAction)(1)代表强制将1转换为BitAction,则为Bit_Set;(BitAction)(0)代表强制将0转换为BitAction,则为Bit_RESET。BitAction出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件
  • 第三个参数还有一个情况:(BitAction)(1-GPIO_ReadOutputDataBit(LEDPORT,LED1))
    • 这个1-GPIO_ReadOutputDataBit(LEDPORT,LED1)是取反的意思。
      • 假设GPIO_ReadOutputDataBit(LEDPORT,LED1)为0时,1-GPIO_ReadOutputDataBit(LEDPORT,LED1)为1。(BitAction)(1)。
      • 假设GPIO_ReadOutputDataBit(LEDPORT,LED1)为1时,1-GPIO_ReadOutputDataBit(LEDPORT,LED1)为0。(BitAction)(0)。
    • GPIO_ReadOutputDataBit(LEDPORT,LED1),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件
  • GPIO_WriteBit函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件
端口输出数据寄存器(GPIOx_ODR)
  • GPIOx_ODR端口输出数据寄存器在参考手册第115页有定义
notion image
端口位设置/清除寄存器(GPIOx_BSRR)
  • GPIOx_BSRR端口位设置/清除寄存器在参考手册第115页有定义
notion image
端口位清除寄存器(GPIOx_BRR)
  • GPIOx_BRR端口位清除寄存器在参考手册第115~116页有定义
notion image
notion image

1.4 GPIO_SetBits(LEDPORT,LED1)和GPIO_ResetBits(LEDPORT,LED1)

  • 含义:前者让引脚0为高电平,后者让引脚0为低电平
  • 第一个参数在之前的“1.2 LED_Init(void)”的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LEDPORT GPIOB ”有说明,即为GPIOB的基地址(0x0x40010C00),GPIO端口B在寄存器的起始地址:0x4001 0C00 ~ 0x4001 0FFF。LEDPORT(即 GPIOB)本质上是一个指向地址 0x40010C00 的结构体指针
  • 第二个参数LED1在之前的“1.2 LED_Init(void)”的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LED1 GPIO_Pin_0#define LED2 GPIO_Pin_1 ”有说明,即(uint16_t)0x0001
  • GPIO_SetBits和GPIO_ResetBits两个函数,都出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件
端口输出数据寄存器(GPIOx_ODR)
  • GPIOx_ODR端口输出数据寄存器在参考手册第115页有定义
notion image
端口位设置/清除寄存器(GPIOx_BSRR)
  • GPIOx_BSRR端口位设置/清除寄存器在参考手册第115页有定义
notion image
端口位清除寄存器(GPIOx_BRR)
  • GPIOx_BRR端口位清除寄存器在参考手册第115~116页有定义
notion image
notion image

1.5 GPIO_Write(LEDPORT,0x0001或者0x0000)

  • 含义:直接数值操作将变量值写入LED
  • 第一个参数在之前的“1.2 LED_Init(void)”的“GPIO_InitStructure.GPIO_Pin = LED1 | LED2”的“#define LEDPORT GPIOB ”有说明,即为GPIOB的基地址(0x0x40010C00),GPIO端口B在寄存器的起始地址:0x4001 0C00 ~ 0x4001 0FFF。LEDPORT(即 GPIOB)本质上是一个指向地址 0x40010C00 的结构体指针
  • GPIO_Write函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件

1.6 delay_us、delay_ms、delay_s

  • 三个函数,出自delay.c代码文件
  • SysTick的来源,出自CMSIS文件夹下的内核相关的core_cm3.h(内核寄存器定义)- - - ✿ 固体库文件
notion image
notion image
notion image
notion image
 

二、按键控制LED程序

main.c文件代码文件:
notion image
notion image

2.1 KEY_Init(void)

key.c代码文件

GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2

  • 含义:引脚设置为KEY1和KEY2,即第0个和第1个引脚,GPIO_InitStructure.GPIO_Pin = 0x0003
  • KEY1和KEY2出自key.h文件
#define KEY1 PAin(0)#define KEY2 PAin(1)
  • 含义:定义KEY1为PAin(0)【值为0x42210100,代表对IDR寄存器的第0位IDR0进行修改读取的虚拟地址(位段)】,定义KEY2为PAin(1)【值为0x42210104,代表对IDR寄存器的第1位IDR1进行修改读取的虚拟地址(位段)】
  • “位段”出自参考手册第29~30页有定义
notion image
notion image
  • PAin(0或1)出自sys.h文件
GPIOA/B/C/D/E/F/G_BASE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 例子中的PAin(1):
PAin(0):

2.2 GPIO_ReadInputDataBit(KEYPORT,KEY1)

  • GPIO_ReadInputDataBit(KEYPORT,KEY1),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_gpio.c(外设固体库文件- - - ✿ 固体库文件
端口输入数据寄存器(GPIOx_IDR)
  • GPIOx_IDR端口输出数据寄存器在参考手册第114页有定义
notion image
Bit_SET和Bit_RESET
  • BitAction出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件
 

三、FLASH读写程序

main.c文件代码文件:

3.1 FLASH_R和FLASH_W

flash.c代码文件:
notion image
RCC_HSICmd(ENABLE)
  • 含义:打开HSI时钟
  • 参数ENABLE为枚举类型FunctionalState,值为1,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • RCC_HSICmd函数出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
*(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState
  • 含义:由于NewState是ENABLE(1),所以将1写入RCC_CR(时钟控制寄存器)的位0的虚拟地址0x42420000,即将位0(HSION)设置为1;
  • CR_HSION_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
    • notion image
      notion image
  • CR_HSION_BB的值为0x42420000,它的值的计算分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算步骤:(外设RCC的起始地址为0x4002 1000 ~ 0x4002 13FF)
FLASH_Unlock()
  • 含义:解锁FLASH编程擦除控制器
  • FLASH_Unlock函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_ClearFlag(FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR)
  • 含义:清除标志位
  • FLASH_FLAG_BSY|FLASH_FLAG_EOP|FLASH_FLAG_PGERR|FLASH_FLAG_WRPRTERR = 0x00000035【0000 0000 0000 0000 0000 0000 0011 0101】
  • 参数FLASH_FLAG_BSY、FLASH_FLAG_EOP、FLASH_FLAG_PGERR、FLASH_FLAG_WRPRTERR,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_flash.h(外设固体库头文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
FLASH_OBR(选项字节寄存器)
  • FLASH_OBR选项字节寄存器在STM32F10xxx闪存编程手册第18页有定义
notion image
notion image
  • FLASH_ClearFlag函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_ErasePage(add)
  • 含义:擦除指定地址页
  • FLASH_ErasePage函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_CR(闪存控制寄存器)
  • FLASH_CR闪存控制寄存器在STM32F10xxx闪存编程手册第17页有定义
notion image
notion image
notion image
FLASH_AR(闪存地址寄存器)
  • FLASH_AR闪存地址寄存器在STM32F10xxx闪存编程手册第18页有定义
notion image
FLASH_Status status = FLASH_COMPLETE
  • 含义:FLASH的状态为操作成功完成(值为4),即对应FLASH_SR(闪存状态寄存器)的第5位
  • 类型FLASH_Status,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_flash.h(外设固体库头文件- - - ✿ 固体库文件
枚举值
数值
含义(大白话)
手册对应位置
对应硬件标志位
FLASH_BUSY
1
FLASH 正在忙,无法进行新的操作
第 16 页,3.4 节,位 0
FLASH_SR->BSY
FLASH_ERROR_PG
2
编程错误,试图向未擦除的地址写入数据
第 16 页,3.4 节,位 2
FLASH_SR->PGERR
FLASH_ERROR_WRP
3
写保护错误,试图写入被写保护的 FLASH 页
第 16 页,3.4 节,位 4
FLASH_SR->WRPRTERR
FLASH_COMPLETE
4
操作成功完成
第 16 页,3.4 节,位 5
FLASH_SR->EOP
FLASH_TIMEOUT
5
操作超时,这是软件添加的状态,手册中没有
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
assert_param(IS_FLASH_ADDRESS(Page_Address))
  • 含义:检查参数是否合法
  • IS_FLASH_ADDRESS函数,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_flash.h(外设固体库头文件- - - ✿ 固体库文件
芯片类型
FLASH 容量
实际结束地址
是否小于0x080FFFFF
小容量
16K~32K
0x08007FFF
中容量
64K~128K
0x0801FFFF
大容量
256K~512K
0x0807FFFF
互联型 (F105/F107)
128K~256K
0x0803FFFF
XL 密度 (F10x_XL)
1MB
0x080FFFFF
✅(刚好等于)
芯片类型
FLASH 总容量
BANK 数量
BANK1 地址范围
BANK2 地址范围
你的 C8T6 属于哪类
小容量
16K~32K
1 个
0x08000000~0x08007FFF
中容量
64K~128K
1 个
0x08000000~0x0801FFFF
✅(C8T6 是 64K)
大容量
256K~512K
1 个
0x08000000~0x0807FFFF
XL 密度
1MB
2 个
0x08000000~0x0807FFFF(512K)
0x08080000~0x080FFFFF(512K)
status = FLASH_WaitForLastBank1Operation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastBank1Operation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank1Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank1Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
status = FLASH_WaitForLastBank2Operation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastBank2Operation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank2Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank2Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)- - - SR2与之一样,只是名字变了
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
status = FLASH_WaitForLastOperation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastOperation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank1Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank1Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
FLASH_ProgramHalfWord(add,dat)
  • 含义:从指定页的add地址开始写
  • FLASH_ProgramHalfWord函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_CR(闪存控制寄存器)
  • FLASH_CR闪存控制寄存器在STM32F10xxx闪存编程手册第17页有定义
notion image
notion image
notion image
status = FLASH_WaitForLastBank1Operation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastBank1Operation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank1Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank1Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
status = FLASH_WaitForLastBank2Operation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastBank2Operation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank2Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank2Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)- - - SR2与之一样,只是名字变了
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
status = FLASH_WaitForLastOperation(EraseTimeout)
  • 含义:返回当前FLASH的状态
  • FLASH_waitForLastOperation函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
status = FLASH_GetBank1Status()
  • 含义:获取FLASH的状态
  • STM32 的 FLASH 擦除和写入操作,不是 CPU 指令直接完成的,而是由一个叫 FPEC(闪存编程 / 擦除控制器) 的独立硬件模块完成的。整个流程的大白话类比:你(CPU)让一个工人(FPEC)去搬砖(擦除 / 写入 FLASH):
    • 你先告诉工人要搬哪块砖(写地址寄存器)
    • 你喊一声 "开始干活"(写 STRT 位触发操作)
    • 工人开始干活,同时举起一个 "正在忙" 的牌子(硬件自动将 BSY 位置 1)
    • 你不能催他,也不能让他同时干另一个活,只能站在旁边等
    • 工人干完活,放下 "正在忙" 的牌子(硬件自动将 BSY 位清 0)
    • 如果干活过程中出错了,他会举起 "编程错误" 或 "写保护错误" 的牌子(硬件自动置 PGERR/WRPRTERR 位)
    • 如果顺利干完,他会举起 "干完了" 的牌子(硬件自动置 EOP 位)
  • FLASH_GetBank1Status函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_SR(闪存状态寄存器)
  • FLASH_SR闪存状态寄存器在STM32F10xxx闪存编程手册第16~17页有定义
notion image
notion image
notion image
FLASH_Lock()
  • 含义:锁定FLASH编程擦除控制器
  • FLASH_Lock函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_flash.c(外设固体库文件- - - ✿ 固体库文件
FLASH_CR(闪存控制寄存器)
  • FLASH_CR闪存控制寄存器在STM32F10xxx闪存编程手册第17页有定义
notion image
notion image
notion image
 

四、蜂鸣器驱动程序和MIDI音乐播放程序

buzzer.c代码文件:
notion image
notion image
notion image
notion image
buzzer.h代码文件:
main.c部分代码文件:
 

五、USART串口发送程序

main.c代码文件:

5.1 USART1_Init(115200)和USART1_printf("STM32 %d %d ",a,b)

  • usart.h代码文件:
  • USART1_Init函数和USART1_printf函数,出自usart.c文件

半主机模式

notion image

#if 1 #endif

  • 这是一个代码开关:
    • #if 1:开启 printf 重定向,能用 printf 打印到串口
    • #if 0:关闭 printf 重定向,回到默认的半主机模式

#progma import(__use_no_semihosting)

  • 这是给编译器下的命令:"我明确告诉你,不要用半主机模式!所有输入输出我自己处理,你别瞎操心。"如果不写这一行,编译器会默认使用半主机模式,拔了调试器程序就会卡死。

struct __FILE {int handle;};FILE __stdout;

  • 为什么要写?
    • printf是 C 标准库的函数,标准库规定:所有输出都要写到一个叫FILE的 "文件" 里
    • 电脑上的FILE对应屏幕、硬盘文件等
    • 单片机上没有这些东西,但标准库还是要求必须有一个FILE对象
    • 所以我们随便定义一个空的FILE结构体,再定义一个__stdout对象(标准输出)
    • 就像你去银行办业务,银行要求你填一张表,虽然有些空你根本不需要填,但你必须填上 "无",不然不给你办
  • FILE是struct __FILE的别名,struct __FILE是结构体的真名,而定义别名这一步,在stdio.h已经写好了,__stdout不能改

_sys_exit(int x){x = x;}

  • 为什么要写?
    • 标准库的printf函数在某些情况下会调用_sys_exit()(程序退出函数)
    • 电脑上的程序可以退出(比如关闭窗口),但单片机的程序是死循环,永远不会退出
    • 所以我们写一个空的_sys_exit()函数,告诉标准库:"我不需要退出,你调用我也什么都不做"
    • 不写的话,编译器会报 "未定义引用_sys_exit" 的错误
  • “系统异常、程序崩溃、程序要退出” 时准备的函数

int fputc(int ch, FILE *f){while((USART_n->SR&0X40)==0); USART_n->DR = (u8) ch; return ch;}

  • fputc函数的原理:printf函数本身并不直接输出字符,它会把要输出的字符串拆成一个一个的字符,然后每一个字符都调用一次fputc函数来输出。原来的fputc是标准库写的,会把字符输出到电脑屏幕。现在我们重写了这个函数,让它把字符发送到 STM32 的串口上。
while((USART_n->SR&0X40)==0);
  • 大白话:等串口把上一个字符发完。
  • 类比:你用快递柜寄快递,必须等上一个人把柜门关上,你才能打开下一个柜门。USART_n->SR是串口的状态寄存器,0x40(0100 0000)是第 6 位(TC 位,发送完成位)。当 TC 位为 1 时,表示上一个字符已经发送完毕,可以发下一个了。如果不等就直接写,会导致字符丢失。
  • TC位=1(发送完成)- - - 退出循环,TC位=0(正在发送,还没完)- - - 等着
  • USART_n值为0x40013800,出自usart.h
且USART1值为0x40013800,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
notion image
SART_n->DR = (u8) ch;
  • 大白话:把要发送的字符扔给串口,让它发出去。
  • USART_n->DR是串口的数据寄存器,你往里面写一个字符,串口硬件就会自动把它转换成电信号发送出去。

#if EN_USART1或EN_USART2或EN_USART3

  • 表示判断串口1或2或3是使能状态还是禁止状态
  • EN_USART1、EN_USART2、EN_USART3,出自usart.h文件

u8 USART1_RX_BUF[USART1_REC_LEN]或USART2_RX_BUF[USART2_REC_LEN]或USART3_RX_BUF[USART3_REC_LEN]

  • 表示定义串口的接受缓冲区(长度在200字节)
  • USART1_REC_LEN、USART2_REC_LEN、USART3_REC_LEN,出自usart.h文件

u16 USART1_RX_STA=0或USART2_RX_STA=0或USART3_RX_STA=0

  • 表示定义无符号的16位的变量名USART1_RX_STA或USART2_RX_STA或USART3_RX_STA
  • USART1_RX_STA、USART2_RX_STA、USART3_RX_STA出自usart.h文件

va-list arg_ptr

  • va-list来自于#include <stdarg.h> 头文件中
  • 含义:专门找可变参数的指针,指向函数里那些“不确定数量的参数”,就比如USART1_printf(”数字:%d,字符串:%s”,123,”abc”),其中123”abc”就是数量不固定、类型也不固定的参数,所以123”abc”在函数参数中一律按USART1_printf(char *fmt, …)

va_start(arg_ptr, fmt)

  • va_start来自于#include <stdarg.h> 头文件中
  • 含义:指向fmt后面的第一个可变参数(也就是上例中的123),即从fmt这个参后面开始找

while((i < USART1_REC_LEN) && (I < strlen(buffer)))

  • 含义:循环发送草稿纸上的每个字符,直到发完为止
    • i < USART1_REC_LEN:防止超过草稿纸的长度
    • i < strlen(buffer):防止超过buffer的本身长度,即防止发送多余的空字符

vsnprintf(buffer, USART1_REC_LEN+1, fmt, arg_ptr)

  • vsnprintf来自于#include "stdio.h" 头文件中
  • 含义:如上例,把%d、%s这些占位符,替换成真正的参数,拼成完整的字符串
  • 参数
    • buffer:草稿纸,把拼好的字符串存在这里
    • USART1_REC_LEN+1:草稿纸的最大长度,防止写超了(这里的加1代表是为了存字符串结尾的'\0'
    • fmt:格式化字符串(如”数字:%d,字符串:%s”)
    • arg_ptr:指向可变参数的探测器

USART_SendData(USART1, (u8)buffer[i++])

  • 含义:将草稿纸上的第i个字符发给串口1,然后计算器i加1
  • USART_SendData函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
IS_USART_ALL_PERIPH(USARTx)
  • IS_USART_ALL_PERIPH函数,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
IS_USART_DATA(Data)
  • IS_USART_DATA函数,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 为什么是小于等于0x1FF(511)呢?
    • 源于这个数据是要存入数据寄存器(USART_DR)中,且该寄存器用于存数据的位有9位,即DR[8:0]
    • USART_DR数据寄存器在参考手册第541~542页有定义
    • notion image
      notion image

while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)

  • 含义:等串口把这个字符发完,再发下一个不然会丢字符
  • USART_GetFlagStatus函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
  • USART_TypeDef,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • USART_FLAG_TC(发送完成)、USART_FLAG_CTS(CTS标志)、IS_USART_FLAG函数、IS_USART_123_PERIPH函数,都出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件
状态寄存器(USART_SR)
  • USART_SR状态寄存器在参考手册第540~541页有定义
notion image
notion image
notion image
notion image

va_end(arg_ptr)

  • va_end来自于#include <stdarg.h> 头文件中
  • 含义:用完探测器了,把它收起来,即结束可变参数使用

GPIO_InitTypeDef GPIO_InitStructure

  • 含义:创建GPIO_InitTypeDef的变量
  • GPIO_InitTypeDef这个类型,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_gpio.h(外设固体库头文件- - - ✿ 固体库文件

USART_InitTypeDef USART_InitStructure

  • 含义:创建USART_InitTypeDef的变量
  • USART_InitTypeDef这个类型,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

NVIC_InitTypeDef NVIC_InitStructure

  • 含义:创建NVIC_InitTypeDef的变量
  • NVIC_InitTypeDef这个类型,出自Lib文件夹下的inc文件夹下的内核相关的misc.h(跟SVIC和SysTICK相关的函数)- - - ✿ 固体库文件

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0)

  • 含义:全局设置中断优先级分组为 Group_0,在此情况下,优先级无论设置什么,都最终变成0,而子优先级的范围为0~15
  • 参数NVIC_PriorityGroup_0,出自Lib文件夹下的inc文件夹下的内核相关的misc.h(跟SVIC和SysTICK相关的函数)- - - ✿ 固体库文件
分组号
抢占优先级占几位
子优先级占几位
抢占优先级范围
子优先级范围
0
0 位
4 位
只有 0 级
0~15
1
1 位
3 位
0~1
0~7
2
2 位
2 位
0~3
0~3
3
3 位
1 位
0~7
0~1
4
4 位
0 位
0~15
只有 0 级
  • NVIC_PriorityGroupConfig函数,出自Lib文件夹下的src文件夹下的内核相关的misc.c(跟SVIC和SysTICK相关的函数)- - - ✿ 固体库文件
SCB->AIRCR
  • SCB,出自CMSIS文件夹下的内核相关的core_cm3.h(内核寄存器定义)- - - ✿ 固体库文件
notion image
notion image

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn

  • 含义:选择串口1中断通道
  • USART1_IRQn,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
以上来源于参考手册第132~134页有定义
notion image
notion image
notion image
notion image

NVIC_Init(&NVIC_InitStructure)

  • NVIC_Init函数,出自Lib文件夹下的src文件夹下的内核相关的misc.c(跟SVIC和SysTICK相关的函数)- - - ✿ 固体库文件
  • 示例:
    • notion image
  • IS_FUNCTIONAL_STATE函数,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • IS_NVIC_PREEMPTION_PRIORITY函数、IS_NVIC_SUB_PRIORITY函数,都出自Lib文件夹下的inc文件夹下的内核相关的misc.h(跟SVIC和SysTICK相关的函数)- - - ✿ 固体库文件
SCB->AIRCR
  • SCB,出自CMSIS文件夹下的内核相关的core_cm3.h(内核寄存器定义)- - - ✿ 固体库文件
notion image
notion image
NVIC->IP、NVIC->ISER、NVIC->ICER
  • NVIC,出自CMSIS文件夹下的内核相关的core_cm3.h(内核寄存器定义)- - - ✿ 固体库文件
RESERVED的作用和计算
  • 作用
    • RESERVED(保留区)是ARM官方规定的内存填充机制,目的是让NVIC_Type结构体的每个成员偏移地址,与Cortex-M3内核手册中定义的NVIC寄存器物理地址完全一一对应
      Cortex-M3内核的NVIC寄存器是稀疏分布的(寄存器之间有大量未使用的地址空间),如果没有这些保留区,结构体成员会自动连续排列,导致后续寄存器的偏移地址全部错位,无法正确访问硬件。
  • 每个RESERVED大小的精确计算
    • 所有计算基于结构体基地址0xE000E100,偏移地址均相对于该基地址。
    • uint32_t类型占4字节
    • uint8_t类型占1字节
    • (1)RESERVED0[24]
    • ISER[8]总大小:8 × 4 = 32字节,占用地址0x000 ~ 0x01F
    • 下一个寄存器ICER的起始偏移是0x080
    • 中间空白地址范围:0x020 ~ 0x07F,总字节数:0x080 - 0x020 = 0x60 = 96字节
    • 保留区元素个数:96 ÷ 4 = 24 → 即RESERVED0[24]
    • (2) RESERVED1[24]
    • ICER[8]总大小:32字节,占用地址0x080 ~ 0x09F
    • 下一个寄存器ISPR起始偏移:0x100
    • 空白地址:0x0A0 ~ 0x0FF,共96字节
    • 保留区元素个数:96 ÷ 4 = 24RESERVED1[24]
    • (3) RESERVED2[24]
    • 计算逻辑同上,空白地址0x120 ~ 0x17F共96字节
    • 保留区元素个数:24 → RESERVED2[24]
    • (4) RESERVED3[24]
    • 空白地址0x1A0 ~ 0x1FF共96字节
    • 保留区元素个数:24 → RESERVED3[24]
    • (5) RESERVED4[56]
    • IABR[8]总大小:32字节,占用地址0x200 ~ 0x21F
    • 下一个寄存器IP起始偏移:0x300
    • 空白地址:0x220 ~ 0x2FF,总字节数:0x300 - 0x220 = 0xE0 = 224字节
    • 保留区元素个数:224 ÷ 4 = 56RESERVED4[56]
    • (6) RESERVED5[644]
    • IP[240]总大小:240 × 1 = 240字节,占用地址0x300 ~ 0x3EF
    • 下一个寄存器STIR起始偏移:0xE00
    • 空白地址:0x3F0 ~ 0xDFF,总字节数:0xE00 - 0x3F0 = 0xA10 = 2576字节
    • 保留区元素个数:2576 ÷ 4 = 644RESERVED5[644]
内核版本
发布时间
实现的优先级位数
代表芯片
Cortex-M3 r0p0
2005 年
3 位
非常早期的原型芯片,市面上几乎没有
Cortex-M3 r1p0
2006 年
3 位
极少数早期的 STM32F101 芯片
Cortex-M3 r2p0 及以上
2007 年以后
4 位
所有你能买到的 STM32F103/F105/F107 芯片
NVIC的IP寄存器解释 1 ,可参考《pm0056-stm32f10xxx-and-stm32f20xxx-cortexm3-programming-manual-stmicroelectronics》的第125页
notion image
翻译为:
notion image
notion image
notion image
NVIC的IP寄存器解释 2 ,可参考《ARM Cortex-M3权威指南 第2版_13598339》的第122~123页
notion image
notion image
NVIC(基地址:0xE000E100)的所有相关寄存器解释【ISER:0xE000E100、ICER:0xE000E180、ISPR:0xE000E200、ICPR:0xE000E280、IABR:0xE000E300、IP:0xE000E400、STIP:0xE000EF00】,可参考《Cortex_M3权威指南(中文)》的第303、304、313页
notion image
notion image
notion image
notion image
notion image

USART_InitStructure.USART_WordLength = USART_WordLength_8b

  • 含义:数据位长度(8位 或 9位),设为8位数据位长度
  • 参数USART_WordLength_8b,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

USART_InitStructure.USART_StopBits = USART_StopBits_1

  • 含义:停止位(1位 或 2位),用来表示一帧数据结束了,设为1位停止位
  • 参数USART_StopBits_1,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

USART_InitStructure.USART_Parity = USART_Parity_No

  • 含义:校验位(奇校验、偶校验、无校验),用来检查数据传输出错没,设为无校验
  • 参数USART_Parity_No,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None

  • 含义:硬件流控制CTS/RTS(用来防止发送太快导致数据丢失),设为无硬件流控
  • 参数USART_HardwareFlowControl_None,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx

  • 含义:模式选择(使能发送(Tx) / 使能接收(Rx) / 都使能),设为收发都开
  • 参数USART_Mode_Rx、USART_Mode_Tx,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件

USART_Init(USART1, &USART_InitStructure)

  • 含义:初始化串口
  • USART_Init函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
RCC_ClocksTypeDef RCC_ClocksStatus
  • 创建了RCC_ClocksTypeDef类型的变量,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
IS_USART_BAUDRATE(USART_InitStruct->USART_BaudRate)
  • 函数IS_USART_BAUDRATE,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件
控制寄存器2(USART_CR2)
  • USART_CR2控制寄存器2在参考手册第544~545页有定义
notion image
notion image
控制寄存器1(USART_CR1)
  • USART_CR1控制寄存器1在参考手册第542~544页有定义
notion image
notion image
notion image
notion image
控制寄存器3(USART_CR3)
  • USART_CR3控制寄存器3在参考手册第545~546页有定义
notion image
notion image
RCC_GetClocksFreq(&RCC_ClocksStatus)
  • RCC_GetClocksFreq函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
tmp = RCC->CFGR & CFGR_SWS_Mask
  • CFGR_SWS_Mask的值为((uint32_t)0x0000000C),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
RCC_Clocks->SYSCLK_Frequency = HSI_VALUE
  • 含义:将SYSCLK 系统主时钟频率设为HSI(内部高速)
  • RCC_Clocks->SYSCLK_Frequency:SYSCLK 系统主时钟频率
  • HSI_VALUE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
RCC_Clocks->SYSCLK_Frequency = HSE_VALUE
  • 含义:将SYSCLK 系统主时钟频率设为HSE(外部高速)
  • RCC_Clocks->SYSCLK_Frequency:SYSCLK 系统主时钟频率
  • HSE_VALUE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
pllmull = RCC->CFGR & CFGR_PLLMull_Mask和pllsource = RCC->CFGR & CFGR_PLLSRC_Mask
  • 含义:前者:读取PLL倍频系数(CFGR寄存器的PLLMULL[21:18]位);后者:读取PLL时钟源选择(CFGR寄存器的PLLSRC[16]位)
RCC_CFGR(时钟配置寄存器,非互联网型)
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
RCC_CFGR(时钟配置寄存器,互联网型)
  • RCC_CFGR时钟配置寄存器在参考手册第86~88页有定义
notion image
notion image
notion image
notion image
prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1和RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull
  • 属于超值型范畴
  • 含义:前者:读取CFGR2寄存器的0~3位,然后在此基础上加上1,最后赋值给prediv1factor。后者:将HSE_VALUE(8000000)除以prediv1factor,得出的值乘以之前“pllmull = (pllmull >> 18) + 2;”处理的倍频系数值,最后写回到RCC_Clocks对象的SYSCLK系统主时钟频率中。
  • CFGR2_PREDIV1,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
RCC->CFGR & CFGR_PLLXTPRE_Mask
  • 含义:读取CFGR寄存器的第17位PLLXTPRE(HSE分频器作为PLL输入)
RCC_CFGR(时钟配置寄存器)
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
prediv1source = RCC->CFGR2 & CFGR2_PREDIV1SRC
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第16位,赋值给prediv1source
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
prediv2factor = ((RCC->CFGR2 & CFGR2_PREDIV2) >> 4) + 1
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第4~7位,然后右移4位,变成原本第4~7位移到了第0~3位,之后加上1,赋值给prediv2factor
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
pll2mull = ((RCC->CFGR2 & CFGR2_PLL2MUL) >> 8 ) + 2
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第8~11位,然后右移8位,变成原本第8~11位移到了第0~3位,之后加上2,赋值给pll2mull
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
usartxbase == USART1_BASE
  • USART1_BASE值为0x40013800,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
 
配置BRR寄存器(波特率寄存器)的第三步到第六步的解释
  • 上面的代码如下:
  • 解释OVER8这一位
    • 因为芯片为STM32F103C8T6,所以是普通型,因此在参考手册中USART_CR1(控制寄存器1)的第14、15位是保留位,硬件强制为0。
    • 而互联网型,则存在第15位为0VER8,值0默认为16倍过采样,1为8倍过采样
    • 而上面的代码,本身是STM32F10系列的固件库文件,所以在一定程度上是兼容所有的STM32F10系列的芯片(包含普通型、互联网型等),因此代码并没有直接显示没有OVER8这一位
    • 普通型是默认16倍过采样,而互联网型则看第15位的值情况
    • 普通型参考手册上的依据
      notion image
      notion image
      notion image
      notion image
过采样的解释
过采样模式
BRR 寄存器位分配
小数部分位数
每一位的权重
小数部分最大值
16 倍(OVER8=0)
高 12 位:整数部分低 4 位(bit3~bit0):小数部分
4 位
1/16
15/16=0.9375
8 倍(OVER8=1)
高 12 位:整数部分低 3 位(bit2~bit0):小数部分bit3:保留位(必须写 0)
3 位
1/8
7/8=0.875
  • 过采样率本质是串口接收端对每个数据比特位的采样次数,直接决定波特率上限、BRR 寄存器计算方式和通信抗干扰能力。
核心公式与BRR位分配对比
  • STM32F103串口波特率由USARTDIV(串口分频系数)决定,公式和BRR寄存器位分配随OVER8位变化:
    • 过采样率
      OVER8位值
      波特率计算公式
      BRR寄存器位分配
      最大波特率(72MHz时钟)
      16倍(默认)
      0
      波特率 = 72000000 / (16 × USARTDIV)
      整数部分:bit4~bit15<br>小数部分:bit0~bit3(4位,0~15)
      4.5Mbps
      8倍
      1
      波特率 = 72000000 / (8 × USARTDIV)
      整数部分:bit4~bit15<br>小数部分:bit0~bit2(3位,0~7)<br>bit3必须强制置0
      9Mbps
115200波特率的实际计算(72MHz时钟)
  • 16倍过采样(默认,最常用)
    • 整数部分:39 → 二进制 100111
    • 小数部分:0.0625 × 16 = 1 → 二进制 0001
    • BRR寄存器值:0x0271(39<<4 + 1 = 624 + 1 = 625)
    • 实际波特率:72000000/(16×39.0625) = 115200 → 误差0%
  • 8倍过采样
    • 整数部分:78 → 二进制 1001110
    • 小数部分:0.125 × 8 = 1 → 二进制 001
    • BRR寄存器值:0x04E1(78<<4 + 1 = 1248 + 1 = 1249)
      • 注意:bit3必须置0,这里小数部分只有3位,所以直接加1即可
    • 实际波特率:72000000/(8×78.125) = 115200 → 误差0%
关键差异与适用场景
特性
16倍过采样(默认)
8倍过采样
抗干扰能力
强(采样点多,能过滤毛刺)
稍弱(采样点少,对线路质量要求高)
波特率上限
低(72MHz下4.5Mbps)
高(72MHz下9Mbps)
波特率误差
通常更小(小数精度4位)
稍大(小数精度3位)
适用场景
绝大多数常规串口通信(115200及以下)
高速串口通信(1Mbps以上)
大白话解释
notion image
notion image
notion image
notion image
notion image
notion image
假设情况:芯片STM32F103C8T6,USART1挂载在APB2总线(72MHz),波特率为115200,那么OVER8默认为16倍过采样(该位值为0)
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
波特比率寄存器(USART_BRR)
  • USART_BRR波特比率寄存器在参考手册第542页有定义
notion image

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)

  • 含义:操作串口控制寄存器,开启对应中断位
  • 这行代码是 STM32 串口「自动接收数据」的总开关
    • 开启它,串口每收到 1 个字节,就会自动通知 CPU,并自动执行接收处理函数;
      不开启它,串口只能被动等待程序手动查询,无法实现中断接收。
  • 第一个参数:USART1值为0x40013800,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • 第二个参数:USART_IT_RXNE值为0x0525【0000 0101 0010 0101】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_usart.h(外设固体库头文件- - - ✿ 固体库文件
控制寄存器1(USART_CR1)
  • USART_CR1控制寄存器1在参考手册第542~544页有定义
notion image
notion image
控制寄存器2(USART_CR2)
  • USART_CR2控制寄存器2在参考手册第544~545页有定义
notion image
notion image
控制寄存器3(USART_CR3)
  • USART_CR3控制寄存器3在参考手册第545~546页有定义
notion image
notion image
notion image
  • 第三个参数ENABLE值为1
  • 函数USART_ITConfig,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件

USART_Cmd(USART1, ENABLE)

  • USART_Cmd函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
控制寄存器1(USART_CR1)
  • USART_CR1控制寄存器1在参考手册第542~544页有定义
notion image
notion image

USART_GetITStatus(USART1, USART_IT_RXNE) != RESET

  • 含义:判断CR1寄存器第五位RXNEIE(接受缓冲区非空中断使能)是否成功设置,若成功设置,则该行代码为true
  • USART_GetITStatus函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件

Res =USART_ReceiveData(USART1)

  • 含义:读取接收到的数据
  • USART_ReceiveData函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
USART_DR(数据寄存器)
  • USART_DR数据寄存器1在参考手册第541~542页有定义
notion image
notion image

USART1_IRQHandler函数的模拟过程

  • 初始状态
    • USART1_RX_STA = 0(空白记录本,没收完、没收回车、收 0 个字节)
    • USART1_RX_BUF 空数组
    • 仓库最大容量 USART1_REC_LEN=200
  • 场景:你在串口助手发 ab + 按回车键(Enter)
    • 电脑发送顺序:ab0x0D(回车) → 0x0A(换行)
    • 第 1 步:收到字节 a
      • Res = 'a'
      • printf 回显a,串口助手显示a
      • 没收完、没收回车 → 把a存进USART1_RX_BUF[0]
      • 字节数 + 1 → USART1_RX_STA = 1
    • 第 2 步:收到字节 b
      • Res = 'b'
      • 回显b,串口助手显示ab
      • 存进USART1_RX_BUF[1]
      • 字节数 + 1 → USART1_RX_STA = 2
    • 第 3 步:收到字节 0x0D(回车)
      • Res = 0x0D
      • 回显回车,串口助手换行
      • 标记收到回车 → USART1_RX_STA |= 0x4000 → 现在STA=0x4002
      • 字节数不增加
    • 第 4 步:收到字节 0x0A(换行)
      • Res = 0x0A
      • 回显换行
      • 已经收到过回车,现在收到换行 → 标记接收完成
      • USART1_RX_STA |= 0x8000 → 最终STA=0xC002
        • bit15=1(收完了)
        • bit14=1(收到回车)
        • 低 14 位 = 2(收了 2 个字节:ab)

USART的各个参数含义

  • 波特率(USART_BaudRate)
    • 是什么?
      • 串口通信的「语速」
      • 单位:bit/s(比特每秒),常见值:9600 / 115200
    • 作用
      • 决定数据传输的快慢
      • 之前算的 BRR 寄存器分频值,就是根据这个数计算出来的
      • 核心要求:STM32 和 电脑串口助手的波特率必须一模一样!
    • 对串口的影响
      • 波特率不一致 → 直接乱码 / 收不到任何数据
      • 115200 比 9600 速度快很多(调试首选 115200)
  • 字长(USART_WordLength)
    • 代码固定:USART_WordLength_8b(8 位字长)
    • 是什么?
      • 每个数据的「长度」,也就是:发一个字符用多少位二进制
    • 作用
      • 我们用的字母 / 数字 / 符号,都是 8 位二进制(ASCII 码)
      • 8 位 = 标准通用长度,对应 a~z0~9、符号
    • 对串口的影响
      • 99% 的串口通信都用 8 位
      • 9 位字长仅用于带硬件校验的特殊场景,我们完全用不到
  • 停止位(USART_StopBits)
    • 代码固定:USART_StopBits_1(1 位停止位)
    • 生活比喻
      • 一句话结尾的「句号」
    • 是什么?
      • 发送完一个字符后,额外发的结束标记位,告诉接收方:这个字符传完了!准备接收下一个!
    • 作用
      • 让 STM32 和 电脑同步信号,避免数据粘连
      • 通用标准:1 位停止位
    • 对串口的影响
      • 停止位不一致 → 数据接收错误、乱码
  • 校验位(USART_Parity)
    • 代码固定:USART_Parity_No(无校验)
    • 生活比喻
      • 数据的「防伪校验码」
    • 是什么?
      • 额外加一位,检查数据在传输过程中有没有被干扰出错
      • 奇校验:数据中 1 的个数凑成奇数
      • 偶校验:数据中 1 的个数凑成偶数
    • 作用
      • 简单的错误检测,普通串口通信完全不需要(现在传输线很稳定,几乎不会出错)
    • 对串口的影响
      • 我们默认无校验,最简单、最通用
      • 开校验会多占用 1 位,降低传输效率
  • 硬件流控(USART_HardwareFlowControl)
    • 代码固定:USART_HardwareFlowControl_None(无硬件流控)
    • 生活比喻
      • 收发数据的「红绿灯」
    • 是什么?
      • 用额外的硬件引脚(CTS/RTS)控制:我忙不过来了,你先别发!
    • 作用
      • 防止数据太多、接收不过来导致溢出
    • 对串口的影响
      • 普通串口通信(连电脑)完全不用,只有蓝牙、WiFi 等高速模块才会用到
      • 关闭(NONE)是标准配置
  • 收发模式(USART_Mode)
    • 代码固定:USART_Mode_Rx | USART_Mode_Tx
    • 是什么?
      • Tx = Transmit 发送
      • Rx = Receive 接收
    • 作用
      • 开启串口的发送功能(STM32 发数据给电脑)
      • 开启串口的接收功能(电脑发数据给 STM32)
    • 对串口的影响
      • 只开 Tx:只能发,不能收
      • 只开 Rx:只能收,不能发
      • 我们两个都开:全双工通信(同时收发)

5.2 USART_SendData(USART1,0x55)

  • USART_SendData函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_usart.c(外设固体库文件- - - ✿ 固体库文件
USART_DR(数据寄存器)
  • USART_DR数据寄存器1在参考手册第541~542页有定义
notion image
notion image

六、LED灯显示RTC走时程序

main.c代码文件:
notion image
rtc.h代码文件:
rtc.c代码文件:

6.1 RTC_First_Config(void)

函数完整流程解析(含顺序逻辑、设计原因、依赖关系)
notion image
notion image
notion image
notion image
notion image
notion image
notion image
什么叫「仅备份域掉电才执行一次,主芯片复位不重复执行」
notion image
notion image
这个初始化流程是怎么想出来的?设计思路是什么?
notion image
notion image
notion image
notion image

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE)

  • 含义:对APB1外设时钟使能寄存器(RCC_APB1ENR)上的第28位PWREN(电源接口时钟使能)和第27位BKPEN(备份接口时钟使能)进行开启操作
  • 第一个参数为外设的相关变量RCC_APB1Periph_PWR【值:0x10000000,二进制:0001 0000 0000 0000 0000 0000 0000 0000 】、RCC_APB1Periph_BKP值:0x08000000,二进制:0000 1000 0000 0000 0000 0000 0000 0000 】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_APB1ENR(APB1外设时钟使能寄存器)
  • APB1外设时钟使能寄存器RCC_APB1ENR在参考手册第71~73页有定义,英文版第115~117页有定义(其中CAN2(第26位)和CEC(第30位),参考手册和英文版都没有找到对应定义处)
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
 
 

PWR_BackupAccessCmd(ENABLE)

  • 含义:主要是对电源控制寄存器(PWR_CR)的第8位DBP(取消后备区域的写保护)设置为1(允许写入RTC和后备寄存器)
  • PWR_BackupAccessCmd函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_pwr.c(外设固体库文件- - - ✿ 固体库文件
*(__IO uint32_t *) CR_DBP_BB = (uint32_t)NewState
  • 外设PWR(电源控制)的起始地址:0x40007000~0x400073FF
  • 含义:对电源控制寄存器(PWR_CR)的第8位DBP(取消后备区域的写保护)设置为1(允许写入RTC和后备寄存器)
  • CR_DBP_BB(值为0x420E0020【0100 0010 0000 1110 0000 0000 0010 0000】)的计算过程涉及的值,分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_pwr.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算过程:
CR_DBP_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
notion image
notion image
PWR_CR(电源控制寄存器)
  • PWR_CR电源控制寄存器在参考手册第44页有定义
notion image
notion image

BKP_DeInit( )

  • 含义:备份域寄存器复位
  • BKP_DeInit函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
为什么要先设置ENABLE,然后在设置DISABLE?目的?
notion image
notion image
notion image
notion image
  • RCC_BackupResetCmd(ENABLE或DISABLE),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
BDCR_BDRST_BB
  • RCC(复位和时钟控制)的起始地址:0x40021000~0x400213FF
  • BDCR_BDRST_BB(值为0x42451180【0100 0010 0100 0101 0001 0001 1000 0000】)的计算过程涉及的值,分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算过程:
BDCR_BDRST_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
notion image
notion image
RCC_BDCR(备份域控制寄存器)
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image

RCC_LSEConfig(RCC_LSE_ON)

  • 含义:将RCC_BDCR备份域控制寄存器的第0位LSEON的值1(外部32kHz振荡器开启)
  • 参数RCC_LSE_ON,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
  • RCC_LSEConfig函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
BDCR_ADDRESS
  • RCC(复位和时钟控制)的起始地址:0x40021000~0x400213FF
  • BDCR_ADDRESS(值为0x40021020【0100 0000 0000 0010 0001 0000 0010 0000】,表示RCC基地址的基础上偏移0x20,即RCC_BDCR(备份域控制寄存器))的计算过程涉及的值,分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算过程:
RCC_BDCR(备份域控制寄存器)
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image
notion image

while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)

  • 含义:判断RCC_BDCR(备份域控制寄存器)的第1位LSERDY(外部低速LSE就绪)是否为0,若等于0,则循环继续;否则结束
  • 参数RCC_FLAG_LSERDY的值为((uint8_t)0x41),出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CR(时钟控制寄存器)- - - 与参数有关
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
notion image
notion image
notion image
RCC_BDCR(备份域控制寄存器)- - - 与参数有关
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image
RCC_CSR(控制/状态寄存器)- - - 与参数有关
  • RCC_CSR控制/状态寄存器在参考手册第75~76页有定义
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image

RCC_GetFlagStatus(RCC_FLAG_LSERDY)

  • 含义:看RCC_BDCR(备份域控制寄存器)的第1位LSERDY(外部低速LSE就绪)是否为1,即看外部32kHz振荡器是否就绪
  • 出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件

RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE)

  • 含义:将RCC_BDCR(备份域控制寄存器)的第8~9位RTCSEL[1:0](RTC时钟源选择)设置值01(LSE振荡器作为RTC时钟)
  • 参数RCC_RTCCLKSource_LSE的值为0x00000100,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
  • RCC_RTCCLKConfig函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_BDCR(备份域控制寄存器)
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image

RCC_RTCCLKCmd(ENABLE)

  • 含义:将RCC_BDCR(备份域控制寄存器)的第15位RTCEN(RTC时钟使能)设为1(RTC时钟开启)
  • RCC_RTCCLKCmd函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
BDCR_RTCEN_BB
  • 含义:代表RCC_BDCR(备份域控制寄存器)的第15位RTCEN(RTC时钟使能)的位带地址
  • RCC(复位和时钟控制)的起始地址:0x40021000~0x400213FF
  • BDCR_RTCEN_BB(值为0x4245117C【0100 0010 0100 0101 0001 0001 0111 1100】)的计算过程涉及的值,分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算过程:
BDCR_RTCEN_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
notion image
notion image
RCC_BDCR(备份域控制寄存器)
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image

RTC_WaitForSynchro()

  • 含义:先对RTC_CRL(RTC控制寄存器低位)的第3位RSF(寄存器同步标志)进行清零,然后等待RTC核心寄存器与APB1总线时钟完成同步,即硬件会将第3位RSF(寄存器同步标志)置为1
  • RTC_WaitForSynchro函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_FLAG_RSF
  • 含义:代表RTC_CRL(RTC控制寄存器低位)的第3位RSF(寄存器同步标志)
  • RTC_FLAG_RSF的值为:0x0008【0000 0000 0000 1000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rtc.h(外设固体库头文件- - - ✿ 固体库文件
 
RTC_CRL(RTC控制寄存器低位)
  • RTC_CRLRTC控制寄存器低位在参考手册第311~312页有定义
notion image
notion image
notion image
notion image

RTC_WaitForLastTask()

  • 含义:等待上一次对RTC寄存器的写操作已经完成,即硬件会将RTC_CRL(RTC控制寄存器低位)的第5位RTOFF(RTC操作关闭)置为1
  • RTC_WaitForLastTask函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_FLAG_RTOFF
  • 含义:代表RTC_CRL(RTC控制寄存器低位)的第5位RTOFF(RTC操作关闭)
  • RTC_FLAG_RTOFF的值为:0x0020【0000 0000 0010 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rtc.h(外设固体库头文件- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image
notion image
notion image

RTC_SetPrescaler(32767)

  • 含义:把32767的值写入PRL寄存器中,目的是把高频的 32.768kHz 时钟,分频降频成 1Hz 的秒脉冲,给 RTC 计数器使用
  • RTC_SetPrescaler函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
IS_RTC_PRESCALER(PrescalerValue)
  • IS_RTC_PRESCALER函数,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rtc.h(外设固体库头文件- - - ✿ 固体库文件
RTC_EnterConfigMode()
  • 含义:将RTC_CRL(RTC控制寄存器低位)的第4位CNF(配置标志)设为1(进入配置模式)
  • RTC_EnterConfigMode函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRL_CNF
  • 出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image
notion image
notion image
RTC->PRLH = (PrescalerValue & PRLH_MSB_MASK) >> 16
  • 含义:将RTC_PRLH(RTC预分频装载寄存器高位)的第0~15位设置为0x0000
  • PRLH_MSB_MASK的值为0x000F0000【0000 0000 0000 1111 0000 0000 0000 0000】
  • (PrescalerValue & PRLH_MSB_MASK):在示例中,PrescalerValue为32767(0x7FFF【0111 1111 1111 1111】),那么(PrescalerValue & PRLH_MSB_MASK)的值为0x00000000
  • (PrescalerValue & PRLH_MSB_MASK) >> 16 的值为0x00000000
RTC_PRLH(RTC预分频装载寄存器高位)
  • RTC预分频装载寄存器高位RTC_PRLH在参考手册第312~313页有定义
notion image
notion image
RTC->PRLL = (PrescalerValue & RTC_LSB_MASK)
  • 含义:将RTC_PRLL(RTC预分频装载寄存器低位)的第0~15位设置为0x7FFF
  • RTC_LSB_MASK的值为0x0000FFFF【0000 0000 0000 0000 1111 1111 1111 1111】
  • (PrescalerValue & RTC_LSB_MASK):在示例中,PrescalerValue为32767(0x7FFF【0111 1111 1111 1111】),那么(PrescalerValue & RTC_LSB_MASK)的值为0x00007FFF
RTC_PRLL(RTC预分频装载寄存器低位)
  • RTC预分频装载寄存器高位RTC_PRLH在参考手册第313页有定义
notion image
RTC_ExitConfigMode()
  • 含义:将RTC_CRL(RTC控制寄存器低位)的第4位CNF(配置标志)设为0(退出配置模式(开始更新RTC寄存器))
  • RTC_EnterConfigMode函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRL_CNF
  • 出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image
notion image
notion image
★ ※ 什么是 RTC 预分频?预分频装载是什么?
notion image
★ ※ 参考手册中寄存器RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)的解释
notion image
notion image
notion image
★ ※ 为什么这么设计?(设计原因深度解析)
notion image
notion image
★ ※ 为什么要设置成 32767?(公式推导)
notion image

RTC_ITConfig(RTC_IT_SEC, ENABLE)

  • 含义:将RTC_CRH(RTC控制寄存器高位)的第0位SECIE(允许秒中断)设置为1(允许秒中断)
  • 第一个参数RTC_IT_SEC的值为0x0001,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
宏定义
十六进制值
对应 CRH 寄存器位
位名称
功能说明
RTC_IT_OW
0x0004
位 2
OWIE
溢出中断使能:1 = 开启溢出中断,0 = 屏蔽
RTC_IT_ALR
0x0002
位 1
ALRIE
闹钟中断使能:1 = 开启闹钟中断,0 = 屏蔽
RTC_IT_SEC
0x0001
位 0
SECIE
秒中断使能:1 = 开启秒中断,0 = 屏蔽
  • RTC_ITConfig函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRH(RTC控制寄存器高位)
  • RTC控制寄存器高位RTC_CRH在参考手册第311页有定义
notion image

6.2 RTC_Config(void)

NRST 是什么
notion image
为什么要写RTC_Config 函数
notion image
函数整体流程框架
逐段拆解:每一步为什么这么设计?寄存器有什么关联?
notion image
notion image
notion image
notion image
notion image
notion image
从零开始:怎么一步步想出这个设计流程?
notion image
notion image
所有寄存器操作的依赖关系
notion image
重新使能RTC(之前错误解释,现在重新解释)
notion image
notion image
notion image
时钟使能
所在寄存器
所属电源域
电源复位(VDD 掉电 / 上电)的影响
RTC 内核时钟使能(RTCEN 位)
RCC_BDCR 第 15 位
备份域(VBAT 供电)
完全无影响,不会清零。只要纽扣电池有电,RTCEN 位一直保持 1,RTC 内核全程计时不中断
RTC/BKP 寄存器访问接口时钟(BKPEN 位)
RCC_APB1ENR 第 18 位
主电源域(VDD 供电)
一定会清零。复位后 CPU 要读写 RTC、BKP 的寄存器,必须重新开启这个接口时钟
notion image
notion image

BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5

  • 含义:从0x40006C04地址读出的备份数据寄存器x(BKP_DRx)的值不等于0xA5A5,则为true;否则为false
  • 参数BKP_DR1的值为0x0004【0000 0000 0000 0100】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_bkp.h(外设固体库头文件- - - ✿ 固体库文件
  • BKP_ReadBackupRegister函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
BKP_BASE
  • 后备寄存器(BKP)的起始地址:0x4000 6C00 ~ 0x4000 6FFF
  • BKP_BASE的值为0x40006C00,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
备份数据寄存器x(BKP_DRx)
  • BKP_DRx备份数据寄存器x在参考手册第48页有定义
notion image

BKP_WriteBackupRegister(BKP_DR1, 0xA5A5)

  • 含义:将0xA5A5的值写入到地址为0x40006C04的备份数据寄存器x(BKP_DRx)
  • 第一个参数BKP_DR1的值为0x0004【0000 0000 0000 0100】(上一个有说明)
  • BKP_WriteBackupRegister函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
备份数据寄存器x(BKP_DRx)
  • BKP_DRx备份数据寄存器x在参考手册第48页有定义
notion image

RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET 和 RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET

  • 含义:
    • 前者:看RCC_CSR(控制/状态寄存器)的第27位PORRSFT(上电/掉电复位标志)是否发生上电/掉电复位,若发生,则该位的值为1,则代码为true;否则值为0,代码为false。
    • 后者:看RCC_CSR(控制/状态寄存器)的第26位PINRSTF(NRST引脚复位标志)是否发生NRST引脚复位,若发生,则该位的值为1,则代码为true;否则值为0,代码为false。
  • 参数RCC_FLAG_PORRST的值为((uint8_t)0x7B)、RCC_FLAG_PINRST的值为((uint8_t)0x7A),出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_CR(时钟控制寄存器)- - - 与参数有关
  • RCC_CR时钟控制寄存器在参考手册第60~61页有定义
notion image
notion image
notion image
notion image
RCC_BDCR(备份域控制寄存器)- - - 与参数有关
  • RCC_BDCR备份域控制寄存器在参考手册第74页有定义
notion image
notion image
RCC_CSR(控制/状态寄存器)- - - 与参数有关
  • RCC_CSR控制/状态寄存器在参考手册第75~76页有定义
notion image
notion image
notion image
notion image
notion image
notion image
notion image
notion image
RCC_GetFlagStatus(RCC_FLAG_PORRST) 和 RCC_GetFlagStatus(RCC_FLAG_PINRST)
  • 整体作用
    • 前者:看是否有上电/掉电复位
    • 后者:看是否有NRST引脚复位
  • 出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件

RCC_ClearFlag( )

  • 含义:对RCC_CSR(控制/状态寄存器)的第24位RMVF(清除复位标志)置为1(清除复位标志),导致硬件自动清零全部复位标志
  • RCC_ClearFlag函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CSR(控制/状态寄存器)
  • RCC_CSR控制/状态寄存器在参考手册第75~76页有定义
notion image
notion image

BKP_TamperPinCmd(DISABLE)

  • 含义:对备份控制寄存器(BKP_CR)的第0位TPE(启动侵入检测TAMPER引脚)设置为0(侵入检测TAMPER引脚作为通用IO口使用)
Tamper 是什么意思?
notion image
Tamper 侵入检测功能是什么?侵入代表什么?(形象举例)
notion image
  • BKP_TamperPinCmd函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
*(__IO uint32_t *) CR_TPE_BB = (uint32_t)NewState
  • 外设BKP(后备寄存器)的起始地址:0x4000 6C00 ~ 0x4000 6FFF
  • 含义:对备份控制寄存器(BKP_CR)的第0位TPE(启动侵入检测TAMPER引脚)设置为0(侵入检测TAMPER引脚作为通用IO口使用)
  • CR_TPE_BB(值为0x420D8600【0100 0010 0000 1101 1000 0110 0000 0000】)的计算过程涉及的值,分别出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
计算过程:
CR_TPE_BB涉及到“位段”的知识点,“位段”出自参考手册第29~30页有定义
notion image
notion image
BKP_CR(备份控制寄存器)
  • BKP_CR备份控制寄存器在参考手册第49页有定义
notion image

BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock)

  • 含义:将BKP_RTCCR(RTC时钟校准寄存器)的第7位CCO(校准时钟输出)设置为1(此位置1可以在侵入检测引脚输出经64分频后的RTC时钟。当CCO位置1时,必须关闭侵入检测功能以避免检测到无用的侵入信号)
  • 参数BKP_RTCOutputSource_CalibClock的值为0x0080【0000 0000 1000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_bkp.h(外设固体库头文件- - - ✿ 固体库文件
寄存器位
位序号
对应功能模式
硬件功能说明
ASOS
位 9
闹钟 / 秒输出选择
仅 ASOE 置 1 时生效:0 = Tamper 引脚输出 RTC 闹钟脉冲1 = Tamper 引脚输出 RTC 秒脉冲
ASOE
位 8
闹钟 / 秒输出使能
总开关:置 1 后允许 RTC 闹钟 / 秒脉冲输出到 Tamper 引脚
CCO
位 7
校准时钟输出使能
置 1 后,Tamper 引脚输出经 64 分频后的 RTC 时钟,用于时钟校准
  • BKP_RTCOutputConfig函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_bkp.c(外设固体库文件- - - ✿ 固体库文件
BKP_RTCCR(RTC时钟校准寄存器)
  • RTC时钟校准寄存器BKP_RTCCR在参考手册第48~49页有定义
notion image
notion image
BKP_RTCCR 寄存器每一位的含义(大白话 + 举例)
notion image
notion image
 
BKP_RTCCR 每个位之间的关联和上一个图片末尾的CAL的举例计算说明
notion image
notion image
notion image
notion image
notion image
notion image

6.3 RTC_IRQHandler(void)

函数整体定位与核心目的
notion image
逐行流程拆解 + 设计逻辑(为什么是这个顺序)
  • 整个函数完全遵循 STM32 外设中断的通用标准流程:「进入中断 → 校验中断源 → 执行业务逻辑 → 清除中断标志 → 等待操作生效 → 退出中断」,每一步的顺序都是硬件机制决定的,不是凭空设计的。
步骤
代码
作用与设计逻辑
硬件寄存器关联
1
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
中断源校验:确认本次中断是不是「秒中断」触发的。👉 设计原因:RTC 的秒、闹钟、溢出 3 个中断共用同一个中断向量,进入中断后必须先区分是哪个事件触发的,避免误处理;同时校验「中断使能 + 事件标志」双条件,排除未使能的干扰。
同时读取两个寄存器:- RTC_CRH 位 0 SECIE(秒中断使能开关)- RTC_CRL 位 0 SECF(秒事件标志)只有两者都为 1,才是合法的秒中断触发。
2
秒中断处理逻辑
业务执行:放在判断分支内,只有确认是秒中断才执行。👉 设计原则:中断服务函数要「快进快出」,这里只放短平快的核心逻辑(如时间计数 + 1),绝对不能放延时、串口打印等耗时操作,否则会阻塞其他中断。
无寄存器操作,纯软件业务逻辑。
3
RTC_ClearITPendingBit(RTC_IT_SEC);
清除中断挂起标志:把秒事件标志位清零,应答本次中断。👉 为什么必须做?硬件机制决定:中断标志位被硬件置 1 后会一直保持,如果软件不清零,退出中断后标志位还是 1,会立刻再次触发中断,导致程序死在中断里永远出不来。
RTC_CRL 位 0 SECF,写 0 清零(硬件规定写 1 无效)。
4
RTC_WaitForLastTask();
等待写操作完成:等待 RTC 硬件真正完成寄存器写入。👉 为什么要等?RTC 是低速外设(时钟 32.768kHz),APB1 总线是高速时钟(最高 36MHz),软件写寄存器只是把数据发到总线接口,硬件需要几个 RTC 时钟周期才能真正写入寄存器。如果不等就退出,后续操作 RTC 可能出现写入失败、值不对的问题。
循环读 RTC_CRL 位 5 RTOFF,直到硬件将其置 1(代表上一次写操作完成)。
寄存器的关联与顺序必然性
notion image
从零推导:没有参考怎么写出这个流程?
notion image
核心疑问解答:为什么不一块清除中断使能?
概念
对应位
作用
类比
中断使能 SECIE
RTC_CRH 位 0
「中断总开关」:决定事件发生时要不要通知 CPU。置 1 就通知,置 0 就不通知,但事件本身还是会发生(标志位照常置 1)。
门铃的电源开关:开着的时候有人按就响,关了之后按了也不响。
中断标志 SECF
RTC_CRL 位 0
「事件标记」:只要秒事件发生,硬件就自动置 1,和使能开关无关。
门铃的铃声:有人按就一直响,直到你手动关掉。
notion image

RTC_GetITStatus(RTC_IT_SEC) != RESET

  • 含义:检查RTC指定中断是否已经触发(同时校验「中断使能状态」与「中断事件标志」),即检查RTC_CRH(RTC控制寄存器高位)的第0位SECIE(允许秒中断)是否为1(允许秒中断)和RTC_CRL(RTC控制寄存器低位)的第0位SECF(秒标志)是否为1(秒标志条件成立),若都为1,则返回1,那么代码为true;否则为false
  • 参数RTC_IT_SEC的值为0x0001,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
宏定义
十六进制值
对应 CRH 寄存器位
位名称
功能说明
RTC_IT_OW
0x0004
位 2
OWIE
溢出中断使能:1 = 开启溢出中断,0 = 屏蔽
RTC_IT_ALR
0x0002
位 1
ALRIE
闹钟中断使能:1 = 开启闹钟中断,0 = 屏蔽
RTC_IT_SEC
0x0001
位 0
SECIE
秒中断使能:1 = 开启秒中断,0 = 屏蔽
  • RTC_GetITStatus函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRH(RTC控制寄存器高位)
  • RTC控制寄存器高位RTC_CRH在参考手册第311页有定义
notion image
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image

RTC_ClearITPendingBit(RTC_IT_SEC)

  • 含义:对RTC_CRL(RTC控制寄存器低位)的第0位SECF(秒标志)置为0(秒标志条件不成立),即清除RTC指定的中断挂起标志位(清除RTC_CRL寄存器中的事件标志)
  • 参数RTC_IT_SEC在上一个有说明,且值为0x0001
  • RTC_ClearITPendingBit函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image

6.4 u8 const table_week[12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}

notion image
notion image
notion image
notion image

6.5 RTC_Set(u16 syear, u8 smon, u8 sday, u8 hour, u8 min, u8 sec)

函数核心定位与设计目的
notion image
逐段流程拆解 + 设计逻辑
notion image
notion image
notion image
硬件场景
重新初始化的作用
第一次使用,备份域完全没电(纽扣电池也空了)
所有配置都丢了,必须从头完整初始化,否则根本写不了 RTC 寄存器
主电源掉电 / 复位,备份域有电池供电
主电源域的 PWR 时钟、BKP 接口时钟会被复位清零,备份域写保护会重新开启;重新初始化能重新开时钟、解写保护,恢复 CPU 对 RTC 的写权限
正常运行中,用户主动修改时间
所有配置本来就是好的,重新初始化只是再写一遍相同的值,没有任何影响,相当于加了一层保险,防止万一寄存器被干扰篡改
notion image
寄存器操作的关联与顺序必然性
notion image
复位过程
notion image

RTC_SetCounter(seccount)

  • 含义:主要是将seccount(秒的差距总数)写入RTC_CNTH / RTC_CNTL(RTC计数器寄存器)中,其中高16位写入RTC_CNTH,低16位写入RTC_CNTL
  • RTC_SetCounter函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image
RTC_CNTH / RTC_CNTL(RTC计数器寄存器)
  • RTC计数器寄存器RTC_CNTH / RTC_CNTL在参考手册第313~314页有定义
notion image
notion image

6.6 RTC_Get(void)

以2024年2月29号18点20分20秒为例子进行计算
notion image
notion image
notion image
notion image
循环次数
当前年份 temp1
年份类型
当年天数
剩余天数 temp
操作
1
1970
平年
365
19782-365=19417
temp1 自增为 1971
2
1971
平年
365
19417-365=19052
temp1 自增为 1972
3
1972
闰年
366
19052-366=18686
temp1 自增为 1973
...
...
...
...
...
...
54
2023
平年
365
59-365?不,循环到第 54 次后 temp 剩余 59
temp1 自增为 2024
notion image
循环次数
月份索引 temp1
对应月份
月份类型
当月天数
剩余天数 temp
操作
1
0
1 月
平年月
31
59-31=28
temp1 自增为 1
2
1
2 月
闰年 2 月
29
28 < 29,不满足减法条件
执行 break,退出循环
notion image
notion image

timecount=RTC_GetCounter()

  • 含义:获取RTC计数器寄存器的值,即之前的时间距离差总秒数
  • RTC_GetCounter函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rtc.c(外设固体库文件- - - ✿ 固体库文件
RTC_CRL(RTC控制寄存器低位)
  • RTC控制寄存器低位RTC_CRL在参考手册第311~312页有定义
notion image
notion image
RTC_CNTH / RTC_CNTL(RTC计数器寄存器)
  • RTC计数器寄存器RTC_CNTH / RTC_CNTL在参考手册第313~314页有定义
notion image
notion image

6.7 RTC_Get_Week(u16 year, u8 month, u8 day)

函数核心定位与设计目的
notion image
逐行代码流程拆解 + 实例验证
notion image
notion image
notion image
notion image
设计思路推导:没有参考也能一步步写出来
notion image
notion image
搞懂 yearL=124 到底是什么意思
notion image
notion image
notion image
年份编号 yearL
对应目标年 1 月 1 日
经过的整年
经过的年是平 / 闰
当年带来的偏移
累计总偏移(实际值)
公式计算值 yearL + yearL/4
差值(公式 - 实际)
0
1900 年
-
0
0
0 + 0 = 0
0
1
1901 年
1900 年
平年
+1
1
1 + 0 = 1
0
2
1902 年
1901 年
平年
+1
2
2 + 0 = 2
0
3
1903 年
1902 年
平年
+1
3
3 + 0 = 3
0
4
1904 年
1903 年
平年
+1
4
4 + 1 = 5
+1 (第一次出现差)
5
1905 年
1904 年
闰年
+2
4+2=6
5 + 1 = 6
0
6
1906 年
1905 年
平年
+1
7
6 + 1 = 7
0
7
1907 年
1906 年
平年
+1
8
7 + 1 = 8
0
8
1908 年
1907 年
平年
+1
9
8 + 2 = 10
+1
9
1909 年
1908 年
闰年
+2
11
9 + 2 = 11
0
10
1910 年
1909 年
平年
+1
12
10 + 2 = 12
0
notion image

七、触摸按键

7.1 根据以上的文档,对下面的图片进行解释

notion image
图1
notion image
图2
notion image
图3
notion image
图4
notion image
图5
notion image
图6
 
  • 根据6张图片,得出已知信息
    • 图1和图2表明:OUT_1 = TTP223-1 = PA0
    • 图5和6表明:PA0端口内部为上拉电阻模式
    • 图4表明:第4脚AHLB和第6脚TOG内部为下拉电阻模式
    • notion image
    • 图3的电路图表明:
      • 线路1:第4脚AHLB与3V电源相连
      • 线路2:第4脚AHLB还连接C4电容到GND
      • 线路3:第5脚VCC与3V电源相连
      • 线路4:第6脚TOG与GND相连
      • 线路5:第3脚IN与(J3与C3组成的并联线路)相连,最终流向GND
      • 线路6:第2脚GND与GND相连
      • 线路7:第1脚OUT与OUT_1相连,即第1脚OUT直接连接在PA0端口上
      • 线路8:同时在第1脚上还并联了(LED0的指示灯并且串联了一个限流电阻R12)的线路,整个电路是连接在3V电源上
    • 图3的外围器件:
    • 器件
      参数
      接线位置
      角色与作用
      R12
      1KΩ 电阻
      串在 OUT 脚和 LED 之间
      限流电阻:限制流过 LED 的电流,防止电流太大烧坏 LED 和芯片输出脚
      D1(LED0)
      发光二极管
      正极接 3V,负极接 R12
      状态指示灯:触摸触发时点亮,直观显示有没有摸到按键
      C3
      15pF 电容
      接在 IN 脚和 GND 之间
      灵敏度调节电容:用来调整触摸的灵敏程度,数值越大灵敏度越低
      C4
      0.1μF 电容
      接在 3V 和 GND 之间
      电源滤波电容:过滤电源里的杂波、抖动,让芯片供电更平稳,避免电源波动导致误触发
    • 图3的J3:是触摸电极接口,本质就是一块裸露的铜箔、金属弹簧片或者导电触摸片,是你手指实际触摸的地方。
      • 角色:触摸传感器的前端,相当于芯片伸到外面的 “感应片”;
      • 作用:手指靠近 / 触摸它时,会改变它的电容大小,芯片通过 3 脚检测到这个变化,就知道有人摸按键了。
      • notion image
    • 图4补充:
      • IO类型解释
      • 类型缩写
        全称
        含义
        对应引脚例子
        O
        Output
        纯输出引脚
        1 脚 Q/OUT:只能往外发高低电平信号,不能当输入用
        P
        Power
        电源引脚
        2 脚 VSS/GND、5 脚 VDD/VCC:只负责供电,不传输信号
        I/O
        Input/Output
        双向输入输出引脚
        3 脚 I/IN:内部有振荡电路,既可以输出充电信号,也可以输入检测电容的信号,双向工作
        I-PL
        Input with Pull-down
        带内部下拉电阻的输入引脚
        4 脚 AHLB、6 脚 TOG:只能读外面的电平,芯片内部自带一个接地的电阻,悬空时默认就是低电平,不用额外接零件
      • 第3脚IN:
        • 内部有一个充放电的电路,可以输入和输出;
        • 内部有一个检测电容变化的电路,原始电路(没触摸状态下)的电容为J3本身的小电容+C3的电容;触摸后,电容变大,变为J3本身小电容+人体中存在的大电容+C3的电容;
      • 第1脚OUT:CMOS输出为可以输出高电平或低电平
      • 第4脚AHLB和第6脚TOG:只能输入
      • 第6脚TOG有两个模式:触发模式和直接模式
        • 触发模式(TOG=1)
          • 也叫翻转模式 / 自锁模式,和家里的墙壁电灯开关逻辑一样:
            • 第一次摸按键:输出翻转一次(从关→开),松开手之后,输出保持开启状态;
            • 第二次摸按键:输出再翻转一次(从开→关),松开手之后,输出保持关闭状态。
          • 适用场景:触摸台灯、电源开关,不需要一直按着,摸一下切换一次状态。
        • 直接模式(TOG=0,本电路就是这个模式)
          • 也叫点动模式,和普通机械按键行为完全一致:
            • 手指按住触摸键:输出一直保持触发状态(本电路里就是 LED 一直亮);
            • 手指一松开:输出立刻恢复成未触发状态(LED 立刻灭)。
          • 适用场景:门铃、键盘按键、需要按住才生效的功能,和 “按下去就通、松开就断” 的普通按钮一模一样。
      • 第4脚AHLB的“输出高电平或者低电平有效选择”解释
        • 通过 AHLB 引脚,你可以选择「摸按键的时候,OUT 脚输出高电平代表触发」,还是「摸按键的时候,OUT 脚输出低电平代表触发」。
        • 高电平有效:没摸 = 低电平,摸了 = 高电平;
        • 低电平有效:没摸 = 高电平,摸了 = 低电平。

八、数码管

8.1 共阴/共阳数码管

notion image

共阴

  • 公共部分都接到GND上
  • 意味着左边只有是高电平,才能使数码管上对应的LED亮
  • 示例:
notion image
如图所示,当要显示数字1时,就需要点亮b、c两个LED,那么按照LED排列(a、b、c、d、e、f、g、dp 依次为 bit0、bit1、bit2、bit3、bit4、bit5、bit6、bit7),又因为点亮LED需要设置为高电平,则二进制位 0000 0110,十六进制为 0x06 = 6H

共阳

  • 公共部分都接到VCC上
  • 意味着右边只有是低电平,才能使数码管上对应的LED亮
  • 示例:
notion image
如图所示,当要显示数字1时,就需要点亮b、c两个LED,那么按照LED排列(a、b、c、d、e、f、g、dp 依次为 bit0、bit1、bit2、bit3、bit4、bit5、bit6、bit7),又因为点亮LED需要设置为低电平,则二进制位 1111 1001,十六进制为 0xF9 = F9H

8.2 两个电路原理图文档相关数码管内容解释

开发板总图文档相关内容和与之相关的数码管文档的部分内容

notion image
notion image
以上两张图:表明PA11连接在TM1640芯片的第8脚SCLK(时钟线)上,PA12连接在TM164芯片的第脚DIN(数据线)上

TM1640数码管文档内容

notion image
  • 这张图:表明 J1 右边方框内的数字 1、2、3、4 表示从下到上的数码管顺序,左边方框内的字母 A~H 分别代表一位数码管中的 a、b、c、d、e、f、g、dp 八个LED灯,且 a、b、c、d、e、f、g、dp 八个LED灯分别在图中为 SEG1、SEG2、SEG3、SEG4、SEG5、SEG6、SEG7、SGE8
  • 由于是共阴数码管,所以若要LED亮,则要使其LED对应位的值为高电平
notion image
  • 这张图:表明 J2 右边方框内的数字 1、2、3、4 表示从下到上的数码管顺序,左边方框内的字母 A~H 分别代表一位数码管中的 a、b、c、d、e、f、g、dp 八个LED灯,且 a、b、c、d、e、f、g、dp 八个LED灯分别在图中为 SEG1、SEG2、SEG3、SEG4、SEG5、SEG6、SEG7、SGE8
  • 由于是共阴数码管,所以若要LED亮,则要使其LED对应位的值为高电平
notion image
  • 结合上两张图片,第一张图 J1 右边方框内的数字 1、2、3、4 根据右边对应关系 1、2、3、4 ,连接在这张图的 TM1640 芯片的第 18 ~ 21 脚 GR1 ~ GR4 ,左边方框内的字母则连接在第 9 ~ 16 脚 SEG1 ~ SEG8;
  • 第二张图 J2 右边方框内的数字 1、2、3、4 根据右边对应关系 5、6、7、8 ,连接在这张图的 TM1640 芯片的第 22 ~ 25 脚 GR5 ~ GR8 ,左边方框内的字母则连接在第 9 ~ 16 脚 SEG1 ~ SEG8;
notion image
  • 这张图:表示为了更形象展示数码管的各个 LED ,又因为之前使用了 8 位 8 段共阴数码管,即第一张和第二张图的数码管,所以只能使用用于表示第 9 位数码管的 GR9(TM1640 芯片第 26 脚),然后 8 个 LED 直接用如图所示的 LED1 ~ LED8 表示;
  • 倘若向 GR9 所在的显存地址 C9H 写入 0x01,那么图中 LED1 亮,其余不亮;比如下面例子。
notion image
notion image

8.3 TM1640数据手册文档解释

SCLK与DIN对应关系

notion image
  • 这张图换种说法说明:最初 SCLK 和 DIN 都是高电平,且分别为时钟线和数据线。开始:当 DIN 出现由高电平变成低电平的过程,且 SCLK 始终为高电平的情况下,则为数据传输开始标志。传输:之后数据从低到高位次依次传输高电平或低电平,则只有当 SCLK 为高电平时有效。结束:最后当在 SCLK 为高电平时,DIN 从低电平变成高电平的过程表示为数据传输结束标志。
  • 代码示例:
  • 可参考 SCL 和 SDA 的传输方式和向寄存器读写方式
notion image
notion image
notion image

自动地址或者固定地址写数据格式

notion image
notion image
  • 这两张图片:表明两种模式下的操作方式,注意每个命令(Command1、Command2、Command3)的开始和结束部分,三种命令不是连在一起发送的,而是各自有开始标志和结束标志
  • 其中数据指令分类、数据命令、显示控制命令、地址命令具体要求如下:
notion image
notion image
notion image
notion image
notion image
notion image
  • 代码示例:

九、旋转编码器

9.1 旋转编码器介绍

notion image
  • 编码器具有左旋,右旋,按下三个功能。4、5 脚是中间按下去的开关接线 1 2 3 脚一般中间 2 脚接地,1、3 脚上拉电阻后,当左转、右转旋纽时,在 1、3 脚就有脉冲信号输出了。
notion image
  • 输出 1 为高电平时,输出 2 出现一个高电平,这时开关就是向顺时针旋转;当输出 1 为高电平,输出 2 出现一个低电平,这时就一定是逆时针方向旋转。编程时只需要判断当输出 1 为高电平时,输出 2 当时的状态就可以判断出是左旋转或是右旋转。

9.2 两个电路原理图文档关于旋转编码器内容的解释

notion image
notion image
  • 第一张图片:表明 JS_X、JS_Y、JS_D 分别连接在 PA6、PA7、PB2端口上
  • 第二张图片:由于这是关于编码器的解释,所以不看模拟量摇杆部分的电路,只看编码器部分。
  • 第一、二张图片结合后的编码器 PD1 连线如下:
    • 1、4 两个脚接在 GND 上
    • 2 脚连在 P18 上的右边 4 脚上,且 4 脚对应左边的 3 脚,又因为左边 3 脚连在 JS_Y(PA7端口)上
    • 3 脚连在 P18 上的右边 6 脚上,且 6 脚对应左边的 5 脚,又因为左边 5 脚连在 JS_D(PB2端口)上
    • 5 脚连在 P18 上的右边 2 脚上,且 2 脚对应左边的 1 脚,又因为左边 1 脚连在 JS_X(PA6端口)上

9.3 旋转编码器波形示意图和机械抖动图

notion image
notion image
  • 第一张图表示:1、2 脚用于按下键的操作,且结合之前的图片可知,1 脚连接在 GND 上,因此 K1 按键为用于 2 脚与 1 脚的开关相连。3、4、5 脚用于左右旋转的操作,且结合之前图片可知,4 脚连接在 GND 上,因此 K2 按键为用于 4 脚与 5 脚的开关相连, K3 按键为用于 4 脚与 3 脚的开关相连
  • 【重点】:第二张图片所示的方向 1 和 2 并不固定,因硬件本身而变,因此方向 1 可能是左转也可能是右转,方向 2 可能是右转也可能是左转
  • 第二张图片表示(PA6/PA7/PB2 三个端口内部是上拉电阻,因此 K2/K3 一开始输出的是高电平):
    • 看 K2/K3 哪个先变成低电平
      • 方向 1 的时候:K3 先变成低电平,随后 K2 才变成低电平
      • 方向 2 的时候:K2 先变成低电平,随后 K3 才变成低电平
    • K2 刚触发从高电平变成低电平的瞬间,K3 是什么情况
      • 方向 1 的时候,K3 处于低电平状态
      • 方向 2 的时候,K3 处于高电平状态
notion image
  • 这张图表明:转动 1 格,由高电平变成低电平的瞬间的机械抖动小于等于 2ms,360 度内有 20 位格指的是我所持有的旋转编码器的格数,不同的旋转编码器格数各有不同

9.4 旋转编码器数码管显示程序的示例代码

  • main.c
  • encoder.h
  • encoder.c
延时代码
作用对象
核心作用
消除 / 解决的问题
时间怎么来的
和图 3 的关联
delay_us(100)
旋转相位 K2(ENCODER_L)
初步毛刺过滤
K2 刚接触瞬间的极短尖峰抖动
经验值,100 微秒很短,只过滤最开头的杂波
弱关联:针对图 3 里抖动最开始的尖峰,不是完整消抖
delay_ms(3)
旋转相位 K2(ENCODER_L)
完整机械消抖
K2 闭合时的机械抖动,避免一次转动识别成多次
图 3 标注抖动≤2ms,取 3ms 略大于最大抖动时间,确保抖完
直接关联:就是针对图 3 的 2ms 机械抖动设计的消抖延时
delay_us(20)
锁死计数器cou
控制循环速度,计算超时时间
不是消抖,是用来算 “停多久算锁死”
经验值,循环一次 20us,60000 次就是 1.2 秒左右
无关联:纯软件逻辑的超时计时,和机械抖动没关系
delay_ms(20)
按键 K1(ENCODER_D)
按键机械消抖
按键按下时的机械抖动,避免按一次识别成多次
普通按键抖动通常 5~10ms,取 20ms 是保守值,确保稳定
原理关联:和图 3 的机械抖动是同一个原理,只是按键行程长,抖动更久,所以延时更长

十、温度传感器数码管显示程序

notion image
I2C手册内容解析
notion image
notion image
解释1
notion image
notion image
notion image
notion image
notion image
解释2
notion image
notion image
涉及到的寄存器位
OAR1 - - - OAR1寄存器
notion image
OAR2、ENDUAL - - - OAR2寄存器
notion image
ENGC - - - CR1寄存器
notion image
notion image
ADDR - - - SR1寄存器
notion image
notion image
ITEVTEN - - - CR2寄存器
notion image
notion image
DUALF - - - SR2寄存器
notion image
notion image
notion image
解释3
notion image
notion image
解释4 - - - 图 243
notion image
notion image
notion image
notion image
notion image
notion image
notion image
涉及到的寄存器位
ADDR、TxE、BTF、AF - - - SR1寄存器
notion image
notion image
notion image
notion image
notion image
ITEVTEN、ITBUFEN - - - CR2寄存器
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
notion image
解释5
notion image
涉及到的寄存器位
ADDR、RxNE、BTF - - - SR1寄存器
notion image
notion image
notion image
notion image
ITEVTEN、ITBUFEN - - - CR2寄存器
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
notion image
解释6
notion image
涉及到的寄存器位
ADDR、RxNE、STOPF - - - SR1寄存器
notion image
notion image
notion image
notion image
ITEVTEN - - - CR2寄存器
notion image
notion image
DR - - - DR(数据)寄存器
notion image
notion image
解释7
notion image
notion image
涉及到的寄存器位
START、PE(启动外设) - - - CR1寄存器
notion image
notion image
notion image
FREQ[5:0](设定该模块的输入时钟以产生正确时序)、ITEVTEN - - - CR2寄存器
notion image
notion image
notion image
CCR时钟控制寄存器 - - - CCR寄存器
notion image
notion image
TRISE上升时间寄存器 - - - TRISE寄存器
notion image
BUSY、MSL - - - SR2寄存器
notion image
notion image
notion image
ADD10、ADDR、SB - - - SR1寄存器
notion image
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
notion image
解释8
notion image
涉及到的寄存器位
ADDR - - - SR1寄存器
notion image
notion image
ITEVTEN - - - CR2寄存器
notion image
notion image
TRA - - - SR2寄存器
notion image
notion image
notion image
解释9
notion image
notion image
notion image
涉及到的寄存器位
ADDR、TxE、BTF、AF、SB、ADD10 - - - SR1寄存器
notion image
notion image
notion image
notion image
notion image
notion image
notion image
ITEVTEN、ITBUFEN - - - CR2寄存器
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
MSL - - - SR2寄存器
notion image
notion image
STOP - - - CR1寄存器
notion image
notion image
notion image
解释10
notion image
涉及到的寄存器位
ADDR、RxNE、BTF - - - SR1寄存器
notion image
notion image
notion image
notion image
ITEVTEN、ITBUFEN - - - CR2寄存器
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
ACK - - - CR1寄存器
notion image
notion image
notion image
解释11
notion image
notion image
notion image
解释12 - - - 图246
notion image
notion image
notion image
涉及到的寄存器位
ADDR、RxNE、SB、ADD10 - - - SR1寄存器
notion image
notion image
notion image
notion image
notion image
DR - - - DR(数据)寄存器
notion image
MSL - - - SR2寄存器
notion image
notion image
ACK、STOP、START - - - CR1寄存器
notion image
notion image
notion image
notion image
LM75温度传感器相关手册和电路图解析
notion image
notion image
notion image
  • 在本案例上(第二张图所示),LM75A温度传感器A0、A1、A2,即第7、6、5脚连接在3V(高电平)的电源上;第三图所示,LM75A温度传感器的SDA、SCL,即第1、2脚分别连接在PB7、PB6端口上;
notion image
notion image
  • LM75温度传感器的从机地址按从高位到低位的顺序规定为1001+A2+A1+A0+R(1)/W(0),根据A2/A1/A0的不同值,可以分出8个不同从地址
  • 温度寄存器的地址为0x00,只能读取,且读取两个字节(共16位)
  • 配置寄存器的地址为0x01,读/写皆可,为1个字节(共8位)
  • 滞后(Thyst)寄存器的地址为0x02,读/写皆可,为0x4B0X(0100 1011 0XXX XXXX)
  • 过温关断阈值(Tos)寄存器的地址为0x03,读/写皆可,为0x500X(0101 0000 0XXX XXXX)
notion image
notion image
notion image
  • 除了第二张图所展示的温度计算方法之外,第一张图所展示的方法为温度相加,因此D7为0.5,D6为0.25,D5为0.125
  • 第二张图所说的补码是在原码的基础上,进行反码操作,再加上1
notion image
  • D0=1,为代码中所说的省电模式
notion image
notion image
main.c文件代码文件:
i2c.h文件代码文件:
i2c.c文件代码文件:
Im75a.h文件代码文件:
Im75a.c文件代码文件:

10.1 I2C_Configuration(void)

I2C_InitTypeDef I2C_InitStructure

  • I2C_InitTypeDef类型的结构体,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件

I2C_InitStructure.I2C_Mode = I2C_Mode_I2C

  • 含义:将I2C_CR1(控制寄存器1)的第1位SMBUS(SMBus模式)设置为0(I2C模式)
  • I2C_Mode_I2C,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)- - -【因涉及代码中I2C模式和SMBUS模式,所以在此做出解释】
对下方手册内容的解释【豆包】- - - SMBUS和I2C区别和联系
notion image
notion image
notion image
notion image
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2

  • 含义:将I2C_CCR(时钟控制寄存器)下的第14位DUTY(快速模式时的占空比)设置为0(快速模式下:/ = 2)
  • I2C_DutyCycle_2,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
I2C_CCR(时钟控制寄存器)- - -【因涉及代码中计算问题(I2C标准/快速模式的CCR),所以在此做出解释】
对下方手册内容的解释【豆包】
notion image
notion image
notion image
notion image
notion image
  • I2C_CCR时钟控制寄存器在参考手册第513~514页有定义
notion image
notion image
 

I2C_InitStructure.I2C_OwnAddress1 = HostAddress

  • 含义:I2C的总线主机的器件地址为0xc0【1100 0000】,即将I2C_OAR1(自身地址寄存器1)的第1~7位ADD[7:1](接口地址)设置为11000000(0xc0,总线主机的器件地址)
  • HostAdress,出自i2c.h文件
I2C_OAR1(自身地址寄存器1)
  • I2C_OAR1自身地址寄存器1在参考手册第508~509页有定义
notion image
notion image

I2C_InitStructure.I2C_Ack = I2C_Ack_Enable

  • 含义:将I2C_CR1(控制寄存器1)的第10位ACK(应答使能)设置为1(在接收到一个字节后返回一个应答(匹配的地址或数据))
  • I2C_Ack_Enable,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit

  • 含义:将I2C_OAR1(自身地址寄存器1)的第15位ADDMODE(寻址模式(从模式))设置为0(7位从地址(不响应10位地址))
  • I2C_AcknowledgedAddress_7bit,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
I2C_OAR1(自身地址寄存器1)
  • I2C_OAR1自身地址寄存器1在参考手册第508~509页有定义
notion image
notion image

I2C_InitStructure.I2C_ClockSpeed = BusSpeed

  • 含义:I2C的总线速度为200000,I2C标准模式和快速模式下的速度分别为100kHz和400kHz
  • BusSpeed,出自i2c.h文件
I2C_CCR(时钟控制寄存器)- - -【因涉及代码中计算问题(I2C标准/快速模式的CCR),所以在此做出解释】
对下方手册内容的解释【豆包】
notion image
notion image
notion image
notion image
notion image
  • I2C_CCR时钟控制寄存器在参考手册第513~514页有定义
notion image
notion image
 

I2C_Init(I2C1,&I2C_InitStructure)

  • 含义:根据之前配置的结构体I2C_InitStruct,来将对应寄存器的相应位进行配置I2C
  • I2C1的起始地址:0x4000 5400 ~ 0x4000 57FF
  • 第一个参数I2C1的地址值为0x4000 5400,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
  • I2C_Init函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
IS_I2C_ALL_PERIPH(I2Cx)
  • IS_I2C_ALL_PERIPH函数,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
I2C_CR2(控制寄存器2)
  • I2C_CR2控制寄存器2在参考手册第507~508页有定义
notion image
notion image
RCC_ClocksTypeDef rcc_clocks
  • 创建了RCC_ClocksTypeDef类型的变量,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_rcc.h(外设固体库头文件- - - ✿ 固体库文件
RCC_GetClocksFreq(&RCC_ClocksStatus)
  • RCC_GetClocksFreq函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
tmp = RCC->CFGR & CFGR_SWS_Mask
  • CFGR_SWS_Mask的值为((uint32_t)0x0000000C),出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR(时钟配置寄存器)- - - 与代码语句有关
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
RCC_Clocks->SYSCLK_Frequency = HSI_VALUE
  • 含义:将SYSCLK 系统主时钟频率设为HSI(内部高速)
  • RCC_Clocks->SYSCLK_Frequency:SYSCLK 系统主时钟频率
  • HSI_VALUE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
RCC_Clocks->SYSCLK_Frequency = HSE_VALUE
  • 含义:将SYSCLK 系统主时钟频率设为HSE(外部高速)
  • RCC_Clocks->SYSCLK_Frequency:SYSCLK 系统主时钟频率
  • HSE_VALUE,出自CMSIS文件夹下的外设相关的stm32f10x.h(外设寄存器的定义)- - - ✿ 固体库文件
pllmull = RCC->CFGR & CFGR_PLLMull_Mask和pllsource = RCC->CFGR & CFGR_PLLSRC_Mask
  • 含义:前者:读取PLL倍频系数(CFGR寄存器的PLLMULL[21:18]位);后者:读取PLL时钟源选择(CFGR寄存器的PLLSRC[16]位)
RCC_CFGR(时钟配置寄存器,非互联网型)
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
notion image
RCC_CFGR(时钟配置寄存器,互联网型)
  • RCC_CFGR时钟配置寄存器在参考手册第86~88页有定义
notion image
notion image
notion image
notion image
prediv1factor = (RCC->CFGR2 & CFGR2_PREDIV1) + 1和RCC_Clocks->SYSCLK_Frequency = (HSE_VALUE / prediv1factor) * pllmull
  • 属于超值型范畴
  • 含义:前者:读取CFGR2寄存器的0~3位,然后在此基础上加上1,最后赋值给prediv1factor。后者:将HSE_VALUE(8000000)除以prediv1factor,得出的值乘以之前“pllmull = (pllmull >> 18) + 2;”处理的倍频系数值,最后写回到RCC_Clocks对象的SYSCLK系统主时钟频率中。
  • CFGR2_PREDIV1,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_rcc.c(外设固体库文件- - - ✿ 固体库文件
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
RCC->CFGR & CFGR_PLLXTPRE_Mask
  • 含义:读取CFGR寄存器的第17位PLLXTPRE(HSE分频器作为PLL输入)
RCC_CFGR(时钟配置寄存器)
  • RCC_CFGR时钟配置寄存器在参考手册第61~63页有定义
notion image
notion image
prediv1source = RCC->CFGR2 & CFGR2_PREDIV1SRC
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第16位,赋值给prediv1source
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
prediv2factor = ((RCC->CFGR2 & CFGR2_PREDIV2) >> 4) + 1
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第4~7位,然后右移4位,变成原本第4~7位移到了第0~3位,之后加上1,赋值给prediv2factor
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
pll2mull = ((RCC->CFGR2 & CFGR2_PLL2MUL) >> 8 ) + 2
  • 属于互联网型范畴
  • 含义:读取CFGR2寄存器的第8~11位,然后右移8位,变成原本第8~11位移到了第0~3位,之后加上2,赋值给pll2mull
RCC_CFGR2(时钟配置寄存器2)
  • RCC_CFGR2时钟配置寄存器2在参考手册第101~103页有定义
notion image
notion image
notion image
I2C_CR1(控制寄存器1)- - -【因涉及代码中I2C模式和SMBUS模式,所以在此做出解释】
对下方手册内容的解释【豆包】- - - SMBUS和I2C区别和联系
notion image
notion image
notion image
notion image
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image
notion image
I2C_CCR(时钟控制寄存器)- - -【因涉及代码中计算问题(I2C标准/快速模式的CCR),所以在此做出解释】
对下方手册内容的解释【豆包】
notion image
notion image
notion image
notion image
notion image
  • I2C_CCR时钟控制寄存器在参考手册第513~514页有定义
notion image
notion image
 
I2C_TRISE(TRISE寄存器)- - -【因涉及代码中计算问题(I2C标准/快速模式的TRISE(单次最大上升时间)),所以在此做出解释】
对下方手册内容的解释【豆包】
PCLK和SCL区别
notion image
notion image
notion image
手册内容解释1
notion image
notion image
notion image
notion image
notion image
手册内容解释2
notion image
notion image
notion image
notion image
notion image
那TRISE最大上升时间指的是总共要花费的时间的吗?还是指单次由低电平到高电平的上升沿的时间?
notion image
  • TRISE寄存器I2C_TRISE在参考手册第514页有定义
notion image
 
I2C_OAR1(自身地址寄存器1)
  • I2C_OAR1自身地址寄存器1在参考手册第508~509页有定义
notion image
notion image

I2C_Cmd(I2C1,ENABLE)

  • 含义:将I2C_CR1(控制寄存器1)的第0位PE(I2C模块使能)设置为1(启用I2C模块:根据SMBus位的设置,相应的I/O口需配置为复用功能)
  • I2C_Cmd函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

10.2 I2C_SAND_BUFFER(u8 SlaveAddr,u8 WriteAddr,u8* pBuffer,u16 NumByteToWrite)

  • 含义:I2C发送数据串(器件地址,寄存器内部地址,数据串,数量)
★※【注意事项】该函数中EV事件的触发顺序(此触发顺序较参考手册略有不同,故在此做出解释)
notion image
notion image
notion image
notion image
notion image

I2C_GenerateSTART(I2C1,ENABLE)

  • 含义:将I2C_CR1(控制寄存器1)的第8位START(起始条件产生)设置为1(在主模式下:重复产生起始条件;在从模式下:当总线空闲时,产生起始条件)
  • I2C_GenerateSTART函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)- - -【因涉及代码中主模式和从模式,所以在此做出解释】
对下方手册内容的解释【豆包】- - - 主模式和从模式
notion image
notion image
notion image
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT))

  • 含义:判断已指定的事件I2C_EVENT_MASTER_MODE_SELECT:EV5(SR1寄存器的第0位SB【起始位(主模式);值:0(未发送起始条件),1(起始条件已发送)】和SR2寄存器的第0位MSL【主从模式;值:0(从模式),1(主模式)】和SR2寄存器的第1位BUSY【总线忙;值:0(在总线上无数据通讯),1(在总线上正在进行数据通讯)】)是否发生(若发生,则三个位都为1),若发生,则退出循环
  • 第二个参数I2C_EVENT_MASTER_MODE_SELECT的值为0x00030001【0000 0000 0000 0011 0000 0000 0000 0001】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
  • I2C_CheckEvent函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_SR1(状态寄存器1)
  • I2C_SR1状态寄存器1在参考手册第510~512页有定义
notion image
notion image
notion image
notion image
notion image
I2C_SR2(状态寄存器2)
  • I2C_SR2状态寄存器2在参考手册第512~513页有定义
notion image
notion image
SR1和SR2区别和各自位详解
notion image
notion image
notion image
notion image
代码为什么要把两个寄存器拼起来
notion image
notion image
为什么要设置三个位(SB/BUSY/MSL),才能表示清除EV5
notion image
notion image

I2C_Send7bitAddress(I2C1,SlaveAddr,I2C_Direction_Transmitter)

  • 含义:将数据寄存器I2C_DR的第0~7位DR[7:0]写入(器件地址(SlaveAddr,高7位)+I2C_Direction_Transmitter(写操作,低1位,值为0))
  • 第二个参数SlaveAddr为器件地址,来源于上一级函数I2C_SAND_BUFFER的第一个参数
  • 第三个参数I2C_Direction_Transmitter,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
  • I2C_Send7bitAddress函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_DR(数据寄存器)
  • I2C_DR数据寄存器在参考手册第509页有定义
notion image

I2C_SendData(I2C1,WriteAddr)

  • 含义:将寄存器内部地址写入I2C_DR(数据寄存器)中
  • 第二个参数WriteAddr,来源于上一层函数的第二个参数WriteAddr,表明寄存器内部地址
  • I2C_SendData函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_DR(数据寄存器)
  • I2C_DR数据寄存器在参考手册第509页有定义
notion image

I2C_GenerateSTOP(I2C1,ENABLE)

  • 含义:将I2C_CR1(控制寄存器1)的第9位STOP(停止条件产生)设置为1(在主模式下:在当前字节传输或在当前起始条件发出后产生停止条件;在从模式下:在当前字节传输或释放SCL和SDA线)
  • I2C_GenerateSTOP函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)- - -【因涉及代码中主模式和从模式,所以在此做出解释】
对下方手册内容的解释【豆包】- - - 主模式和从模式
notion image
notion image
notion image
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

10.3 I2C_READ_BUFFER(u8 SlaveAddr,u8 readAddr,u8* pBuffer,u16 NumByteToRead)

  • 含义:I2c读取数据串(器件地址,寄存器内部地址,数据串,数量)

while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY))

  • 含义:根据I2C_FLAG_BUSY的值,首先将该值与SR2寄存器进行与运算,判断SR2寄存器的位1:总线忙标志。0=总线空闲无通信,1=总线正在被占用通信中)是否设置为1,如果设置为1,那么为true,则继续循环;否则为false,退出循环
  • 第二个参数I2C_FLAG_BUSY值为0x00020000【0000 0000 0000 0010 0000 0000 0000 0000】,出自Lib文件夹下的inc文件夹下的外设相关的stm32f10x_i2c.h(外设固体库头文件- - - ✿ 固体库文件
  • I2C_GetFlagStatus函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件

I2C_AcknowledgeConfig(I2C1,DISABLE)

  • 含义:将I2C_CR1(控制寄存器1)的第10位ACK(应答使能)设置为0(无应答返回)
  • I2C_AcknowledgeConfig函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_CR1(控制寄存器1)- - -【因涉及代码中主模式和从模式,所以在此做出解释】
对下方手册内容的解释【豆包】- - - 主模式和从模式
notion image
notion image
notion image
  • I2C_CR1控制寄存器1在参考手册第505~507页有定义
notion image
notion image

*pBuffer = I2C_ReceiveData(I2C1)

  • 含义:读取I2C1外设数据寄存器DR中的接收字节,将该字节写入指针pBuffer指向的内存位置
  • I2C_ReceiveData函数,出自Lib文件夹下的src文件夹下的外设相关的stm32f10x_i2c.c(外设固体库文件- - - ✿ 固体库文件
I2C_DR(数据寄存器)
  • I2C_DR数据寄存器在参考手册第509页有定义
notion image

十一、温度值OLED屏显示程序

main.c文件代码文件:
oled0561.c文件代码文件:
oled0561.h文件代码文件:
ASCII_8x16.h文件代码文件:

11.1 OLED0561_ADD、COM、DAT的值解释(oled0561.h中定义的)

在SH1106的手册上是这么定义的
notion image
notion image
notion image
notion image
解释1
notion image
notion image
notion image
notion image
notion image
notion image

11.2 OLED0561_Init (void)

  • 含义:OLED屏开显示初始化
  • OLED0561_Init (void)函数,出自oled0561.c文件
OLED_DISPLAY_OFF()
  • 含义:OLED屏关显示
  • 该函数,出自oled0561.c文件
buf数组的解释(L = 0,H = 1
0xae(关显示
  • 含义: 这是关闭 OLED 面板显示的命令。当 D=0 时,显示关闭。
  • 设置原因: 在进行一系列初始化配置时,通常先关闭显示,以避免在配置过程中屏幕出现闪烁或显示异常内容。配置完成后再统一开启。
notion image
0x8d,0x10(关显示时:关闭电荷泵(断电))
notion image
notion image
notion image
0xaf(开显示
  • 含义: 这是开启 OLED 面板显示的命令。当 D=1 时,显示开启。
  • 设置原因: 在所有初始化配置完成后,发送此命令正式点亮屏幕,开始显示内容。
notion image
I2C_SAND_BUFFER(OLED0561_ADD,COM,buf,3)
  • 含义:将数组的3个数据发送给0x78的器件地址
  • 该函数本身含义:I2C发送数据串(器件地址,寄存器内部地址,数据串,数量),具体可参考上文中“10.2 I2C_SAND_BUFFER(u8 SlaveAddr,u8 WriteAddr,u8* pBuffer,u16 NumByteToWrite)”这一部分
OLED_DISPLAY_CLEAR()
  • 含义:清屏操作
  • 该函数,出自oled0561.c文件
0xB0(设置页地址
  • 含义: 将页地址设置为 0 (命令范围是 0xB0 到 0xB7,对应页 0-7)。
  • 设置原因: SH1106 将 64 行分为 8 个页(Page),每页 8 行。此命令将操作的起始页设置为第 0 页(最顶部的 8 行)。
notion image
0x00,0x10(设置列地址的低/高四位
  • 含义: 这两个命令共同设置显示 RAM 的起始列地址。0x00 设置低 4 位为 0,0x10 设置高 4 位为 0。组合起来,起始列地址为 0x00
  • 设置原因: 将显示的起始位置设置为最左边的第 0 列,这是最常用的显示模式。
notion image
  • A7/6/5/4是代表高四位,A3/2/1/0是代表低四位
notion image
notion image
notion image
OLED_DISPLAY_ON()
  • 含义:OLED屏初始值设置并开显示
  • 该函数,出自oled0561.c文件
buf数组的解释(L = 0,H = 1)- - - 【命令也可以改,也可以不改,在实际开发中,他们都是通用的!一般的方法就是直接问豆包他,让他给我生成一个初始化程序】
0xae(关显示
  • 含义: 这是关闭 OLED 面板显示的命令。当 D=0 时,显示关闭。
  • 设置原因: 在进行一系列初始化配置时,通常先关闭显示,以避免在配置过程中屏幕出现闪烁或显示异常内容。配置完成后再统一开启。
notion image
0x00,0x10(设置列地址的低/高四位
  • 含义: 这两个命令共同设置显示 RAM 的起始列地址。0x00 设置低 4 位为 0,0x10 设置高 4 位为 0。组合起来,起始列地址为 0x00
  • 设置原因: 将显示的起始位置设置为最左边的第 0 列,这是最常用的显示模式。
notion image
  • A7/6/5/4是代表高四位,A3/2/1/0是代表低四位
notion image
notion image
notion image
0xd5,0x80(设置显示时钟分频/振荡器频率
  • 含义: 这是一个双字节命令。0xd5 是命令本身,0x80 是参数。
    • 参数 0x80 (二进制 1000 0000) 的高 4 位 1000 设置振荡器频率为 POR (Power-On Reset) 默认值
    • 低 4 位 0000 设置分频比为 1 (分频比 = A[3:0] + 1)。
  • 设置原因: 配置屏幕的刷新时钟。使用默认频率和 1 分频是一个标准且稳定的设置,能确保屏幕正常刷新。
notion image
notion image
notion image
notion image
notion image
0xa8,0x3f(设置复用率
  • 含义0xa8 是命令,0x3f (十进制 63) 是参数。这表示设置复用率为 1/64
  • 设置原因: 你的 OLED 屏幕是 128x64 分辨率,共有 64 个 COM 行。此命令告诉驱动芯片需要驱动 64 行,以匹配屏幕的物理特性。
notion image
notion image
notion image
notion image
0xd3,0x00(设置显示偏移
  • 含义0xd3 是命令,0x00 是参数。这表示显示起始行映射到 COM0,即 无垂直偏移
  • 设置原因: 确保屏幕显示的内容从最顶部的物理行开始,没有向上或向下移动。
notion image
notion image
notion image
  • 这里有存疑:偏移值不知道是指谁移到哪里去?
0xB0(设置页地址
  • 含义: 将页地址设置为 0 (命令范围是 0xB0 到 0xB7,对应页 0-7)。
  • 设置原因: SH1106 将 64 行分为 8 个页(Page),每页 8 行。此命令将操作的起始页设置为第 0 页(最顶部的 8 行)。
notion image
0x40(设置显示起始行
  • 含义: 设置显示 RAM 的哪一行作为屏幕的起始显示行。0x40 (二进制 0100 0000) 的低 6 位为 0,表示从 RAM 的第 0 行开始显示。
  • 设置原因: 与 0xd3 命令类似,确保显示内容从 RAM 的顶部开始,通常与物理屏幕顶部对齐。
notion image
0x8d,0x14(设置电荷泵
  • 含义: 这是一个非常常见的命令,通常用于兼容 SSD1306 等其他驱动芯片。0x8d 是设置电荷泵的命令,0x14 是开启内部电荷泵的参数。电荷泵的作用是为 OLED 像素提供所需的高驱动电压。
  • 设置原因: 尽管 SH1106 手册使用 0xAD, 0x8B 来开启内部 DC-DC,但许多模块为了兼容性,也支持 0x8D, 0x14 这种写法。其目的都是为了开启内部电压倍增电路,为屏幕发光提供能量。
notion image
解释1
notion image
notion image
notion image
解释2
notion image
notion image
notion image
0xa1(设置段重映射
  • 含义: 设置段(列)驱动的输出方向。0xa1 表示左右反向映射(列地址 127 映射到 SEG0)。
  • 设置原因: 这通常与屏幕的物理安装方向有关。如果屏幕是倒置安装的,使用此命令可以将显示内容水平翻转过来,使其看起来是正的。
notion image
0xc8(设置 COM 输出扫描方向 
  • 含义: 设置 COM(行)的扫描方向。0xc8 表示从 COM[N-1] 扫描到 COM0(即从下到上扫描)。
  • 设置原因: 与 0xa1 类似,这用于垂直翻转显示内容。通常与 0xa1 配合使用,将整个画面旋转 180 度,以匹配屏幕的物理安装方向。
notion image
0xda,0x12(设置 COM 引脚硬件配置
  • 含义0xda 是命令,0x12 (二进制 0001 0010) 是参数。
    • 高 4 位 0001 表示启用交替 COM 引脚配置 (Alternative)。
    • 低 4 位 0010 。
  • 设置原因: 这是为了匹配 OLED 面板的物理引脚布局。0x12 是 128x64 分辨率屏幕的一个标准配置。
notion image
notion image
notion image
notion image
notion image
notion image
notion image
0x81,0xff(设置对比度控制
  • 含义0x81 是对比度设置命令,0xff (十进制 255) 是对比度值。
  • 设置原因: 设置屏幕的亮度/对比度。0xff 是最大值,表示将屏幕设置为最高亮度
notion image
notion image
0xd9,0xf1(设置预充电周期
  • 含义0xd9 是命令,0xf1 (二进制 1111 0001) 是参数。
    • 高 4 位 1111 设置预充电周期为 15 个 DCLK。
    • 低 4 位 0001 设置去放电周期为 1 个 DCLK。
  • 设置原因: 调整像素点亮的时序,可以影响屏幕的亮度和显示效果,是一个高级优化参数。
notion image
0xdb,0x30(设置 VCOM 取消选择电平
  • 含义0xdb 是命令,0x30 (二进制 0011 0000) 是参数。高 4 位 0011 用于设置 VCOMH 电压。
  • 设置原因: VCOMH 是公共电极的电压,调整它可以影响屏幕的整体亮度和功耗。0x30 是一个常见的设置值。
notion image
notion image
notion image
notion image
notion image
0x20,0x00(设置内存寻址模式
  • 含义: 这同样是来自 SSD1306 等兼容芯片的命令。0x20 是设置寻址模式的命令,0x00 表示设置为水平寻址模式 (Horizontal Addressing Mode)。
  • 设置原因: 在水平寻址模式下,写完一个字节的数据后,列地址指针会自动加 1,写满一页后会自动跳到下一页的起始列。这极大地简化了连续写入一屏数据的编程工作。
0xa4(设置全局显示开/关
  • 含义0xa4 表示恢复正常显示,即显示内容由显示 RAM 中的数据决定。
  • 设置原因: 确保屏幕显示的是我们写入 RAM 的数据,而不是强制全亮或全灭。
notion image
notion image
notion image
0xa6(设置正常/反色显示
  • 含义0xa6 表示正常显示。RAM 中为 1 的像素点亮,为 0 的像素点灭。
  • 设置原因: 设置屏幕为正常的显示逻辑。
notion image
0xaf(开显示
  • 含义: 这是开启 OLED 面板显示的命令。当 D=1 时,显示开启。
  • 设置原因: 在所有初始化配置完成后,发送此命令正式点亮屏幕,开始显示内容。
notion image
I2C_SAND_BUFFER(OLED0561_ADD,COM,buf,28)
  • 含义:将数组的28个数据发送给0x78的器件地址
  • 该函数本身含义:I2C发送数据串(器件地址,寄存器内部地址,数据串,数量),具体可参考上文中“10.2 I2C_SAND_BUFFER(u8 SlaveAddr,u8 WriteAddr,u8* pBuffer,u16 NumByteToWrite)”这一部分
那么为什么COM设为0x00,明明buf数组中有命令,也有数据呀?
notion image
notion image

11.3 OLED_DISPLAY_LIT (u8 x)

  • 含义:OLED屏亮度设置(0~255)
  • 该函数,出自oled0561.c文件
0x81,0xff(设置对比度控制
  • 含义0x81 是对比度设置命令,0xff (十进制 255) 是对比度值。
  • 设置原因: 设置屏幕的亮度/对比度。0xff 是最大值,表示将屏幕设置为最高亮度
notion image
notion image

11.4 OLED_DISPLAY_8x16(u8 x, u8 y, u16 w)

  • 含义:显示英文与数字8*16的ASCII码,取模大小为16*16,取模方式为“从左到右从上到下”“纵向8点下高位”
  • 该函数,出自oled0561.c文件
y = y + 2(探究为什么要加上2)
notion image
I2C_SAND_BYTE(OLED0561_ADD, COM, (y / 16) + 0x10)以及I2C_SAND_BYTE(OLED0561_ADD, COM, y % 16) (探究为什么要除以或者取余16,16从哪来的)
notion image
notion image
步骤
核心操作
目的
坐标偏移
y = y + 2
修正硬件物理显示起点偏移。
双页循环
for (t = 0; t < 2; t++)
16像素高度的字符需要占用 2 个页(Page)来显示。
定位行列
发送 0xb0+xy/16+0x10y%16
告诉屏幕:“接下来要往第 x 页、第 y 列开始写数据”。
写入数据
发送 DAT (0x40) 标志位及 8 字节数据
写入具体的像素点亮数据(字模)。
字库寻址
(w * 16) + c - 512
精确计算字模数据在数组中的存储位置。
(w * 16) + c - 512 寻址公式详解
notion image
notion image
notion image
notion image
notion image
notion image

11.5 OLED_DISPLAY_8x16_BUFFER(u8 row,u8 *str)

  • 含义:在 OLED 指定行连续显示一串 ASCII 字符 (8x16 字体)
  • 该函数,出自oled0561.c文件

11.6 OLED_DISPLAY_16_16(u8 x, u8 y, u16 w)

  • 含义:在 OLED 上显示一个 16x16 大小的汉字,取模大小为16*16,取模方式为“从左到右从上到下”“纵向8点下高位”
  • 该函数,出自oled0561.c文件
下面这个文件是显示“成功了哦”的字库数组文件:

11.7 OLED_DISPLAY_16_16_UC(u16 w)

  • 含义:用户自定义汉字库调用(显示 16x16 汉字)
  • 该函数,出自oled0561.c文件

11.8 ASCII数据表来源

 
模拟电路仿真软件CircuitJSGraceUI5.0手册 (1)
Loading...
目录
0%
清弦子
清弦子
本人很懒
目录
0%