一、概述
本文主要通过学习定时器、中断知识与相关原理,实现稍微复杂一点的PWM呼吸灯功能,旨在通过此文掌握STM32的相关技能。
二、定时器原理
定时器的本身是一个计数器,他记录着时钟信号周期数,每个时钟周期都会使定时器里的计数器增加或减少,当我们知道了时钟周期的频率,算出每个时钟周期的时间,进而就可以通过定时器中的计数器进行定时的操作。
定时器的模式有向上计、向下计、中心计数的模式,以向上计数为例,如下图,当计数值达到重装载值时,触发定时器中断,随后CNT继续从初始值开始计数。
三、定时器中断的配置
首先新建STM32CubeMx工程,并自主完成基础的时钟树配置与工程配置,随后开始进行定时器的配置。
受芯片型号的影响,各芯片各定时器的功能不同,需要用户自行选择。这里选了一个通用定时器TIM2,开启的方法是将时钟源选择为内部时钟。
生成代码,并在main.c中启动定时器。
我们重写中断处理函数,并在其中写LED闪烁程序。
/* USER CODE BEGIN 0 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim2)
{
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
}
}
/* USER CODE END 0 */
相关库函数
拉高,拉低输出
//拉高引脚输出电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
//拉低引脚输出电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
RCC(Reset and Clock Control)是STM32微控制器中的一个模块,用于控制和配置各种外设的时钟和复位信息。在初始化STM32引脚之前,需要先开启相应引脚所对应的GPIO外设的时钟。
开启GPIO外设的时钟是为了确保引脚能够正常工作。因为STM32中的GPIO引脚是通过GPIO外设来控制的,而GPIO外设需要时钟信号来运行。通过RCC开启GPIO外设的时钟后,才能正常地对引脚进行配置和操作。
四、PWM配置
PWM即脉冲宽度调制,当高电平触发的LED,我们通过在相同时间内控制其高电平所占的时间来控制LED的亮度,这种方式就是PWM。我们将高电平时间与周期的比值称为占空比。
那么如何在定时器中使用PWM呢?定时器中的通道作为PWM输出的时候,可以连接到一个IO口,那么这个IO口的电平可以通过定时器的计数值发生变化,通过这种方法,我们可以产生PWM波或改变占空比。
此处我选择TIM4的Channel3进行后续的呼吸灯开发,在STM32CubeMx配置好相关参数。
仍然要先开启定时器,不过方法有些许改变。
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
最后我们在主函数中加入改变计数值的代码,即可实现呼吸灯功能:
for(int i=0;i<99;i++)
{
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,i);
HAL_Delay(1);
}
#include "stm32f10x.h"
//定义LED端口引脚
#define LED0_GPIO_PORT GPIOB /* GPIO端口 */
#define LED0_GPIO_CLK RCC_APB2Periph_GPIOB /* GPIO端口时钟 */
#define LED0_GPIO_PIN GPIO_Pin_8 //引脚
/* 使用标准的固件库控制IO*/
#define LED(a) if (a) \
GPIO_SetBits(LED0_GPIO_PORT,LED0_GPIO_PIN);\
else \
GPIO_ResetBits(LED0_GPIO_PORT,LED0_GPIO_PIN)
//初始化LED引脚
void GPIO_init_LED(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure0;
/*开启LED相关的GPIO外设时钟*/
RCC_APB2PeriphClockCmd( LED0_GPIO_CLK,ENABLE);
/*选择要控制的GPIO引脚*/
GPIO_InitStructure0.GPIO_Pin = LED0_GPIO_PIN;
/*设置引脚模式为通用推挽输出*/
GPIO_InitStructure0.GPIO_Mode = GPIO_Mode_Out_PP;
/*设置引脚速率为50MHz */
GPIO_InitStructure0.GPIO_Speed = GPIO_Speed_50MHz;
/*调用库函数,初始化GPIO*/
GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStructure0);
}
主函数:
int main(void)
{
uint32_t t;
GPIO_init_LED();
while(1)
{
LED(0); //开灯
t=9900000;
while(t!=0)
{t--;}
LED(1); //灭灯
t=9900000;
while(t!=0)
{t--;}
}
}
效果展示:
五、实验心得
这次定时器&PWM应用编程实验使我在理论知识和实践技能方面都取得了显著的进步。通过实验,我深入了解了定时器和PWM的工作原理及应用,并掌握了相关的编程技巧和硬件配置方法。理解定时器工作原理:在开始实验之前,我深入学习了定时器的工作原理。这使我了解到定时器是如何在指定的时间段内生成脉冲的,以及如何通过编程控制这些脉冲的宽度。掌握PWM控制:通过实验,我进一步理解了PWM控制的概念,包括如何生成和调节脉冲的宽度。