历史上的今天

今天是:2024年10月06日(星期日)

2018年10月06日 | STM32如何实现可调频率、占空比的PWM波形

发布者:心若澄明 来源: eefocus关键字:STM32  可调频率  占空比  PWM波形 手机看文章 扫描二维码
随时随地手机看文章

使用两个TIM定时器:
一个输出可调频率、占空比的PWM,
一个对输出PWM脉冲计数(计时)。
1.门控方式能实现,但需要复杂的配置和计算,不推荐。

2.脉冲计数是比较实际,也是比较简单的方式;

对输出PWM脉冲计数(计时)方法有多种:

1.IO中断计数,或同步定时中断计数:用另外一个定时器,按照相同频率中断计数(类似IO中断);

2.由PWM频率和脉冲个数,计算输出全部所需的时间,使用定时中断,关闭输出PWM;

3.利用定时器外部脉冲触发(外部时钟模式2功能),计数个数为所需脉冲个数(10个脉冲),则关闭输出PWM;

STM32定时器
利用阻塞延时,控制IO高低变化输出PWM这种方式就行啦,也很简单。其实,这种方法的弊端很大。
1.输出的PWM可能存在误差;
2.对整个系统的实时性可能有影响;
所以不建议使用该方法。
几种实现方法
 使用两个定时器配合输出可调频率、占空比的PWM波形,且可指定输出脉冲个数的方法和原理其实不难。
输出PWM的方法就是使用TIM定时器自带有的PWM模式即可完成。主要难点在于还要控制指定输出脉冲的个数。
对于如何控制输出指定脉冲个数,下面大概说下三种方法:

1.脉冲中断计数法
IO中断,或者定时器同步(脉冲)中断。

定时器同步(脉冲)中断简单的说,就是利用定时器同时产生一个相同频率(或者说波形)的中断信号,在中断里面对其累计,累加个数为指定输出波形个数则关闭PWM波形的输出,同时关闭中断计数。

比如:我输出10个波形,10次中断(每次+1)之后,关闭输出。

它的原理,大致如下图:

STM32如何实现可调频率、占空比的PWM波形,且可指定输出脉冲个数?


此方法建议在输出高频PWM时不要使用,频繁中断对系统实时性也是有一定影响。 建议低于1KHz的PWM才使用此方法。
2.定时中断法
基于上面第一种,不适合高频PWM脉冲中断。经过思考,我们是否可以将多次中断的时间累加,只响应一次中断。
原理就是把定时的时间设定为单个脉冲的n倍(n个脉冲),只使用一次中断。

它的原理,大致如下图:

STM32如何实现可调频率、占空比的PWM波形,且可指定输出脉冲个数?


看图片中的提示,建议这个地方使用一个32位的定时器,这个值可能很大。
3.脉冲触发法
此方法可以避免上面两种方法中不足的地方, 相对上面两对实用性更强。电路上面,需要将PWM输出的波形,连接到另一个定时器的ETR引脚。

它的原理没什么特殊的,就是和我们常用的定时更新中断类似,只是输入信号改成PWM脉冲波形(默认为内部时钟CK_INT  如:36M)。

STM32如何实现可调频率、占空比的PWM波形,且可指定输出脉冲个数?


外部时钟源模式2实现方法

上面说过,使用PWM作为另一个定时器的输入时钟,即可达到对PWM计数的功能。

STM32如何实现可调频率、占空比的PWM波形,且可指定输出脉冲个数?


请参看手册中TIM定时器时钟选择章节。

1.输出PWM配置
void PWM_TIM_Configuration(void) {  GPIO_InitTypeDef        GPIO_InitStructure;  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  TIM_OCInitTypeDef       TIM_OCInitStructure;

   RCC_APB1PeriphClockCmd(PWM_TIM_CLK, ENABLE);  RCC_AHB1PeriphClockCmd(PWM_TIM_GPIO_CLK, ENABLE);  GPIO_InitStructure.GPIO_Pin = PWM_TIM_PIN;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  GPIO_Init(PWM_TIM_GPIO_PORT, &GPIO_InitStructure);

   GPIO_PinAFConfig(PWM_TIM_GPIO_PORT, PWM_TIM_SOURCE, PWM_TIM_AF);
 
   TIM_TimeBaseStructure.TIM_Prescaler = PWM_PRESCALER;               //预分频值  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //向上计数  TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                         //定时周期  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;            //分频因子  TIM_TimeBaseInit(PWM_TIMx, &TIM_TimeBaseStructure);

   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                  //PWM1模式  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;      //使能输出  TIM_OCInitStructure.TIM_Pulse = 0xFFFF;                            //脉宽值  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;          //输出极性  PWM_TIM_OCxInit(PWM_TIMx, &TIM_OCInitStructure);  TIM_Cmd(PWM_TIMx, DISABLE); }
初始化频率和占空比填充的值是最大值,即TIM_Period = 0xFFFF;TIM_Pulse = 0xFFFF; 实际没有使能定时器(输出的配置见下面函数接口)

2.选择外部时钟,定时中断配置
void CNT_TIM_Configuration(void) {  GPIO_InitTypeDef        GPIO_InitStructure;  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;  NVIC_InitTypeDef        NVIC_InitStructure;

   RCC_APB1PeriphClockCmd(CNT_TIM_CLK, ENABLE);  RCC_AHB1PeriphClockCmd(CNT_TIM_GPIO_CLK, ENABLE);  GPIO_InitStructure.GPIO_Pin = CNT_TIM_PIN;  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  GPIO_Init(CNT_TIM_GPIO_PORT, &GPIO_InitStructure);
 
   GPIO_PinAFConfig(CNT_TIM_GPIO_PORT, CNT_TIM_SOURCE, CNT_TIM_AF);

   NVIC_InitStructure.NVIC_IRQChannel = CNT_TIM_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = CNT_TIM_Priority;  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  NVIC_Init(&NVIC_InitStructure);

   TIM_ETRClockMode2Config(CNT_TIMx, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0);

   TIM_TimeBaseStructure.TIM_Prescaler = 0;                           //预分频值  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;        //向上计数  TIM_TimeBaseStructure.TIM_Period = 0xFFFF;                         //定时周期  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;            //分频因子  TIM_TimeBaseInit(CNT_TIMx, &TIM_TimeBaseStructure);  TIM_ClearFlag(CNT_TIMx, TIM_FLAG_Update);  TIM_ITConfig(CNT_TIMx, TIM_IT_Update, ENABLE);                     //使能"更新"中断  TIM_Cmd(CNT_TIMx, DISABLE); }

和常规的不同点在于: 使用外部时钟源

TIM_ETRClockMode2Config(CNT_TIMx, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_Inverted, 0);

注意检测(捕获)极性TIM_ExtTRGPolarity_Inverted,一般PWM都是高电平为脉冲波形,下降沿才算一个波形的计数。
3.输出PWM函数接口

void PWM_Output(uint32_t Frequency, uint32_t Dutycycle, uint32_t NumPulse) {  uint32_t pwm_period;  uint32_t pwm_pulse;

   pwm_period = PWM_CK_CNT/Frequency - 1;                             //计算出计数周期(决定输出的频率)  pwm_pulse  = (pwm_period + 1)*Dutycycle / 100;                     //计算出脉宽值(决定PWM占空比)  TIM_Cmd(PWM_TIMx, DISABLE);                                        //失能TIM  TIM_SetCounter(PWM_TIMx, 0);                                       //计数清零  TIM_SetAutoreload(PWM_TIMx, pwm_period);                          //更改频率  PWM_TIM_SetComparex(PWM_TIMx, pwm_pulse);                          //更改占空比  TIM_Cmd(PWM_TIMx, ENABLE);                                         //使能TIM    TIM_Cmd(CNT_TIMx, DISABLE);  TIM_SetCounter(CNT_TIMx, 0);  TIM_SetAutoreload(CNT_TIMx, NumPulse-1);                          //设置中断更新数  TIM_ClearFlag(CNT_TIMx, TIM_FLAG_Update);  TIM_Cmd(CNT_TIMx, ENABLE); }

void PWM_Output(uint32_t Frequency, uint32_t Dutycycle, uint32_t NumPulse);

我们只需要调用该函数接口就可以实现指定个数PWM输出了。中途不用软件参数,输出结束时自动响应定时中断,关闭定时器。

中断接口函数

void CNT_TIM_IRQHandler(void) {
 if(TIM_GetITStatus(CNT_TIMx, TIM_IT_Update) != RESET)  {    TIM_ClearITPendingBit(CNT_TIMx, TIM_IT_Update);    TIM_Cmd(PWM_TIMx, DISABLE);                  //关闭PWM输出    TIM_Cmd(CNT_TIMx, DISABLE);                  //关闭计数  } }


关键字:STM32  可调频率  占空比  PWM波形 引用地址:STM32如何实现可调频率、占空比的PWM波形

上一篇:STM32F407ADC多通道+定时器触发+DMA模式设置
下一篇:关于STM32进入低功耗模式后无法烧写程序的解决办法

推荐阅读

STM32 PB2(BOOT1)使用注意 由于STM32 PB2脚是复用引脚,而且该复用功能是用于启动选择,使用时就要小心了 -------------------------------------------------------------------------BOOT1 BOOT0 启动模式 说明 X 0 用户闪存存储器 用户闪存存储器被选为启动区域 0 1 系统存储器 ...
翻译自——spectrum,Jeremy Hsu 中文和英文密码的差异对现在流行的Web服务有很大的安全影响。 无论语言和文化有何不同,中、英文互联网用户都能在通过使用“123456”等密码变体时找到共同点。但最近研究发现,从比较两种语言密码模式来看,中文密码具有显著而独特的特点,对中国以外的互联网安全具有重大影响。 令人惊讶的是,由于使用中文用户的密码只...
  工业机器人目前在工业中逐渐适用,工业机器人将代替人工重复性劳动。现实中,更多工厂均采用进口工业机器人,那国产工业机器人与其到底有何差距呢?此外,目前工业机器人又有何应用呢?本文将揭露这些问题的答案。如果你对本文具有兴趣,不妨继续往下阅读哦。   一、国内外工业机器人差距分析   在我国工业机器人市场的需求一直在持续增长,但...
来源:学习军团·解放军新闻传播中心融媒体作者:解放军报记者 韩 成 通讯员 于 晨“机器人技术正在深刻改变着人类的生产和生活方式,中国空间站机械臂也助力我们完成了两次出舱任务。”9月中旬,在北京亦庄开幕的2021世界机器人大会上,神舟十二号飞行乘组3位航天员聂海胜、刘伯明、汤洪波从中国空间站传来“太空点赞”。被表扬的主角,是我国自主研...

史海拾趣

问答坊 | AI 解惑

砷化镓

(gallium arsenide)化学式 GaAs。黑灰色固体,熔点 1238℃。它在 600℃以下,能在空气中稳定存在,并且不为非氧化性的酸侵蚀。砷化镓可作 半导体材料,性能比硅更优良。它的禁带宽度大,电子迁移率高,介电常数 小,能引入深能级杂质,电子有 ...…

查看全部问答∨

一个嵌入式开发的资料(希望抛砖引玉)

嵌入式的开发如今是变的越来越复杂,对嵌入式工程师的要求越来越高。如何从一个应届毕业生, 或者普通的工程师向嵌入式迈进呢。网络上的资料很多,书店的书籍也很多,但大家都很难下手或者靠自学提高。 在最近的公司招聘面试的过程中,发现很多面试者( ...…

查看全部问答∨

LCD501液晶屏电子钟和电压表程序

本帖最后由 paulhyde 于 2014-9-15 08:57 编辑 见附件  …

查看全部问答∨

编译PassThru出现函数没有定义的问题

小弟我刚接触驱动开发,现在在学习PassThru,把书上的例子用VS2008+DDKWinWiard+XP SP3+DDK(server 03)编译PassThru 但是却出现了莫名奇妙的错误: c:\\MyProject\\PassThru\\PassThru\\miniport.c(74) : error C4013: \'NdisIMGetDeviceContext\ ...…

查看全部问答∨

请问没有系统的UART编程和CE下的UART编程的区别?

撇开软件部分不说,单看硬件方面的设置: 1)基于ARM7裸机的串口简单的编程:如串口初始化,设置波特率,寄存器设置,中断向量设置等 2)自己基于CE下编一个串口驱动,也是要向上面一样设置ARM芯片的初始化吗?和裸机的那些设置是一样 ...…

查看全部问答∨

急!!!eboot.bin文件怎么解压缩!!!

eboot.bin文件烧进系统以后,会自行压缩成eboot.nb0文件。我现在需要知道这个压缩的过程的代码是在哪个文件的哪个函数里的!有知道的吗??? 我找了F:\\WINCE500\\PUBLIC\\COMMON\\OAK\\DRIVERS\\ETHDBG\\BLCOMMON的BLCOMMON.c文件的DownloadImage函 ...…

查看全部问答∨

求救,按键驱动

现在我想写一个2440的按键驱动,只需要几个按键就可以了,比较(上,下,左,右功能)。 要求能够传递给任意进程中,比如按上下左右键能够操作控制界面(UI)。 请问是不是只能在提供的标准的键盘驱动中写,有没有更简单的方法,哪位大哥给点思路呀…

查看全部问答∨

ATMEGA8--想要爱你不容易!!

      在这夏天,炎热酷暑。在这夏天,躲在架设有几十台电脑的实验室,狭窄的空间,空气是凝固的,室内气温自然上去了。就这样,度过了一个刻骨铭心的暑假!然而,一个暑假下来,付出是多,收获也是多的。你们是否记得, ...…

查看全部问答∨

IAR使用J-Link仿真的问题

我写了一个LM3S9B92的UART简单收发程序,想下载到开发板中,用的是IAR软件,和J-LINK仿真器,请高手指教一下具体的步骤,比如说软件的相关配置等等问题,谢了   我在下载的 过程中出现了这个问题 Fatal Error[Lc002]: could not open file ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved