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

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

3天内不再提示

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

FPGA之家 来源:FPGA之家 作者:FPGA之家 2021-03-29 14:19 次阅读

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

一、利用TIM1的CH1产生PWM波pwm.c

#include “pwm.h” void TIM1_PWM_Init(u16 arr,u16 psc) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); //使能GPIO外设时钟使能 //设置该引脚为复用输出功能,输出TIM1 CH1的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的频率为200 000/100=2 000 HZ=2K 实际示波器测量

2.00055K TIM_TimeBaseStructure.TIM_Prescaler =psc; //驱动(单片机提供给)计数器的时钟是72 000 000/36 0=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” void TIM1_PWM_Init(u16 arr,u16 psc); #endifmain.c

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

二、将PA8与PA0相连接这里利用PA8输出的PWM波形让PA0外部中断引脚测量。

三、外部中断和定时器测量频率在配置定时器时最重要的就是配置定时器的预分频系数和重装载值。定时器的本质就是一个计数器,计数到我们设定的值后就会溢出,也就是重新从0开始开始计数。设置预分频系数就是设置计数器的频率,假设为71,F1的系统时钟为72M,经过72分频,给计数器的时钟频率就是1M,周期就是1/1M=1us。也是就1us计一个数。那么计几个数呢?这就要看重装载值ARR,这里我们设置为0XFFFF,也就是计数65536个数,就是计满整个寄存器的值。为什么要分频系数为72,重装载值为0XFFFF?这里给出详细的分析过程。

1 为什么要分频系数为72F1的系统时钟为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波对吧!如果我们测量到一个周期的时间,那么不就知道了信号的频率了吗?

测量方案:在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。然后等待第二次中断到来,在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,关闭计数器。因为我们知道了计数器计数一个数的时间,所以我们到在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,通过这个值就知道一个脉冲的时间周期。时间周期的倒数就是外部信号的频率。

具体代码如下:

void EXTI0_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++; }

else if(CaptureNumber==1)//第2次上升沿触发 { TimeCntValue = TIM_GetCounter(TIM2); Capture = TimeCntValue; 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); } }当然你可能觉得这只是测量信号的一个周期脉冲不够准确,那么也可以测量100次脉冲的时间再除以100,就是一个脉冲的时间,然后再取倒数就可以算出频率,这种方法也是可以的。具体代码如下:

void EXTI0_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++; } else if(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); } }程序流程图

26aa9646-8ecc-11eb-8b86-12bb97331649.png

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

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

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

责任编辑:haq

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

    关注

    2270

    文章

    10900

    浏览量

    355955
  • 定时器
    +关注

    关注

    23

    文章

    3248

    浏览量

    114789

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

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

收藏 人收藏

    评论

    相关推荐

    是德KEYSIGHT53200A 系列射频/通用频率计数器/定时器

    是德KEYSIGHT53200A系列射频/通用频率计数器/定时器 53200A频率计数器能在研发和制造中进行快速、精确频率和时间间隔测量
    的头像 发表于 12-01 22:52 114次阅读

    定时器的基本组成和工作模式

    定时器是计算机或电子设备中常见的一个硬件或软件组件,其主要功能是测量和控制时间的流逝。它在各种应用中起着至关重要的作用,如操作系统调度、多媒体播放、网络通信、工业自动化控制以及家电设备的定时功能等。
    的头像 发表于 08-19 18:28 1291次阅读

    定时器的工作方式介绍

    或实现周期性事件的硬件模块。它可以用于实现各种定时任务,如定时中断、PWM(脉冲宽度调制)输出、频率测量等。定时器通常由一个计数
    的头像 发表于 07-12 10:29 951次阅读

    定时器相关的寄存有哪些类型

    在微控制编程中,定时器是一种非常常见的功能模块,用于实现各种定时和计数功能。定时器的工作原理是通过内部的计数来跟踪时间的流逝,当计数
    的头像 发表于 07-12 10:25 934次阅读

    使用定时器的编码接口模式,打开定时器的溢出中断,当定时器上溢出和下溢出是,是否都会产生溢出中断

    使用定时器的编码接口模式,打开定时器的溢出中断,当定时器上溢出和下溢出是,是否都会产生溢出中断
    发表于 05-24 07:41

    stm32定时器的如何外部启动?

    我想利用stm32定时器精确定时一个信号从发生到结束的时间,想让定时器通过外部触发开启,一般有什
    发表于 05-10 06:40

    STM32的GPIO引脚能同时用作外部中断定时器输入捕获吗?

    今天突然在项目中想到一种用法,将GPIO的某一个引脚,同时配置外部中断(在中断中做一些逻辑)和复用为定时器的输入捕获引脚。 查看GPIO的原理框图,感觉可行。找个机会试试这种用法,于是
    发表于 05-09 08:22

    如何实现一个软件定时器

    在Linux,uC/OS,FreeRTOS等操作系统中,都带有软件定时器,原理大同小异。典型的实现方法是:通过一个硬件定时器产生固定的时钟节拍,每次硬件定时器中断到,就对一个全局的时间
    的头像 发表于 04-29 11:00 652次阅读

    使用555定时器的可调双定时器电路

    定时器 IC 555 是最通用和最常用的 IC 之一,因为它的应用范围更广,如 PWM放大器、延迟定时器、开关电路、占空比选择、时钟脉冲发生等。这也可用于各种应用,如精确
    的头像 发表于 02-25 15:16 2223次阅读
    使用555<b class='flag-5'>定时器</b>的可调双<b class='flag-5'>定时器</b>电路

    国产嵌入式教学实验箱操作教程:2-13 定时器控制实验

    独立32位计数及自动重装32位计数,可以产生周期中断DMA事件及外部事件。定时器/计数还可
    发表于 02-21 14:09

    浅谈时间间隔计数定时器间隔测量功能

    频率计数器一样,定时器计数或间隔定时器也具有许多组成测试仪器的模块。它们与计数中使用的非常相似,只需要重新配置即可提供间隔
    的头像 发表于 02-08 07:32 1737次阅读

    单片机外部中断定时器中断的区别和用法

    单片机外部中断定时器中断在触发来源、应用场景以及功能特点上存在明显差异** **。
    的头像 发表于 01-28 17:35 3125次阅读

    定时器原理能控制马达吗为什么

    定时器原理可以用于控制马达。马达是一种将电能转换为机械能的设备,通常由电动机和传动装置组成。定时器是一种电子设备,用来生成和计时精确而稳定的时间信号。通过将定时器与马达控制电路相连,可
    的头像 发表于 01-23 15:21 668次阅读

    555定时器的基本功能 555定时器的工作原理及其应用

    555定时器是一种非常常见和常用的集成电路,它具有广泛的应用领域,例如计时、频率分频、脉冲宽度调制等。本文将详细介绍555定时器的基本功能、工作原理以及应用。 一、555定时器的基本功
    的头像 发表于 01-18 11:12 1.5w次阅读

    典型定时器电路图分享

    定时器是一种用于测量和控制系统时间的装置。它可以根据设定的时间间隔或延迟,输出特定的信号或执行特定的操作。
    的头像 发表于 01-11 17:16 5965次阅读
    典型<b class='flag-5'>定时器</b>电路图分享