4、NUCLEO-L476RG试验三_LED闪闪亮续(定时、串口)
本帖最后由 wolfgang2015 于 2017-6-17 10:51 编辑一、实验开始之前二、实验过程0、上次实验回顾 上次实验中,我们通过STM32CubeMX创建了通过按键捕获中断,实现LED变频闪亮的工程,通过不断按下用户键实现LED,让LED从延时512开始,逐次减半延时至0的规律循环。 回顾实验,有几个核心函数出现在试验中:1、按键功能并没有接其它元器件,只使用了MCU上GPIO的中断捕获功能,用到的中断回调函数 void HAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin),在中断使能情况下,当捕获到了对应中断,进入中断回调函数中,执行中断代码逻辑。在HAL库中。
2、调用这个回调函数的函数为:void HAL_GPIO_EXTI_IRQHandler(uint16_tGPIO_Pin) 而, 这个函数是由void EXTI4_15_IRQHandler(void)中调用,EXTI4_15_IRQHandler是在启动汇编文件中的中断向量表中供ARM系统调用。当ARM系统产生中断而没有被屏蔽,立即会触发中断函数中的内容。 3、GPIO口的相关定义,B1_Pin、B1_GPIO_Port
GPIO_InitStruct.Pin = B1_Pin;
这几个引脚的定义在{项目名称}\Inc\ mxconstants.h 文件中,定义内容如下:
#define B1_Pin GPIO_PIN_13 #define B1_GPIO_Port GPIOC
GPIO_PIN_13的定义在 {项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h 文件中
....... #define GPIO_PIN_13 ((uint16_t)0x2000U)/* Pin 13 selected*/ ......
GPIOC的定义在 {项目名称}\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 GPIOC ((GPIO_TypeDef *) GPIOC_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 文件中
4、GPIO口的模式: 上升沿触发
...... GPIO_InitStruct.Mode=GPIO_MODE_IT_RISING; ......
GPIO_MODE_IT_RISING的定义在 {项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_gpio.h 文件中
.... #defineGPIO_MODE_IT_RISING(0x10110000U) /*!< External Interrupt Mode with Rising edge trigger detection */ ......
5、外部中断初始化并中断使能。
...... HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI4_15_IRQn); ......
中断的相关初始化和使能,在{项目名称}\Drivers\STM32L4xx_HAL_Driver\Inc\stm32l4xx_hal_cortex.h 文件中。
1、新实验设想 GPIO的输出、中断捕获功能原理熟悉之后,可以进一步设想,能否对实验进行改进,利用CPU的定时器作为参照灯或心跳灯,检测程序是否运行;并利用串口将按键后改变的延时值输出到上位机进行展示。 A)定时器设置: 使用CubeMX打开芯片引脚设置,将定时器1的时钟源设置为内部时钟。
系统时钟频率设置为80MHz
在定时器功能中设置如下:设置预分频40000-1(0~39999),计数时间1000-1(0~1999),确定每次中断计数就是一个2000次计数,每次计数是1ms,。
定时器中断使能。
B)串口设置: 选择功能树上Usart2,为异步模式,VCP仅使用了Rx和Tx 并无流控,因此硬件流控为禁用:设定PIN脚 PA2为Usart_TX,PA3为Usart_RX。
在串口功能中设置如下:
波特率:115200,数据长度,8bits,起停位1bit,其他的保持默认
USART2 中断使能
GPIO口及标签设置如上图设置完以上内容后,通过CubeMX创建试验代码。
CubeMX创建的实验代码有专门的章节介绍,这里介绍分析省略。
2、实验步骤A)定时器设置:定时器设置虚要外界一个LED或者蜂鸣器,通过GPIO F4口来进行控制先设置好定时器的回调函数,通过回调函数控制LED的闪亮和熄灭:在mxconstants.h 文件定义定时器的GPIO引脚,GPIO的相关设置参考前面的设置方法:
...... #define LDTimer_Pin GPIO_PIN_4 #define LDTimer_GPIO_Port GPIOF .......
在main.h设置定时器控制的LED相关控制函数
...... #define TIMERLED(STA) (STA)?HAL_GPIO_WritePin(LDTimer_GPIO_Port,LDTimer_Pin,GPIO_PIN_SET):HAL_GPIO_WritePin(LDTimer_GPIO_Port,LDTimer_Pin,GPIO_PIN_RESET) ......
定义定时器回调函数中的内容:
....... static uint8_t staTimer = ON; ...... void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { TIMERLED(staTimer); staTimer = !staTimer; } ......
在main()函数中主循环里设置启动定时器:
....... //TIME启动; HAL_TIM_Base_Start_IT(&htim1); ......
B)串口设置:先设置串口的发送数据缓冲区和接收缓冲区在main.h 文件定义发送和接收缓冲区的大小:
...... #define RxBufferSize64 #define TxBufferSize64 .......
在main.c文件中定义发送和接收缓冲区的数组:
...... static uint8_t Rx_Buffer = { 0 }; static uint8_t Tx_Buffer = { 0 }; .......
在非DMA方式下实现串口通信时需要设置以下内容:在Usart2的初始化函数(MX_USART2_UART_Init)中,设置中断和数据接收缓冲区
...... HAL_UART_Receive_IT(&huart2,Rx_Buffer,RxBufferSize); .......
在Main.c文件中,设置好串口中断回调函数:
........ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){if (huart==&huart2){ //printf("Rx: %s \n",Rx_Buffer);//设置好Printf方式输出后可去掉注释符号 .........//捕获中断后,将接收到的缓冲数据,进行数据处理的函数(这里略) HAL_UART_Receive_IT(&huart2,Rx_Buffer,RxBufferSize); } } .......
在Main.c文件中,设置好发送数据函数
........ static uint8_t *TxBuffer; static uint32_t StrN; //设置动态字符串长度值 ........ void SendWithOutDMA_Len(void) { TxBuffer = (uint8_t *) malloc(StrN * sizeof(uint8_t)); .......//组织TxBuffer 将发送的字符串拼接起来; HAL_UART_Transmit(&huart2, TxBuffer, StrN, 0xff); free(TxBuffer); } .......
将 SendWithOutDMA_Len();函数放到需要发送数据的功能下便可实现串口发送数据;这里将函数放在按键响应函数中:
........ void KeyPass(void) { ........ //按键发送数据 SendWithOutDMA_Len(); ...... } .......
通过Printf函数进行串口输出设置:
........ /* USER CODE BEGIN Includes */ ....... #ifdef __GNUC__ /* With GCC, small printf (option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ ...... /* USER CODE END Includes */ .......
/* USER CODE BEGIN 4 */ ........ /* retarget the C library printf function to the USART */ PUTCHAR_PROTOTYPE { /* Place your implementation of fputc here */ /* e.g. write a character to the EVAL_COM1 and Loop until the end of transmission */ HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 0xFFFF); return ch; } ....... /* USER CODE END 4 */
经过以上设置之后,即可用printf函数向串口输出字符串了printf("HelloSTM32L476RC! \n"); 3、实验的观察结果A)定时器:外接的LED(注意串接一个分压电阻)每一秒钟闪亮一次;B)串口:可通过SendWithOutDMA_Len()函数向串口输出信息;也可通过Printf("xxxxxxx")函数向串口输出信息;三、实验后的心得
这个实验,可以了解到定时器回调函数、串口回调函数的使用方式,在串口发送数据的实验中,还体验到串口不同的数据发送方式(使用中断方式方式发送和接收数据,使用Printf函数发送数据)。
此前以为发了次文章,后来检查文章时才发现忘发此帖了(补一个)界此,基于Nucleo系列板卡的试验基础环境搭建好了,之后回基于这些基本LED、按键、中断、串口、定时器的基本功能做一系列的试验,下一个系列是低功耗系列
前文回顾:
1、NUCLEO-L476RG试验(一)_LED闪闪亮(环境搭建与开发工具介绍) 2、NUCLEO-L476RG试验(二)_LED闪闪亮续一(按键、中断)
3、NUCLEO-L476RG实验心得(三)_Eclipse环境配置
后文连接:
1、ST线下培训(05-23成都站)STM32L476低功耗设计(一)
学习学习。。。。。。。 谢谢大佬
页:
[1]