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

查看: 3598|回复: 9

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

[复制链接]

74

主题

1368

回帖

194

蝴蝶豆

版主

最后登录
2020-5-12
发表于 2015-11-24 22:49:05 | 显示全部楼层 |阅读模式
本帖最后由 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)

评分

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

查看全部评分

<
回复

使用道具 举报

60

主题

2051

回帖

31

蝴蝶豆

版主

最后登录
2020-12-9
发表于 2015-11-24 23:14:26 | 显示全部楼层
不闪是因为超过了人眼能分辨的范围了。
回复 支持 反对

使用道具 举报

74

主题

1368

回帖

194

蝴蝶豆

版主

最后登录
2020-5-12
 楼主| 发表于 2015-11-24 23:19:21 | 显示全部楼层
creep 发表于 2015-11-24 23:14
不闪是因为超过了人眼能分辨的范围了。

哈哈,顺便做了扫屏测试
回复 支持 反对

使用道具 举报

40

主题

1595

回帖

1

蝴蝶豆

论坛元老

最后登录
2018-7-23
发表于 2015-11-25 08:40:28 | 显示全部楼层
多谢分享
回复 支持 反对

使用道具 举报

307

主题

3125

回帖

0

蝴蝶豆

论坛元老

最后登录
2020-7-17
发表于 2015-11-25 09:05:30 | 显示全部楼层
赞个,这教程写的,好像回到课堂上了
回复 支持 反对

使用道具 举报

74

主题

1368

回帖

194

蝴蝶豆

版主

最后登录
2020-5-12
 楼主| 发表于 2015-11-25 09:51:23 | 显示全部楼层
沐紫 发表于 2015-11-25 09:05
赞个,这教程写的,好像回到课堂上了

(*^_^*)
被沐紫mm,赞了太荣幸了~~
回复 支持 反对

使用道具 举报

10

主题

1651

回帖

0

蝴蝶豆

论坛元老

最后登录
2020-2-15
发表于 2015-11-25 09:57:23 | 显示全部楼层
呵呵,天天更新。
回复 支持 反对

使用道具 举报

47

主题

3404

回帖

30

蝴蝶豆

版主

最后登录
2020-12-7
发表于 2015-11-25 09:57:23 | 显示全部楼层
多谢分享。。。。
回复 支持 反对

使用道具 举报

41

主题

2476

回帖

282

蝴蝶豆

论坛元老

最后登录
2020-12-8
发表于 2015-11-25 22:08:43 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

1

主题

879

回帖

6

蝴蝶豆

论坛元老

最后登录
2020-12-9
发表于 2018-3-15 09:01:29 | 显示全部楼层
很详细,跟羊脚印来的
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版