PWM输出原理
PWM的PWM输出需要利用定时器中断,32位单片机的PWM输出原理通过配置计数器和定时器来生成特定频率和占空比的脉冲信号。首先设置计数器的初值和上限值,然后通过改变比较值来控制占空比。在每个计数周期中,当计数器的值达到或超过比较值时,输出引脚的电平发生翻转,生成脉冲信号。通过循环重复计数器和定时器的操作,可连续输出PWM信号。具体的配置和操作可能因单片机型号和开发环境而有所差异,建议参考相关文档获取详细指南。
一般步骤:
-
配置计数器和定时器:为了生成PWM信号,首先需要配置单片机的计数器和定时器。这些硬件资源是用于生成特定频率和占空比的脉冲信号的关键部分。
-
设置计数器的值:根据所需的PWM频率,配置计数器的初始值和上限值。计数器的计数范围决定了PWM信号的周期。
-
设置占空比:通过改变计数器的上限值,可以控制PWM信号的占空比。占空比是指PWM信号中高电平或低电平所占的时间比例。通常通过改变定时器的比较值来实现对占空比的调节。
-
输出PWM信号:在每个计数周期中,当计数器的值达到或超过比较值时,输出引脚的电平将翻转。这样就可以生成规律的脉冲信号。
-
循环重复:计数器和定时器会根据设定的数值进行循环计数和重新触发,以生成连续的PWM信号。通过不断重复此过程,可以保持PWM信号的连续输出。
PWM相关寄存器
与PWM相关的寄存器共有4个,分别为捕获/比较模式寄存器、捕获/比较使能寄存器
捕获/比较模式寄存器(TIMx_CCMR1/2)
该寄存器总共有 2 个,TIMx _CCMR1 和 TIMx _CCMR2。TIMx_CCMR1 控制 CH1 和 2,而 TIMx_CCMR2 控制 CH3 和 4。需要说明的是模式设置位 OCxM, 此部分由 3 位组成。总共可以配置成 7 种模式,我们使用的是 PWM 模式,这 3 位必须设置为 110/111。这两种 PWM 模式的区别就是输出电平的极性相反。另外 CCxS 用于设置通道的方向 (输入/输出)默认设置为 0,就是设置通道作为输出使用。
捕获/比较使能寄存器 (TIMx_CCER)
该寄存器我们只用到了最低位,要想 PWM 从 IO 口输出,这个位必须设置为1。
捕获/比较寄存器(TIMx_CCR1~4)
刹车和死区寄存器(TIMx_BDTR)
该寄存器只有在高级寄存器中才使用我们只需要关注最高位:MOE 位,要想高级定时器的 PWM 正常输出,则必须设置 MOE 位为 1,否则不会有输出。
一般步骤
-
配置计数器和定时器:为了生成PWM信号,首先需要配置单片机的计数器和定时器。这些硬件资源是用于生成特定频率和占空比的脉冲信号的关键部分。
-
设置计数器的值:根据所需的PWM频率,配置计数器的初始值和上限值。计数器的计数范围决定了PWM信号的周期。
-
设置占空比:通过改变计数器的上限值,可以控制PWM信号的占空比。占空比是指PWM信号中高电平或低电平所占的时间比例。通常通过改变定时器的比较值来实现对占空比的调节。
-
输出PWM信号:在每个计数周期中,当计数器的值达到或超过比较值时,输出引脚的电平将翻转。这样就可以生成规律的脉冲信号。
-
循环重复:计数器和定时器会根据设定的数值进行循环计数和重新触发,以生成连续的PWM信号。通过不断重复此过程,可以保持PWM信号的连续输出。
通过以上 6 个步骤,我们就可以控制 TIM1 的 CH1 输出 PWM 波了。
具体步骤
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
uart_init(72,9600); //串口初始化
LED_Init(); //初始化与LED连接的硬件接口
TIM1_PWM_Init(899,0);//不分频。PWM频率=72000/(899+1)=80Khz
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;
else led0pwmval--;
if(led0pwmval>300)dir=0;
if(led0pwmval==0)dir=1;
LED0_PWM_VAL=led0pwmval;
}
}
首先,我们需要启用TIM1的时钟,并将PA8配置为复用输出。为了使用TIM1,我们必须先打开TIM1的时钟(通过APB2ENR设置)。同时,我们还需要将PA8配置为复用输出,因为TIM1_CH1通道将使用PA8的复用功能作为输出。
接下来,我们需要设置TIM1的自动重载寄存器(ARR)和预分频器(PSC)的值来控制PWM输出的周期。设置合适的ARR和PSC值可以避免PWM周期过慢(低于50Hz)导致的闪烁现象。
然后,我们需要将TIM1_CH1设置为PWM模式和输出方向。我们希望当CCR1的值较小时,对应的输出引脚暗;而CCR1值较大时,对应的输出引脚亮。为此,我们需要通过配置TIM1_CCMR1寄存器的相关位来控制TIM1_CH1的模式。同时,我们还需要将CH1配置为输出,这可以通过将CC1S[1:0]设置为00来实现(该寄存器的默认值即为0,所以这一步可以省略)。
接下来,我们需要启用TIM1的通道1输出和时钟。通道1的输出可以通过设置TIM1_CCER寄存器来实现,这是单个通道的开关控制;而整个TIM1的时钟可以通过设置TIM1_CR1寄存器来实现。只有在设置了这两个寄存器之后,我们才能在TIM1的通道1上看到PWM波的输出。
对于高级定时器,除了完成以上设置外,我们还需要启用刹车和死区寄存器(TIM1_BDTR)中的MOE位,以使OCx(即PWM)输出生效。
最后,通过修改TIM1_CCR1的值,我们可以控制通道1的占空比,从而控制DS0(可能是LED等设备)的亮度。通过以上6个步骤,我们就能够实现对TIM1的通道1进行PWM波输出的控制。
LED相关代码:
中断相关代码:
void LED_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
RCC->APB2ENR|=1<<5; //使能PORTD时钟
GPIOA->CRH&=0XFFFFFFF0;
GPIOA->CRH|=0X00000003;//PA8 推挽输出
GPIOA->ODR|=1<<8; //PA8 输出高
GPIOD->CRL&=0XFFFFF0FF;
GPIOD->CRL|=0X00000300;//PD.2推挽输出
GPIOD->ODR|=1<<2; //PD.2输出高
}
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //TIM3时钟使能
TIM3->ARR=arr; //设定计数器自动重装值
TIM3->PSC=psc; //预分频器设置
TIM3->DIER|=1<<0; //允许更新中断
TIM3->CR1|=0x01; //使能定时器3
MY_NVIC_Init(1,3,TIM3_IRQn,2);//抢占1,子优先级3,组2
}
void TIM1_PWM_Init(u16 arr,u16 psc)
{
//此部分需手动修改IO口设置
RCC->APB2ENR|=1<<11; //TIM1时钟使能
GPIOA->CRH&=0XFFFFFFF0; //PA8清除之前的设置
GPIOA->CRH|=0X0000000B; //复用功能输出
TIM1->ARR=arr; //设定计数器自动重装值
TIM1->PSC=psc; //预分频器设置
TIM1->CCMR1|=7<<4; //CH1 PWM2模式
TIM1->CCMR1|=1<<3; //CH1预装载使能
TIM1->CCER|=1<<0; //OC1 输出使能
TIM1->BDTR|=1<<15; //MOE 主输出使能
TIM1->CR1=0x0080; //ARPE使能
TIM1->CR1|=0x01; //使能定时器1
}