转自:作者:马一飞 QQ:791729359
看了这位博主的博客学到了很多东西,一开始有些地方不是很明白,现在看懂了,稍微修改了下,原文连接如下
https://blog.csdn.net/qq_34952376/article/details/81172535
下面开始正文:
之前我们讲解了通用定时器使用PWM模式产生PWM波,但是到最后我们总结出了一个缺点:PWM模式同一定时器中,不同的通道下,输出的频率固定,由时基单元初始化时设置决定的,占空比可变。也就是说在初始化时频率设置成多少,那么在这个定时器下的各个通道产生个PWM波频率也是相同的。
那么如果想各个通道产生的PWM频率不同,占空比也不同,那我们就需要借助一个通用定时器的输出比较模式了。
首先我们先理解一下什么叫输出比较,我给大家简单画一个简图。
我们知道,stm32f1的通用定时器位数的16位的,那么就代表计数值最大可以达到0xFFFF,如果到了0xFFFF再继续往下计数的话就会清0重新向上技术。那么我们可以利用定时器的这个特点,来产生一个PWM波。
我们把计数值设置成0xFFFF,那么定时器就会一直向上计数,pulse就相当于我们设定的周期值,也就是我们所说的频率。那么,在一个周期内,占空比是多少?就是Duty所决定的,在一个pulse内,小于Duty为高电平,大于Duty为低电平,直到进入下一个pulse。这就是输出比较模式的特点。为什么把它称作为输出比较模式呢?就是因为定时器的计数值一直向上计数的同时,他要不断的跟我们设定的pulse和Duty做比较。
我们把这个概念理解好了之后,就可以开始编写代码了。为了更好的让大家学习PWM波,上一次用的是TIM3,这次我就用TIM2来产生PWM
同样的方法,首先我们先查看有哪些引脚是复用为TIM2的
我们可以看到PA1,PA2,PA3都可以复用为TIM2,这次我们就用了PA1,PA2做双通道比较输出吧。如果大家想再开启PA3也是相同的方法。
我们使用输出比较PWM的话是要用到定时器中断的,但是这个中断又不等同于定时中断。既然用到中断的话就一定要吧misc.c这个库函数添加进工程目录里。
1. 首先当然得使能PA口和TIM2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
2.初始化PA1,PA2设置复用推挽输出模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
3.配置TIM2中断
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
4. 配置定时器2基础设置,我们把计数值设置到最大,也就是0xffff,并且71分频。
TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
TIM_TimeBaseInitStructure.TIM_Prescaler = 71;
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseInitStructure.TIM_CounterMode = 0x0;
TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);
5. 通过输入的频率值,算出pulse的值,也就是周期值
//表示在当前定时器配置下要达到要求频率的实际计数值
CH2_Val = 1000000 / ch2_fre; //频率为捕获比较寄存器的值,要计数到这个值的时间为T=1us*ch2_fre
CH3_Val = 1000000 / ch3_fre; //则频率就是1/T=1000000/ch2_fre
CH2_Duty = CH2_Val * ch2_duty / 100; //形参中占空比用×100后的整数表示
CH3_Duty = CH3_Val * ch3_duty / 100;
因为是71分频,所以pulse的值就等于1000000 除 输入的频率值。
同时还得通过设定的占空比数,算出Duty的位置。
6. 设定输出模式为触发模式,并且极性为低极性,使能输出,把算出来的周期指赋给Pulse。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //定时器通道工作于输出比较模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //初始输出极性,表示低电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CH2_Val; //捕获比较寄存器的初始值,可设置初始相位
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = CH3_Val;
TIM_OC3Init(TIM2,&TIM_OCInitStructure);
7. 把定时器计数值清0,并且把通道2,通道3的比较值也设置为0,在接下来只要一启动定时器就直接开始比较了。
TIM_SetCounter(TIM2,0x0); //从0开始计数,对初相位有要求时必须设置
TIM_SetCompare2(TIM2,0x0); //初相位为0
TIM_SetCompare3(TIM2,0x0);
8.启动定时器,并使能通道2、通道3比较中断。
TIM_Cmd( TIM2, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC2 | TIM_IT_CC3, ENABLE);
这个时候我们就把输入比较初始化完成了。
那么我们就要开始编写中断处理函数,手动的让定时器按照我们的要求,去产生指定占空比的PWM波形。
我们先定义两个标志位 channel_2_flag,channel_3_flag。用来确定我们当前比较的状态。
channel_2_flag=1,表示接下来为输出高电平,反之接下来输出低电平
然后就开始编写中断服务函数了,
u16 capture;
if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == 1)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC2); //这里现在代表的是输出比较中断,不是输入捕获
capture = TIM_GetCapture2(TIM2);
if(channel_2_flag)
{
TIM_SetCompare2(TIM2,capture + CH2_Duty); //接下来为输出高电平时间
}else //输出极性会自动翻转
{
TIM_SetCompare2(TIM2,capture + CH2_Val - CH2_Duty);
}
channel_2_flag ^= 1;
}
我们要写定义一个16位的变量,用处是
来获取我们通道当前的比较值。在每次进入比较中断时,我们都把通道当前的比较值获取到capture里,当我们channel_2_flag为真的时候,代表将进入Duty以下的位置,channel_2_flag为假则代表将进入Duty以上的位置。当我们每次得到一个中断,引脚都会自动的把电平翻转,我们再中断处理函数中只需要设定好比较值就ok了。
TIM_SetCompare2(TIM2,capture + CH2_Duty);
代表在当前的比较值,加上一个高电平时间作为通道2的比较值。而
TIM_SetCompare2(TIM2,capture + CH2_Val - CH2_Duty);
则是在当前的比较值加上一个低电平时间作为通道2的比较值。那么当我们初始化完成之后,比较通道的值就会不断的与计数值进行比较,假如计数值到达我们比较值,那么就会产生一个中断请求,并且引脚的电平会翻转。
同理,通道3的设置也是相同的。
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == 1)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
capture = TIM_GetCapture3(TIM2);
if(channel_3_flag)
{
TIM_SetCompare3(TIM2,capture + CH3_Duty);
}else
{
TIM_SetCompare3(TIM2,capture + CH3_Val - CH3_Duty);
}
channel_3_flag ^= 1;
}
那么我们写好之后就可以烧录这个程序到开发板上看看效果。
TIM2_PWM_OUTPUT(1000,40,5000,80);
我们把通道2的频率设置为1000HZ,占空比为40%,通道3的频率设置为5000HZ,占空比为80%。
我们用逻辑分析仪看看PA1,PA2引脚上产生的波形。
先看PA1的波形
PA2的波形
我们能够看到,完全达到我们的要求,且产生的波形频率和占空比,非常准确无误差。
我们能够发现,比较通道的优点是:同一定时器下,不同通道能够产生频率不同,占空比不同,甚至相位也不同的方波。
至于相位不同怎么设置,也很简单,这个任务就交给你们思考啦。
---------------------
作者:eavane
来源:CSDN
原文:https://blog.csdn.net/qq_34952376/article/details/81172535
版权声明:本文为博主原创文章,转载请附上博文链接!