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/
  • 相关阅读:
    开始学习编写用于 Windows SideShow 设备的小工具【转】
    Windows Mobile 6.5 Developer Tool Kit 下载
    Microsoft Security Essentials 微软免费杀毒软件下载
    SQL Server 2008 空间数据存储摘抄(SRID 点 MultiPoint LineString MultiLineString 多边形 MultiPolygon GeometryCollection)
    Vista Sidebar Gadget (侧边栏小工具)开发教程 (2)
    Vista Sidebar Gadget (侧边栏小工具)开发教程 (4)
    负载测试、压力测试和性能测试的异同
    Windows Server 2008 Vista Sidebar Gadget (侧边栏小工具) 入门开发实例
    Silverlight Tools 安装失败 解决办法
    SQL Server 2008 空间数据库 空间索引概念及创建(取自帮助)
  • 原文地址:https://www.cnblogs.com/kevin-nancy/p/12569382.html
Copyright © 2011-2022 走看看