1.1 GPIO 输出电压 - 实验篇
1.1 GPIO 输出电压 - 实验篇
Sarzn经过了刚刚原理部分的学习, 你已经对这个陌生的单片机有了一定的信心, 那么接下来我们开始实操吧!
注意观察, 这是一篇结构较为严谨的博客, 你可以从旁边的目录看到每一个 Step 之后所有的实验篇, 将遵循
Step X - 对应说明
- 具体步骤 1
- 步骤的解释 1
- 步骤的解释 2
- 具体步骤 2
希望这样的结构严谨的文章对你的学习会有帮助 !
我们这一章的内容是通过 GPIO 点灯
- BulePile - 蓝色小药丸, 就是我们使用的这个 STM32 F03C8T6 开发板
- 灯, 仔细观察你的开发板, 在靠近SWD 调试接口的位置有一个 PC13 指示灯, 我们点的便是这个灯
- GPIO, 前文提到的通用输入输出接口
这一部分是最基础的构建整个工程的部分.
今后你的每个新工程都要进行如下的步骤来进行相应的配置
Step 1 - 芯片选型
- 打开 CubeMX
- 搜索并选择对应型号的 MCU 芯片
Step2 - 工程配置
1. 配置复位时钟控制器 (RCC) - Reset Clock Control
配置成晶振 - Crystal/ceramic resonator
- 注意观察, 点选之后, 你的页面发生了怎样的变化?(说明了什么?)
2. 配置时钟树 - Clock Configuration
- HSE 一般设置为 8MHz
- 通过开发板晶振的频率来设置 HSE 的频率, 这里我们采用的芯片(F103C8T6)
- 梯形框框 - PLL Source Mux (PLL
时钟源选择器)选择主频通过 HSE 输出
- 还记得PLL吗?, 这个梯形是时钟源选择器, 是选择 PLL 的输入时钟, 不是 PLL 哦)
- 通过 PLL 倍率设置 - PLLMul 将系统时钟 - SYSCLK配置成 72MHz
如果你激起了有关时钟的好奇心那么详细细节请看番外篇
配置如下图所示
小练习: 用你自己的话说一说图上的这个过程吧! 注意我用绿色剪头标注的小节点都是什么意思 - 将回答写在下方的评论区
3. 选择正确的调试模式
根据不同的烧写器, 选择不同的调试模式
这里说的调试模式就是下图中的Debug,
他在 SYS下面 - 我们需要将 Debug 配置成 Serial
Wire
3. 配置引脚
根据原理图我们确定蓝色逍遥丸上的灯是挂载在 PC13 引脚上 原理图:


- LED 左侧连接到高电平
- LED侧连接到 PC13
这就说明, 如果 PC13 设置为高电平, LED 无电流通过此时为灯灭 ; 如果 PC13 变成低电平, LED 有电流通过, 此时为灯亮
我们前面学习了 GPIO 分为输入和输出两种不同的模式, 在这里我们需要控制 PC13 这个 GPIO 接口, 所以我们需要将其配置为输出模式
在 CubeMX 里面搜索 PC13, 并左键将其配置为输出模式 -
GPIO_Output
配置 GPIO 详情信息
GPIO output level用来确定默认电平, 这里我们选择 high 表示 PC13 默认为高电平, LED 中无电流通过. 现象就是 LED 默认不亮GPIO mode指定 GPIO 的模式, 这里我们选择推挽输出, 因为推挽对高低电平都有驱动能力GPIO Pull-up/Pull-down指定上下拉电阻, 这里是推挽模式, 选择什么都不影响推挽的效果, 但是为了最大程度减少上下拉电阻对推挽的驱动能力, 我们选择浮空Maximum output speed: 指的是引脚输出驱动器的翻转速率(slew rate),也就是引脚电平在高低之间切换时,边沿能跳得多快(上升/下降时间多短),而不是指你能多快地去翻转这个引脚. 看不懂没关系, 反正能 low 就 low. 如果感兴趣就去看番外篇 - GPIO 配置里的[Maximum output speed 是什么意思?]User Label: 给这个 GPIO 引脚写个备注吧!, 这里最好使用下划线_分割单词
配置工程管理
命名这个项目, 不要使用中文和空格
选择项目所在的文件夹, 这里就是我在 example 这个文件夹下面会有一个叫做example_F103_LED的项目文件夹
Toolchain/IDE选择 cmake, 方便我们使用 Clion 编写代码编译链接器 默认选择 GCC就行
在
code generator中勾选选择Generate peripheral initialization as a pair of '.c/.h' files per periphera表示给每个外设单独拆一对文件, 便于保持项目结构的清晰
Step3 - 生成项目
点右上角的GENERATE CODE 生成项目代码, 读条完成后使用
Clion 打开工程
在 Clion
中选择打开你的项目
配置好一个 OpenOCD运行配置, 如果对环境还有问题的可以接着这个番外篇看[番外篇 - STM32_CubeMX_CLion_全平台配置教程]
Step4 - 写代码
位置
在这个由 CubeMX 生成的项目中的手写代码不能乱放位置, 必须夹在 begin 和
end 之间. 如果不在这之间, 那么再次GENERATE CODE
的时候你的代码就会被覆盖
这里有一对begin 和 end 这就是我们这个实验要写代码的地方
因为我的灯要一直能够闪烁, 所以 我们需要把代码写在 main 函数的
while(1){} 中
函数
为了点灯我们会用到两个函数
HAL_GPIO_TogglePin()
它的作用是翻转(toggle)一个引脚的输出电平 : 当前是高电平就变成低,是低就变成高。每调用一次,电平就反转一次
我希望之后你们能别害怕函数的带参写法, 其实
HAL_GPIO_TogglePin()和HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)是同样的, 这里是第一次出现, 为了避免吓住你们我没有写参数, 以后的函数都会写上参数
它有两个参数:
GPIOx:哪个端口,比如GPIOCGPIO_Pin:哪个引脚,比如GPIO_PIN_13
如果你刚刚定义了自己的 GPIO 口备注, 比如你备注
Blue_Pill_LED , 那么
- 端口就可以写成
Blue_Pill_LED_GPIO_Port - 引脚就可以写成
Blue_Pill_LED_Pin
用法(两种写法等价,后者用的是 CubeMX 帮你生成的 Label 宏):
1 | HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); |
为什么可以这样呢?
你在 CubeMX 里面写的备注其实被自动转为代码了, 这段代码放在 main.h 中, 你可以看到
1 | /* Private defines -----------------------------------------------------------*/ |
这个自动帮你写好的 define 便是原因
HAL_Delay(uint32_t Delay)
它的作用是阻塞延时 单位是毫秒(ms) 程序执行到这里会”卡住”等待指定的毫秒数,然后才继续往下走
1 | HAL_Delay(500); // 延迟 500 ms |
Step5 - 构建并烧录代码
现在代码已经写完。接下来,先在电脑上完成编译构建、生成固件文件(.elf),然后再把这个固件烧录到开发板上运行
常见 bug
出现 1
Error: Error connecting DP: cannot read IDR
原因: - 你在 CubeMX 里,SYS 的 Debug 设成了 “No Debug”,而不是 “Serial Wire” - 线接错了, 检查接线
如果是选成了 No Debug, 解决方法如下: ### 救法一, BOOT0 法
Blue Pill 复位按钮旁边有两个黄色跳线帽,标着
BOOT0 和 BOOT1 原理是: 把 BOOT0 设为
1,芯片上电后会进自带的出厂
Bootloader,而不会运行你的程序,于是 SWD
就空出来了,就能重新连上烧录
但在救之前,必须先把出问题的固件改好,否则烧回去又会被锁
第 1 步:先在 CubeMX 里改好根因
CubeMX 打开你的 .ioc System Core - SYS -
Debug,把它设成 Serial Wire(不要选
No Debug)。顺便看一眼 PA13、PA14 没有被配成普通
GPIO。然后 重新生成代码 → 在 CLion 里
Build,得到一个修正后的 .elf
第 2 步:用 BOOT0 进 Bootloader
- 把 BOOT0 跳线帽移到
1的位置(靠 3.3V 那一侧),BOOT1 保持0 - 按一下板上的 RESET 按钮(或断电重新上电)
第 3 步:重新烧录修正后的固件
保持接线和供电不变,跑你那条 OpenOCD 命令(注意烧的是新生成的
.elf)。这次因为你的程序没在跑、SWD 是空的,应该能正常连上,读出
0x1BA01477,然后烧录成功
第 4 步:恢复 BOOT0
- 把 BOOT0 跳线帽移回
0 - 按 RESET。这次运行的是你修正后的程序(SWD 保持开启),灯应该正常闪,而且以后再烧录就不用动 BOOT0 了
救法二, connect under reset 法
如果你不想动跳线,也可以接上复位线来”复位时连接”:
- 把调试器的 RST/nRST 接到 Blue Pill 的 R(RESET)脚;
- 在你的
daplink.cfg里加一行(放在source target之前):
1 | reset_config srst_only srst_nogate connect_assert_srst |
- 这样 OpenOCD 会在连接时一直按住复位,让你的程序来不及运行去关 SWD,从而连上重烧















