一、PWM
1.定义
英文全称:PULSE WIDTH MODULATION,脉冲宽度调制。
脉冲:频率,方波
宽度:占空比(duty),高电平的宽度
2.用途
(1)控制输出的电压和电流
(2)灯光的亮度
(3)电机
二、编程细节
PWM输出是没有中断触发的,PWM由硬件输出波形,用了中断反而会影响系统定时的效率。
所以,记住以后使用定时器输出PWM都不需要使用到中断
1.如配置STM32F407的TIM14的通道1,10ms即100Hz.
1ms = 0.01s=100HZ
84000000 /8400 = 10000
10000/x = 100
x=100
得到周期8400-1,分频系数10-1
基本配置如下
2.然后还要再配置定时器的输出功能,可以参考固件库手册的例子TIM_PWMOutPut
,
这里涉及到了一个寄存器
TIMx_CCMR1:capture/compare mode register 1 --捕获/比较模式寄存器1
从上图可以看出,我们设置占空比是可以动态调整的,关键就在于设置中间这个比较值的大小。
我们会使用到下面这个函数设置TIMx通道1比较值函数,如果使用到通道2,改1为2即可。
假如100hz内,比较值设置为80hz,那么0-79为高电平,80-100为低电平。
void TIM_SetCompare1(TIM_TypeDef* TIMx,uint16_t Comarex);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//pwm模式1,解释如上图所示
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//允许输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//有效的时候,输出高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);//因为要周期性输出,所以要自动重装载初值,不断输出PWM脉冲
TIM_ARRPreloadConfig(TIM14,ENABLE);//自动重载使能
3.下面讲一下设置gpio的注意事项
(1)将引脚设置为复用功能
(2)将引脚与定时器进行绑定,告知是复用定时器功能
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM14);
(3)最好是按照固件库手册的例程来写,有些定时器使能需要配置下面这个函数
TIM_CtrlPWMOutputs(TIM1,ENABLE);
4.主函数部分
uint32_t pwm_cmp = 0;//新建一个比较值
添加两个延时函数
while(1)
{
for(pwm_cmp =1;pwm_cmp<100;pwm_cmp++)
{
//设置比较值,查看所接的LED渐灭,因为0点亮
//如果想要渐亮,设置pwm_cmp为从100--1即可
TIM_SetCompare1(TIM14,pwm_cmp);
delay_ms(10);
}
for(pwm_cmp=99;pwm_cmp>0;pwm_cmp--)
{
TIM_SetCompare1(TIM14,pwm_cmp);
delay_ms(10);
}
}
下面是使用野火开发板STM32F429写的PWM输出
#include "stm32f4xx.h"
//R 红色灯
#define LED1_PIN GPIO_Pin_10
#define LED1_GPIO_PORT GPIOH
#define LED1_GPIO_CLK RCC_AHB1Periph_GPIOH
static __IO u32 TimingDelay;
/**
* @brief 启动系统滴答定时器 SysTick
* @param 无
* @retval 无
*/
void SysTick_Init(void)
{
/* SystemFrequency / 1000 1ms中断一次
* SystemFrequency / 100000 10us中断一次
* SystemFrequency / 1000000 1us中断一次
*/
if (SysTick_Config(SystemCoreClock / 100000))
{
/* Capture error */
while (1);
}
}
/**
* @brief us延时程序,10us为一个单位
* @param
* @arg nTime: Delay_us( 1 ) 则实现的延时为 1 * 10us = 10us
* @retval 无
*/
void Delay_us(__IO u32 nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
/**
* @brief 获取节拍程序
* @param 无
* @retval 无
* @attention 在 SysTick 中断函数 SysTick_Handler()调用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
/*
1-初始化LED灯所在的GPIO引脚
PH10 定时器5的CH1
2-查看说明手册,判断定时器是否有输出功能
16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5) 递增、递减和递增/递减自动重载计
数器。
说明可用
3-编写GPIO初始化
4-编写定时器初始化
5-主函数调用
*/
void tim14_init(void)
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
/*开启LED相关的GPIO外设时钟*/
RCC_AHB1PeriphClockCmd ( LED1_GPIO_CLK, ENABLE);
RCC_APB1PeriphClockCmd ( RCC_APB1Periph_TIM5, ENABLE);
GPIO_PinAFConfig(GPIOH,GPIO_PinSource10,GPIO_AF_TIM5);
GPIO_InitStructure.GPIO_Pin = LED1_PIN; /*选择要控制的GPIO引脚*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; /*设置引脚模式为输出模式*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /*设置引脚的输出类型为推挽输出*/
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /*设置引脚为上拉模式*/
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; /*设置引脚速率为2MHz */
GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStructure); /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
//90Mhz 设置到100HZ输出,90000000/9000/100 = 100hz
TIM_TimeBaseStructure.TIM_Period = 100-1;
TIM_TimeBaseStructure.TIM_Prescaler = 9000-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM5,&TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM5,TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM5,ENABLE);
// 使能定时器
TIM_Cmd(TIM5, ENABLE);
}
int main(void)
{
uint32_t pwm_cmp = 0;//新建一个比较值
SysTick_Init();
tim14_init();
while(1)
{
for(pwm_cmp =1;pwm_cmp<100;pwm_cmp++)
{
//设置比较值,查看所接的LED渐灭,因为0点亮
//如果想要渐亮,设置pwm_cmp为从100--1即可
TIM_SetCompare1(TIM5,pwm_cmp);
Delay_us(5000); // 1000 * 10us = 100ms
}
for(pwm_cmp=99;pwm_cmp>0;pwm_cmp--)
{
TIM_SetCompare1(TIM5,pwm_cmp);
Delay_us(5000); // 100 * 10us = 1000us = 1ms *100 = 100ms
}
}
}
/*********************************************END OF FILE**********************/
在stm32f4xx_it.c
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}