你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
wolfgang 提问时间:2015-11-24 22:49 /
本帖最后由 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/reset  register,  Address offset: 0x18  */
  __IO uint32_t LCKR; /*!< GPIO port    configuration lock register,  Address    offset: 0x1C  */
  __IO uint32_t AFR[2]; /*!< 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。
  [url=]结论是:HAL_Delay(delay)是闪亮500ms、熄灭延时500ms。[/url]

1、新实验设想
当我们知道了点灯的原理之后,我就就在想,能否对试验进行改进,再增加些已有的外设,比如,用按钮B1来控制等的闪亮延时长短,当检查到GPIO连接的B1发生按键时发起延时值得改变。除了事用HAL_GetTick()之外还有那些定义的时钟函数可以使用。
  使用CubeMX打开芯片引脚设置,观察B1所用的PC13 引脚设置:
2_图1.jpg
设置为GPIO_EXIT13:GPIO口启用外部中断13。
2_图2.jpg
GPIO 类型设置为外部中断,在上升沿触发检测。
2_图3.jpg
NVIC:嵌套向量中断控制器:NestedVectored Interrupt Controller (NVIC)
在NVIC这里我们查询我们设置的中断向量:
2_图4.jpg
启用GPIO[15:10]的中断。
在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回调函数这仅是众多回调函数的一个案例,虽则对功能模块的熟悉还有机会接触到更多的[url=]系统[/url][ZL2] 回调函数。
  经常看见有人问如何来避免抖动,这里用检测中断来判断按键。这种方法是比较好的一种方法,几乎不会出现按键抖动情况。而且这里使用检测GPIO的上升沿来触发中断,根据电路图上按键接的是一个下拉电阻,松开按键的瞬间引发上拉电平。检测电平上拉这时候的上升沿往往自只有一个,只要是按钮或按键没有接触不良的情况,几乎都不会出现抖动现象,若出现就是你要更换按键了,鼠标的微动开关就是出现连击情况就是这样,你要跟换鼠标微动开关/鼠标了。
  到这里,刚拿到板子时的延时程序就还原了,诸位是否有收获呢?以后的实验我们需要外设了,Uart TTL电平转串口的芯片、SPI 液晶显示屏、IIC时钟模块或者IIC的Flash、做PWM实验的电机驱动模块及直流电机等等,或许还有其他我们自己制作的模块。


2、NUCLEO-L476RG试验(二)_LED闪闪亮续一(按键、中断).pdf (549.49 KB, 下载次数: 43)

评分

参与人数 1 ST金币 +30 收起 理由
沐紫 + 30

查看全部评分

收藏 1 评论9 发布时间:2015-11-24 22:49

举报

9个回答
creep 回答时间:2015-11-24 23:14:26
不闪是因为超过了人眼能分辨的范围了。
wolfgang 回答时间: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
赞个,这教程写的,好像回到课堂上了
wolfgang 回答时间: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
多谢分享。。。。
埃斯提爱慕 回答时间:2015-11-25 22:08:43
提示: 作者被禁止或删除 内容自动屏蔽
板子粉丝 回答时间:2018-3-15 09:01:29
很详细,跟羊脚印来的

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版