目录
STM32F1外部中断的硬件设计
STM32F1外部中断的软件设计
通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下:
中断在嵌入式应用中占有非常重要的地位,几乎每个控制器都有中断功能。中断对保证紧急事件在第一时间处理是非常重要的。 设计使用外接的按键作为触发源,使得控制器产生中断,并在中断服务函数中实现控制RGB彩灯的任务。
STM32F1外部中断的硬件设计
外部中断设计实例的硬件设计同按键的硬件设计,如图所示。 从按键的原理图可知,这些按键在没有被按下的时候,GPIO引脚的输入状态为低电平 (按键所在的电路不通,引脚接地),当按键按下时,GPIO引脚的输入状态为高电平(按键所在的电路导通,引脚接到电源)。轻触按键在按下时会使得引脚接通,通过电路设计可以使得按下时产生电平变化。 在本实例中,我们根据图5-33所示的电路设计一个示例,通过按键控制LED,如下: (1)按下KEY1,LED变亮;再按下KEY1,LED变暗。 (2)按下并弹开KEY2,LED变亮;再按下并弹开KEY2,LED变暗。
STM32F1外部中断的软件设计
下面讲述如何通过STM32CubeMX新建工程、如何通过Keil MDK实现工程。 1. 通过STM32CubeMX新建工程 通过STM32CubeMX新建工程的步骤如下:
(1)新建文件夹 Demo目录下新建文件夹EXTI,这是保存本章新建工程的文件夹。
(2)新建STM32CubeMX工程 在STM32CubeMX开发环境中新建工程。
(3)选择MCU或开发板 Commercial Part Number和MCUs/MPUs List选择STM32F103ZET6,选择Start Project启动工程。
(4)保存STM32Cube MX工程 使用STM32CubeMX菜单File→Save Project,保存工程。
(5)生成报告 使用STM32CubeMX菜单File→Generate Report生成当前工程的报告文件。
(6)配置MCU时钟树 STM32CubeMX Pinout & Configuration子页面下,选择System Core→RCC,High Speed Clock(HSE)根据开发板实际情况,选择Crystal/Ceramic Resonator(晶体/陶瓷晶振)。
STM32CubeMX切换到Clock Configuration子页面下,根据开发板外设情况配置总线时钟。此处配置PLL Source Mux为HSE,PLLMul为9倍频72MHz,System Clock Mux为PLLCLK,APB1 Prescaler为X2,其余默认设置即可。
(7)配置MCU外设 根据LED和KEY电路,整理出MCU连接的GPIO引脚的输入/输出配置,如表所示。
进行GPIO引脚配置。具体步骤如下。 STM32CubeMX Pinout & Configuration子页面下选择System Core→GPIO,对使用的GPIO口进行设置。LED输出端口:LED1_RED(PB5)、LED2_GREEN(PB0)和LED3_BLUE (PB1)。按键输入端口:KEY1(PA0)和KEY2(PC13),配置为GPIO_EXTI模式。 作为中断/时间输入线把GPIO配置为中断上升沿触发模式,这里不使用上拉或下拉,由外部电路完全决定引脚的状态。按键1使用下降沿触发方式,按键2为上升沿触发方式。 PA0配置为下降沿触发方式External lnterrupt Mode with Falling edge trigger detection和不使用上拉或下拉No pull-up and no pull-down,PC13配置为上升沿触发方式External lnterrupt Mode with Rising Trigger detection和不使用上拉或下拉No pull-up and no pull-down
切换到STM32CubeMX Pinout & Configuration子页面下选择System Core→NVIC,修改Priority Group为2 bits for pre-emption priority(2位抢占优先级),Enabled栏勾选EXTI line0 interrupt和EXTI line[15:10] interrupts。修改Preemption Priority(抢占优先级)和Sub Priority(子优先级)
Code Generation 页面Select for init sequence ordering栏勾选EXTI line0 interrupt和EXTI line[15:10] interrupts。NVIC Code Generation配置页面
(8)配置工程 STM32CubeMX Project Manager子页面Project栏下Toolchain/IDE选择MDK-Arm,Min Version选择V5,可生成Keil MDK工程;选择STM32CubeDE,可生成STM32CubeIDE工程。
(9)生成C代码工程 STM32CubeMX主页面,单击GENERATE CODE按钮生成C代码工程。
通过Keil MDK实现工程 通过Keil MDK实现工程的步骤如下:
(1)打开工程 打开EXTI\MDK-Arm文件夹下的工程文件。
(2)编译STM32CubeMX自动生成的MDK工程 在MDK开发环境中通过菜单Project→Rebuild all target files或工具栏 Rebuild按钮编译工程。
(3)STM32CubeMX自动生成的MDK工程 main.c文件中函数main()依次调用了HAL_Init()函数用于复位所有外设,初始化Flash接口和Systick定时器。SystemClock_Config()函数用于配置各种时钟信号频率。MX_GPIO_Init()函数初始化GPIO引脚。 在STM32CubeMX中,为LED和KEY连接的GPIO引脚设置了用户标签,这些用户标签的宏定义在文件main.h里。代码如下:
/* Private defines ---------------------------------------------------*/
#define KEY2_Pin GPIO_PIN_13
#define KEY2_GPIO_Port GPIOC
#define KEY2_EXTI_IRQn EXTI15_10_IRQn
#define KEY1_Pin GPIO_PIN_0
#define KEY1_GPIO_Port GPIOA
#define KEY1_EXTI_IRQn EXTI0_IRQn
#define LED2_GREEN_Pin GPIO_PIN_0
#define LED2_GREEN_GPIO_Port GPIOB#define LED3_BLUE_Pin GPIO_PIN_1
#define LED3_BLUE_GPIO_Port GPIOB
#define LED1_RED_Pin GPIO_PIN_5
#define LED1_RED_GPIO_Port GPIOB
/* USER CODE BEGIN Private defines */
文件gpio.c包含了函数MX_GPIO_Init()的实现代码,如下。
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOB,
LED2_GREEN_Pin|LED3_BLUE_Pin|LED1_RED_Pin, GPIO_PIN_SET);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = KEY2_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(KEY2_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = KEY1_Pin;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(KEY1_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pins : PBPin PBPin PBPin */GPIO_InitStruct.Pin = LED2_GREEN_Pin|LED3_BLUE_Pin|LED1_RED_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
本实验使用到了中断,因此main()函数调用中断初始化函数MX_NVIC_Init()。MX_NVIC_Init()是在文件main.c中定义的函数,它的代码里调用了HAL_NVIC_SetPriority()和HAL_NVIC_EnableIRQ(),用于设置中断的优先级和使能中断。MX_NVIC_Init()实现的代码如下。
static void MX_NVIC_Init(void) { /* EXTI0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); /* EXTI15_10_IRQn interrupt configuration */ HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); }
(4)新建用户文件 在EXTI\Core\Src下新建bsp_led.c和bsp_exti.c,在EXTI\Core\Inc下新建bsp_led.h和bsp_exti.h。将bsp_led.c和bsp_exti.c添加到工程Application/User/Core文件夹下。 (5)编写用户代码 bsp_led.h和bsp_led.c文件实现LED操作的宏定义和LED初始化。 stm32f1xx_it.c中根据STM32CubeMX的NVIC配置,自动生成相应的中断函数。本实例自动生成的外部中断函数,如下。
void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY1_Pin); } void EXTI15_10_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY2_Pin); } bsp_exti.h和bsp_exti.c添加外部中断的回调函数HAL_GPIO_EXTI_Callback()的处理。按键1让LED1翻转其状态,按键2让LED2翻转其状态。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == KEY1_Pin){// LED1 取反 LED1_TOGGLE;} else if(GPIO_Pin == KEY2_Pin) {// LED2 取反 LED2_TOGGLE;} }
main.c文件添加对用户自定义头文件的引用。 /* Private includes ---------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include " bsp_led.h" #include "bsp_exti.h" /* USER CODE END Includes */ main.c文件添加对LED的初始化,按键的处理在中断服务程序中已完成,主函数不再操作。
/* USER CODE BEGIN 2 *//* LED 初始化 */LED_GPIO_Config();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}
(6)重新编译工程 重新编译添加代码后的工程。
(7)配置工程仿真与下载项 在MDK开发环境中通过菜单Project→Options for Target或工具栏 配置工程。 打开Debug选项卡,选择使用的仿真下载器ST-Link Debugger。Flash Download下勾选Reset and Run选项。单击确定。
(8)下载工程 连接好仿真下载器,开发板上电。 在MDK开发环境中通过菜单Flash→Download或工具栏 下载工程。
工程下载完成后,此时RGB彩色灯是暗的。如果按下开发板上的按键1,RGB彩灯变亮,再按下按键1,RGB彩灯又变暗;如果按下开发板上的按键2并弹开,RGB彩灯变亮,再按下开发板上的KEY2并弹开,RGB彩灯又变暗。按键按下表示上升沿,按键弹开表示下降沿,跟软件设置是一样的。