wolfgang2015 发表于 2015-11-24 22:49:05

2、NUCLEO-L476RG实验心得 (二)_LED闪闪亮续一 (按键、中断)

本帖最后由 wolfgang2015 于 2017-6-17 10:49 编辑

一、实验开始之前二、实验过程0、上次实验回顾 上次实验中,我们通过STM32CubeMX创建了一个Keil工程,增加了少量代码就实现了点亮LED灯的试验目的;板子能按HAL_Delay(x)函数,在x=500时,按照这个时间间隔闪亮熄灭LED灯。回顾实验,有几个核心函数出现在试验中:1、GPIO口操作函数,HAL_GPIO_WritePin: HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_SET) HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_RESET); 上面两个函数将GPIO口设置为高电平、低电平实现了LED的点亮、熄灭,制造了LED的闪亮。
2、GPIO口引脚的相关定义,LD2_GPIO_Port,LD2_Pin,GPIO_PIN_SET、GPIO_PIN_RESET 这几个引脚的定义在{项目名称}\Inc\ mxconstants.h 文件中,定义内容如下:

   #define LD2_Pin GPIO_PIN_5#define LD2_GPIO_Port GPIOA

   GPIO_PIN_5的定义在 {项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h 文件中


.......#define    GPIO_PIN_5                  ((uint16_t)0x0020)/* Pin 5    selected    */.......
   GPIOA的定义在 {项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal.h 文件中


.........
#define    PERIPH_BASE            ((uint32_t)0x40000000) /*!< Peripheral base address */.........#define    AHB2PERIPH_BASE       (PERIPH_BASE +    0x08000000)........#define    GPIOA_BASE               (AHB2PERIPH_BASE + 0x0000).......#define    GPIOA               ((GPIO_TypeDef *)    GPIOA_BASE).......
这里我们可以发现GPIOA是一个32位的寄存器,每个GPIO引脚都由这个积存器的bit来控制,而且这个寄存器的基地址由GPIOA_BASE 得来,GPIOA_BASE这个基地址是由AHB2PERIPH_BASE + 0x0000得来,AHB2PERIPH_BASE这个基地址是由 PERIPH_BASE +0x08000000得来;PERIPH_BASE这个基地址是由(uint32_t)0x40000000。这种用基址+偏移的方法来定义常量很不错,寄存器往往有一个固定的地址,如果编译、移植,如果偏移不变,只需要更换基址即可。
GPIO_TypeDef 结构体是在{项目名称}\Drivers\CMSIS\Device\ST\STM32L4xx\Include\stm32l476xx.h
typedef    struct
{__IO uint32_t MODER; /*!< GPIO port    mode register,         Address    offset: 0x00*/__IO uint32_t OTYPER; /*!< GPIO port    output type register,    Address    offset: 0x04*/__IO uint32_t OSPEEDR; /*!< GPIO port    output speed register,Address    offset: 0x08*/__IO uint32_t PUPDR; /*!< GPIO port    pull-up/pull-down register,Address    offset: 0x0C*/__IO uint32_t IDR; /*!< GPIO port    input data register,   Address    offset: 0x10*/__IO uint32_t ODR; /*!< GPIO port    output data register,Address    offset: 0x14*/__IO uint32_t BSRR; /*!< GPIO port bit    set/resetregister,Address offset: 0x18*/__IO uint32_t LCKR; /*!< GPIO port    configuration lock register,Address    offset: 0x1C*/__IO uint32_t AFR; /*!< GPIO    alternate function registers,      Address offset: 0x20-0x24 */__IO uint32_t BRR; /*!< GPIO Bit Reset    register,Address offset: 0x28*/__IO uint32_t ASCR; /*!< GPIO analog    switch control register,   Address    offset: 0x2C*/} GPIO_TypeDef;

GPIO_PIN_SET、GPIO_PIN_RESET的定义在{项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h 文件中
.............typedef    enum{GPIO_PIN_RESET = 0,GPIO_PIN_SET}GPIO_PinState;........................
定义GPIO_PIN_RESET 低电平,GPIO_PIN_SET 高电平。
3、亮与暗的时间间隔我们是用HAL_Delay(delay)函数来实现的,delay是在程序体中定义的一个变量值来定义的uint16_t delay = 500;HAL_Delay(uint32_tDelay) 是在{项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal.h 定义,在{项目名称} \Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c的函数中HAL_GetTick()-tickstart< Delay,来实现的。
HAL_GetTick是在{项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal.h 定义,在{项目名称} \Drivers\STM32L4xx_HAL_Driver\Src\stm32l4xx_hal.c的函数中用uwTick实现的。查资料得到, HAL_IncTick(void) 中断函数是1ms进来一次,也就是说uwTick+1就代表1ms。结论是:HAL_Delay(delay)是闪亮500ms、熄灭延时500ms。
1、新实验设想 当我们知道了点灯的原理之后,我就就在想,能否对试验进行改进,再增加些已有的外设,比如,用按钮B1来控制等的闪亮延时长短,当检查到GPIO连接的B1发生按键时发起延时值得改变。除了事用HAL_GetTick()之外还有那些定义的时钟函数可以使用。使用CubeMX打开芯片引脚设置,观察B1所用的PC13 引脚设置:设置为GPIO_EXIT13:GPIO口启用外部中断13。
GPIO 类型设置为外部中断,在上升沿触发检测。
NVIC:嵌套向量中断控制器:NestedVectored Interrupt Controller (NVIC)在NVIC这里我们查询我们设置的中断向量:
启用GPIO的中断。在CubeMX设置好后,创建实验代码。
2、实验步骤先在main.h中增加定义延时的值:

enum Enum_Delay{Delay_512=512,Delay_256=256,
Delay_128=128,
Delay_64=64,
Delay_32=32,
Delay_16=16,
Delay_8=8,
Delay_4=4,
Delay_2=2,
Delay_1=1,
Delay_0=0
} ;
   
在main.c中引用main.h,并在USER CODEBEGIN 0处定义延时初始值;USER CODE BEGIN 1处初始化亮灯的值;USER CODE BEGIN 3处将循环中加入闪亮等的相关操作(继续沿用前面试验中LED亮灯的设置;USER CODE BEGIN 4 处增加按键中断的相应代码,即修改延时的值。

....../* USER CODE BEGIN Includes */#include "main.h"/* USER CODE END Includes */......./* USER CODE BEGIN 0 */static enum Enum_Delay delay    =Delay_512;/* USER CODE END 0 */................../* USER CODE BEGIN 1 */uint8_t sta = ON;   /* USER CODE END 1 */......................./* USER CODE BEGIN 3 */while(1){   LED(sta);   sta =!sta;   HAL_Delay(delay);}/* USER CODE END 3 */......................../* USER CODE BEGIN 4 */void HAL_GPIO_EXTI_Callback(uint16_t    GPIO_Pin){   switch(delay) {       case Delay_512:    delay=Delay_256; break;       case Delay_256:    delay=Delay_128; break;       case Delay_128:    delay=Delay_64; break;       case Delay_64:    delay=Delay_32; break;       case Delay_32:    delay=Delay_16; break;       case Delay_16:    delay=Delay_8; break;       case Delay_8: delay=Delay_4;    break;       case Delay_4: delay=Delay_2;    break;       case Delay_2: delay=Delay_1;    break;       case Delay_1: delay=Delay_0;    break;       case Delay_0:    delay=Delay_512; break;       default: delay=Delay_512;   }}/* USER CODE END 4 */

3、实验的观察结果当我们把程序下载到板子中后,按下Reset按钮重起系统,这时LED闪亮,我们按下LB按钮,闪亮频率加快,大约按下6~7下后,几乎看不出闪亮了;
通过实验发现 Delay_8到Delay_0LED几乎不闪,这是为什么呢?频率太高?还是((HAL_GetTick() - tickstart) < Delay)的时代码有缺陷呢?这里通过Debug是无法跟踪到的,F5按键的频率决定了程序响应速度,我们只好通过其它方式来验证;HAL_GetTick 调试中固定值为 0x08000FD0。看来还得引入其他方法来验证,这里暂且不表,等到后边的实验来验证。

三、实验后的心得这个实验,可以了解STM32l4xx_hal_gpio.h/.c中 HAL_GPIO_EXTI_Callback回调函数的定义和调用。通过__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 定义回调函数,在程序运行空间中定义具体的实现内容。GPIO回调函数这仅是众多回调函数的一个案例,虽则对功能模块的熟悉还有机会接触到更多的系统 回调函数。经常看见有人问如何来避免抖动,这里用检测中断来判断按键。这种方法是比较好的一种方法,几乎不会出现按键抖动情况。而且这里使用检测GPIO的上升沿来触发中断,根据电路图上按键接的是一个下拉电阻,松开按键的瞬间引发上拉电平。检测电平上拉这时候的上升沿往往自只有一个,只要是按钮或按键没有接触不良的情况,几乎都不会出现抖动现象,若出现就是你要更换按键了,鼠标的微动开关就是出现连击情况就是这样,你要跟换鼠标微动开关/鼠标了。到这里,刚拿到板子时的延时程序就还原了,诸位是否有收获呢?以后的实验我们需要外设了,Uart TTL电平转串口的芯片、SPI 液晶显示屏、IIC时钟模块或者IIC的Flash、做PWM实验的电机驱动模块及直流电机等等,或许还有其他我们自己制作的模块。


前文回顾
   1、NUCLEO-L476RG试验(一)_LED闪闪亮(环境搭建与开发工具介绍)
后文链接
   3、NUCLEO-L476RG实验心得(三)_Eclipse环境配置
   4、NUCLEO-L476RG试验三_LED闪闪亮续(定时、串口)

creep 发表于 2015-11-24 23:14:26

不闪是因为超过了人眼能分辨的范围了。

wolfgang2015 发表于 2015-11-24 23:19:21

creep 发表于 2015-11-24 23:14
不闪是因为超过了人眼能分辨的范围了。

哈哈,顺便做了扫屏测试

lkl0305 发表于 2015-11-25 08:40:28

多谢分享

沐紫 发表于 2015-11-25 09:05:30

赞个,这教程写的,好像回到课堂上了

wolfgang2015 发表于 2015-11-25 09:51:23

沐紫 发表于 2015-11-25 09:05
赞个,这教程写的,好像回到课堂上了

(*^_^*)
被沐紫mm,赞了太荣幸了~~

yanhaijian 发表于 2015-11-25 09:57:23

呵呵,天天更新。

Paderboy 发表于 2015-11-25 09:57:23

:loveliness:多谢分享。。。。

dsjsjf 发表于 2015-11-25 22:08:43

谢谢分享

板子粉丝 发表于 2018-3-15 09:01:29

很详细,跟羊脚印来的
页: [1]
查看完整版本: 2、NUCLEO-L476RG实验心得 (二)_LED闪闪亮续一 (按键、中断)