由于内容比较多,为了更详细的说明,我也会花比较多的时间研究。而为了及时更新,我会把有些文章分成几个部分,谢谢大家理解 。
目录
前文链接:【蓝桥杯嵌入式】四、各种外设驱动(三)NVIC中断程序通用步骤——分析与配置-CSDN博客
三、代码编写
先引入led.c和key.c
将main( )函数中的代码清除。
只需要写中断服务函数即可。
1、快速找到中断服务函数的方法:
先编译一下,建立文件之间的关联
CubeMX为我们自动生成的中断服务函数都在"stm32g4xx_it.c"文件中。
双击打开这个文件,直接向下滑动到最底部,中断服务函数就在这里:
现在找到了中断服务函数;
比赛时,你可以直接在这里处理中断。但更标准的做法是重写中断回调函数,感兴趣的可以去拓展部分查看。
2、编写中断服务函数
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(KEY1_Pin);
/* USER CODE BEGIN EXTI0_IRQn 1 */
/* USER CODE END EXTI0_IRQn 1 */
}
这里有两个用户代码段,HAL_GPIO_EXTI_IRQHandler(KEY1_Pin)函数会清除中断标志位,为了避免无法响应多次连续中断应该先清除标志位,所以在第二个代码段实现功能会更合适。
根据之前的设计,编写代码。(建议自己写一下练练手)
在中断回调函数中编写代码,当KEY2按下时所有LED点亮,KEY1按下时熄灭LED1~4(为了验证正确性,这里延时1s)。KEY3按下后会产生软中断,出发EXTI0中断。
代码如下:
/**
* @brief This function handles EXTI line0 interrupt.
*/
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(KEY1_Pin);
/* USER CODE BEGIN EXTI0_IRQn 1 */
LED_change(LED5_Pin|LED6_Pin|LED7_Pin|LED8_Pin);
HAL_Delay(1000);
/* USER CODE END EXTI0_IRQn 1 */
}
/**
* @brief This function handles EXTI line1 interrupt.
*/
void EXTI1_IRQHandler(void)
{
/* USER CODE BEGIN EXTI1_IRQn 0 */
/* USER CODE END EXTI1_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(KEY2_Pin);
/* USER CODE BEGIN EXTI1_IRQn 1 */
LED_change(LED_ALL);
/* USER CODE END EXTI1_IRQn 1 */
}
/**
* @brief This function handles EXTI line2 interrupt.
*/
void EXTI2_IRQHandler(void)
{
/* USER CODE BEGIN EXTI2_IRQn 0 */
/* USER CODE END EXTI2_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(KEY3_Pin);
/* USER CODE BEGIN EXTI2_IRQn 1 */
__HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0);
/* USER CODE END EXTI2_IRQn 1 */
}
运行结果如下:
四、各种外设驱动(三)NVIC中断程序通用步骤,测试结果
可以发现,按下KEY1后,立即按下KEY2,是没反应的,大约1s后,才会点亮所有灯。说明程序运行正常。
拓展:中断回调函数
1、查找
a、根据文件搜索
可以看到中断服务函数调用了中断通用处理函数;
而中断处理函数会调用中断回调函数;
(就是这样一个俄罗斯套娃,这是为了为了可以让这种框架通用于各种芯片)
然后鼠标放到 HAL_GPIO_EXTI_IRQHandler 函数位置上,右击,然后点击 "Go To Definition ..."
如果,没问题的话,就会跳转到这里:
用同样的方式,右击 HAL_GPIO_EXTI_Callback 函数,跳转到这里:
这就找到了弱回调函数:HAL_GPIO_EXTI_Callback
如果熟练的话,找到这里只需要十几秒钟。
b、记住部分名称直接搜索
优点:快
缺点:要背部分函数名
HAL库中的一般外设的中断函数名都有规律。
一般为:HAL_XXXX_XXXX_Callback或HAL_XXXX_xxxxCallback
所以我们只需要先搜索 HAL_GPIO_EXTI
现在选择 "Find in files",输入搜索内容后,点击Find All
下面就会显示所有出现 HAL_GPIO_EXTI 字段的位置,将它向上拉起,如图:
在一列冒号后面,很容易找到有 "__weak ..."的函数,那就是我们要找的,双击即可跳转到改位置。
2、编写中断回调函数
直接从 void 开始复制,复制如下内容:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
到main.c 的下图位置处:(在最下面然后朝上一点的位置,这里是实现弱函数的位置)
让它变成这样:
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
}
/* USER CODE END 4 */
然后实现这个函数就行。
因为是通用回调函数,所以这里就需要做一些判断。
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==KEY1_Pin) //0
{
}
else if(GPIO_Pin==KEY2_Pin) //1
{
}
else if(GPIO_Pin==KEY3_Pin) //2
{
}
}
/* USER CODE END 4 */
根据之前的设计,编写代码。(建议自己写一下练练手)
在中断回调函数中编写代码,当KEY2按下时所有LED点亮,KEY1按下时熄灭LED1~4(为了验证正确性,这里延时1s)。KEY3按下后会产生软中断,出发EXTI0中断。
代码如下:
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==KEY1_Pin) //1
{
LED_change(LED5_Pin|LED6_Pin|LED7_Pin|LED8_Pin);
HAL_Delay(1000);
}
else if(GPIO_Pin==KEY2_Pin)//2
{
LED_change(LED_ALL);
}
else if(GPIO_Pin==KEY3_Pin)//2
{
__HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0);
}
}
/* USER CODE END 4 */
运行结果完全相同。