0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

黄工的嵌入式技术圈 来源:网站整理 2020-03-12 11:04 次阅读

读者朋友“*imYan*”问:

pwm实现频率可调和占空比可调后怎么来实现输出10个脉冲呢?我这边看有门控或者单脉冲加重复计数,黄老师平时用的什么方法?

我的回答:

使用两个TIM定时器:一个输出可调频率、占空比的PWM,一个对输出PWM脉冲计数(计时)。

1.门控方式能实现,但需要复杂的配置和计算,不推荐

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

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

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

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

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

STM32定时器

STM32的TIM定时器少则五六个,多则二十个。 可能许多初学者觉得:那么多定时器用的完吗? 那么多不是浪费吗?

这么说吧,STM32的定时器功能非常强大,之所以有那么多定时器,原因在于使用定时器的地方有许多,本文要讲的这个例子只是很基础的一个例子。

当然,可能很多人想问:利用阻塞延时,控制IO高低变化输出PWM这种方式就行啦,也很简单。其实,这种方法的弊端很大。

1.输出的PWM可能存在误差;

2.对整个系统的实时性可能有影响;

所以不建议使用该方法。

Ⅱ几种实现方法

使用两个定时器配合输出可调频率、占空比的PWM波形,且可指定输出脉冲个数的方法和原理其实不难。

输出PWM的方法就是使用TIM定时器自带有的PWM模式即可完成。主要难点在于还要控制指定输出脉冲的个数。

对于如何控制输出指定脉冲个数,下面大概说下三种方法:

1.脉冲中断计数法

IO中断,或者定时器同步(脉冲)中断。

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

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

它的原理,大致如下图:

此方法建议在输出高频PWM时不要使用,频繁中断对系统实时性也是有一定影响。建议低于1KHz的PWM才使用此方法。

2.定时中断法

基于上面第一种,不适合高频PWM脉冲中断。经过思考,我们是否可以将多次中断的时间累加,只响应一次中断。

原理就是把定时的时间设定为单个脉冲的n倍(n个脉冲),只使用一次中断。

它的原理,大致如下图:

看图片中的提示,建议这个地方使用一个32位的定时器,这个值可能很大。

3.脉冲触发法

此方法可以避免上面两种方法中不足的地方, 相对上面两对实用性更强。电路上面,需要将PWM输出的波形,连接到另一个定时器的ETR引脚。

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

下面章节我就以该方法(第3种方法),PWM波形作为定时器的输入时钟的方式,用代码给大家讲述一下。

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

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

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

1.输出PWM配置

/************************************************函数名称 : PWM_TIM_Configuration功 能 : PWM输出定时器配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/ 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); /* PWM模式配置 */ 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.选择外部时钟,定时中断配置

/************************************************函数名称 : CNT_TIM_Configuration功 能 : 计时定时器配置参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/ 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配置 */ 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函数接口

/************************************************函数名称 : PWM_Output功 能 : 输出PWM参 数 : Frequency --- 频率 Dutycycle --- 占空比(12代表占空比为12%) NumPulse --- 脉冲个数返 回 值 : 无作 者 : strongerHuang*************************************************/ void PWM_Output(uint32_t Frequency, uint32_t Dutycycle, uint32_t NumPulse){ uint32_t pwm_period; uint32_t pwm_pulse; /* 输出PWM */ 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输出了。中途不用软件参数,输出结束时自动响应定时中断,关闭定时器。

中断接口函数

/************************************************函数名称 : CNT_TIM_IRQHandler功 能 : 计时中断参 数 : 无返 回 值 : 无作 者 : strongerHuang*************************************************/ 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); //关闭计数 }}

Ⅳ实际效果和代码

为方便大家,提供了一个简单裸机程序:

int main(void){ System_Initializes(); while(1) { LED_TOGGLE(); //LED变化 Delay(5); //延时(约240ms) PWM_Output(1000, 20, 10); //1KHz, 20%占空比, 10个脉冲 }}

main函数中实现效果:间隔240ms(软件延时不精确)输出10个PWM波形

波形具体情况:输出1KHz, 20%占空比, 10个脉冲精确的PWM波形

下载地址(STM32F401为例工程,STM32其他芯片类似):

链接:https://pan.baidu.com/s/10GPPxCky8SZmU9S9pleqJg

密码:4jf3

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • PWM
    PWM
    +关注

    关注

    114

    文章

    4900

    浏览量

    209904
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348736
  • 输出脉冲
    +关注

    关注

    0

    文章

    4

    浏览量

    6338
收藏 人收藏

    评论

    相关推荐

    一文带你了解PWM原理、频率占空比

    会下降。也就是,在一定的频率下,通过不同的占空比 即可得到不同的输出模拟电压。pwm就是通过这种原理实现D/A转换的。总结:
    发表于 03-27 14:12

    pwm如何产生指定个数脉冲,而不占用cpu?

    pwm如何产生指定个数脉冲,而不占用cpu?目前我能想到的办法是:1.定时器产生一次中断,在中断函数里计数。这种方法频繁中断,影响cpu效率。并且当所产生的
    发表于 03-14 06:34

    GTM怎么输出指定脉冲数的PWM呢?

    我们都知道GTM生成独立的可调占空比可调周期PWM,或带死区的互补PWM,那么怎么
    发表于 01-26 08:08

    pwm频率占空比的计算公式

    和应用。 一、PWM的基本原理 PWM是一种将模拟信号转化为数字信号的技术,通过调整数字信号的脉冲宽度来控制输出电平的高低。基本原理如下: 1.1
    的头像 发表于 12-28 11:40 5541次阅读

    怎么实现dsp芯片输出占空比固定的pwm波形

    实现DSP芯片输出占空比固定的PWM波形需要以下步骤:定义占空比、设置计时器、计算周期和持续时间
    的头像 发表于 12-26 17:28 794次阅读

    一文详解PLC高速脉冲输出指令

    利用高速脉冲输出指令可让CPU模块内部的高速脉冲发生器输出占空比为50%、周期可调的方波
    的头像 发表于 12-19 14:04 3404次阅读
    一文详解PLC高速<b class='flag-5'>脉冲</b><b class='flag-5'>输出</b>指令

    STM32PWM波形输出配置的大神总结

    STM32PWM波形输出配置的大神总结
    的头像 发表于 10-24 16:00 2276次阅读
    <b class='flag-5'>STM32</b>的<b class='flag-5'>PWM</b><b class='flag-5'>波形</b><b class='flag-5'>输出</b>配置的大神总结

    STM32H7芯片系列中定时器同步启动并输出PWM波形实现方法

    本文主要研究了STM32H7芯片系列中定时器同步启动并输出PWM波形实现方法。
    的头像 发表于 10-24 14:56 683次阅读
    <b class='flag-5'>STM32</b>H7芯片系列中定时器同步启动并<b class='flag-5'>输出</b><b class='flag-5'>PWM</b><b class='flag-5'>波形</b>的<b class='flag-5'>实现</b>方法

    STM32 TIMER+DMA输出PWM异常案例的问题解析

    有人使用STM32U575的TIMER加上DMA做PWM输出。具体就是利用某TIMER的一个通道的比较事件触发DMA,通过DMA修改CCR值来实现
    的头像 发表于 09-28 09:04 4242次阅读
    <b class='flag-5'>STM32</b> TIMER+DMA<b class='flag-5'>输出</b><b class='flag-5'>PWM</b>异常案例的问题解析

    举个例子来说明PWM如何输出指定脉冲

    举个例子来说明PWM如何输出指定脉冲数: 假设我们需要使用PWM来控制一个直流电机的转速。电机的转速可以通过调节
    发表于 09-21 08:55

    pwm就能输出指定脉冲

    PWM(Pulse Width Modulation)是一种调制技术,通过改变高电平和低电平的持续时间来调节输出脉冲宽度。通过PWM技术,我们可以在不改变
    发表于 09-21 08:52

    M0系列亮点: NCO和CCL, PWM细致调频和内置编程逻辑

    M0系列亮点: NCO和CCL, PWM细致调频和内置编程逻辑 MG32F02V032芯片也具有NCO(数字控制振荡器),输出
    发表于 08-29 15:40

    如何用一个定时器实现3路时差和占空比可调波形

    有人想实现下面的PWM输出波形,三路频率相同,占空比同步可调
    的头像 发表于 07-06 15:22 1104次阅读
    如何用一个定时器<b class='flag-5'>实现</b>3路时差和<b class='flag-5'>占空比</b><b class='flag-5'>可调</b>的<b class='flag-5'>波形</b>

    如何利用M051实现PWM输出频率可调

    我想用M051实现PWM输出频率0.1Hz-20Hz间的低频调频。但是该PWM我是用P2.0引
    发表于 06-25 06:40

    STM32CubeMX输出可调频率占空比PWM

    1,新建工程,我选的是STM32F103ZET6芯片,选择定时器的PWM功能。2、配置时钟,我这里配的是内部时钟,有需要的可以自己改。3、配置定时器,默认就可以,因为代码里面需要对配置的初始化代码
    的头像 发表于 05-11 10:00 2444次阅读
    <b class='flag-5'>STM32</b>CubeMX<b class='flag-5'>输出</b><b class='flag-5'>可调频率</b>与<b class='flag-5'>占空比</b>的<b class='flag-5'>PWM</b>