zoukankan      html  css  js  c++  java
  • 第二节: 外部中断学习(用CubeMX学习STM32)

    STM32外部中断


    《用CubeMX学习STM32》

    注释 点击上面蓝字进入完整专栏,这个系列所有文章都会整合到这个专栏


    STM32外部中断

    前言: 关于中断简单介绍

    中断的流程:

    中断流程图:
    在这里插入图片描述

    中断方式传送数据具有可以有效提高单片机工作效率, 适合于实时控制系统等优点, 相对于查询方式更为常用。

    当CPU处理某件事情的时候, 外部发生的某一事件(如电平的改变、脉冲边沿跳变、定时器/计数器溢出等)请求CPU迅速处理, 于是CPU暂时中断当前的工作, 转去处理发生的事件。 处理完该事件后, 再回到原来中断处, 继续工作。 这样的过程称为中断 上图为中断流程图

    这个中断的概念是不是有点晦涩难懂? 主要是这个是书上的内容, 所以不是很形象. 我再解释一遍:想象一个场景,

    1、当有一天你正在和川建国同志吃饭(你和他吃饭这个事情就是主程序);
    2、突然有个电话打给你, 说有个十五亿的小单子需要你去处理一下(这件事就是中断源),
    3、 你停止吃饭, 川建国同志在这等你, 你去处理你的十五亿小合同(就是响应中断请求, 签合同过程就是中断服务程序),
    4、处理完合同之后你又回到餐桌继续和他就餐(这就是返回主程序, 然后继续执行主程序).

    这样解释是不是清晰一点.

    在这里插入图片描述

       关于STM32F407的中断介绍可以看一下原子的或者火哥的pdf, 如果实在看得下去, 看官方手册也行。 这里就不赘述, 通过Cube配置以及编程过程理解这个外部中断会好很多, 通过现象再回去看本质

       同样的, 还使用前面两篇博客所用到的工程即可, 也可以自己新建一个, 当做对自己的测试

    2-1. 使用核心板自带按键

    操作简介 :    通过板子上的两个按钮控制LED灯的亮灭 WK_UP按键按下则进入中断, 并翻转LED0的状态, KEY0按下时翻转LED1的状态. 两者虽然功能一样, 但却有质的区别

       这里要做的和按键那一篇一样, 只是把其中一个按键改为中断, 而不是作为GPIO_input 所以可以看完上一篇直接看这一篇继续。 点击下方蓝字可以看上一篇的博客

    第一节补充: 按键操作(CubeMX加HAL库学STM32系列)


    Step1 <CubeMX配置>


    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 ) : 中断向量控制器

    在中断向量表里面使能EXIT line0中断

    关于抢占优先级和子优先级: 当你使用多个中断的时候会用到这个。 就是为了防止多个中断冲突, 所以需要给他们每个中断排个号, 就不会乱了。 抢占优先级高的先执行, 若抢占优先级相同, 再看子优先级

    (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效率, 也不会让自己的代码全部写成一坨在主函数里面


    破晓之日, 你的所有努力都会助你看到黎明的第一缕阳光。
    请坚信: 你是一道光, 也是一把剑 ! 你终将刺破寒冰和黑夜, 重新定义你的人生 !

    Author : 李光辉
    date : Sun Dec 29 20:54:17 CST 2019
    blog ID: Kevin_8_Lee
    blog site : https://blog.csdn.net/Kevin_8_Lee/
  • 相关阅读:
    「联赛模拟测试33」题解
    分享几个基于vue的移动端框架
    11-15
    test
    联赛模拟测试20 C. Weed
    联赛模拟测试20 D. Drink
    联赛模拟测试24 联合权值·改
    联赛模拟测试21 表格
    近期的一些考试题目
    shell脚本执行错误 $' ':command not found
  • 原文地址:https://www.cnblogs.com/kevin-nancy/p/12569382.html
Copyright © 2011-2022 走看看