当前位置: 首页 > news >正文

13.【NXP 号令者RT1052】开发——实战-QTMR 定时器中断

13.【NXP 号令者RT1052】开发——实战-QTMR 定时器中断

这一章,我们将向大家介绍如何使用 RT1052 的四定时器(Quad Timer,简称:QTMR),RT1052内部集成了 4 个 QTMR 定时器,每个 QTMR 定时器又有 4 个通道,每个通道都有独立的:1 个 16 位计数器、1 个预分频器、1 个加载值寄存器、1 个捕获寄存器、2 个比较寄存器、两个状态寄存器和 1 个控制寄存器等,完全就是一个独立定时器的功能。因此,我们可以将QTMR 看成是一个拥有 4*4 个定时器的集合,这样光 QTMR 就拥有 16 个定时器之多。

13.1 RT1052 通用定时器简介

RT1052 内部包含 4 个四定时器(QTMR1~4),每个 4 定时器又包含 4 个独立的通道,4 个通道完全独立,不共用任何资源
在这里插入图片描述

基本结构

  • 单个通道由 输入时钟部分、计数器(CNTR)、加载寄存器(LOAD)、捕获寄存器(CAPTURE)、两个比较器 等组成。
  • RT1052 内部共有 16 个通道(4 个定时器 × 每个 4 通道)。

功能特点

  1. 16 位计数器 CNTR,支持向上/下计数。
  2. 可级联,组成 32/48/64 位计数器
  3. 独立分频器(支持 1/2/4/8/16/32/64/128 分频)。
  4. 支持 输出比较输入捕获
  5. 提供 14 种工作模式
  6. 输入捕获支持 滤波器
  7. 最大计数频率可达 150 MHz
  8. 支持 单次计数 / 连续计数
  9. 比较寄存器具有 预装载功能
  10. 4 个通道可 同步启动

QTMR 工作模式

  • 共 14 种模式,详见《RT1050 参考手册》第 47.6.5 节。
  • 本章使用 计数模式(CTRL[CM] = 001)
    • 通道计数器在时钟上升沿计数(时钟源由 CTRL[PCS] 设置)。
    • 计数方向可选递增/递减(由 CTRL[DIR] 设置)。
    • 适合周期性中断、计时或外部脉冲计数。

应用示例:QTMR1 通道 0 周期性中断

  1. 设置计数方向:CTRL[DIR] = 0 → 向上计数。
  2. 设置初始值:LOAD
  3. 设置匹配值:COMP1(向上计数时的比较匹配值)。
  4. 设置计数模式:CTRL[CM] = 001
  5. 工作过程:
    • CNTR 从 LOAD 值开始递增。
    • 当 CNTR = COMP1 时,产生比较匹配事件 → 触发中断。
    • CNTR 重新加载 LOAD 值,继续递增计数。
    • 循环往复,实现周期性中断。
      在这里插入图片描述
      图中 t1、t2 和 t3 是 3 次比较匹配的时刻,会产生中断和重置 CNTR 寄存器(需要设置CTRL[LENTH]=1,否则 CNTR 将持续计数到 0XFFFF(溢出)),重置 CNTR 寄存器使用 LOAD寄存器的值来初始化,所以通道 0 的定时时间由 LOAD0 和 COMP1 以及输入时钟三个参数决定。特别的,当 LOAD0=0 的时候,定时时间就由 COMP1 和时钟频率决定了。

实验目标

使用 QTMR1 通道 0 产生周期性中断,在中断服务函数中翻转 DS1 电平,指示定时器中断的发生。

实现步骤

1. QTMR1 时钟使能

c

CLOCK_EnableClock(kCLOCK_Timer1);

实际上 QTMR_Init() 内部已调用,无需重复。

2. 初始化 QTMR1

c

qtmr_config_t qtimer1_config;
QTMR_GetDefaultConfig(&qtimer1_config);              // 默认配置
qtimer1_config.primarySource = kQTMR_ClockDivide_128;// 设置第一时钟源为 IPG_CLK_ROOT 128 分频
QTMR_Init(TMR1, kQTMR_Channel_0, &qtimer1_config);   // 初始化 QTMR1 通道 0
3. 设置定时周期

c

QTMR_SetTimerPeriod(TMR1, kQTMR_Channel_0, ticks);
  • ticks 为匹配比较值,决定溢出时间。
  • 当计数器 CNTR0 达到该值时产生中断。
  • 默认计数方向为 向上计数
4. 使能比较中断

c

QTMR_EnableInterrupts(TMR1, kQTMR_Channel_0, kQTMR_CompareInterruptEnable);
  • 开启 比较中断,当 CNTR0 = COMP 值时触发。
5. 启动 QTMR

c

QTMR_StartTimer(TMR1, kQTMR_Channel_0, kQTMR_PriSrcRiseEdge);
  • 设置计数模式为 第一时钟源上升沿计数
6. 配置 NVIC 中断优先级并使能

c

RT1052_NVIC_SetPriority(TMR1_IRQn, 6, 0); // 抢占优先级 6,子优先级 0
EnableIRQ(TMR1_IRQn);                     // 使能 TMR1 中断
7. 编写中断服务函数

c

void TMR1_IRQHandler(void)
{if(QTMR_GetStatus(TMR1, kQTMR_Channel_0) & kQTMR_CompareFlag){LED1_Toggle(); // 翻转 DS1QTMR_ClearStatusFlags(TMR1, kQTMR_Channel_0, kQTMR_CompareFlag); // 清除比较标志位}
}

定时周期计算

  • 时钟源:IPG_CLK_ROOT = 75 MHz
  • 分频:128 → 有效频率 = 75 MHz / 128 ≈ 585.9 kHz
  • 周期时间 = ticks / 有效频率

实验结果

  • DS1 在 QTMR1 通道 0 中断中翻转,实现周期性闪烁。
  • 通过调整 ticks 值可改变闪烁频率。

13.2硬件设计

本实验用到的硬件资源有:

  1. 指示灯 DS0 和 DS1
    2.QTMR1 定时器
    本章将通过 QTMR1 的中断来控制 DS1 的亮灭,DS1 是直接连接到 GPIO3_IO03(P303)上的,这个前面已经有介绍了。而 QTMR1 属于 RT1052 的内部资源,只需要软件设置即可正常工作。

13.3 软件设计

软件设计我们在之前的工程上面增加,首先,打开上次的工程,然后在 HARDWARE 下新建 QTIMER 文件夹,在 QTIMRE 下新建一个 qtimer.c 的文件和 qtimer.h 的头文件。

qtimer.c

#include "qtimer.h"
#include "led.h"//QTIMER1配置结构体
qtmr_config_t qtimer1_config;//初始化QTIMER,TMR定时器的时钟源为IPG_CLK_ROOT=150MHz
//prisrc : 第一时钟源选择
//         0000~0011,通道0~3的输入引脚.
//         0100~0111,通道0~3的输出.可用于级联.
//         1000~1111,IPG_CLK_ROOT时钟的:1,2,4,8,16,32,64,128分频.
//cmp1	 : COMP1寄存器值,0~65535.
//定时时间=cmp1/QTMR1_CLK
//假设prisrc=1111,则QTMR1_CLK=1171875Hz.
//若cmp1=46875,则定时时间= 46875/1171875=0.04秒.
//当使用IPG_CLK_ROOT作为时钟源时,最大延时时间=65535*128/150M=55.9ms
void QTMR1_CH0_Int_Init(u8 prisrc,u16 cmp1)
{qtmr_primary_count_source_t qtimer1_source;qtimer1_source=(qtmr_primary_count_source_t)prisrc;QTMR_GetDefaultConfig(&qtimer1_config);             //先设置为默认配置,后面在根据实际情况配置qtimer1_config.primarySource=qtimer1_source;        //设置第一时钟源QTMR_Init(TMR1,kQTMR_Channel_0,&qtimer1_config);    //初始化QTIMERQTMR_SetTimerPeriod(TMR1,kQTMR_Channel_0,cmp1);     //设置COMP1匹配值(向上计数用COMP1,向下用COMP2)//配置中断QTMR_EnableInterrupts(TMR1,kQTMR_Channel_0,kQTMR_CompareInterruptEnable);  //使能通道0的比较中断RT1052_NVIC_SetPriority(TMR1_IRQn,6,0);             //抢占优先级6,子优先级0EnableIRQ(TMR1_IRQn);                               //是能TMR1中断//开始通道0QTMR_StartTimer(TMR1, kQTMR_Channel_0,kQTMR_PriSrcRiseEdge);    //通道0在primary时钟源的上升沿计数
} //TMR1中断服务函数
void TMR1_IRQHandler(void)
{static u8 count=0;	    //计数器//判断是不是TMR1通道0的比较中断if((QTMR_GetStatus(TMR1,kQTMR_Channel_0)&kQTMR_CompareFlag)==kQTMR_CompareFlag){count++;if(count==25)       //每进入25次中断服务函数,才执行一次.{ LED1_Toggle;    //DS1翻转count=0;	    //清零计数器}QTMR_ClearStatusFlags(TMR1,kQTMR_Channel_0,kQTMR_CompareFlag); //清除中断标志位 }__DSB();                //数据同步屏蔽指令
}

该文件下包含一个中断服务函数和一个 QTMR1 通道 0 中断初始化函数,中断服务函数比较简单,在每次中断后,判断是否是 QTMR1 通道 0 的中断,如果是,则每进入 25 次,执行一次 LED1(DS1)的取反,并清除中断标志位(每次进入都要执行)。QTMR1_CH0_Int_Init 函数就是执行我们上面介绍的那 7 个步骤,设置 QTMR1 定时器通道0 的中断。该函数有 2 个参数:prisrc 和 cmp1。prisrc 用于选择第一时钟源;cmp1 用于设置COMP1 的值;这两个参数共同决定了定时器的溢出时间(中断时间)。
我们将 qtimer.c 文件保存,然后加入到 HARDWARE 组下。接下来,在 qtimer.h 文件里,我们输入如下代码:

#ifndef _QTIMER_H
#define _QTIMER_H
#include "sys.h"void QTMR1_CH0_Int_Init(u8 prisrc,u16 cmp1);
#endif

最后,我们在主程序里面输入如下代码:

#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdog.h"
#include "rtwdog.h"
#include "gptimer.h"
#include "pitimer.h"
#include "qtimer.h"int main(void)
{u8 key=0;MPU_Memory_Protection();    //初始化MPURT1052_Clock_Init();	    //配置系统时钟DELAY_Init(600);		    //延时函数初始化LPUART1_Init(115200);       //初始化串口1RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4
#ifdef LED_DEBUGu8 led0sta=1,led1sta=1;     //LED0,LED1的当前状态LED_Init();				    //初始化LED
#endif
#ifdef KEY_DEBUGKEY_Init();                 //初始化KEY
#endif
#ifdef LPUART_DEBUGu8 len;					//接收数据长度u16 times=0;            //延时计数器LED0(0);					//先点亮红灯 
#endif
#ifdef EXTIX_DEBUGEXTIX_Init();			    //初始化外部中断
#endif
#ifdef WDOG_DEBUGWDOG1_Init(3,2);		    //初始化看门狗1,2秒溢出,提前1秒进入中断,方便喂狗LED0(0);               	    //先点亮LED灯delay_ms(300);				//延时300ms再初始化看门狗,LED0的变化"可见"
#endif
#ifdef RTWDOG_DEBUGLED_Init();				    //初始化LED KEY_Init();                 //初始化KEYdelay_ms(100);         	    //延时100ms再初始化看门狗,LED0的变化"可见"MYRTWDOG_Init(1,0,32768,0);	//初始化RT看门狗,1秒溢出,非窗口模式LED0(0);               	    //先点亮LED灯
#endif
#ifdef GPT1_DEBUGLED_Init();				    //初始化LED  KEY_Init();                 //初始化按键GPT1_Int_Init(3750-1,10000); //设置GPT1 0.5秒钟产生一次中断
#endif
#ifdef PIT_DEBUGLED_Init();				    //初始化LED  PIT_CH0_Int_Init(75000000/2);	//设置PIT 0.5秒钟产生一次中断
#endifKEY_Init();                 //初始化按键LED_Init();				            //初始化LEDQTMR1_CH0_Int_Init(15,46875);	//设置QTMR1 0.04秒钟产生一次中断while(1){LED0_Toggle;delay_ms(1000);
#ifdef PIT_DEBUGLED0_Toggle;delay_ms(1000);
#endif
#ifdef GPT1_DEBUGLED0_Toggle;delay_ms(1000);
#endif
#ifdef RTWDOG_DEBUGkey=KEY_Scan(0);if(key==WKUP_PRES)		//如果按键按下,则喂狗.{RTWDOG_Feed();} delay_ms(10);
#endif
#ifdef WDOG_DEBUGLED0(1);				//关闭DS0,如不复位,DS0将一直处于关闭状态.delay_ms(100);
#endif
#ifdef EXTIX_DEBUGprintf("Int example driver!\r\n");delay_ms(1000);
#endif
#ifdef KEY_DEBUGkey=KEY_Scan(0); 		    //得到键值if(key){	switch(key){				 case WKUP_PRES:	//控制LED0,LED1互斥点亮led1sta=!led1sta;led0sta=!led1sta;break;case KEY2_PRES:	//控制LED0翻转led0sta=!led0sta;break;case KEY1_PRES:	//控制LED1翻转	 led1sta=!led1sta;break;case KEY0_PRES:	//同时控制LED0,LED1翻转 led0sta=!led0sta;led1sta=!led1sta;break;}LED0(led0sta);		//控制LED0状态LED1(led1sta);		//控制LED1状态}else delay_ms(10);
#endif // KEY_DEBUG
#ifdef LPUART_DEBUGif(LPUART_RX_STA&0x8000){					   len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度printf("\r\n发送的消息为:\r\n");LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据printf("\r\n\r\n");//插入换行LPUART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");}if(times%200==0)printf("请输入数据,以回车键结束\r\n");  if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.delay_ms(10);   }
#endif // LPUART_DEBUG}
}

在这里插入图片描述

这里的代码和之前大同小异,此段代码通过 QTMR1_CH0_Int_Init 函数,初始化 QTMR1 的通道 0,设置其为 0.04 秒中断一次。在中断服务函数里面,每进入 25 次,执行一次 DS0 取反,这样就是 1 秒钟取反一次。同样,在死循环里面,我们对 DS0 也是 1 秒钟执行一次取反,因此,可以看到 DS0 和 DS1 几乎是同步亮灭。

总结

本章通过配置 RT1052 的 QTMR1 通道 0,实现了周期性中断控制 LED 翻转的功能:通过初始化时钟源、设置匹配值、使能比较中断并编写中断服务函数,使定时器每 0.04 秒触发一次中断,在中断中每累计 25 次翻转一次 DS1,从而实现 1 秒闪烁一次的效果;同时主循环中 DS0 也以 1 秒周期翻转,最终呈现 DS0 与 DS1 几乎同步的亮灭现象,验证了 QTMR 在周期性中断应用中的基本用法。
OK,谢谢大家

http://www.dtcms.com/a/593440.html

相关文章:

  • LeetCode 739. 每日温度
  • seo网站优化专家绿色资源网
  • 数据库迁移实操与金仓数据库技术优势:从语法兼容到自动化落地
  • 监听错误的方式有哪些?
  • 一阶时域信号的分类
  • 网站搭建推广优化企业网站建公司
  • Supabase 全景解析:开源后端的全栈开发革命
  • 2025年主流跨平台框架全面对比:选型指南与趋势展望
  • 徐州手机网站开发公司上海知名的seo推广咨询
  • 51自学网官方网站深州市住房保障和城乡建设局网站
  • 在超算上启动h5bench
  • 财报OCR录入识别软件准确率高吗?易道博识财报录入实测效果如何?
  • WPF MatrixTransform 矩阵参数的疑问?
  • 公网IP与私有IP的区别
  • 怎么做兼职类网站吗WordPress头像不能本地化
  • 丰城市建设局网站广安网站建设推荐
  • 【Jenkins/Termius/集群概念】
  • pyenv-win更新最新的python安装库使其可以安装最新python版本
  • 忘记密码页测试用例
  • 长沙 网站设计 公司旬阳做网站
  • ✨实验6:从2D混合几何到3D模型渲染
  • 医药研发项目管理系统(PMS)有哪些?如何提升新药研发过程中的效率?
  • 全球物联网蜂窝模组市场格局与海外销售趋势分析
  • 网络命令ping、netstat、pidof
  • 与做网站有关的参考文献帝国cms7.0模板 绿色企业网站模板(整站带数据)
  • RK3588作为主控,STM32F103作为下位机,思岚S2雷达,四路电机驱动板,进行地图构建计划
  • VSR字幕检测模块PaddleOCR模型升级:从PP-OCRv4到PP-OCRv5​(当前最新的PaddleOCR模型)
  • AbMole小课堂丨Tirzepatide:GIP/GLP-1双重受体激动剂在糖尿病、肥胖症、心脏保护等动物模型中的研究应用
  • Flutlab使用指南及功能介绍
  • Datawhale coze-ai-assistant task1