参考该博主的文章,对该文档代码做补充说明:
STM32单片机一个定时器输出不同频率PWM波_利用定时器输出不同频率的pwm信号-CSDN博客
- 该博主的文章讲得非常不错,在他的基础上做一些补充以及自己的理解。
如何设置我们自己想要的频率呢?接下来这两个参数很关键
TIM_TimeBaseInitStructure.TIM_Period = arr;
TIM_TimeBaseInitStructure.TIM_Prescaler = psc;
首先先说一下psc这个参数,这个分频系数确定之后,最大计数值arr也就定了。举个例子:
假设:psc是72 那么最大计数值
arr = 72 000 000 / 72 = 1000 000
理论上arr = 1000 000 但是我们从资料上查找计数器是一个16位的计数器,最大值只能为65536。
如果:psc 为 7200
arr = 72 000 000 / 7200 = 10000
那么arr 计数最大为10000,计数值并没有超出65536。
PSC的范围是1~65536
理解了这一部分之后,我们来看代码:
这里的PSC = 0 STM32芯片会自动加1,所以分频系数为1,也就是说不分频。然后
arr = 72 000 000 / 1 = 72 000 000
(也就是说1秒钟可以计72 000 000个数)
但是arr 只能为65535,原因上面已经说了。那么我们可以算出计一个数的时间:
1 / 72 000 000 约等于13.8ns。
根据我们设定的比较值
也就可以算出对应的时间:
CCR1_Val = 32768
对应的周期是 32768 x 13.8 = 455 111.111ns = 455.111us
CCR2_Val = 16384
对应的周期是 16384 x 13.8 = 226.099us
CCR3_Val = 8192
对应的周期是 8192 x 13.8 = 113.049us
CCR3_Val = 4096
对应的周期是 4096 x 13.8 =56.524us
也就是下面的周期(如图所示):
上面的波形是占空比设定了
以上是对博主的代码解读, 有解读不对的地方请指正。
根据上面的计算,我们能设置的最慢是时间是
13.8 x 65536 = 904.396us。往往这个时间太快了,不是我们所需要的。接下来是我在博主基础上更改的参数:
1、本人使用的是定时器4
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = TIM4_Period;
TIM_TimeBaseStructure.TIM_Prescaler = TIM4_Prescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
TIM4_Period 设置的是 10000 - 1
TIM4_Prescaler 设置的是 7200 – 1 72000000 / 7200 = 10000 此时计数值最大是10000
从而算出记一个数所需要的时间是 1s / 10000 = 100us
设定的比较值
u16 CCR1_Val = 5000;
u16 CCR2_Val = 2500;
也就可以算出对应的时间:
CCR1_Val = 5000
对应的周期是 5000 x 100us= 500ms
CCR1_Val = 2500
对应的周期是 2500 x 100us= 250ms
如下图所示,黄色线与绿色线
需要注意的是:红色标注是需要添加的,不然输出的频率会不对
//占空比 0 --- 100
u16 CCR1_dc = 50;
u16 CCR2_dc = 50;
u32 capture = 0;
u8 flag1 = 0,flag2 = 0,flag3 = 0,flag4 = 0;//标志位
u16 setcap = 0;
void TIM4_IRQHandler( void )
{
if( TIM_GetITStatus( TIM4, TIM_IT_CC1 ) != RESET )
{
TIM_ClearITPendingBit( TIM4, TIM_IT_CC1 );
capture = TIM_GetCapture1( TIM4 ); //获取输入捕获比较器 1 的值
//设置占空比
if( flag1 == 0 )
{
flag1 = 1;
setcap = capture + ( u32 )CCR1_Val * CCR1_dc / 100;
}
else
{
flag1 = 0;
setcap = capture + ( u32 )CCR1_Val * ( 100 - CCR1_dc ) / 100;
}
if(setcap > TIM4_Period)
{
setcap %= TIM4_Period + 1;
}
TIM_SetCompare1( TIM4, setcap);
}
if( TIM_GetITStatus( TIM4, TIM_IT_CC2 ) != RESET )
{
TIM_ClearITPendingBit( TIM4, TIM_IT_CC2 );
capture = TIM_GetCapture2( TIM4 ); //获取输入捕获比较器 1 的值
//设置占空比
if( flag2 == 0 )
{
flag2 = 1;
setcap = capture + ( u32 )CCR2_Val * CCR2_dc / 100;
}
else
{
flag2 = 0;
setcap = capture + ( u32 )CCR2_Val * ( 100 - CCR2_dc ) / 100;
}
if(setcap > TIM4_Period)
{
setcap %= TIM4_Period + 1;
}
TIM_SetCompare2( TIM4, setcap);
}
}
解读:
因为setcap累加会超出TIM4_Period(也就是10000),超出时需要给它取余。
if(setcap > TIM4_Period)
{
setcap %= TIM4_Period + 1;
// 加1是因为TIM4_Period设置的是10000 – 1,如果这句不理解。把TIM4_Period + 1 改成10000
}