STM32如何实现同个管脚PWM输出不同频率无缝切换
我要实现PWM交替输出50KHz和100KHz,占空比都是50%,在同一个管脚上。
现在用TIM,捕获比较方式,每次改变频率时,都有从新设置,拿示波器看,发现频率交替时,有大概50us的停顿时间。
请问版主,STM32能否实现无缝交替,或者是很小,只有几us的停顿时间?多谢先。
程序如下,每次交替,都有从新设置,但只改变一下红色部分的值。
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Enable AFIO clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* Enable GPIOE clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
GPIO_PinRemapConfig(GPIO_FullRemap_TIM1,ENABLE);
/* Configure PE11 PE13 as IPD */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOE, &GPIO_InitStructure);
TIM_DeInit(TIM1);
/* ---------------------------------------------------------------
TIM1 Configuration: Free Up Count Mode:
TIM1CLK = HCLK(32MHz), Prescaler = 1, TIM1 counter clock = 32 MHz
--------------------------------------------------------------- */
TIM1->BDTR=0x0000;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 320-1;
TIM_TimeBaseStructure.TIM_Prescaler = 1-1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
思路: 把TIM_TimeBaseStructure定义为全程变量。初始化时按照1楼的代码初始化,交替变换时只用以下语句即可:
TIM_TimeBaseStructure.TIM_Period = 320-1;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
不过:只减少代码执行的一丁点时间,估计停顿时间不会减少多少。
这个调用PWM输出,本身已经是在中断里面产生的了啊。当DMA中断产生的时候,在DMA中断响应函数里,对PWM输出进行设置,然后使能输出。每个输出的频率都有可能是不一样的。
可能对版主的话,不是太明白,能否说的详细一点?何为更新中断?
我刚才搜了一下,搜到了版主的这个回帖
https://bbs.eeworld.com.cn/icview-158988-1-1.html
“但使用我建议的更新中断(事件),将在每个周期的开始更新比较寄存器的数值,不会出现上述问题。”
看这意思是,改变占空比的么?我这里要求占空比一直都是50%。只能改变频率。
这个我之前试过,没有用 TIM_DeInit(TIM1); 等。会出现几个跳变,这样来说,对我的系统更危险。呵呵
回6楼:怎么会有DMA中断?楼主位的问题没有DMA的问题,产生PWM信号也不需要DMA操作。
关于更新中断的问题,你需要看看STM32参考手册,我的博客中也有介绍:
STM32定时器的预装载寄存器与影子寄存器之间的关系
9# 版主
DMA中断是ADC采样的时候要用到,用来控制传输速率。在DMA中断里,根据是1或0,发送不同的频率。而且下一个信号是0或1是不确定的,只有在检测到是1或0时,马上按对应频率在同一管脚上输出。
设计preload register和shadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。
但我现在是在TIM1的一个通道上实现,频率变化。
不管是在一个还是多个通道上,问题的关键是,使用更新中断,使你可以准确地同步输出的信号。
非常感谢版主,把版主的博客仔细看了。改了程序。把原来的一大段改成这两行
TIM_SetAutoreload(TIM1,PeriodPFM);
TIM_GenerateEvent(TIM1,TIM_EventSource_Update);
目前模拟看效果可以,大概只有几us的延迟。明天实际运行看看。
再次感谢版主!
有一个问题有点疑问
TIM_SetAutoreload(TIM1,PeriodPFM);
TIM_GenerateEvent(TIM1,TIM_EventSource_Update);
TIM_SetCompare2(TIM1,PeriodPFM/2);//
这样可以正常输出。
但如果把设置占空比的放到更新事情前,会有尖脉冲产生。
TIM_SetAutoreload(TIM1,PeriodPFM);
TIM_SetCompare2(TIM1,PeriodPFM/2);//
TIM_GenerateEvent(TIM1,TIM_EventSource_Update);
更新事件或更新中断都是在每个PWM周期结束时产生,这时修改PWM的参数可以使下一个周期始终是完整的,如果在没有发生更新事件时修改PWM参数,则会使一个没有结束的周期提前结束或延后结束,结果就是你开始看到的样子。
现在你在硬件没有产生更新事件,强制用软件TIM_GenerateEvent产生它,则根本没有起到使用更新事件修改PWM参数的作用,当然不能有满意的结果。
还是我在5楼说的:需要在更新中断中改变参数,这样就不会有任何的停顿。
实际上,如果你不需要在更新中断中处理什么事情,可以不使能更新中断,也不要使用软件触发TIM_GenerateEvent,直接设置参数,等待硬件在产生更新事件时自动更新那些实际寄存器即可。
版主, 您说的硬件中断是指,计数器向上计数溢出产生的中断么?
如果是这样,在每个周期,都会产生中断,怎么才能在我需要改变频率的那一刻,执行中断函数?
15# 版主
版主, 您说的硬件中断是指,计数器向上计数溢出产生的中断么?
如果是这样,在每个周期,都会产生中断,怎么才能在我需要改变频率的那一刻,执行中断函数? ...
请看我在16楼的补充说明。
就你的情况,更新事件的条件是:每个PWM周期结束而不是计数器向上计数溢出。
我按您16楼的说法,关闭update中断。同时只用这两行代码
TIM_SetAutoreload(TIM1,PeriodPFM);
// TIM_GenerateEvent(TIM1,TIM_EventSource_Update);
TIM_SetCompare2(TIM1,PeriodPFM/2);//
产生有周期提前结束现象,而且有时候整个某个频率就没有,全部为高电平或低电平。
你是否调用TIM_OC1PreloadConfig使能了Preload功能?