STM32F407HAL库-12.PWM输出

通过配置STM32F407定时器来实现呼吸灯。

PWM输出就是通过定时器通道对外输出脉宽(即占空比)可调的方波信号,信号频率由定时器自动重装寄存器 ARR 的值决定,占空比由定时器比较寄存器 CCR 的值决定。

PWM模式分为两种,PWM1和 PWM2,具体区别如下表:

模式

计数器CNT计算公式

说明

PWM1

递增

CNT<CCR,通道CH为有效,否则为无效

递减

CNT>CCR,通道CH为无效,否则为有效

PWM2

递增

CNT<CCR,通道CH为无效,否则为有效

递减

CNT>CCR,通道CH为有效,否则为无效

下面我们以PWM1模式来讲解,以计数器CNT计数的方向不同还分为边沿对齐模式和中心对齐模式。

1、PWM边沿对齐模式

在递增模式下,计数器从0计数到自动重载值(TIMx_ARR寄存器的内容),然后重新从0开始计数并生成计数器上溢事件,PWM1模式的边沿对齐波形如下所示(ARR=8):

 在边沿对齐模式下,计数器CNT只工作在一种模式下,递增或者递减模式。这里我们以CNT工作在递增模式为例,在图中,ARR=8,CCR=4,CNT从0开始计数,当CNT<CCR的值时,OCxREF为有效的高电平,于此同时,比较中断寄存器CCxIF置位。当CCR<=CNT<=ARR时,OCxREF为无效的低电平。然后CNT又从0开始计数并生成计数器上溢事件,以此循环往复。

2、PWM中心对齐模式

在中心对齐模式下,计数器 CNT 是工作在递增/递减模式下。开始的时候,计数器 CNT 从 0 开始计数到自动重载值减 1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到 1 并生成计数器下溢事件。之后从 0 开始重新计数,PWM1模式的中心对齐波形如下:

 

在图中,ARR=8,CCR=4,第一阶段计数器CNT工作在递增模式下,从0开始计数,当CNT<CCR的值时,OCxREF为有效的高电平,当CCR<=CNT<<ARR时,OCxREF为无效的低电平。第二阶段计数器CNT工作在递减模式,从ARR的值开始递减,当CNT>CCR时,OCxREF为无效的低电平,当CCR>=CNT>=1时,OCxREF为有效的高电平。

中心对齐模式又分为中心对齐模式 1/2/3 三种,具体由寄存器 CR1位CMS[1:0]配置。具体的区别就是比较中断标志位 CCxIF 在何时置 1:中心对齐模式 1 在 CNT 递减计数的时候置 1,中心对齐模式 2 在 CNT 递增计数时置 1,中心对齐模式 3 在 CNT 递增和递减计数时都置1。

呼吸灯,就是指灯光设备的亮度随着时间由暗到亮逐渐增强,再由亮到暗逐渐衰弱,很有节奏感地一起一伏,就像是在呼吸一样,因而被广泛应用于手机、电脑等电子设备的指示灯中,冰冷的电子设备应用呼吸灯后,顿时增添了几分温暖。

要使用STM32控制LED灯实现呼吸灯效果,可以通过输出脉冲的占空比来实现。如下图:

 

图中列出了周期相同而占空比分别为 100%、80%、50 和 20%的脉冲波形,假如利用这样的脉冲控制 LED 灯,即可控制 LED 灯亮灭时间长度的比例。若提高脉冲的频率,LED 灯将会高频率进行开关切换,由于视觉暂留效应,人眼看不到 LED 灯的开关导致的闪烁现象,而是感觉到使用不同占空比的脉冲控制 LED 灯时的亮度差别。即单个控制周期内,LED 灯亮的平均时间越长,亮度就越高,反之越暗。

要想使用STM32F4的定时器产生PWM输出,需要使用下面三个寄存器(寄存器详细描述请参考STM32F407参考手册):

  • 捕获/比较模式寄存器(TIMx_CCMR1/2)

Bits 6:4:此部分为模式设置位,可以配置成7种模式,我们使用的是PWM模式,所以这3位必须设置位110/111。

Bits 1:0:此部分为通道方向选择位,用于设置通道的方向(输入/输出)默认设置为0,就是设置通道作为输出使用。

  • 捕获/比较使能寄存器(TIMx_CCER)

  •  捕获比较寄存器(TIMx_CCR1~4)

在输出模式下,该寄存器的值与CNT的值比较,根据比较结果产生相应动作。利用这点,我们通过修改这个寄存器的值,就可以控制PWM的输出脉宽了。

呼吸灯程序如下:

TIM_HandleTypeDef TIM_Handle; // 定时器初始化结构体变量
TIM_OC_InitTypeDef TIM_OC_Handle; // 定时器输出初始化结构体变量

// 定时器输出PWM初始化
void TIM_PWM_Init(void)
{
	    // 定时器初始化
	    TIM_Handle.Channel = HAL_TIM_ACTIVE_CHANNEL_1; // 通道1
	    TIM_Handle.Instance = TIM14; // 选择定时器14
	    TIM_Handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟1分频
	    TIM_Handle.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
	    TIM_Handle.Init.Period = 500; // 自动重装载值
	    TIM_Handle.Init.Prescaler = 168; // 预分频系数
	    HAL_TIM_PWM_Init(&TIM_Handle); // 初始化定时器
	
	    // 定时器输出PWM初始化
	    TIM_OC_Handle.OCMode = TIM_OCMODE_PWM1; // 模式选择PWM1
	    TIM_OC_Handle.OCPolarity = TIM_OCPOLARITY_LOW; // 输出比较极性为低
	    TIM_OC_Handle.Pulse = 250; // 设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
	    HAL_TIM_PWM_ConfigChannel(&TIM_Handle, &TIM_OC_Handle, TIM_CHANNEL_1); // 配置PWM输出
	
	    HAL_TIM_PWM_Start(&TIM_Handle, TIM_CHANNEL_1); // 开始PWM输出
}

// 定时器使用引脚初始化
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	    GPIO_InitTypeDef GPIO_Handle; // GPIO初始化结构变量
	
	    if(htim->Instance == TIM14)
	    {
		    __HAL_RCC_GPIOF_CLK_ENABLE(); // 使能GPIO
		    __HAL_RCC_TIM14_CLK_ENABLE(); // 使能定时器
		
		    GPIO_Handle.Pin = GPIO_PIN_9; // PF9
		    GPIO_Handle.Mode = GPIO_MODE_AF_PP; // 复用 推挽模式
		    GPIO_Handle.Pull = GPIO_PULLUP; // 上拉电阻
		    GPIO_Handle.Speed = GPIO_SPEED_HIGH; // 高速
		    GPIO_Handle.Alternate = GPIO_AF9_TIM14; // 将GPIO复用为定时器14
		    HAL_GPIO_Init(GPIOF, &GPIO_Handle); // 初始化GPIO
	    }
}
// 设置定时器输出占空比
void TIM_SetPluse(uint32_t pluse)
{
	    TIM14->CCR1 = pluse; // 设置占空比
}

main.c程序如下:

uint16_t pulse; // 占空比
uint8_t dir = 1; // 占空比增长的方向
int main(void)
{
	    CLOCLK_Init(); // 初始化系统时钟
	    TIM_PWM_Init(); // 定时器输出PWM初始化
	
	    while(1)
	    {
		    if(dir) pulse++; // dir==1  占空比递增
		    else    pulse--; // dir==0  占空比递减
		    if(pulse > 300) dir = 0; // 占空比到达300后,开始递减
		    if(pulse == 0) 	dir = 1; // 占空比到达0后,开始递增
		    TIM_SetPluse(pulse); // 设置定时器占空比
		    HAL_Delay(10); // 延时10ms   
	    }
}

实验现象:

将程序下载到开发板中,我们可以看到LED1灯由暗到亮,然后又从亮变到暗。

参考文章链接:

https://www.cnblogs.com/firege/p/5805894.html

参考资料:正点原子 STM32F4开发指南-库函数版本_V1.1.pdf

  • 3
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值