STM32基于HAL库的中断流水灯
实验要求:以 STM32 最小系统核心板(STM32F103C8T6)+面板板+3 只 LED 搭建电路,控制 LED 灯,轮流闪烁,间隔时长 1 秒。用 GPIOA 端某一管脚接一个开关(用杜邦线模拟代替)。采用中断模式编程,当开关接高电平时,LED 流水灯工作;接低电平时,LED 流水灯停止工作。
本次实验所使用的 STM32CubeMX 版本为 6.15.0
1.创建 CubeMX 项目
① 打开 STM32CubeMX 将鼠标移至 File 选择 New Project。
② 在弹出的窗口中搜索自己要使用的芯片,然后双击选择,之后就会看见芯片出现在界面中。
Tips:对于常用的芯片可以点击旁边的 ⭐ 收藏方便之后更快找到。
这样一个基本项目就创建完成了。
2.芯片配置
① 点击左侧侧边栏 System Core 然后再点击 SYS,将里面的 Debug 模式改为 Serial Wire,方便我们之后使用 ST-LINK 或其他方式来进行程序的烧录。
② 点击左侧 RCC,将里面的 High Speed Clock(HSE)调为 Crystal/Ceramic Resonator 来打开高速晶振时钟。
③ 接下来选择上方 Clock Configuration 来配置时钟树,将 PLL Source Mux 的输入选择为 HSE,再将 System Clock Mux 的输入选为 PLLCLK 这样我们的时钟源就配置好了。
④ 接着我们返回一开始的界面即 Pinout & Configuration 界面来配置 GPIO 口。点击你想要使用的 GPIO 口(这里我以 PA5 作为示例)选择 GPIO_Output 即可将其设置为输出模式作为之后用来点灯的 GPIO 口。
⑤ 点击左侧的 GPIO,再选择我们想要配置的 GPIO 口,然后进行如下操作:
a.GPIO output level 改为 High(即输出电平为高电平)。
b.GPIO mode 改为 Output Push Pull(即输出模式为推挽输出模式)。
c.GPIO Pull-up/Pull-down 改为 Pull-up(即 GPIO 的电平上拉到高电平)。
d.Maximum output speed 选为 Low(即最大输出速度为 Low,对于本次实验点灯来说此设置无明显影响)
e(可选).User Label 栏后可自定义 IO 口名称方便自己查看(尤其是使用端口较多时),并且可以在后续编程中使用,这里我将 PA5 命名为 LED0。
重复以上操作来配置其他两个 GPIO 口。这里我使用 PA5, PA6, PA7 这三个 GPIO 口作为流水灯的输出。
⑥ 选择一个 GPIO 口作为开关,这里我使用 PA2 作为示例。点击想要使用的 GPIO 口选择设置为 GPIO_EXTIx 也就是第 x 号外部中断线(x 的数字由端口数字决定)。
⑦ 点击左侧的 GPIO 选择刚刚设置为 GPIO_EXTIx 的 GPIO 口将其进行一下设置。
a.GPIO mode 设置为 External Interrupt Mode with Falling edge trigger detection(即下降沿触发)。
b.GPIO Pull-up/Pull-down 改为 Pull-down(即 GPIO 的电平下拉到低电平)。
c(可选).User Label 栏后可自定义 IO 口名称方便自己查看,这里我将其命名为 KEY0。
⑧ 点击左侧 NVIC 即中断控制器,然后勾选开启中断向量 EXTI line2 interrupt。
Tips:由于 EXTI0 到 EXTI4 有自己的中断向量,5-9 共享 EXTI9_5, 而 10-15 共享 EXTI15_10,所以选择不同的 GPIO 口此处所勾选的会有所不同。例如选择的 GPIO 口编号在 5-9 之间此处应勾选 EXTI line [9:5] interrupt。
⑨ 选择上方 Project Manager, 然后在 Project Name 栏为项目命名(最好确保名字及文件路径只包含英语或下划线‘__’因为 Keil5 不会识别中文),然后将 Toolchain/IDE 一栏改为 MDK-ARM 即使用 Keil5。
⑩ 点击左侧 Code Generator 勾选上 Generated files 的第一项,然后点击右上角的 GENERATE CODE 来生成代码,最后再点击弹出窗口中的 Open Project 即可打开 Keil5 对代码进行编写了。
Tips1:如果点击 GENERATE CODE 后提醒没有安装或需要更新包,点击下载即可。但下载需要登陆 ST 的账号,没有账号的可以自己创建一个。
Tips2:如果在已经打开 Keil5 对代码进行的情况下,由于更改了 CubeMX 项目中的配置需要再次生成代码不需要点击 Open Project,因为直接回到 Keil5 中时 Keil5 会提醒你文件更新了点击 OK 更新文件即可,如果点击 Open Project 可能会打开多个 Keil5。
3.代码实现
① 打开 Keil5 后点击左侧 Application/User/Core 文件夹旁边的 + 号展开,然后选择 main.c 文件,接着再 main.c 中找到 int main(void)
函数(64 行左右)中的 while(1)
这里就是我们编写流水灯主要功能的地方。
② 接下来我们来编写流水灯的主要代码。注意代码一定要在 /* USER CODE BEGIN WHILE */
与 /* USER CODE END WHILE */
之间,因为之后如果需要再次使用 STM32CubeMX 生成代码时在只有 /* xxx BEGIN xxx */
与 /* xxx END xxx */
的之间的代码才会被保留,其余位置的代码均会被删除。流水灯代码实现如下。
Tips:如果在之前的步骤中没有对 GPIO 口进行命名则应对部分代码进行修改,例如:
LED0_GPIO_Port,LED0_Pin
应更改为 GPIOA, GPIO_Pin_5
。
/* USER CODE BEGIN WHILE */
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); //设定初始状态为全灭
while (1)
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_SET){
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_SET) //判断按钮是否是高电平
{
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET); //LED0亮
HAL_Delay(1000); //间隔1秒
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET); //LED0灭
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); //LED1亮
HAL_Delay(1000);
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); //LED1灭
HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET); //LED2亮
HAL_Delay(1000);
HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); //LED2灭
}
}
/* USER CODE END WHILE */
至此一个正常的流水灯就已经完成了,效果如下。
③ 然后来为流水灯添加一个开关并使用中断来控制。在左侧 Application/User/Core 文件夹中找到并打开 stm32f1xx_it.c 文件,然后下拉到该文件最底端就能看到中断处理函数 void EXTI2_IRQHandler(void)
(其中 EXTI 后面的数字与使用的 GPIO 端口有关),我们就可以在这里编写开关控制的代码了。
代码实现如下:
/* USER CODE BEGIN EXTI2_IRQn 0 */
while(1){
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_SET){ //检测开关是否是高电平
break; //退出死循环,继续执行流水灯
}
}
/* USER CODE END EXTI2_IRQn 0 */
至此我们已成功为流水灯添加了中断开关的功能了,其效果是当接通时流水灯正常工作,断开时暂停并保持暂停时的状态,效果如下。