正在学TIVA的TM4C123GH6PM板子,记录一下学习输入边沿计时模式的过程

2019年10月15日01:14:06更新

今天修复了Project里频率计的一个Bug。

可以测量低频率和任意频率啦!!!

原来的版本无法得到广谱上的正确频率,只能正确地得到几个分立的频率点。分析发现这些频率点其实都是时钟频率的约数,也就是说他们的整数倍正好可以得到时钟频率的数值。但是频率谱上抛开这几个点的其他频率,则会闪屏,也就是无法得到计算值在跳变。

我最开始以为,是因为在CCP在ReLoad的时候,结合图像来看就是那段斜率为90度的那段,在ReLoad的那个瞬间TIMER_TICK数组的两个值被更新导致差值正好是SysCtlClockGet() - (SysCtlClock() - freq), 导致计算得到错误的频率并且刷屏。

但其实不是,后来单步运行,发现是calc_freq()在执行的过程中,多次被打断而进入CCPIntHandler(),这改变了计算频率的参数TIMER_TICK数组的值。后来我尝试在调用calc_freq()时清除中断,却发现仍会进入CCPIntHandler()。

整个人都不好了

想了个笨方法,定义了个全局变量tmp来记录进入中断函数那个瞬间他们的差值,即使仍然会进入CCPIntHandler(),其差值也已经被记录了下来。

不过还有一个问题就是测量的带宽不够大,一旦频率变高了,比如说大于200kHz,就会因为进入中断函数太快而导致无法执行calc_freq(),它被忽略掉了…导致频率测不出来


一. 实验简介

  • 使用两个定时器
  • 一个用PWM模式产生PWM波形
  • 将此方波信号接入另一定时器的输入端,通过边沿计时模式来测量该信号的周期,并将其显示在液晶屏上

二. TM4C123输入边沿计时模式介绍

  • 输入边沿计时模式用于捕捉输入信号的边沿时间,当输入信号有一个待捕捉的边沿时(上升沿或下降沿),计数器会产生一个中断信号。
  • 对于上升沿检测,输入信号必须在上升沿之后保持高电平至少两个系统时钟周期,对于下降沿检测,输入信号必须在下降沿之后保持低电平至少两个系统时钟周期。根据这个标准,边沿检测的最大输入频率是系统频率的1/4。
  • 选择输入边沿计时模式,需要将寄存器GPTMTnMR中的TnCMR位置1,且TnMR位置0x3,以选择捕获模式。
  • 在输入边沿计时模式下,可以选择的边沿同样有上升沿,下降沿或双边沿,通过配置寄存器GPTMCTLTnEVENT位来选择。当定时器器独立工作时,可以使用预分频器将计数器的位数由16/32位扩展为24位/48位。
  • GPTMCTL中的TnEN被置位,计时开始。当有捕获事件(捕获到边沿信号)发生时,计数器的数值会被存储在寄存器GMTMTnRGPTMTnPS中,并且可以被微处理器读取,之后产生一个捕获事件中断用于处理捕获事件。也就是说,只要检测到了自己设定的边沿的到来,就会进入一次中断
  • 处理完成后计数继续进行,直到GPTMCTL中的TnEN位被置0。而GPTMTnV寄存器和GPTMTnPV寄存器会保存当前独立运行的计数值和预分频器的值。当计数从0达到了计数的初值(递增计数模式,由装载寄存器设置)或是由初值达到0(递减计数模式)时,计数器重新装载初始值继续计数。

下图示范了采用递减计数模式,只捕获上升沿,计数器预设值为GPTMTnILR=0Xffff,每当捕获一个上升沿时,计数器中的数值被写入GPTMTnRGPTMTnPS寄存器(当使用预分频器时才使用此寄存器)中,注意只要检测到了边沿的到来就会进入一次中断。(当初我这块没弄明白,卡顿了好久…)

三. 库函数编程方法

  • 首先使能对应的定时器模块,比如Timer0

    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    //prototype:SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMERx);
    
  • 找到该GPTM模块中TnCCP0TnCCP1(或是WTnCCP0WTnCCP1)所对应的GPIO引脚,使能这些引脚所属的GPIO模块的时钟信号

    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    //prototype:SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOBx);
    
  • 将引脚设置为复用外设功能,如果要设置为定时器功能,调用以下函数

    GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);
    //prototype:GPIOPinTypeTimer(GPIO_PORTx_BASE, GPIO_PIN_x);
    
  • 将GPTM模块的信号TnCCP0TnCCP1(或是WTnCCP0WTnCCP1)配置到具体的的GPIO引脚上去:配置寄存器GPIOPCTL。实际调用的是GPIOPinConfigure()函数

    GPIOPinConfigure(GPIO_PB6_T0CCP0);
    //prototype:GPIOPinConfigure(GPIO_Pxx_TxCCPx);
    
  • 配置定时器模块为捕捉-边沿计时模式

    • 需要注意的是,在该模式下,TimerConfigure第二个参数是TIMER_CFG_SPLIT_PAIR和一下之一相或:

      • TIMER_CFG_A_CAP_TIME模块A捕捉-边沿减计时模式
      • TIMER_CFG_A_CAP_TIME _UP 模块A捕捉-边沿加计时模式
      • TIMER_CFG_B_CAP_ TIME 模块B捕捉-边沿减计时模式
      • TIMER_CFG_B_CAP_ TIME _UP 模块B捕捉-边沿加计时模式
    • 例如

    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP);
    
  • 设置计时范围,TimerLoadSet无论加计时还是减计时,都用这个函数设置Preload值,这个值是指经过了多少个检测到的脉冲边沿后将重新装载(而不是检测到了多少个边沿才发生一次中断

  • 除了要作通用配置外,每种定时器根据不同模式还要作具体的初始化配置,一会儿在src里体现

四. 示例代码

实现了输入任意频率PWM波形的频率检测,可以充当频率计使用,PB6接收PWM脉冲边沿,PF3输出PWM波形

#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/hw_ints.h"
#include "inc/hw_gpio.h"
#include "inc/hw_i2c.h"
#include "inc/hw_sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/sysctl.h"
#include "driverlib/systick.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/ssi.h"
#include "driverlib/i2c.h"
#include "driverlib/udma.h"
#include "driverlib/fpu.h"
#include "driverlib/rom.h"
#include "uc1701.h"//*****************************************************************************
//Attention
//TM4C123 NMI unlock - To those who want to use PF0 and PD7, be reminded that these pins defaults as NMI ! ! !
//
//*****************************************************************************// The error routine that is called if the driver library encounters an error.
#ifdef DEBUG
void __error__(char *pcFilename, unsigned long ulLine)
{}
#endif
//*****************************************************************************//*************************Global variables*************************//
unsigned char pulse;
unsigned long freq;
unsigned long TIMER_TICK[2];
unsigned short i = 0;
unsigned long CCPLoadSet;
unsigned long PWM_Frep;
//******************************************************************////*************************Function dedclarations*************************//
void calc_freq(void);
void PWM_1B_IntHandler(void);
void CCP_Init(void);
void PWM_Set_PWM_Frep(unsigned long freq);//modified parts
void CCP_Set_Load(unsigned long load);//modified parts
void PWM_Init(unsigned long Freq_Hz, unsigned char duty);
void CCPIntHandler(void);
//*************************Function dedclarations*************************//
void main(void)
{SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);PWM_Set_PWM_Frep(131e3);         //modified partsPWM_Init(PWM_Frep, 1);InitUC1701();UC1701CharDispaly(0, 4, "Freq Meter");UC1701CharDispaly(1, 9, "Hz");UC1701CharDispaly(2, 9, "kHz");UC1701CharDispaly(3, 9, "%");CCP_Set_Load(SysCtlClockGet() - 1);     //modified partsCCP_Init();IntMasterEnable();while(1){calc_freq();UC1701DisplayN(1, 2, freq);DisPlayDataFloat_lower_than_100(2, 2, freq / 1000.00);UC1701DisplayN(3, 4, 100 - pulse);}
}
//*************************Initialization modules*************************//
void PWM_Init(unsigned long Freq_Hz, unsigned char duty){pulse = 100 - duty;SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);GPIOPinConfigure(GPIO_PF3_T1CCP1);GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_3);TimerConfigure(TIMER1_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PWM);TimerIntRegister(TIMER1_BASE, TIMER_B, PWM_1B_IntHandler);IntEnable(INT_TIMER1B);  //Enables a timer interruptTimerIntEnable(TIMER1_BASE, TIMER_CAPB_EVENT);   //Enables individual timer interrupt sourcesIntMasterEnable();  //Enables the processor interruptTimerLoadSet(TIMER1_BASE, TIMER_B, SysCtlClockGet() / Freq_Hz - 1);TimerMatchSet(TIMER1_BASE, TIMER_B, (SysCtlClockGet() / Freq_Hz - 1) * (pulse / 100.0));TimerEnable(TIMER1_BASE, TIMER_B);
}
void CCP_Init(void){SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);GPIOPinConfigure(GPIO_PB6_T0CCP0);GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);GPIOPadConfigSet(GPIO_PORTB_BASE, GPIO_PIN_6, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP);TimerControlEvent(TIMER0_BASE, TIMER_A, TIMER_EVENT_NEG_EDGE);TimerLoadSet(TIMER0_BASE, TIMER_A, CCPLoadSet);TimerIntRegister(TIMER0_BASE, TIMER_A, CCPIntHandler);IntMasterEnable();TimerIntEnable(TIMER0_BASE, TIMER_CAPA_EVENT);IntEnable(INT_TIMER0A);TimerEnable(TIMER0_BASE, TIMER_A);
}
//*************************Initialization modules*************************////*************************Modified parts*************************//
void PWM_Set_PWM_Frep(unsigned long freq){PWM_Frep = freq;
}
void CCP_Set_Load(unsigned long load){CCPLoadSet = load;
}
//*************************Modified parts*************************////*************************InterruptHandlers modules*************************//
void PWM_1B_IntHandler(void){TimerIntClear(TIMER1_BASE, TIMER_CAPB_EVENT);
}
void CCPIntHandler(void){TimerIntClear(TIMER0_BASE, TIMER_CAPA_EVENT);if(i == 2)i = 0;TIMER_TICK[i++] = TimerValueGet(TIMER0_BASE,TIMER_A);
}
//*************************InterruptHandlers modules*************************////*************************Calculate frequence*************************//
void calc_freq(void)
{static unsigned long tmp;//ignore the re-execution of CCPIntHandler//save the current TIMER_TICK[0] - TIMER_TICK[1]//although TIMER_TICK is still varyingTimerIntClear(TIMER0_BASE, TIMER_A);tmp = abs(TIMER_TICK[1] - TIMER_TICK[0])freq = SysCtlClockGet() / tmp;
}

这个链接里可以找到完整项目代码,zip里有一些头文件和库
提取码: snih

五. 结果

别忘了把PB6和PF3跳线!因为它们是PWM接收和输出的端口~
我设置的PWM占空比为1%(设这么小主要是想看看极端条件下灵不灵敏),频率为50kHz


参考链接
[1]: Help with Frequency Meter(Google)
[2]: https://github.com/WadeGao/TIVA

TIVA-TM4C123GH6PM的输入边沿计时模式的配置相关推荐

  1. TIVA 123GXL的边沿计数模式测量低频PWM

    TM4C123GXL频率计第二弹 上篇文章讲到了使用Edge Timer模式来测量频率较高的PWM信号的方法,这次写了个用另一种原理来测量频率的方法,那就是采用Edge Count(边沿计数模式)的方 ...

  2. linux(centos) NET模式网络配置

    2019独角兽企业重金招聘Python工程师标准>>> linux虚拟机一般使用桥接和net模式,但是由于桥接在不同的网络环境中,需要重新配置,所以建议使用net模式,net模式的配 ...

  3. Vue Router history模式的配置方法及其原理

    转载地址:https://segmentfault.com/a/1190000019391139 vue-router分为hash和history模式,前者为其默认模式,url的表现形式为http:/ ...

  4. VMware安装Ubuntu 18.04虚拟机(镜像下载、硬盘分区、创建虚拟机、安装系统、桥接模式网络配置)

    1. VMware安装 安装VMware,Player免费,而且功能足够个人开发使用.(Pro的主要区别在于可以同时运行多个虚拟机,而Player只能同时运行一个) VMware Workstatio ...

  5. 三.STM32嵌入式学习--GPIO口(3)----通用输入的应用--按键的配置

    前面我们讲了IO的通用输出的配置--点灯,今天我们讲讲按键输入. 依旧是学习思路: 如何让芯片内核判断到按键是否按下? 如果按键未按下,内核检测IO口是低电平,如果按下,则检测高电平. 如何检测IO口 ...

  6. GPIO的八种模式以及配置

    STM32的GPIO 有8种可能的配置:(4种输入+2种输出+2种复用输出) (1) 浮空输入 GPIO_Mode_IN_FLOATING (2) 带上拉输入 GPIO_Mode_IPU (3) 带下 ...

  7. 帧中继环境下NBMA模式的配置

    帧中继环境下NBMA模式的配置 1.  实验目的: 通过本次的实验,我们可以掌握如下技能 1)        帧中继静态映射及其broadcast参数的含义. 2)        NBMA模式下的DR ...

  8. Apache之三种工作模式和配置性能优化

    1 Apache的3种模式和版本 Apache目前一共有三种稳定的MPM(Multi-Processing Module,多进程处理模块)模式,它们分别是prefork,worker和event. 我 ...

  9. linux桥接设置静态,centos6.10 桥接模式下配置静态ip

    centos6.10 桥接模式下配置静态ip主要是修改以下三个地方: /etc/sysconfig/network-scripts/ifcfg-eth0(这个文件名版本不同文件名也不同,可以先cd / ...

最新文章

  1. 7_12_2013 G: Mahjong problem
  2. 有向图缩点:tarjan强连通缩点(模板)
  3. linux_base-f10-10_7 linuxulator is not (kld)loaded
  4. 全球视频监控设备市场规模分析
  5. 使用 Tye 辅助开发 k8s 应用竟如此简单(五)
  6. 1095 解码PAT准考证 (25分)
  7. JavaScript文档对象模型document对象改变Html元素内容(3)
  8. 游戏开发之运算符重载(C++基础)
  9. Flutter String 常用方法
  10. 《吊打分析师》实战—深圳链家租房数据分析 | 附源码
  11. rcond--矩阵可逆的条件数估值
  12. 通信:5G孕育上游投资空间
  13. 神经网络预测鸢尾花的种类
  14. 山东赛区|数学建模国赛山东赛区成绩发布
  15. 使用canvas 绘制象棋棋盘
  16. 软件测试之第三方快捷支付_支付宝遭遇最强对手:银联正面PK快捷支付
  17. 淘宝直通车表格拖动时间段选择插件,纯手写80%还原
  18. Python爬取10529条《三十而已》热评,看看大家都说了些啥!
  19. Win10 / Win11、VScode内置终端美化教程(适用于 oh-my-posh 老版本 新版本请查看官网教程...)
  20. qq音乐正式版官方免费版

热门文章

  1. java 后台大写到前端变小写
  2. Fseek()与Ftell()函数的作用
  3. linux下修改windows密码忘记,不记得linux/windows中mysqlroot密码万能修改方法
  4. 利用ntp服务同步时间(史上最简单)
  5. 【DDR3 控制器设计】(1)MIG IP 核的详解与配置
  6. 量化交易学习0--量化投资交易资源汇总
  7. 树莓水果创意广告文案,朋友圈晒水果走心文案树莓
  8. SDK接口调用主流程
  9. c++中冒号(:)的用法
  10. 航空软件静态测试标准,静态试验