STM32 HAL库编程(2)—— 外部中断、ADC
学习外部中断和ADC,使用战舰mini开发板文章目录
- STM32 HAL库编程(2)—— 外部中断、ADC
- 前言
- 一、新建工程
-
- 1. 查看手册,看芯片型号和LED、按键引脚
- 2. 使用CUBEMX新建工程
- 二、配置按键引脚为外部中断
-
- 1. 配置引脚为外部中断
- 2. 配置中断方式
- 3. 配置中断优先级
- 三、代码介绍
- 四、编写代码
-
- 1. 中断回调函数
- 2. 烧录测试
- 五、代码优化
- 六、串口配置
-
- 1. 串口介绍
- 2. 串口配置
- 3. 串口代码介绍
- 4. 编写串口代码1——发送数据
- 5. 使用printf发送数据
前言
- 外部中断:指的是某一个引脚从低电平变高电平,或高电平变低电平而产生的中断,区别于定时器内部中断。这个常用于按键读取,按键按下去之后,比如从高电平变成低电平,自动就跳到了中断函数。如果没有中断函数,就需要一直在while中读取按键的高低电平,这种轮询方式效率太低。
- ADC:模数转换,将模拟信号转换位数字信号。STM32可以读取的模拟电压位0-3.3V,12位精度(即模拟信号的0-3.3 转换为 数字信号的0-4095)。
一、新建工程
1. 查看手册,看芯片型号和LED、按键引脚
2. 使用CUBEMX新建工程
依照步骤:选择CPU、选择debug方式、配置时钟、配置LED引脚、最后工作来进行。并且在生成的代码上测试LED闪烁代码,观察是否正常运行。
二、配置按键引脚为外部中断
1. 配置引脚为外部中断
- 根据上方的原理图,设置三个按键为外部中断方式,外部中断的英文名为EXTI。在配置中断时,会发现EXTI后有一个中断号,这是与引脚号对应的,例如PA0就是EXTI0,PC5就是EXTI5,有中断号才能判断是哪一个引脚产生的中断。
- 实际上,PA0,PB0,PC0等都是共用中断EXTI0的,其他EXTI1、EXTI2等也都是这样。这样做的目的是减少外部中断数量,单片机速度本来就不高,太多的中断会降低运行效率。
- 那如果PA0、PB0都用到了中断EXTI0,如何判断出中断是由哪一个引脚产生的呢?一个办法就是在产生中断后,在中断函数中读取PA0和PB0的引脚高低电平,从而判断出哪一个引脚发生了中断。
- 产生了中断,代码会自动跳到中断函数中,需要运行的代码就放在中断函数中,比如转变LED灯的亮灭。在以前的库函数中,中断0-4由单独的中断函数,中断5-9共用一个中断函数,中断10-15也共用一个中断函数,但HAL库中,所有的外部中断共用一个中断函数。进入中断函数后,首先需要通过**中断句柄(中断号)**判断是哪一个中断。
2. 配置中断方式
- 中断方式:上升沿中断和下降沿中断,最常用的两种中断方式。上升沿中断就是当引脚从低电平变成高电平时,会产生一个中断,下降沿中断反之。比如一个按键,没按的时候时低电平,按下去的时候是高电平,那我就配置这个引脚的中断方式为上升沿中断。
- 引脚上拉下拉:一个引脚默认既不是高电平也不是低电平,这样就可能导致中断异常。为稳定中断,我们需要通过上拉或下拉的方式,让引脚在平时的状态下,保持高电平或低电平。原理图中按键都没有设置外部上拉或者下拉,我们需要配置KEY0和KEY1为上拉,WK_UP为下拉。
- 三个按键的中断配置为:PA0:标签WK_UP,上升沿中断,引脚下拉;PC5:标签KEY0,下降沿中断,引脚上拉;PA15:标签KEY1,下降沿中断,引脚上拉。
配置完成后的图如下图:可以顺带设置LED的标签为LED0和LED1
3. 配置中断优先级
三、代码介绍
- 右击上方的中断提交函数,点击查看该函数的定义:
四、编写代码
1. 中断回调函数
代码为不同引脚让LED灯发生变化,代码如下。只需要将中断回调函数复制到放在合适的位置,每次中断就会自动调用这个函数。
2. 烧录测试
五、代码优化
问题:对于按键而言,会有按键抖动,即在按下去的时候,会产生多个上升沿和下降沿,导致多次产生中断。
解决:一个是通过添加滤波电容的方式,硬件方式消去按键的抖动信号;另一个办法是添加延时并判断,软件方式消去抖动。由于电路已经设计,这里使用软件方式。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == WK_UP_Pin) // 按键WK_UP中断
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port, WK_UP_Pin) == 1)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // 更改LED0亮灭
}
}
else if(GPIO_Pin == KEY0_Pin) // KEY0中断
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == 0)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); // 更改LED1亮灭
}
}
else if(GPIO_Pin == KEY1_Pin) // KEY1中断
{
HAL_Delay(20);
if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == 0)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // 更改LED0亮灭
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); // 更改LED1亮灭
}
}
}
六、串口配置
1. 串口介绍
- 串口是单片机中很常见的一种通信方式,可以与电脑通信、与传感器通信、与其他单片机通信等。
- 异步串口(UART)是用的最多的一种串口,仅包含TX和RX两条通信线。
2. 串口配置
- 可以看到,对于这个stm32而言,有很多个串口。这里我们选择串口1,并配置为异步串口,波特率为115200。
- 对于一个串口,它可以映射到不同的引脚上,除了这里使用的PA9和PA10,串口1还可以使用PB6和PB7,
3. 串口代码介绍
4. 编写串口代码1——发送数据
发送数据使用以下函数进行:
在main中编写以下代码,每隔1s发送hello给电脑:
uint8_t buff[10] = { "hello\r\n"};
HAL_UART_Transmit(&huart1, buff, 10, 1000);
HAL_Delay(1000);
连接USB到电脑,发开串口助手,注意选择对应的波特率115200。
5. 使用printf发送数据
在C语言学习中,printf可以很方便的输出内容,例如printf(“a is %d”, a)可以输出a的值。为使用printf,需要在代码中添加stdio.h库和重定向函数,如下图。
#include "stdio.h"
// 重定向函数,可以使用printf
int fputc(int ch,FILE *f)
{
uint8_t temp[1]={ ch};
HAL_UART_Transmit(&huart1,temp,1,2);
}
在while中测试printf,输出一些内容测试一下。