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

发布者:RadiantGaze最新更新时间:2024-07-12 来源: elecfans关键字:外部中断  定时器  信号频率 手机看文章 扫描二维码
随时随地手机看文章

摘要:利用定时器产生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?imageView2/2/w/1000

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


关键字:外部中断  定时器  信号频率 引用地址:如何利用外部中断和定时器测量信号频率?

上一篇:浅谈定时器基础知识与PWM输出原理
下一篇:机械变阻器的控制器设计原理及控制命令

推荐阅读最新更新时间:2026-03-21 01:53

如何利用外部中断定时器测量信号频率
摘要:利用定时器产生PWM波。然后利用32的外部中断和定时器来测量32输出的波形硬件:STM32F103C8T6核心板、示波器、串口调试助手所用到的的引脚为PA8和PA0。测量方案:在第一次外部中断(上升沿触发)到之时,开启定时器,同时计数器清零。 然后等待第二次中断到来,在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,同时关闭计数器。因为知道了计数器计数一个数的时间,所以在第二次外部中断(上升沿触发)到之时,获取计数器的计数值,通过这个值就知道一个脉冲的时间周期。时间周期的倒数就是外部信号的频率。 一、利用TIM1的CH1产生PWM波 pwm.c pwm.h main.c 定时器1的通道1对应的是PA
[单片机]
如何利用<font color='red'>外部中断</font>和<font color='red'>定时器</font>测量<font color='red'>信号频率</font>
51单片机~定时器外部中断(各个位控制作用详解)
(一)中断 (二)定时器,计数器中断 TL0低八位先进行存储,达到0XF,向上进一,直到高低八位都满时就可以产生中断或者控制TF0口。 (1). TMOD低四位控制T0,高四位控制T1。 GATE:(门控位) (2)控制寄存器TCON:(低四位控制外部中断,高四位控制计数器启动和中断申请) (3)定时器的四种工作方式: 定时器开启工作原理: 四种工作方式:(机器周期(脉冲)和T0引脚来绝定电路触发) 区别在于TH0和TL0的位数和输出) 常用1和2 1. 2.用于比较精确的脉冲信号发射器: 3. 程序化步奏: 计算:初值==2^n-N(公式要根据你使用那种方式0.1
[单片机]
51单片机~<font color='red'>定时器</font>和<font color='red'>外部中断</font>(各个位控制作用详解)
51单片机入门——定时器外部中断
1. 定时器 1.1. 定时器的初步认识 在认识定时器之前我们先了解两个基本概念。 时钟周期:时钟周期 T 是时序中最小的时间单位,具体计算方法就是 1 / 时钟源频率,一般情况下单片机的晶振都是 11.0592 MHz 的,对于这个单片机系统来说时钟周期就是 1 / 11059200 秒。 机器周期:我们的单片机完成一个操作的最短的时间。机器周期主要针对于汇编语言,在汇编语言下程序的每一条语句所使用的时间都是机器语言的整数倍,而且语句占用的时间是可以计算出来的,而 C 语言一条语句所占用的时间是不确定的,受诸多因数的影响。51 单片机系列,在其标准架构下一个机器语言是 12 个时钟周期,也就是 12 / 11059200
[单片机]
51单片机入门——<font color='red'>定时器</font>与<font color='red'>外部中断</font>
ATmega8 定时器 中断 外部中断 程序
4MHZ时钟 #include iom8v.h #include macros.h #include stdio.h #include stdlib.h #include string.h #include lcd1602.h int getKeyBoardValue( void ) { return(0); } /*定时器1中断服务程序*/ #pragma interrupt_handler Timer1_ovf:9 void Timer1_ovf( void ) { TCNT1H = (65535 - 20000) / 256; /* 5ms */ TCNT1L = (6
[单片机]
C51联盟 —— 外部中断+定时器中断
/*****************************************************/ void Int0Init(); //开启外部中断INTR0 void Timer1Init(); //定时器中断 5毫秒@12.000MHz /*****************************************************/ void main() { SEG = 0; Int0Init(); Timer1Init(); while(1); } /*****************************************************/ void FlowLED
[单片机]
STM32Cube MX学习二--定时器外部中断
对于一些基本操作可以参照第一篇的内容学习,几乎都是步骤图片,步骤内容都是在图里了。这个软件的学习主要分为基础的两三篇,然后转为RTOS的学习,毕竟是工具的使用,原理的东西虽然会涉及描述,但应该不会在这个系列里面太多。遇到困难的知识,我还会再次分类学习。 本章学习一下配置定时器,或者外部中断,内容比较相近,就不分开讲述了,进入学习内容,重点请看图: 1、开启定时器功能 选择自己想要配置的定时器,如TIM1/TIM2/TIM3....,当然定时器有很多的模式,那个是定时计数模式? 第一步:图中,mode板块里,第三个选项:Clock Source :选Internal Clock。这个就是定时计数模式了。 2、定时计算
[单片机]
STM32Cube MX学习二--<font color='red'>定时器</font>、<font color='red'>外部中断</font>
单片机学习笔记外部中断定时器,串口中断
CPU收到中断请求,停下正在处理的工作A,去处理事件B,处理完后继续回到中断的地方继续执行事件A的过程,称为中断 51有5个中断源 外部中断0 定时计数中断0 外部中断1 定时继续中断1 串口中断 MCS-51单片机中断系统的结构: 5个中断源的符号、名称及产生的条件如下。 INT0:外部中断0,由P3.2端口线引入,低电平或下跳沿引起。 INT1:外部中断1,由P3.3端口线引入,低电平或下跳沿引起。 T0:定时器/计数器0中断,由T0计满回零引起。 T1:定时器/计数器l中断,由T1计满回零引起。 TI/RI:串行I/O中断,串行端口完成一帧字符发送/接收后引起。
[单片机]
单片机学习笔记<font color='red'>外部中断</font>,<font color='red'>定时器</font>,串口中断
51定时器外部中断
#include reg52.h #define uint unsigned int #define uchar unsigned char sbit p2_0=P2^0; sbit p2_2=P2^1; sbit p2_4=P2^2; uchar num=11; uchar tt=0; uchar bai,shi,ge,bai1,num1; uchar code table = {~0x3f,~0x06,~0x5b,~0x4f, ~0x66,~0x6d,~0x7d,~0x07, ~0x7f,~0x6f,~0x77,~0x7c, ~0x39,~0x5e,~0x79,~0x71}; void delay(uint z)
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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