51 单片机的定时计数器
定时 / 计数器的核心部件是一个加法(或减法)计数器;若计数脉冲来自零碎时钟,则为定时形式;若计数脉冲来自单片机内部引脚,则为计数形式。
根本介绍
定时器:
- 定时器是 SOC 的外部外设。
- 定时器就是 CPU 的闹钟。
计数器:
- 单片机实现定时器其实质是用计数器来实现的。
- 计数器能够计算内部脉冲的个数。
- 当单片机计算外部脉冲个数时就相当于定时器,当计算内部脉冲个数就相当于计数器。
加法计数器和减法计数器:(51 单片机是加法计数器)
-
加法计数器:从咱们给定的值开始加,加到溢出,而后触发中断。
- 例如:16 位定时器最大计数 65535 次,如果咱们想计数 50000 次,那么设置的 TH 和 TL 应设为 65535-50000 = 15535。
-
减法计数器;从咱们给定的值开始减,减到 0 就溢出,而后触发中断。
- 例如:16 位定时器最大计数 65535 次,如果咱们想计数 50000 次,那么设置的 TH 和 TL 应设为 50000。
-
计算 TL 和 TH:
- 首先确定定时工夫,time(例如 50ms)。
- 确定外部时钟周期,因为是 12T 模式,晶振 12MHz,所以外部频率 1MHz,周期 1us。
- 定时计个数 = time ÷ 周期。(50000)
- TL1 = 个数 % 256(取余);TH1 = 个数 / 256(取整)。
工作流程
- 设置定时器时钟源(作定时器应用时,须要外部的脉冲,这个脉冲来源于时钟源)
- 初始化定时器相干寄存器。
- 设置定时工夫(计数个数)
- 设置中断处理程序。
- 关上定时器。
- 运行时:定时器计数到设置值后产生中断,执行中断处理程序。
定时 / 计数器相干寄存器。
管制寄存器 TCON
- TF1:定时器 / 计数器 T1 溢出标记位。T1 被容许计数后,从初值开始加一,计数实现后由硬件置位,收回中断请求;中断响应后硬件主动复位。
- TR1:定时器 T1 容许管制位,由软件置位和清零。GATE(TMOD.7)= 0,TR1 = 1 时才容许 T1 开始计数。
- IE1:内部中断 1 申请源标记。IE1 = 1,内部中断向 CPU 申请中断,CPU 响应后由硬件清零。、
- IT1:内部中断 1 触发形式管制位。IT1 = 0 时,内部中断 1 为低电平触发形式;IT1 = 1 时,内部中断 1 为高电平触发形式。
工作模式寄存器 TMOD
- GATE(TMOD.7):与 TCON.6(TR1)配合管制定时器运行
- C/T(TMOD.6): 管制定时器 1 用作定时器还是计数器。清零用作定时器,置一用作计数器。
- M1/M0(TMOD.5/TMOD4): 定时计数器模式抉择位。
- (00)模式 0(13 位定时器 / 计数器);(01)模式 1(16 位定时器 / 计数器模式);(10)模式 2(8 位主动重装模式);(11)模式 3(两个 8 位定时器 / 计数器)。
示例代码
//TIM1 定时器初始化
void TIM1_Init()
{
TMOD = 0x10; // T0 设置工作在定时器模式下,模式一 16 位定时器
TL1 = (65535 - 50000) % 256;
TH1 = (65535 - 50000) / 256;
TR1 = 1; // 开启计数器,开始计数了
ET1 = 1; // 开启 T1 中断
EA = 1; // 开启中断总开关
count = 10; // 10 次,对应 500ms
}
//TIM1 中断处理程序;定时 500ms
void timer1_isr(void) interrupt 1 using 1
{TL1 = (65535 - 50000) % 256;
TH1 = (65535 - 50000) / 256; // 手工重装载计数值
// 因为模式一不能主动重装载,所以要手工重装载计数值。if (count-- == 0)
{
// 阐明曾经中断了 10 次了,500ms 到了,该干活了
LED = !LED; // LED 取反
count = 10;
}
}
STM32 单片机的定时 / 计数器
独立看门狗(IWDG)
- 当计数器达到给定的超时值时会产生零碎复位。
- 独立看门狗 (IWDG) 由专用的低速时钟 (LSI) 驱动,即便主时钟产生故障它也依然无效。
- 独立看门狗(IWDG)是减法计数器。
- 看门狗被激活后,则在计数器计数至 0x000 时产生复位(复位的意思是指从 0xfff 开始递加)
- 独立看门狗能够在任何时候进行喂狗操作。喂狗后,计数器从设定的值开始计数。
- IWDG 最适宜利用于那些须要看门狗作为一个在主程序之外(次要是为了避免程序跑飞),可能齐全独立工作,并且对工夫精度要求较低的场合。
窗口看门狗(WWDG)
- 当计数器达到给定的超时值时会产生零碎复位或触发一个中断。
- 窗口看门狗由从 APB1 时钟分频后失去的时钟驱动。
- 窗口看门狗(WWDG)是减法计数器。
- 窗口看门狗(WWDG)喂狗工夫有严格控制。必须要在规定的工夫内(窗口)喂狗才无效。如果在其余工夫喂狗则会产生复位,如果在窗口没有喂狗,则计数完后也会产生复位。
- WWDG 最适宜那些要求看门狗在准确计时窗口起作用的应用程序。
通用定时器(TIMx)((TIM2、TIM3、TIM4、TIM5)
TIMx 简介
- 16 位向上(加法计数)、向下(减法计数)、向上 / 向下主动装载计数器。
- 向上 / 向下计数(地方对齐模式):计数器从 0 加到(设定值 -1)触发溢出中断,再从(设定值 -1)减到 1 触发下溢中断。
- 加法计数和减法计数:例如想计数 500 次,加法计数器是从 0 开始计数到 500,而减法计数器是从 500 减到 0。
- 性能:输出捕捉、输入比拟、PWM。
- 16 位可编程 (能够实时批改) 预分频器,计数器时钟频率的分频系数为 1~65536 之间的任意数值。(计数器的时钟频率是由下级频率通过预分频器分频失去的,下级频率每个定时器可能不同,可能是 APB1 或 APB2,下级频率设置办法请查看另外一篇文章“STM32 时钟体系”)
- 计数器、主动装载寄存器和预分频器寄存器能够由软件读写,在计数器运行时仍能够读写。
- 计数器由预分频器的时钟输入 CK_CNT 驱动,仅当设置了计数器 TIMx_CR1 寄存器中的计数器使能位 (CEN) 时,CK_CNT 才无效。
-
主动重装载寄存器、预装载寄存器、影子寄存器、计数器关系:(集体了解,不肯定对)
- ARPE:管制寄存器 1(TIMx_CR1)中预装载寄存器容许位。(0:不应用预装载寄存器)
- 计数器是计算次数的,而影子寄存器则是用来与计数器做比拟的。(实用于加法计数中)
- 例如:以后计数值为 500,当初想将计数个数改为 1000。
- 当 APRE 为 0 时:先将 1000 写入主动重装载寄存器,主动重装载寄存器立马将 1000 装入影子寄存器中。以后计数到 1000 后才触发中断,而不是 500。
- 当 APRE 为 1 时:先将 1000 写入主动重装载寄存器,主动重装载寄存器将 1000 写入预装载寄存器中,当此次计数实现即计数到 500 后触发中断,预装载寄存器才将 1000 写入影子寄存器中。下次计数到 1000 触发中断。
TIMx 寄存器形容
管制寄存器 1(TIMx_CR1)
- 复位值:0x0000
- CKD: 时钟分频因子
- ARPE:主动重装载预装载容许位(1:容许预装载)
- CMS:抉择地方对齐模式。
- DIR:抉择计数方向(0 上 1 下)
- URS:URS:更新申请源(1:如果使能了更新中断或 DMA 申请,则只有计数器溢出 / 下溢才产生更新中断或 DMA 申请)
- UDIS:禁止更新(1:禁止更新,不触发任何中断或事件)
- CEN:使能计数器(1:使能计数器)
DMA/ 中断使能寄存器(TIMx_DIER)
- 复位值:0x0000
- TDE:容许触发 DMA 申请(1:容许)
- UDE:容许更新的 DMA 申请(1:容许)
- TIE:触发中断使能(1:使能触发中断)
- UIE:容许更新中断(1:容许更新中断)
- 中断服务程序程序执行完当前,要把中断关上(即把标记地位位),以便下一次还能触发该中断。这就是更新中断。
状态寄存器(TIMx_SR)
- 复位值:0x0000
- TIF:触发器中断标记(当产生触发事件时由硬件对该地位一,它由软件清零)(1:触发器中断期待响应)
- UIF:更新中断标记(当产生更新事件时该位由硬件置一。它由软件清零)(1:更新中断期待响应)
事件产生寄存器(TIMx_EGR)
- 复位值:0x0000
- TG:产生触发事件,由软件置一硬件清零(1:当 TIMx_SR 寄存器的 TIF=1,若开启对应的中断和 DMA,则产生相应的中断和 DMA。)
- UG:产生更新事件,由软件置一硬件清零(1:从新初始化计数器,并产生一个更新事件。)
示例
/*******************************************************************************
* 函 数 名 : TIM4_Init
* 函数性能 : TIM4 初始化函数
* 输 入 : per: 重装载值
psc: 分频系数
* 输 出 : 无
*******************************************************************************/
void TIM4_Init(u16 per,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);// 使能 TIM4 时钟
TIM_TimeBaseInitStructure.TIM_Period=per; // 主动装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; // 分频系数
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; // 设置 CKD 时钟分频因子
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; // 设置向上计数模式
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 开启定时器中断
TIM_ClearITPendingBit(TIM4,TIM_IT_Update); // 革除中断挂起位
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;// 定时器中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; // 子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM4,ENABLE); // 使能定时器
}
/*******************************************************************************
* 函 数 名 : TIM4_IRQHandler
* 函数性能 : TIM4 中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void TIM4_IRQHandler(void)
{if(TIM_GetITStatus(TIM4,TIM_IT_Update))
{led2=!led2;}
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}