同一定时器输出4路不同频率且占空比可调的PWM
创作时间:
作者:
@小白创作中心
同一定时器输出4路不同频率且占空比可调的PWM
引用
1
来源
1.
https://www.cnblogs.com/wchmcu/p/18325273
在嵌入式系统开发中,定时器常用于生成PWM信号。通常情况下,一个定时器可以输出4路占空比独立可调的PWM,但这些输出的频率是相同的。然而,在某些应用场景中,可能需要使用一个定时器输出不同频率的PWM信号。本文将详细介绍如何通过定时器的中断处理机制实现这一功能。
原理分析
定时器的工作原理基于三个关键参数:预分频值(psc)、重装载值(arr)和比较值(ccp)。
- 预分频值决定了定时器的计数频率。
- 重装载值确定了一个PWM周期内计数的次数,这两个参数组合决定了PWM的频率。
- 比较值则控制PWM的占空比。
以向上计数、小于比较值为有效电平、有效电平极性为高为例,PWM输出的波形如下图所示:
不难发现,当计数值等于比较值时,输出电平会进行翻转。因此,可以通过在比较捕获中断中重新设置比较值(ccp),实现在一个重装载值周期内完成多次电平的翻转。由于每个通道的比较值都能够独立设置,因此可以实现不同通道翻转的频率不同,即输出不同频率的PWM。下图展示了一个通道在重装载周期内实现多次电平翻转的情况:
软件配置
以CH32V307的TIM2为例,输出4路频率分别为1K、2K、8K、10K,占空比分别为10%、20%、50%、80%的PWM。
1. 定时器初始化
/*******************************************************************************
* Function Name : TIM2_PWM_Init
* Description : Initializes the TIM2
* Input : arr - 重装载值
* psc - 预分频值
* ch1_ccp ~ ch4_ccp - 通道1~通道4的比较捕获值
* Return : None
*******************************************************************************/
void TIM2_PWM_Init(u16 arr, u16 psc, u16 ch1_ccp, u16 ch2_ccp, u16 ch3_ccp, u16 ch4_ccp)
{
GPIO_InitTypeDef GPIO_InitStructure={0};
TIM_OCInitTypeDef TIM_OCInitStructure={0};
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure={0};
NVIC_InitTypeDef NVIC_InitStructure = {0};
/* 使能时钟 */
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
/* GPIO配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
/* TIM配置 */
TIM_TimeBaseInitStructure.TIM_Period = arr; // 重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler = psc; // 预分频值
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
TIM_TimeBaseInit( TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; // 翻转模式
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 有效电平为高电平
TIM_OCInitStructure.TIM_Pulse = ch1_ccp; // 通道1的比较值
TIM_OC1Init( TIM2, &TIM_OCInitStructure );
TIM_OC1PreloadConfig( TIM2, TIM_OCPreload_Disable );
TIM_OCInitStructure.TIM_Pulse = ch2_ccp; // 通道2的比较值
TIM_OC2Init( TIM2, &TIM_OCInitStructure );
TIM_OC2PreloadConfig( TIM2, TIM_OCPreload_Disable );
TIM_OCInitStructure.TIM_Pulse = ch3_ccp; // 通道3的比较值
TIM_OC3Init( TIM2, &TIM_OCInitStructure );
TIM_OC3PreloadConfig( TIM2, TIM_OCPreload_Disable );
TIM_OCInitStructure.TIM_Pulse = ch4_ccp; // 通道4的比较值
TIM_OC4Init( TIM2, &TIM_OCInitStructure );
TIM_OC4PreloadConfig( TIM2, TIM_OCPreload_Disable );
/* 中断配置 */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
TIM_CtrlPWMOutputs(TIM2, ENABLE ); // 使能PWM输出
TIM_ARRPreloadConfig( TIM2, ENABLE ); // 使能自动重装载
TIM_ITConfig( TIM2, TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3 | TIM_IT_CC4, ENABLE ); // 使能比较捕获中断
TIM_Cmd( TIM2, ENABLE ); // 使能TIM
}
TIM_OCMode
设置为Toggle
翻转模式;TIM_OCPreload_Disable
禁止预装载功能,保证可随时更新比较值寄存器以控制输出波形;- 使能输出通道的比较捕获中断;
2. 中断处理
u16 CCR1_dc = 10; // 通道1的占空比
u16 CCR2_dc = 20; // 通道2的占空比
u16 CCR3_dc = 50; // 通道3的占空比
u16 CCR4_dc = 80; // 通道4的占空比
u32 capture = 0;
u8 flag1 = 0, flag2 = 0, flag3 = 0, flag4 = 0;
u16 setcap = 0;
/*******************************************************************************
* Function Name : TIM2_IRQHandler
* Description : TIM2中断服务函数
* Input : None
* Return : None
*******************************************************************************/
void TIM2_IRQHandler( void )
{
if( TIM_GetITStatus( TIM2, TIM_IT_CC1 ) != RESET ) // 判断是否为通道1的比较捕获中断
{
TIM_ClearITPendingBit( TIM2, TIM_IT_CC1 ); // 清除中断标志
capture = TIM_GetCapture1( TIM2 ); // 获取通道1的比较值
/* 设置占空比 */
if( flag1 == 0 )
{
flag1 = 1;
setcap = capture + ( u32 )CCR1_CCP * CCR1_dc / 100;
}
else
{
flag1 = 0;
setcap = capture + ( u32 )CCR1_CCP * ( 100 - CCR1_dc ) / 100;
}
TIM_SetCompare1( TIM2, setcap ); // 设置比较值
}
if( TIM_GetITStatus( TIM2, TIM_IT_CC2 ) != RESET )
{
TIM_ClearITPendingBit( TIM2, TIM_IT_CC2 );
capture = TIM_GetCapture2( TIM2 );
if( flag2 == 0 )
{
flag2 = 1;
setcap = capture + CCR2_CCP * CCR2_dc / 100;
}
else
{
flag2 = 0;
setcap = capture + CCR2_CCP * ( 100 - CCR2_dc ) / 100;
}
TIM_SetCompare2( TIM2, setcap );
}
if( TIM_GetITStatus( TIM2, TIM_IT_CC3 ) != RESET )
{
TIM_ClearITPendingBit( TIM2, TIM_IT_CC3 );
capture = TIM_GetCapture3( TIM2 );
if( flag3 == 0 )
{
flag3 = 1;
setcap = capture + CCR3_CCP * CCR3_dc / 100;
}
else
{
flag3 = 0;
setcap = capture + CCR3_CCP * ( 100 - CCR3_dc ) / 100;
}
TIM_SetCompare3( TIM2, setcap );
}
if( TIM_GetITStatus( TIM2, TIM_IT_CC4 ) != RESET )
{
TIM_ClearITPendingBit( TIM2, TIM_IT_CC4 );
capture = TIM_GetCapture4( TIM2 );
if( flag4 == 0 )
{
flag4 = 1;
setcap = capture + CCR4_CCP * CCR4_dc / 100;
}
else
{
flag4 = 0;
setcap = capture + CCR4_CCP * ( 100 - CCR4_dc ) / 100;
}
TIM_SetCompare4( TIM2, setcap );
}
}
总结
通过上述方法,可以使用同一定时器输出不同频率和占空比的PWM信号。实际效果如下图所示:
参考程序:CH32V307_TIM2_PWM
热门推荐
争了六年,湖北湖南之间这条高铁,终于尘埃落定,今年快速推进!
黄花鱼和黄鱼怎么选?四大维度对比告诉你
淡水黄花鱼VS海水黄鱼:体型、营养与烹饪全对比
黄鱼黄花鱼营养对比:一个护心,一个益智
哪一首贝多芬奏鸣曲最能触动人心?
贝多芬与康德:音乐与哲学的碰撞
贝多芬的自励人格:如何面对困境
从过度用药到系统治疗:青少年心理健康服务待完善
止痛药和安眠药能一起吃吗?医生详解使用风险与建议
驱寒暖身吃这些,身体暖、病不来!
美国留学冬季气候如何适应
北碚蔡家有一座80多年的清代院子,为一举人而建,门前银杏成网红
零库存:丰田精益管理的成功之道
汽车和食品消费强劲 日本第三季度GDP年率增长0.9%
冬季鸡蛋储存与美食指南:四种古法保鲜,八道暖心料理
每周吃5个鸡蛋可降低心血管疾病风险,哈佛研究给出新结论
广州塔夜景、永庆坊涂鸦、白云山全景:广州摄影攻略
从烧鹅到肠粉:广州十大美食的匠心制作与文化传承
普及教育:助力社会平等的关键力量
九孔莲藕怎么挑?大厨教你3招,凉拌爽脆又好看
秋冬养生必备:凉拌莲藕的营养密码
夏日必备:凉拌莲藕,美食博主都在晒!
骶管囊肿手术风险知多少?一文揭秘!
《求佛》背后的情感故事:一段未果恋情如何成就经典
什刹海风味菜谱:宅家也能吃遍京城美味
宫西达也×奥特曼:当超级英雄变身新手爸爸
书法大赛评委最爱用哪些专业术语?
书法展热议:这些术语你知道几个?
格雷厄姆价值投资法:如何用资产负债表评估企业价值
所有者权益:企业财务健康的关键指标与提升路径