完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
扫一扫,分享给好友
前言: 关于中断简单介绍
中断的流程: 中断流程图: 中断方式传送数据具有可以有效提高单片机工作效率, 适合于实时控制系统等优点, 相对于查询方式更为常用。 当CPU处理某件事情的时候, 外部发生的某一事件(如电平的改变、脉冲边沿跳变、定时器/计数器溢出等)请求CPU迅速处理, 于是CPU暂时中断当前的工作, 转去处理发生的事件。 处理完该事件后, 再回到原来中断处, 继续工作。 这样的过程称为中断 上图为中断流程图 这个中断的概念是不是有点晦涩难懂? 主要是这个是书上的内容, 所以不是很形象. 我再解释一遍:想象一个场景, 1、当有一天你正在和川建国同志吃饭(你和他吃饭这个事情就是主程序);这样解释是不是清晰一点. 关于STM32F407的中断介绍可以看一下原子的或者火哥的pdf, 如果实在看得下去, 看官方手册也行。 这里就不赘述, 通过Cube配置以及编程过程理解这个外部中断会好很多, 通过现象再回去看本质 同样的, 还使用前面两篇博客所用到的工程即可, 也可以自己新建一个, 当做对自己的测试 2-1. 使用核心板自带按键 操作简介 : 通过板子上的两个按钮控制LED灯的亮灭 WK_UP按键按下则进入中断, 并翻转LED0的状态, KEY0按下时翻转LED1的状态. 两者虽然功能一样, 但却有质的区别 这里要做的和按键那一篇一样, 只是把其中一个按键改为中断, 而不是作为GPIO_input 所以可以看完上一篇直接看这一篇继续。 点击下方蓝字可以看上一篇的博客 第一节补充: 按键操作(CubeMX加HAL库学STM32系列) Step1 RCC&SYS配置这些都不用动, 时钟树的配置也不用动 (1) RCC&SYS以及时钟树配置不用改变 (2)更改一下PA0引脚配置: 把WKUP按键对应的PA0引脚模式由GPIO_input改为GPIO_EXIT0, 再把GPIO的配置更改一下即可 具体操作见下图注 : 如果是用的原来的工程, 只改这个即可, 其他的LED引脚和按键引脚不用动, 如果是自己又新建了一个工程, 那其他引脚按照前面两篇的介绍配置, 然后这个PA0按照这一篇配置就好了, 问题不大 对应GPIO配置改为下图 (3)中断NVIC配置 我们设置了中断, 在NVIC里面要记得使能PA0引脚的中断 NVIC ( Nested Vectored Interrupt Controller ) : 中断向量控制器(4)以上配置完之后就可以Generate CODE Step2 <程序编写> (1) 中断服务函数 stm32f4xx_it.c 这个文件里面看到我们要用的中断服务函数 我们要在中断里面做什么事情, 就要写在中断服务函数里面, 然后中断到来之后, 单片机就回去处理中断服务函数里面的工作 这个函数里面调用了 HAL_GPIO_EXTI_IRQHandler() 这个函数, 这个函数是处理GPIO外部中断的函数 可以看到里面的参数是GPIO_PIN_0, 因为我们用的是PA0即GPIOA的0引脚 Go to definition 一下, 可以看这个函数的定义 /** * @brief This function handles EXTI interrupt request. // 这个功能是处理外部中断请求 * @param GPIO_Pin Specifies the pins connected EXTI line // GPIO_Pin指定连接EXTI线的引脚 * @retval None // 无返回值 */ void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) { /* EXTI line interrupt detected */ if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); // 清除这个引脚的中断标识位 HAL_GPIO_EXTI_Callback(GPIO_Pin); // 回调外部中断 } } 综上: 中断服务函数最终会执行中断回调函数 HAL_GPIO_EXTI_Callback() (2) 中断回调函数 中断回调函数如下图 这个函数是空的, 所以我们可以自己重构这个函数, 在它内部实现我们要做的功能 我们需要重构中断回调函数 在main.c里面写入我们的代码 : 提示 : 不要忘了把代码写在 /* USER CODE BEGIN / / USER CODE END */ 之间 /* USER CODE BEGIN 0 */ // 重构中断回调函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { // 判断是否为WKUP引脚(即GPIO_PIN_0)进入中断 if (WKUP_Pin == GPIO_Pin) { HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin); // 翻转LED0的的电平状态 /* 下面这一句话与上面一句是等价的, 因为LED0是我们给这个引脚起的别名, 在main.h文件里面有对应的宏定义 */ //HAL_GPIO_TogglePin(GPIOF, GPIO_PIN_10); } } /* USER CODE END 0 */ (3) 主函数 在主函数里面用KEY0做一个一样的功能, 作为对比 /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // 在while(1)里面循环扫描, 判断读取的按键引脚状态 // 下面扫描KEY0按键的引脚信号 if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET) { HAL_Delay(10); // 延时10ms, 做一个软件的消抖, 防止因抖动而检测到按键按下 if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET) { // 做一个松手检测, 若KEY0一直是RESET(低电平),则一直在死循环 // 当KEY0位SET才会跳出,进而继续执行下面的对 LED1 的操作 while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET); HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin); } } } /* USER CODE END 3 */ (4) 编译下载到单片机, 看看单片机什么反应 左边的红色按键是WKUP, 左边的蓝色LED是LED0 仔细看一下动图中的效果可以发现, 中断的WKUP按键的功能并不是很完美, 这是因为没有消抖导致的, 在中断里面加个软件消抖的程序就可以了。 此外, 虽然两种方式实现的功能是一样的, 但是他们的区别就在于, KEY0翻转LED状态实在while(1)循环里面做的, 这就相当于主函数里面一直循环扫描这个按键的状态, 比较耗费资源. 而WKUP按键按下翻转LED是在中断里面做的,不影响主函数里面做其他事情. 如果以后做的东西要求写很多代码, 最好多多利用中断,这样会更高效。只有当事情来了CPU再去处理,其他时间主函数里面正常做其他事情。 这样既能提高MCU效率, 也不会让自己的代码全部写成一坨在主函数里面 |
|
|
|
只有小组成员才能发言,加入小组>>
3278 浏览 9 评论
2956 浏览 16 评论
3457 浏览 1 评论
8995 浏览 16 评论
4050 浏览 18 评论
1106浏览 3评论
571浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
568浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2301浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1858浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-23 01:57 , Processed in 1.365239 second(s), Total 102, Slave 82 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号