CPUTimer定时器配置使用,CPUTimer定时器本身寄存器不多,用到的寄存器也不多,本文就不详细解释每个寄存器的作用了
请下载最后的修改后的最新测试工程!
文章提供测试代码讲解、完整工程下载、测试效果图
目录
有关于无法直接输出CpuTimer0.InterruptCount:
我的单片机平台是这个:
CPUTimer 结构体:
不论你在哪个文件初始化的 CPUTimer ,这三个用到的结构体都要冗余声明一下
没有就会报错,虽然在 f28p55x_cputimers.h 早有定义
我本人是不太明白为何这么做的,就是编译不通过,我就强加了
应该是empty工程没有合理包含它的.h文件的原因,但.c能正常编译
//这三个声明要有,没有就会报错,虽然在 f28p55x_cputimers.h 早有定义 struct CPUTIMER_VARS CpuTimer0; struct CPUTIMER_VARS CpuTimer1; struct CPUTIMER_VARS CpuTimer2;
CPUTimer定时器初始化预配置:
CPUTimer 一共有0~2,三个
初始化它们之前先预设定一下,防止芯片内部有残留寄存器配置
// 预配置 三个CPUtimer void InitCpuTimers(void) { // CPU Timer 0 // Initialize address pointers to respective timer registers: CpuTimer0.RegsAddr = &CpuTimer0Regs; // 将CPU Timer 0的周期寄存器PRD设置为最大值0xFFFFFFFF,以便稍后根据需要的周期进行调整 CpuTimer0Regs.PRD.all = 0xFFFFFFFF; // 将预分频器寄存器TPR和TPRH设置为0,表示使用系统时钟SYSCLKOUT直接作为定时器的时钟源(即不分频)。 CpuTimer0Regs.TPR.all = 0; CpuTimer0Regs.TPRH.all = 0; // 设置定时器控制寄存器TCR的TSS位为1,停止CPU Timer 0。 CpuTimer0Regs.TCR.bit.TSS = 1; // 设置TCR的TRB位为1,以重新加载周期寄存器PRD的值到计数器中。 CpuTimer0Regs.TCR.bit.TRB = 1; // 将CPU Timer 0的中断计数器重置为0。 CpuTimer0.InterruptCount = 0; // 接下来的代码重复了上述过程,但用于初始化CPU Timer 1和CPU Timer 2: CpuTimer1.RegsAddr = &CpuTimer1Regs; CpuTimer2.RegsAddr = &CpuTimer2Regs; //周期寄存器PRD设置为最大值0xFFFFFFFF,以便稍后根据需要的周期进行调整 CpuTimer1Regs.PRD.all = 0xFFFFFFFF; CpuTimer2Regs.PRD.all = 0xFFFFFFFF; // 将预分频器寄存器TPR和TPRH设置为0,表示使用系统时钟SYSCLKOUT直接作为定时器的时钟源(即不分频)。 CpuTimer1Regs.TPR.all = 0; CpuTimer1Regs.TPRH.all = 0; CpuTimer2Regs.TPR.all = 0; CpuTimer2Regs.TPRH.all = 0; // 设置定时器控制寄存器TCR的TSS位为1,停止CPU Timer 1 和 2。 CpuTimer1Regs.TCR.bit.TSS = 1; CpuTimer2Regs.TCR.bit.TSS = 1; // 设置TCR的TRB位为1,以重新加载周期寄存器PRD的值到计数器中。 CpuTimer1Regs.TCR.bit.TRB = 1; CpuTimer2Regs.TCR.bit.TRB = 1; // 将CPU Timer 1 和 2 的中断计数器重置为0。 CpuTimer1.InterruptCount = 0; CpuTimer2.InterruptCount = 0; }
CPUTimer定时器初始化函数:
传入三个参数:
1.CPUTimer 结构体 2.分频 3.重载值
void Init_CPU_TIMER(struct CPUTIMER_VARS *Timer, float Freq, float Period) { Uint32 temp; //设定频率 Timer->CPUFreqInMHz = Freq; Timer->PeriodInUSec = Period; temp = (Uint32) (Freq * Period); Timer->RegsAddr->PRD.all = temp - 1; Timer->RegsAddr->TPR.all = 0; Timer->RegsAddr->TPRH.all = 0; // Initialize timer control register: Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart // Timer Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer Timer->RegsAddr->TCR.bit.SOFT = 0; Timer->RegsAddr->TCR.bit.FREE = 0; // Timer Free Run Disabled Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer // Interrupt // Reset interrupt counter: Timer->InterruptCount = 0; }
主函数初始化部分:
调用初始化函数:
调用之前写好的初始化函数:
链接 中断服务函数:
初始化完了就要链接它们的中断服务函数:
编写中断服务函数具体实现:
这个中断服务函数的具体实现写在主函数是正常的,我之前尝试放在TIMER.h文件过,但没法正常进入...
主函数文件整体代码:
/* 名称 : CPU 定时器 测试工程 * 创建者 : NULL指向我 * 日期 : 2025.3.11 * 功能 : SCI打印 CPUtime 0 中断溢出次数 * 平台 : LAUNCHXL-F28P55x * 型号 : TMS320F28P550SJ9 * 备注 : * 主函数 * * */ //头文件 #include "f28x_project.h" #include "driverlib.h" #include "device.h" #include "sci.h" #include "TIMER.h" #include "string.h" #include "stdio.h" // 这个 CPU定时器的 中断服务函数貌似只能 定义在 主函数文件 __interrupt void cpuTimer0ISR(void); __interrupt void cpuTimer1ISR(void); __interrupt void cpuTimer2ISR(void); // 抵充编译BUG (本来正常情况 无需声明这三个函数) void Init_GPIO_LEDPort(void); //初始化LED端口 void Init_SCIA(uint32_t baund,uint32_t lspclk); //初始化SCI @LSPCLK = 37.5 MHz (150 MHz SYSCLK) HBAUD = 0x01 and LBAUD = 0xE7. void SCIa_Printf(char *fmt,...); // 自定义printf函数 //主函数 main void main(void) { int temp=0; Device_init(); //初始化系统时钟 Device_initGPIO(); //解锁GPIO端口 Init_GPIO_LEDPort(); //初始化LED端口 // @LSPCLK = 37.5 MHz (150 MHz SYSCLK) HBAUD = 0x01 and LBAUD = 0xE7. Init_SCIA(9600,37500000);//初始化SCI InitCpuTimers(); //初始化定时器CUPTIMER 0 Init_CPU_TIMER(&CpuTimer0, 150, 1000000);//时钟来源 SYSCLKOUT 150Mhz / 150分频 /1000 000计数重载值 / 1000 ms溢出中断频率 InitPieVectTable(); Interrupt_initModule(); Interrupt_initVectorTable(); // 链接 中断服务函数 ISR functions EALLOW; PieVectTable.TIMER0_INT = &cpuTimer0ISR; PieVectTable.TIMER1_INT = &cpuTimer1ISR; PieVectTable.TIMER2_INT = &cpuTimer2ISR; EDIS; CpuTimer0Regs.TCR.all = 0x4000; CpuTimer1Regs.TCR.all = 0x4000; CpuTimer2Regs.TCR.all = 0x4000; IER |= M_INT1; IER |= M_INT13; IER |= M_INT14; // Enable TINT0 in the PIE: Group 1 interrupt 7 PieCtrlRegs.PIEIER1.bit.INTx7 = 1; EINT; ERTM; while(1) { temp=CpuTimer0.InterruptCount; //需要用中间值复读寄存器,你无法直接输出 CpuTimer0.InterruptCount SCIa_Printf("CpuTimer0 InterruptCounts: %d \r\n",temp); //计数 DEVICE_DELAY_US(500000); } } // cpuTimer0ISR - CPU Timer0 ISR with interrupt counter __interrupt void cpuTimer0ISR(void) { CpuTimer0.InterruptCount++; PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; } // cpuTimer1ISR - CPU Timer1 ISR with interrupt counter __interrupt void cpuTimer1ISR(void) { CpuTimer1.InterruptCount++; } // cpuTimer2ISR CPU Timer2 ISR with interrupt counter __interrupt void cpuTimer2ISR(void) { CpuTimer2.InterruptCount++; } //主文件结尾
TIMER.c与TIMER.h 整体代码:
TIMER.c
/* * TIMER.c * * Created on: 2025年3月11日 * Author: 30313 */ #include "TIMER.h" //这三个声明要有,没有就会报错,虽然在 f28p55x_cputimers.h 早有定义 struct CPUTIMER_VARS CpuTimer0; struct CPUTIMER_VARS CpuTimer1; struct CPUTIMER_VARS CpuTimer2; // 预配置 三个CPUtimer void InitCpuTimers(void) { // CPU Timer 0 // Initialize address pointers to respective timer registers: CpuTimer0.RegsAddr = &CpuTimer0Regs; // 将CPU Timer 0的周期寄存器PRD设置为最大值0xFFFFFFFF,以便稍后根据需要的周期进行调整 CpuTimer0Regs.PRD.all = 0xFFFFFFFF; // 将预分频器寄存器TPR和TPRH设置为0,表示使用系统时钟SYSCLKOUT直接作为定时器的时钟源(即不分频)。 CpuTimer0Regs.TPR.all = 0; CpuTimer0Regs.TPRH.all = 0; // 设置定时器控制寄存器TCR的TSS位为1,停止CPU Timer 0。 CpuTimer0Regs.TCR.bit.TSS = 1; // 设置TCR的TRB位为1,以重新加载周期寄存器PRD的值到计数器中。 CpuTimer0Regs.TCR.bit.TRB = 1; // 将CPU Timer 0的中断计数器重置为0。 CpuTimer0.InterruptCount = 0; // 接下来的代码重复了上述过程,但用于初始化CPU Timer 1和CPU Timer 2: CpuTimer1.RegsAddr = &CpuTimer1Regs; CpuTimer2.RegsAddr = &CpuTimer2Regs; //周期寄存器PRD设置为最大值0xFFFFFFFF,以便稍后根据需要的周期进行调整 CpuTimer1Regs.PRD.all = 0xFFFFFFFF; CpuTimer2Regs.PRD.all = 0xFFFFFFFF; // 将预分频器寄存器TPR和TPRH设置为0,表示使用系统时钟SYSCLKOUT直接作为定时器的时钟源(即不分频)。 CpuTimer1Regs.TPR.all = 0; CpuTimer1Regs.TPRH.all = 0; CpuTimer2Regs.TPR.all = 0; CpuTimer2Regs.TPRH.all = 0; // 设置定时器控制寄存器TCR的TSS位为1,停止CPU Timer 1 和 2。 CpuTimer1Regs.TCR.bit.TSS = 1; CpuTimer2Regs.TCR.bit.TSS = 1; // 设置TCR的TRB位为1,以重新加载周期寄存器PRD的值到计数器中。 CpuTimer1Regs.TCR.bit.TRB = 1; CpuTimer2Regs.TCR.bit.TRB = 1; // 将CPU Timer 1 和 2 的中断计数器重置为0。 CpuTimer1.InterruptCount = 0; CpuTimer2.InterruptCount = 0; } void Init_CPU_TIMER(struct CPUTIMER_VARS *Timer, float Freq, float Period) { Uint32 temp; //设定频率 Timer->CPUFreqInMHz = Freq; Timer->PeriodInUSec = Period; temp = (Uint32) (Freq * Period); Timer->RegsAddr->PRD.all = temp - 1; Timer->RegsAddr->TPR.all = 0; Timer->RegsAddr->TPRH.all = 0; // Initialize timer control register: Timer->RegsAddr->TCR.bit.TSS = 1; // 1 = Stop timer, 0 = Start/Restart // Timer Timer->RegsAddr->TCR.bit.TRB = 1; // 1 = reload timer Timer->RegsAddr->TCR.bit.SOFT = 0; Timer->RegsAddr->TCR.bit.FREE = 0; // Timer Free Run Disabled Timer->RegsAddr->TCR.bit.TIE = 1; // 0 = Disable/ 1 = Enable Timer // Interrupt // Reset interrupt counter: Timer->InterruptCount = 0; }
TIMER.h
/* * TIMER.h * * Created on: 2025年3月11日 * Author: 30313 */ #ifndef USER_TIMER_H_ #define USER_TIMER_H_ #include "f28x_project.h" #include "driverlib.h" #include "device.h" void InitCpuTimers(void); void Init_CPU_TIMER(struct CPUTIMER_VARS *Timer, float Freq, float Period); /* __interrupt void cpuTimer0ISR(void); __interrupt void cpuTimer1ISR(void); __interrupt void cpuTimer2ISR(void); */ #endif /* USER_TIMER_H_ */
测试效果图:
通过打印可以看出,定时器在时序上是正常运行的
但测试结果中,数字打印是连续的,我主循环每500ms读取一次定时器中断次数寄存器的值
并打印,本应该每个数字出现2次,但总会偶尔出现某个数字只打印了一次的情况出现
这说明某次打印被打断了!
而且还貌似有点规律,4 8 13 17 21 26 ....基本这个规律
测试工程下载:
https://download.youkuaiyun.com/download/qq_64257614/90473931
问题记录:
有关于主函数的抵充声明:
发现原因是因为有俩个sci.h文件,冲突了:
但这样声明一下就没啥问题
后续我修改自己俩个文件的名称就好了:
有关于无法直接输出CpuTimer0.InterruptCount:
这个问题在主函数中:
本质原因是我的打印函数没法正确处理Uint32位的数据,导致数据位丢失了
这里你只要把temp也定义为 Uint32 尝试输出就能看出
修改后的测试工程:
https://download.youkuaiyun.com/download/qq_64257614/90474100