本帖最后由 Peixu 于 2023-11-20 18:12 编辑
#申请原创# @21小跑堂
在嵌入式系统开发中,时间管理是至关重要的。定时器在这方面扮演着关键角色,用于测量时间间隔、生成脉冲、控制任务执行周期等。
某些系列不具有32位计时器,自带的定时器均为16位。所以常常使用16位定时器来完成这些任务。然而,在某些情况下,当你需要进行某些同时需要精度与时长的计时内容时,16位计时器并不够用。
在这种情况下,将两个16位定时器级联成一个32位定时器就显得尤为重要。
目前使用的是一颗ARM Cortex-M0+内核的APM32F003是一款广泛应用于嵌入式系统中的低功耗、高性能的微控制器核心。
包含 2 个16bit高级控制定时器(TMR1 和 TMR1A)、1 个16bit通用定时器(TMR2)、1 个8bit基本型定时器(TMR4)、2 个看门狗定时器、1 个系统滴答定时器和 1 个自动唤醒定时器。
接下来将介绍如何使用APM32F003的两个16位定时器,将它们级联起来,实现一个功能强大的32位定时器。
1. 选择和初始化定时器一般微控制器通常具有多个定时器,我们需要选择两个可用的16位定时器并对它们进行初始化。这中间会涉及到设置时钟源、计数模式、中断使能等。请参考微控制器手册以获取特定寄存器的详细信息。 2. 配置级联模式在级联模式下,一个定时器被设置为主定时器(例如定时器2),另一个被设置为从定时器(例如定时器1)。主定时器的计数器溢出会触发一个中断,在该中断服务程序中,更新从定时器的计数器。 3. 中断服务程序设计设计主定时器的中断服务程序,以处理主定时器计数器溢出。在这个中断服务程序中,更新从定时器的计数器,可以是递增、清零或其他需求的操作。 4. 计算32位定时器的值在主程序中,可以在循环中读取定时器1和定时器2的值。通过位操作(如位移和逻辑或操作),将这两个16位计数器的值合并成一个32位的计时值。 temp = TMR1_ReadCounter(TMR1);
temp <<= 16;
temp |= TMR2_ReadCounter();
5. 测试和验证对32位定时器进行全面的测试,包括检查溢出情况、正确性、稳定性等。确保它按照预期工作,并满足你的应用需求。
APM32F003这个主频可以跑48Mhz 以我们的48M主频不分频直接计数为例:
那么计数单位时间为:
16bit 的定时器是2的16次方 = 65535 ,那么最大计时时间为:
16bit = 1.36ms
32bit = 89.4s
对于某些毫秒级高精度计时来说,使用32位定时器还是很有必要的。
使用TMR1 和TMR2级联。
原理:
设置TMR2为主定时器,TMR1从为定时器。
在定时器互连中可以:
将一个定时器作为另一个寄存器的预分频器
用一个定时器的使能信号启动另一个寄存器
用一个定时器的更新事件启动另一个寄存器
用一个定时器的使能选通另一个定时器
用一个外部触发同步两个定时器
将TMR2级联到TMR1 的后面,当TMR2出现 “溢出 更新事件” 的时候,TMR1就自动计数一次 软读出。
void TMR2Init(void)
{
/** Divider = 0x00, counter = 0xFFFF */
TMR2_ConfigTimerBase(0x00, 0XFFFF);
/** Master mode Configuration */
TMR2_ConfigMasterMode(TMR2_MASTER_MODE_UPDATE);
/** Enable TMR2 Master mode */
TMR2_EnableMasterMode();
/** Enable TMR2 */
TMR2_Enable();
}
void TMR1Init(void)
{
TMR1_TimeBaseConfig_T timeBaseConfig;
/** Up-counter */
timeBaseConfig.cntMode = TMR1_CNT_MODE_UP;
/** Set divider */
timeBaseConfig.divider = 0;
/** Repetition counter = 0x0 */
timeBaseConfig.repetitionCount = 0X0;
/** specifies the counter */
timeBaseConfig.count = 0xFFFF;
TMR1_ConfigTimerBase(TMR1, &timeBaseConfig);
/** The update event is selected as trigger Input */
TMR1_ConfigInputTrigger(TMR1,TMR1_ITC_TMR2);
/** Set TMR1 Slave mode */
TMR1_ConfigSlaveMode(TMR1,TMR1_SLAVE_MODE_EXTERNAL1);
/** Enable TMR1 */
TMR1_Enable(TMR1);
}
需要注意TMR2初始化要在TMR1前面, 因为TMR2是主定时器。
int main(void)
{
USARTInit();
TMR2Init(); // TMR2 is Master and needs to be before TMR1
TMR1Init();
uint32_t temp = 0;
while(1)
{
temp = TMR1_ReadCounter(TMR1);
temp <<= 16;
temp |= TMR2_ReadCounter();
printf("Count Value: 0x%8x\r\n",temp);
}
}
通过以上步骤,已经成功地使用了两个16位定时器,将它们级联成一个32位定时器。
|