1、PIC32参考资源
PIC32系列参考手册 中文版 链接地址:PIC32系列参考手册 第14章 定时器(https://download.csdn.net/download/Huangtop/20299476?spm=1001.2014.3001.5503)
2、16位同步外部定时器方案说明
步骤1:TMR3产生固定频率的脉冲信号;
步骤2:TMR2设置为外部时钟输入;
步骤3:将TMR3产生的脉冲信号呈现到引脚电平变化上,并将引脚接入到TMR2的外部时钟输入引脚上;
步骤4:TMR2中断中设置为固定时间设置LED电平翻转;
3、16位同步外部定时器Harmony3配置
1、定时器3配置分频系数为2,内部时钟源,定时时间为0.5ms,频率为1Khz;
2、定时器2配置分频系数为1,时钟源选择外部时钟源,时钟频率填写1000Hz,定时时间填写500ms;
3、组件配置完成后点击左侧的Generate Code按钮生成代码;
4、生成的代码与原始代码存在差异,需进行确认;
5、代码生成后需要的操作;
1、添加定时器TMR3以及TMR2的启动;
2、为TMR3中断服务函数中添加引脚电平翻转,产生脉冲信号用于提供外部时钟输入;
3、在TMR2中断服务函数中添加LED电平翻转;
4、外部接口中将TMR3输出引脚接入的TMR2时钟外部输入引脚;
6、编译运行将代码烧录到开发板中;
点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,开发板上的LED灯闪烁。
4、工程配置分析
1、TMR3定时器工程配置
定时器TMR3主要用于产生外部时钟,我们将分频系数修改为2,时钟源选择内部时钟,那么定时器的时钟频率为40MhHz,我们使定时时间为0.5ms,也就是周期为1kHz。
我们在中断中将某个IO口电平翻转,用于产生TMR2需要的外部时钟,通过波形抓取如下所示,时间为0.5ms,频率为1kHz;
2、TMR2工程配置
定时器TMR2主要是以外部频率为基准,进行计数。我们设置分频系数为1,时钟源选择外部时钟,外部时钟频率填写1000Hz,定时时间我们设置为500ms。
也就是说以1ms的频率,计数500次为500ms。这个时候在TMR2的中断服务函数中设置LED灯翻转,那么翻转的时间就是500ms。
5、具体代码分析
定时器TMR3
//定时器TMR3初始化 void TMR3_Initialize(void) { /* Disable Timer */ T3CONCLR = _T3CON_ON_MASK; //禁止定时器,清零ON控制位 /* SIDL = 0 //空闲模式停止位 TCKPS =1 //预分频设置 T32 = 0 //32定时器 TCS = 0 //时钟源选择,内部时钟源或外部时钟源 */ T3CONSET = 0x10; //TxCON与定时器相关的 16 位控制寄存器 /* Clear counter */ TMR3 = 0x0; //TMRx 16位定时器计数器寄存器 /*Set period */ PR3 = 19999U; //PRx与定时器相关的 16 位周期寄存器 /* Enable TMR Interrupt */ IEC0SET = _IEC0_T3IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器中 } //开启定时器TMR3 void TMR3_Start(void) { T3CONSET = _T3CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中; } //关闭定时器TMR3 void TMR3_Stop (void) { T3CONCLR = _T3CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中; } //设置周期寄存器 void TMR3_PeriodSet(uint16_t period) { PR3 = period; //PRx与定时器相关的16位周期寄存器 } //获取周期寄存器 uint16_t TMR3_PeriodGet(void) { return (uint16_t)PR3; //PRx与定时器相关的16位周期寄存器 } //获取计数值 uint16_t TMR3_CounterGet(void) { return (uint16_t)(TMR3); //TMRx 16位定时器计数器寄存器 } //获取定时器频率 uint32_t TMR3_FrequencyGet(void) { return (40000000); //返回定时器的时钟频率 } //定时器3中断服务函数 void TIMER_3_InterruptHandler (void) { uint32_t status = 0U; status = IFS0bits.T3IF; IFS0CLR = _IFS0_T3IF_MASK; /*可在这添加中断处理内容*/ GPIO_RB1_Toggle(); if((tmr3Obj.callback_fn != NULL)) { tmr3Obj.callback_fn(status, tmr3Obj.context); } } //中断使能 void TMR3_InterruptEnable(void) { IEC0SET = _IEC0_T3IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器 } //禁止中断 void TMR3_InterruptDisable(void) { IEC0CLR = _IEC0_T3IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器 } // void TMR3_CallbackRegister(TMR_CALLBACK callback_fn, uintptr_t context) { /* Save callback_fn and context in local memory */ tmr3Obj.callback_fn = callback_fn; tmr3Obj.context = context; } //中断服务函数,在interrupts.c中,调用TIMER_3_InterruptHandler void __ISR(_TIMER_3_VECTOR, ipl1SOFT) TIMER_3_Handler (void) { TIMER_3_InterruptHandler(); }
定时器TMR2
//定时器TMR2初始化 void TMR2_Initialize(void) { /* Disable Timer */ T2CONCLR = _T2CON_ON_MASK; //禁止定时器,清零ON控制位 /* SIDL = 0 //空闲模式停止位 TCKPS =0 //预分频设置 T32 = 0 //32定时器 TCS = 1 //时钟源选择,内部时钟源或外部时钟源 */ T2CONSET = 0x2; //TxCON与定时器相关的 16 位控制寄存器 /* Clear counter */ TMR2 = 0x0; //TMRx 16位定时器计数器寄存器 /*Set period */ PR2 = 499U; //PRx与定时器相关的 16 位周期寄存器 /* Enable TMR Interrupt */ IEC0SET = _IEC0_T2IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器中 } //开启定时器TMR2 void TMR2_Start(void) { T2CONSET = _T2CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中; } //关闭定时器 void TMR2_Stop (void) { T2CONCLR = _T2CON_ON_MASK; //TxIF中断标志状态位在IFS0 中断寄存器中; } //设置周期寄存器 void TMR2_PeriodSet(uint16_t period) { PR2 = period; //PRx与定时器相关的16位周期寄存器 } //获取周期寄存器 uint16_t TMR2_PeriodGet(void) { return (uint16_t)PR2; //PRx与定时器相关的16位周期寄存器 } //获取计数值 uint16_t TMR2_CounterGet(void) { return (uint16_t)(TMR2); //TMRx 16位定时器计数器寄存器 } //获取定时器频率 uint32_t TMR2_FrequencyGet(void) { return (1000); //返回定时器的时钟频率 } //定时器中断服务函数 void TIMER_2_InterruptHandler (void) { uint32_t status = 0U; status = IFS0bits.T2IF; IFS0CLR = _IFS0_T2IF_MASK; /*可在这添加中断处理内容*/ GPIO_RB0_Toggle(); if((tmr2Obj.callback_fn != NULL)) { tmr2Obj.callback_fn(status, tmr2Obj.context); } } //中断使能 void TMR2_InterruptEnable(void) { IEC0SET = _IEC0_T2IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器 } //禁止中断 void TMR2_InterruptDisable(void) { IEC0CLR = _IEC0_T2IE_MASK; //TxIE中断允许控制位在IEC0中断寄存器 } // void TMR2_CallbackRegister(TMR_CALLBACK callback_fn, uintptr_t context) { /* Save callback_fn and context in local memory */ tmr2Obj.callback_fn = callback_fn; tmr2Obj.context = context; } //中断服务函数,在interrupts.c中,调用TIMER_2_InterruptHandler void __ISR(_TIMER_2_VECTOR, ipl1SOFT) TIMER_2_Handler (void) { TIMER_2_InterruptHandler(); }
中断优先级配置
//中断优先级设置,设置TMR2以及TMR3优先级 void EVIC_Initialize( void ) { INTCONSET = _INTCON_MVEC_MASK; /* Set up priority and subpriority of enabled interrupts */ IPC2SET = 0x4 | 0x0; /* TIMER_2: Priority 1 / Subpriority 0 */ IPC3SET = 0x4 | 0x0; /* TIMER_3: Priority 1 / Subpriority 0 */ }
6、16位同步外部时钟计数器说明
同步外部时钟计数器操作提供了以下功能:
• 对周期性或非周期性脉冲进行计数
• 使用外部时钟作为定时器的时基
A 类和 B 类定时器都可工作于同步外部时钟计数器模式。在该模式下,定时器的输入时钟源是施加于 TxCK 引脚上的外部时钟。选择它的方法是将时钟源控制位 TCS 置 1 (TxCON<1> = 1)。B 类定时器会自动提供外部时钟源同步;但是,A 类定时器不会,并要求外部时钟同步位 TSYNC(T1CON<2>)置 1 (= 1)。
依靠同步外部时钟源工作的 A 类或 B 类定时器在 Sleep(休眠)模式下不工作,因为同步电路在Sleep(休眠)模式下被禁止。
TCLK引脚分别为RC1、RC2、RC3、RC4、RC14,需要注意。
7、16位同步外部时钟计数器初始化步骤
1. 清零 ON 控制位 (TxCON<15> = 0)以禁止定时器。
2. 将 TCS 控制位置 1 (TxCON<1> = 1)以选择外部时钟源。
3. 如果使用了 A 类定时器,则将 TSYNC 控制位置 1 (T1CON<2> = 1)以使能时钟同步。
4. 选择所需的定时器输入时钟预分频比。
5. 装载 / 清零定时器寄存器 TMRx。
6. 如果使用周期匹配:
a) 将所需的 16 位匹配值装入周期寄存器 PRx。
7. 如果使用了中断:
a) 清零 IFSx 寄存器中的 TxIF 中断标志位。
b) 在 IPCx 寄存器中配置中断优先级和子优先级。
c) 将 IECx 寄存器中的 TxIE 中断允许位置 1。
8. 将 ON 控制位置 1 (TxCON<15> = 1)以使能定时器。
8、实验验证
点击编译按钮,编译提示BUILD SUCCESSFUL,点击烧录,提示Programming/Verify complete,开发板上的LED灯闪烁。
————————————————
版权声明:本文为CSDN博主「Huangtop」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Huangtop/article/details/119317537