本帖最后由 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 引脚设置: 设置为GPIO_EXIT13:GPIO口启用外部中断13。
GPIO 类型设置为外部中断,在上升沿触发检测。
NVIC:嵌套向量中断控制器:NestedVectored Interrupt Controller (NVIC) 在NVIC这里我们查询我们设置的中断向量:
启用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)
|