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

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

3天内不再提示

如何利用定时器产生PWM波

FPGA之家 来源:FPGA之家 作者:FPGA之家 2022-08-16 09:09 次阅读

摘要:利用定时器产生PWM波。然后利用32的外部中断和定时器来测量32输出的波形硬件:STM32F103C8T6核心板、示波器、串口调试助手所用到的的引脚为PA8和PA0。 测量方案:在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。然后等待第二次中断到来,在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,同时关闭计数器。因为知道了计数器计数一个数的时间,所以在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,通过这个值就知道一个脉冲的时间周期。时间周期的倒数就是外部信号的频率。

一、利用TIM1的CH1产生PWM波

pwm.c


#include"pwm.h" voidTIM1_PWM_Init(u16arr,u16psc) { GPIO_InitTypeDefGPIO_InitStructure; TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure; TIM_OCInitTypeDefTIM_OCInitStructure;  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能GPIO外设时钟使能 //设置该引脚为复用输出功能,输出TIM1CH1的PWM脉冲波形 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;//TIM_CH1 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period=arr;//输出PWM的频率为200000/100=2000HZ=2K实际示波器测量2.00055K TIM_TimeBaseStructure.TIM_Prescaler=psc;//驱动(单片机提供给)计数器的时钟是72000000/360=200kHZ TIM_TimeBaseStructure.TIM_ClockDivision=0;//设置时钟分割:TDTS=Tck_tim TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上计数模式 TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位  TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM2;//选择定时器模式:TIM脉冲宽度调制模式2 TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//比较输出使能 TIM_OCInitStructure.TIM_Pulse=3600;//设置待装入捕获比较寄存器的脉冲值这个值要为arr:自动重装值的一半,占空比才为50% TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;//输出极性:TIM输出比较极性高 TIM_OC1Init(TIM1,&TIM_OCInitStructure);//根据TIM_OCInitStruct中指定的参数初始化外设TIMx TIM_CtrlPWMOutputs(TIM1,ENABLE);//MOE主输出使能 TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);//CH1预装载使能 TIM_ARRPreloadConfig(TIM1,ENABLE);//使能TIMx在ARR上的预装载寄存器 TIM_Cmd(TIM1,ENABLE);//使能TIM1 } pwm.h

#ifndef__PWM_H #define__PWM_H #include"sys.h" voidTIM1_PWM_Init(u16arr,u16psc); #endif main.c

#include"delay.h" #include"sys.h" #include"pwm.h" intmain(void) { delay_init();//延时函数初始化 //10k7199 //20k3599 //8k8999 TIM1_PWM_Init(7199,0);//不分频,输出PWM频率=72000K/(7199+1)=10Khz while(1) { } } 定时器1的通道1对应的是PA8引脚,连接示波器可以测出波形

71e05130-1cfd-11ed-ba43-dac502259ad0.jpg

二、将PA8与PA0相连接

这里利用PA8输出的PWM波形让PA0外部中断引脚测量。

71f27dec-1cfd-11ed-ba43-dac502259ad0.jpg

三、外部中断和定时器测量频率

在配置定时器时最重要的就是配置定时器的预分频系数和重装载值。定时器的本质就是一个计数器,计数到我们设定的值后就会溢出,也就是重新从0开始开始计数。设置预分频系数就是设置计数器的频率,假设为71,F1的系统时钟为72M,经过72分频,给计数器的时钟频率就是1M,周期就是1/1M=1us。也是就1us计一个数。那么计几个数呢?这就要看重装载值ARR,这里我们设置为0XFFFF,也就是计数65536个数,就是计满整个寄存器的值。为什么要分频系数为72,重装载值为0XFFFF?这里给出详细的分析过程。 1 为什么要分频系数为72 F1的系统时钟为72M,F1的系统时钟为72M,如果不分频的话,提供给定时器的时钟就直接是72MHZ。72MHz是个什么概念?72MHz它对应的周期就是(1/72000000)秒,也就是计数器从0计数到最大值65535,只需要花费(65535/72000000)秒≈1ms。这句话的意思就是如果你不分频,计数器最大只能定时1ms。那么你的定时器每隔1ms就会溢出一次。如果经过72分频,给计数器的时钟频率就是1M,周期就是1/1M=1us,也是就1us计一个数。换句话就是可以采样的波形频率为1M,提高了采样频率。另一方面也是容易计算,计一个数1us,计count个数就是count个us,频率就是1000000/count(HZ)。 2 为什么要重装载值为0XFFFF 最大采样间隔是跟定时器的中断间隔相关的,定时器产生溢出中断后计数值CNT会自动清0,定时器的中断间隔由分频系数Prescaler和自动重装载寄存器Period决定,分频系数前面已经确定,那最大采样间隔只需要考虑自动重装载寄存器Period的设置,比如频分析系数71,自动重装寄存器值65535,则中断间隔=65536/72000000/72=65.536ms,即最大采样间隔65.536ms,如果65.536ms内没有检测到一个脉冲,则这么设定间隔是不合理的,必须想办法牺牲最小的采样时间1us(扩大分频系数)或者扩大自动重装寄存器值(16位<65535)来增加定时器中断间隔,也可以编写自己的应用函数来计算溢出的定时时间。 一般来说我们使用外部中断是不需要用到定时器的,看原子和野火的外部中断实验也没有用到外部中断。但是现在不是利用外部中断简单的处理一件事,而是利用外部中断测量频率,而测频率就涉及到时间,而只要涉及到时间,就需要用到定时器了。测量外部信号的频率,就是测量PWM波对吧!如果我们测量到一个周期的时间,那么不就知道了信号的频率了吗? 测量方案:在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。然后等待第二次中断到来,在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,关闭计数器。因为我们知道了计数器计数一个数的时间,所以我们到在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,通过这个值就知道一个脉冲的时间周期。时间周期的倒数就是外部信号的频率。

具体代码如下:


voidEXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line0);//清除EXTI0线路挂起位 if(CaptureNumber==0)//第1次上升沿触发 { TIM_Cmd(TIM2,ENABLE);//使能定时器2 TIM_SetCounter(TIM2,0);//清零计数器的值,因为一开始就开始计数了 CaptureNumber++; } elseif(CaptureNumber==1)//第2次上升沿触发 { TimeCntValue=TIM_GetCounter(TIM2); Capture=TimeCntValue; CaptureNumber=0; TIM_Cmd(TIM2,DISABLE);//使能定时器2 } } } intmain(void) { floatx; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); delay_init(); uart_init(115200); TIM2_Init(); TIM1_PWM_Init(7199,0);//不分频,输出PWM频率=72000K/(7199+1)=10Khz EXTIA0_Init(); while(1) { printf("Fre=%.2fkHz ",1000000/Capture); delay_ms(1000); } } 当然你可能觉得这只是测量信号的一个周期脉冲不够准确,那么也可以测量100次脉冲的时间再除以100,就是一个脉冲的时间,然后再取倒数就可以算出频率,这种方法也是可以的。具体代码如下:

voidEXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0)!=RESET) { EXTI_ClearITPendingBit(EXTI_Line0);//清除EXTI0线路挂起位 if(CaptureNumber==0)//第1次上升沿触发 { TIM_Cmd(TIM2,ENABLE);//使能定时器2 TIM_SetCounter(TIM2,0);//清零计数器的值,因为一开始就开始计数了 CaptureNumber++; } elseif(CaptureNumber>0&&CaptureNumber<100)   {     TimeCntValue0 = TIM_GetCounter(TIM2);       CaptureNumber++;       }   else if(CaptureNumber==100)//第100次上升沿触发   {       TimeCntValue = TIM_GetCounter(TIM2);    Capture = TimeCntValue/100;    CaptureNumber = 0;     TIM_Cmd(TIM2,DISABLE);//使能定时器2       }  }  } int main(void) {   float x;  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  delay_init();   uart_init(115200);     TIM2_Init();  TIM1_PWM_Init(7199,0);  //不分频,输出PWM频率=72000K/(7199+1)=10Khz  EXTIA0_Init();  while(1)  {   printf("Fre=%.2f kHz ",1000000/Capture);   delay_ms(1000);   } } 程序流程图

720556b0-1cfd-11ed-ba43-dac502259ad0.png

串口打印结果

7224b938-1cfd-11ed-ba43-dac502259ad0.png

当然测量信号频率的方法可以直接利用TIM的输入捕获的方法就可以实现。用外部中断只是另一种测量方案,具体用哪一种还要看具体情况。

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

    关注

    113

    文章

    6303

    浏览量

    186039
  • 定时器
    +关注

    关注

    23

    文章

    3256

    浏览量

    115517
  • PWM波
    +关注

    关注

    0

    文章

    99

    浏览量

    16966

原文标题:利用外部中断和定时器测量信号频率

文章出处:【微信号:zhuyandz,微信公众号:FPGA之家】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    定时器产生PWM

    我用定时器产生20ms为周期的PWM,可以实现,但是我的步进有0.08ms,我现在想实现步进0.02ms,怎么办。
    发表于 08-09 15:33

    利用定时器产生PWM

    摘要利用定时器产生PWM。然后利用32的外部中断和定时器
    发表于 08-16 08:37

    如何利用定时器TIM1的CH1产生PWM

    如何利用定时器TIM1的CH1产生PWM?如何利用STM32的外部中断和
    发表于 11-16 09:23

    如何利用定时器产生PWM

    点击上方“果果小师弟”,选择“置顶/星标公众号”干货福利,第一时间送达!摘要:利用定时器产生PWM。然后
    发表于 12-06 07:54

    如何使用cc2530定时器产生pwm

    如何使用cc2530定时器产生pwm
    发表于 01-25 06:55

    如何利用Cortex-M7的低功耗定时器LPTIM去产生PWM

    如何利用Cortex-M7的低功耗定时器LPTIM去产生PWM呢?有哪些操作步骤?
    发表于 01-26 06:10

    如何使用标准51定时器0产生pwm

    如何使用标准51定时器产生pwm
    发表于 10-30 07:03

    定时器输出PWM实验

    定时器输出PWM 实验 一. 实验目的利用定时器控制产生占空比可变的PWM
    发表于 09-22 10:49 7463次阅读

    利用定时器产生乐曲

    利用定时器产生乐曲,有兴趣可以下载试试,挺好玩的
    发表于 11-30 17:35 2次下载

    如何利用stm32的高级定时器产生PWM

    用stm32的高级定时器TIM1和TIM8产生PWM,需要注意: 1.都有TIM1,但只有flash容量大于256K的大容量单片机才有TIM8 2.高级定时器相对于通用
    发表于 10-24 15:48 6731次阅读
    如何<b class='flag-5'>利用</b>stm32的高级<b class='flag-5'>定时器</b><b class='flag-5'>产生</b><b class='flag-5'>PWM</b>

    如何利用外部中断和定时器测量信号频率

      摘要:利用定时器产生PWM。然后利用32的外部中断和
    的头像 发表于 12-22 16:42 6849次阅读
    如何<b class='flag-5'>利用</b>外部中断和<b class='flag-5'>定时器</b>测量信号频率

    如何利用外部中断和定时器测量信号频率?

    摘要:利用定时器产生PWM。然后利用32的外部中断和定时器
    的头像 发表于 03-29 14:19 4085次阅读
    如何<b class='flag-5'>利用</b>外部中断和<b class='flag-5'>定时器</b>测量信号频率?

    用单片机制作简单的频率计

    点击上方“果果小师弟”,选择“置顶/星标公众号”干货福利,第一时间送达!摘要:利用定时器产生PWM。然后
    发表于 11-23 18:21 8次下载
    用单片机制作简单的频率计

    如何使用555定时器产生PWM

    生成PWM ,那么我们更喜欢一些通用IC,如运算放大器,定时器,脉冲发生等。这里我们使用 555定时器IC来产生
    的头像 发表于 01-25 15:09 8432次阅读
    如何使用555<b class='flag-5'>定时器</b>来<b class='flag-5'>产生</b><b class='flag-5'>PWM</b>

    高精度定时器与高级控制定时器 PWM后再恢复的区别

    高精度定时器与高级控制定时器 PWM后再恢复的区别
    的头像 发表于 10-17 16:52 876次阅读
    高精度<b class='flag-5'>定时器</b>与高级控制<b class='flag-5'>定时器</b> <b class='flag-5'>PWM</b> 封<b class='flag-5'>波</b>后再恢复的区别