定时器

很多新手在单片机上走的第一步是点亮第一个LED灯,实际上因为开发板的不同,所编写的代码也不同,关键是你要去了解你用的开发板的电路布局。对于电路方面的知识我这里也不祥讲,我要做的是无论你用哪一种开发板我的文章都能帮助你。

  P0 = 0xFE;

  这句代码大家不陌生。

  void main(){
    unsigned char count = 0;
    while(1){
      P0 = ~(0x01 << count);
      Delay();    //单独实现一个延时函数
      count++;
      if(count > =8){
        count = 0;
      }
    }
  }

以上就是实现流水灯的基本代码,这里没有电路供你分析,但是无论什么开发板,核心代码可以用以上代码实现。

我相信你能看到这里也是有点基础的,这里的延时函数Delay,接下来要讲的是定时器,定时器就是可以替代延时函数的。

定时器

标准的51单片机内部有T0和T1两个定时器,实际上就是TCON特殊功能的寄存器来控制这两个定时器的。

单片机定时器与数码管静态显示

除此之外,定时值存储寄存器有TH和TL,给TL赋值后,TL会自动加1,加到255后TH加1,有趣的TH也可以提前赋值,但这只是定时器工作的一种模式,定时器有四种模式,这里我不祥讲,而且我们几乎用的模式就是这种,后面涉及到会详细讲解。这里只需要知道TCON(地址0x88)位分配,以后会经常用到。

还有一个TMOC就是定时器作用的模式,位分配如下图:

单片机定时器与数码管静态显示

代码:

void main()
{
  TH0 = 0xB8;  //给TH0赋值,后面的0代表是给定时器T0的TH赋值
  TL0 = 0x00;
  TR0 = 1;   //启动T0定时器
  if(TF0 == 1)    //判断T0是否溢出,TF是个标志位
  {
    //重置
  TH0 = 0xB8;  
  TL0 = 0x00;
  } 
}

以上就是定时器,时间多少呢?

我们以晶振位11.0592为例,时钟周期是1/11059200,机器周期(1ms)12/11059200,如果我们定时20ms,那个要执行20*(12/110592)次,算出来是18432次,换成十六进制是B800,所以对TH0赋值B8,对TL0赋值00;

数码管

#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main() {
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 1;
ADDR3 = 1;
ENLED = 0;
P0 = 0XF8;
while(1);
}

上面代码是用位STC-51开发板写的,在最后一个数码管上显示数字7,数码管难度简单,只需要针对数码管等的排布编程即可。

下面我们用关键字code定义数码管所能够显示所有字符的数组,这里再结合定时器一起。

#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
//数组 unsigned char code led[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E };
void main() {
unsigned char count = 0;
//记录T0中断次数
unsigned char secnt = 0;
//记录经过的秒数
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 0;
ADDR3 = 1;
ENLED = 0;
//设置T0模式
TMOD = 0x01;
//为T0的TH0,TL0初始化
TH0 = 0xB8;
TL0 = 0x00;
//启动T0 TR0 = 1;
while(1)
{ if(TF0 ==1)
{ TH0 = 0xB8;
TL0 = 0x00;
count++;
TF0 = 0; }
if(count >=50)
{ count = 0;
P0 = led[secnt];
secnt++;
if(secnt>=16)
{ secnt = 0; }
}
}
}

这里代码比较紧凑,不过不影响。上面的代码我相信你也能懂,但是你能发现定时器在这里起到了一个定时中断的作用。

这里讲一下中断。

中断

下面是中断IE寄存器位分配图:

单片机定时器与数码管静态显示

直接上代码:

#include <reg52.h>
//数码管显示字符真值数组
unsigned char code ledchar[]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E };
//数码管显示区数组
unsigned char ledbuff[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char i = 0;
//动态扫描索引
unsigned int c = 0;
//记录中断次数
void main() {
unsigned long s = 0;
//记录秒数
//使能U3
ADDR3 = 1;
ENLED = 0;
//设置T0模式
TMOD = 0x01;
//初始化TH0,TL0
TH0 = 0xFC; TL0 = 0x66;
//启动TR0
TR0 = 1;
//使能总中断
EA = 1;
//使能T0中断
ET0 = 1;
//主循环
while(1)
{
//1s中断
if(c>=1000)
{
s++;
c=0;
//为数码管显示区赋值
ledbuff[0] = ledchar[s%10];
ledbuff[1] = ledchar[s/10%10];
ledbuff[2] = ledchar[s/100%10];
ledbuff[3] = ledchar[s/1000%10];
ledbuff[4] = ledchar[s/10000%10];
ledbuff[5] = ledchar[s/100000%10];
}
}
}

//定时器T0中断服务
void InterruptTimer0() interrupt 1
{
//重新赋值
TH0 = 0xFC;
TL0 = 0x66;
c++;
//显示消隐
P0 = 0xFE;
//完成数码管动态扫描
switch(i)
{
case 0:
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 1;
i++;
P0 = ledbuff[0];
break;
case 1:
ADDR2 = 1;
ADDR1 = 0;
ADDR0 = 0;
i++;
P0 = ledbuff[1];
break;
case 2:
ADDR2 = 0;
ADDR1 = 1;
ADDR0 = 1;
i++;
P0 = ledbuff[2];
break;
case 3:
ADDR2 = 0;
ADDR1 = 1;
ADDR0 = 0;
i++;
P0 = ledbuff[3];
break;
case 4:
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 1;
i++;
P0 = ledbuff[4];
break;
case 5:
ADDR2 = 0;
ADDR1 = 0;
ADDR0 = 0;
i=0;
P0 = ledbuff[5];
break;
default:break; } }

这组代码能够按照我们计算好的时间为单位显示秒数。

我们能够提出中断核心代码

EA = 1//中断总开关

ET0 = 1//确认使用T0定时器中断开关

TR0 = 1//肯定要启动T0定时器

void InterruptTimer0() interrupt 1//定时器T0中断服务,中断代码写在这里面,至于interrupt 1是因为interrupt会去寻找地址' 1 ',而T0定时器中断的地址就是1,所以我们可以直接在此函数中写中断期间的代码。至于各种中断的地址我也不再这里多写了。值得一谈的是IP——中断优先级寄存器位分配

单片机定时器与数码管静态显示

各级中断都差不多,中断发生的也很多,当同时有许多中断发生时,可以通过置上面的值为1升级成优先级中断。

转自:嵌入式开发员

围观 5
175

1、555定时器原理分析

555定时器的功能主要由两个比较器决定。两个比较器的输出电压控制RS触发器和放电管的状态。在电源与地之间加上电压,当5脚悬空时,则电压比较器C1的同相输入端的电压为2VCC/3,C2的反相输入端的电压为VCC/3。若触发输入端 TR 的电压小于VCC /3,则比较器 C2 的输出为 0,可使 RS 触发器置 1,使输出端 OUT=1。如果阈值输入端 TH 的电压大于 2VCC/3,同时 TR 端的电压大于VCC /3,则 C1 的输出为 0,C2 的输出为 1,可将 RS 触发器置 0,使输出为低电平。

555引脚

四款555定时器产生方波的电路

引脚功能
四款555定时器产生方波的电路

单稳态模式:

在单稳态工作模式下,555定时器作为单次触发脉冲发生器工作。当触发输入电压降至VCC的1/3时开始输出脉冲。输出的脉宽取决于由定时电阻与电容组成的RC网络的时间常数。当电容电压升至VCC的2/3时输出脉冲停止。根据实际需要可通过改变RC网络的时间常数来调节脉宽。

输出脉宽t,即电容电压充至VCC的2/3所需要的时间由下式给出:

四款555定时器产生方波的电路

虽然一般认为当电容电压充至VCC的2/3时电容通过OC门瞬间放电,但是实际上放电完毕仍需要一段时间,这一段时间被称为“弛豫时间”。在实际应用中,触发源的周期必须要大于弛豫时间与脉宽之和(实际上在工程应用中是远大于)。

双稳态模式:

双稳态工作模式下的555芯片类似基本RS触发器。在这一模式下,触发引脚(引脚2)和复位引脚(引脚4)通过上拉电阻接至高电平,阈值引脚(引脚6)被直接接地,控制引脚(引脚5)通过小电容(0.01到0.1μF)接地,放电引脚(引脚7)浮空。所以当引脚2输入高电压时输出置位,当引脚4接地时输出复位。

无稳态模式:

无稳态工作模式下555定时器可输出连续的特定频率的方波。电阻R1接在VCC与放电引脚(引脚7)之间,另一个电阻(R2)接在引脚7与触发引脚(引脚2)之间,引脚2与阈值引脚(引脚6)短接。工作时电容通过R1与R2充电至2/3VCC,然后输出电压翻转,电容通过R2放电至1/3VCC,之后电容重新充电,输出电压再次翻转。

无稳态模式下555定时器输出波形的频率由R1、R2与C决定:

四款555定时器产生方波的电路

对于双极型555而言,若使用很小的R1会造成OC门在放电时达到饱和,使输出波形的低电平时间远大于上面计算的结果。

为获得占空比小于50%的矩形波,可以通过给R2并联一个二极管实现。这一二极管在充电时导通,短路R2,使得电源仅通过R1为电容充电;而在放电时截止以达到减小充电时间降低占空比的效果。

2、555定时器产生方波原理电路图解

555定时器产生方波原理(一):占空比可调的方波发生器

CB555定时器的工作原理可列表说明:

四款555定时器产生方波的电路

空比可调的方波信号发生器电路图
四款555定时器产生方波的电路
图:利用CB555定时器设计方波电路原理图

占空比可调的方波信号发生器分析如图2所示,电路只要一加上电压VDD,振荡器便起振。刚通电时,由于C上的电压不能突变,即2脚电位的起始电平为低电位,使555置位,3脚呈高电平。C通过AR、D1对其充电,充电时间CRtA7.0充。压充到阈值电平2/3VDD时,555复位,3脚转呈低电平,此时C通过Dl、RB、555内部的放电管放电,放电时间CRtB7.0放。则振荡周期为放充ttT。

四款555定时器产生方波的电路

555定时器产生方波原理(二):555定时器的方波发生器

这是一个无线电信号线路和电视的最有用的方波发生器项目。方波是最适合用于测试信号的中频(IF)地带,将通过中频变压器没有任何衰减,不管是什么电路的调谐频率。555TImer是配置非稳态运行,这意味着它将触发本身作为一个多谐振荡器自由运行。计时元件电阻R1,R2和电容器(C1-6)在此图中显示的值,产生的六个频率1Hz的,10HZ,100HZ,1KHZ,如果你想产生一个可变频率10kHz到100kHz您可以用一个100K的迷你系列10K电阻微调电位连接,68K电阻。这方波振荡器的电子项目,可提供5至18伏直流输出电压从电源供电,但通常建议使用9伏直流电源。

四款555定时器产生方波的电路

555定时器产生方波原理(三):秒信号的发生电路
秒信号发生电路由集成电路555定时器与RC组成的多谐振荡器构成。需要的芯片有集成电路555定时器,还有电阻和电容。下图为其电路图:

四款555定时器产生方波的电路

振荡电路是数字钟的核心部分,它的频率和稳定性直接关系到表的精度。因此选择555定时器构成的多谐振荡器,其中电容C1为47微法,C2为0.01微法,两个电阻R1=R2=10K欧姆。此时在电路的输出端就得到了一个周期性的矩形波,其振荡频率为:

f = 1.43 / [ ( R1 + 2R2 ) C ]

由公式代入R1,R2和C的值得,f=1Hz。即其输出频率为1Hz的矩形波信号

555定时器产生方波原理(四):555定时器实现波形发生器

555定时器的功能主要由两个比较器决定。两个比较器的输出电压控制RS触发器和放电管的状态。在电源与地之间加上电压,当5脚悬空时,则电压比较器C1的同相输入端的电压为2VCC/3,C2的反相输入端的电压为VCC/3。若触发输入端TR的电压小于VCC/3,则比较器C2的输出为0,可使RS触发器置1,使输出端OUT=1。如果阈值输入端TH的电压大于2VCC/3,同时TR端的电压大于VCC/3,则C1的输出为0,C2的输出为1,可将RS触发器置0,使输出为低电平。

多谐振荡器原理图

四款555定时器产生方波的电路

THR和TRI分别为基准电压为2VCC/3和VCC/3的两个比较器,当初始电容C1两端的电压值小于VCC/3时,输出端输出高电平,则在输出端和C1之间产生电位差,于是通过二极管D1给电容充电,在C1两端电压小于2VCC/3时输出端一直输出高电平;当电容两端电压由充电上升到2VCC/3时,555定时器输出端输出低电平,此时电容C1两端的电压高于输出端,于是电容放电,直到电容两端电压降到VCC/3,输出端电压变为高点平。于是产生稳定的方波。其中占空比和方波的频率由两个电位器来调节。充电的时间由电流的大小决定,即有充放电的电路中的电阻大小所决定,故可通过调节充电和放电电路中的电阻的大小来调节方波的占空比和频率。

积分电路

选择了通过运算放大器构成的反相积分器。如图

四款555定时器产生方波的电路

通过积分电路可将方波滤成三角波。

RC低通滤波

四款555定时器产生方波的电路

通过对电容C4的充电和放电,可将规则三角波滤成规则的正弦波。

来源:网络

围观 14
286

MM32L0系列MCU内嵌两个通用比较器 COMP1 和 COMP2,为通用的可编程电压比较器,可独立使用(适用所有终端上的 I/O 口),也可与定时器结合使用, 支持两个独立的比较器。它们可用于多种功能,包括:由模拟信号触发低功耗模式唤醒事件调节模拟信号与 DAC 和定时器输出的 PWM 相结合,组成逐周期的电流控制回路。

比较器框图
MM32 定时器捕获比较器输出

COMPx信号宽度需要测量的输入信号连接到 PA0-PA7。参考信号可通过以下方式供电:

● 内部参考电压(VREFINT、 3/4 VREFINT、 1/2 VREFINT 或 1/4 VREFINT)

● PA4\ PA5\ PA0\ PA7的外部引脚(COMP1),PA4\ PA5\ PA2\ PA7的外部引脚(COMP2)COMPx 输出重映射通过COMP1_CSR[13:10],COMP2_CSR[13:10]比较器 x 输出选择位实现。

在 MM32L0系列MCU中,COMP1 \COMP2 输出可以重映射到内置定时器 TIM1 的 BKIN(刹车输入)和IC4上。重映射 COMP21\COMP2 输出时,可以测量具有特定高/低电平的信号宽度或频率(例如,移位信号)。

定时器输入捕获通道应配置为同时在上升沿和下降沿保存定时计数器值。当输入信号高于参考电压时, COMPx 输出处于高电平,此时会在定时器输入捕获上生成一个上升沿。当输入信号低于参考电压时, COMPx输出处于低电平,此时会生成一个下降沿。两个连续事件之间经过的时间(下降沿到上升沿或者上升沿到下降沿)表示脉冲宽度。因此,只需对计数器值做减法即可测量脉冲宽度。

COMPx输出重映射到定时器
MM32 定时器捕获比较器输出

1、将定时器输入捕获通道配置为仅在上升沿或下降沿保存计数器值,即可获得信号频率。

2、参考电压可以使用内部参考电压(0.4v、0.6v、0.9v和1.2v),也可以使用外部 GPIO 接到某一个电压值(0-5v)作为反相输入。

脉冲宽度测量应用:

将 COMPx 输出连接到定时器的输入捕获通道,则可以测量电容值,电容测量过程包括通过电阻对电容进行充电和放电。测量原理基于电阻、电容 (RC) 网络充电时间的测量过程,方法如下:

● 测量充电时间
● 已知充电电阻 (R)
● 可计算未知的电容 (C)

测量电容的电路图
MM32 定时器捕获比较器输出

通过 PWM 模式下配置的定时器输出比较通道 (TIMx OC),可确保 RC 网络周期性的充电和放电过程。

输入电压连接到 COMPx 同相输入,而阈值连接到 COMPx 反相输入。当输入电压超过阈值时, COMPx 输出切换为高电平,同时发生保存计数器值的捕获事件。

MM32 定时器捕获比较器输出

充电函数如下所示:

Input voltage =VDD(1- exp(- t /T))

其中:

● VDD 为正电源电压
● t 为时间
● T 为 RC 常数

根据上述公式可以推算:

C = -t / ( R x In( 1-threshold /(VDD) ))

比较器配置程序:

void Comp_Config(uint32_t COMP_Selection_COMPx)
{
COMP_InitTypeDef COMP_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_COMP, ENABLE);//开比较器时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);//开GPIOA的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_7);// 复用AF7,比较器输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;//模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
//内部参考电压1.2v(可以内部基准设置0.4v、0.6v、0.9v和1.2v)
COMP_InitStructure.COMP_InvertingInput = COMP_InvertingInput_VREFINT;
//PA5为正相输入引脚
COMP_InitStructure.COMP_NonInvertingInput = COMP_NonInvertingInput_IO6;
//输出重印射到TIM1的输入捕获通道4
COMP_InitStructure.COMP_Output = COMP_Output_TIM1IC1;
//比较器不上锁
COMP_InitStructure.COMP_BlankingSrce = COMP_BlankingSrce_None;
//比较器输出极性:同相输出
COMP_InitStructure.COMP_OutputPol = COMP_OutputPol_NonInverted;
//比较器迟滞电压:0mV(可设置迟滞电压0-27mV)
COMP_InitStructure.COMP_Hysteresis = COMP_Hysteresis_No;
//比较器模式:中等速率(可设置极低速率、低速率、中等速率、高速率)
COMP_InitStructure.COMP_Mode = COMP_Mode_MediumSpeed; COMP_Init(COMP_Selection_COMPx, &COMP_InitStructure);
//使能比较器
COMP_Cmd(COMP_Selection_COMPx, ENABLE);
}

定时器TIM1配置程序:

void TIM1_PWMINPUT_INIT(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_ICInitTypeDef TIM1_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);//TIM1时钟使能
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);GPIOA时钟使能

TIM_TimeBaseStructure.TIM_Period = arr; //设置重装载值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = 0;// TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

NVIC_InitStructure.NVIC_IRQChannel = TIM1_IRQn; //配置中断优先级
NVIC_InitStructure.NVIC_IRQChannelPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

TIM1_ICInitStructure.TIM_Channel = TIM_Channel_1; //选择输入端 IC1映射到TI1 上
TIM1_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
TIM1_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到 TI1 上
TIM1_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //不分频
TIM1_ICInitStructure.TIM_ICFilter = 0x0; //不滤波
TIM_PWMIConfig(TIM1, &TIM1_ICInitStructure);

TIM_ITConfig(TIM1, TIM_IT_CC1|TIM_IT_Update, ENABLE); //使能捕获和更新中断
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1|TIM_IT_Update); //清中断
TIM_Cmd(TIM1, ENABLE); //定时器使能
}

定时器TIM1中断服务函数:

void TIM1_CC_IRQHandler (void)
{
if (TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET)
{
period = TIM_GetCapture1(TIM1);
duty = TIM_GetCapture2(TIM1);
CollectFlag = 1;
}
TIM_ClearITPendingBit(TIM1, TIM_IT_CC1|TIM_IT_Update);
}

小结:

1、为保证恶劣环境下比较器设置不能被无效寄存器访问或者程序计数器破坏所改变,比较器控制和状态寄存器可以设为写保护(只读),一旦设置完成, LOCK 位必须设为 1,这导致整个 COMPx_CSR 寄存器变成只读,包括 LOCK 位在内。写保护只能被 MCU 复位所清除。

2、在某些用电池供电的应用中,MCU需要在环境明亮时上电;其它情况下,微控制器必须保持断电状态。对于此类应用,可以使用电阻随光强度变化的光敏电阻 (LDR) 来控制MCU的状态。使用 LDR 传感器时,MCU可根据 LDR 电阻提供的电压切换到低功耗模式或退出低功耗模式。MM32L0系列MCU 的比较器COMP1和COMP2的可在内部将该输出分别连接到 EXTI 线19和20。

转自:灵动微电子

围观 4
528

一、应用简介

在实际应用的一些产品上可能需要使用到对脉冲的个数进行计数,本文小编将给大家介绍如何使用TIM来做一个脉冲计数的功能。在MM32 TIM中正好有一个外部时钟模式1可以来帮助我们实现这个功能。

二、外部时钟源模式1描述

首先我们来了解一下外部时钟源模式1,当 TIMx_SMCR 寄存器的 SMS = 111 时,此模式被选中。计数器可以在选定输入端的每个上升沿或下降沿计数。下图是TI2外部时钟连接例子。

如何使用定时器做脉冲计数

例如,要配置向上计数器在 T12 输入端的上升沿计数,使用下列步骤:
1. 配置 TIMx_CCMR1 寄存器 CC2S = 01,配置通道 2 检测 TI2 输入的上升沿。
2. 配置 TIMx_CCMR1 寄存 器的 IC2F[3: 0],选择输入滤波器带宽(如果不需要滤波器,保持 IC2F= 0000) 。
3. 配置 TIMx_CCER 寄存器的 CC2P = 0,选定上升沿极性。
4. 配置 TIMx_SMCR 寄存器的 SMS = 111,选择定时器外部时钟模式 1。
5. 配置 TIMx_SMCR 寄存器中的 TS = 110,选定 TI2 作为触发输入源。
6. 设置 TIMx_CR1 寄存器的 CEN = 1,启动计数器。

注:捕获预分频器不用作触发,所以不需要对它进行配置。

当上升沿出现在 TI2,计数器计数一次,且 TIF 标志被设置。

在 TI2 的上升沿和计数器实际时钟之间的延时取决于TI2输入端的重新同步电路。

外部时钟模式1下的控制电路

如何使用定时器做脉冲计数

三、定时器代码配置

如何使用定时器做脉冲计数

四、实验结果

实验信号发生器从PA1输入1HZ的方波,进入KEIL的调试模式观察TIM->CNT的变化,TIM的计数器以每秒加1的速度向上计数,停止输入方波,计数器停止计数。说明我们实现了使用TIM进行计数的功能

转自:灵动MM32

围观 4
462

1. STM32的Timer简介

STM32中一共有11个定时器,其中2个高级控制定时器,4个普通定时器和2个基本定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器 ,看门狗定时器暂不讨论。今天主要是研究剩下的8个定时器。

STM32通用定时器功能和用法

其中TIM1和TIM8是能够产生3对PWM互补输出的高级登时其,常用于三相电机的驱动,时钟由APB2的输出产生。TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。由于STM32的TIMER功能太复杂了,所以只能一点一点的学习。因此今天就从最简单的开始学习起,也就是TIM2-TIM5普通定时器的定时功能。

2.普通定时器TIM2-TIM5

2.1 时钟来源

计数器时钟可以由下列时钟源提供:

·内部时钟(CK_INT)

·外部时钟模式1:外部输入脚(TIx)

·外部时钟模式2:外部触发输入(ETR)

·内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。

由于今天的学习是最基本的定时功能,所以采用内部时钟。TIM2-TIM5的时钟不是直接来自于APB1,而是来自于输入为APB1的一个倍频器。这个倍频器的作用是:当APB1的预分频系数为1时,这个倍频器不起作用,定时器的时钟频率等于APB1的频率;当APB1的预分频系数为其他数值时(即预分频系数为2、4、8或16),这个倍频器起作用,定时器的时钟频率等于APB1的频率的2倍。

通过倍频器给定时器时钟的好处是:APB1不但要给TIM2-TIM5提供时钟,还要为其他的外设提供时钟;设置这个倍频器可以保证在其他外设使用较低时钟频率时,TIM2-TIM5仍然可以得到较高的时钟频率。

2.2 计数器模式

TIM2-TIM5可以由向上计数、向下计数、向上向下双向计数。向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器内容),然后重新从0开始计数并且产生一个计数器溢出事件。

在向下模式中,计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。而中央对齐模式(向上/向下计数)是计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。

2.3 编程步骤

1. 配置系统时钟;

2. 配置NVIC;

3. 配置GPIO;

4. 配置TIMER;

第4项配置TIMER有如下配置:

(1)利用TIM_DeInit()函数将Timer设置为默认缺省值;

(2)TIM_InternalClockConfig()选择TIMx来设置内部时钟源;

(3)TIM_Perscaler来设置预分频系数;

(4)TIM_ClockDivision来设置时钟分割;

(5)TIM_CounterMode来设置计数器模式;

(6)TIM_Period来设置自动装入的值

(7) TIM_ARRPerloadConfig()来设置是否使用预装载缓冲器

(8)TIM_ITConfig()来开启TIMx的中断 其中(3)-(6)步骤中的参数由TIM_TimerBaseInitTypeDef结构体给出。

步骤(3)中的预分频系数用来确定TIMx所使用的时钟频率,具体计算方法为:CK_INT/(TIM_Perscaler+1)。CK_INT是内部时钟源的频率,是根据2.1中所描述的APB1的倍频器送出的时钟,TIM_Perscaler是用户设定的预分频系数,其值范围是从0 – 65535。

步骤(4)中的时钟分割定义的是在定时器时钟频率(CK_INT)与数字滤波器(ETR,TIx)使用的采样频率之间的分频比例。TIM_ClockDivision的参数如下表:

STM32通用定时器功能和用法

数字滤波器(ETR,TIx)是为了将ETR进来的分频后的信号滤波,保证通过信号频率不超过某个限定。 步骤(7)中需要禁止使用预装载缓冲器。当预装载缓冲器被禁止时,写入自动装入的值(TIMx_ARR)的数值会直接传送到对应的影子寄存器;如果使能预加载寄存器,则写入ARR的数值会在更新事件时,才会从预加载寄存器传送到对应的影子寄存器。

ARM中,有的逻辑寄存器在物理上对应2个寄存器,一个是程序员可以写入或读出的寄存器,称为preload register(预装载寄存器),另一个是程序员看不见的、但在操作中真正起作用的寄存器,称为shadow register(影子寄存器);设计preload register和shadow register的好处是,所有真正需要起作用的寄存器(shadow register)可以在同一个时间(发生更新事件时)被更新为所对应的preload register的内容,这样可以保证多个通道的操作能够准确地同步。如果没有shadow register,或者preload register和shadow register是直通的,即软件更新preload register时,同时更新了shadow register,因为软件不可能在一个相同的时刻同时更新多个寄存器,结果造成多个通道的时序不能同步,如果再加上其它因素(例如中断),多个通道的时序关系有可能是不可预知的。

3. 程序源代码

本例实现的是通过TIM2的定时功能,使得LED灯按照1s的时间间隔来闪烁

#include "stm32f10x_lib.h"
 
void RCC_cfg();
void TIMER_cfg();
void NVIC_cfg();
void GPIO_cfg();
 
int main()
{
       RCC_cfg();
       NVIC_cfg();
       GPIO_cfg();
       TIMER_cfg();
 
       //开启定时器2
       TIM_Cmd(TIM2,ENABLE);
 
       while(1);
}
 
void RCC_cfg()
{
      
       //定义错误状态变量
       ErrorStatus HSEStartUpStatus;
      
       //将RCC寄存器重新设置为默认值
       RCC_DeInit();
 
       //打开外部高速时钟晶振
       RCC_HSEConfig(RCC_HSE_ON);
 
       //等待外部高速时钟晶振工作
       HSEStartUpStatus = RCC_WaitForHSEStartUp();
       if(HSEStartUpStatus == SUCCESS)
       {
              //设置AHB时钟(HCLK)为系统时钟
              RCC_HCLKConfig(RCC_SYSCLK_Div1);
 
              //设置高速AHB时钟(APB2)为HCLK时钟
              RCC_PCLK2Config(RCC_HCLK_Div1);
 
              //设置低速AHB时钟(APB1)为HCLK的2分频
              RCC_PCLK1Config(RCC_HCLK_Div2);
             
              //设置FLASH代码延时
              FLASH_SetLatency(FLASH_Latency_2);
 
              //使能预取指缓存
              FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
 
              //设置PLL时钟,为HSE的9倍频 8MHz * 9 = 72MHz
              RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
 
              //使能PLL
              RCC_PLLCmd(ENABLE);
 
              //等待PLL准备就绪
              while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
 
              //设置PLL为系统时钟源
              RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
 
              //判断PLL是否是系统时钟
              while(RCC_GetSYSCLKSource() != 0x08);
       }
 
       //允许TIM2的时钟
       RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
       //允许GPIO的时钟
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
 
}
 
void TIMER_cfg()
{
       TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
 
       //重新将Timer设置为缺省值
       TIM_DeInit(TIM2);
       //采用内部时钟给TIM2提供时钟源
       TIM_InternalClockConfig(TIM2);
       //预分频系数为36000-1,这样计数器时钟为72MHz/36000 = 2kHz
       TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
       //设置时钟分割
       TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
       //设置计数器模式为向上计数模式
       TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
       //设置计数溢出大小,每计2000个数就产生一个更新事件
       TIM_TimeBaseStructure.TIM_Period = 2000 - 1;
       //将配置应用到TIM2中
       TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
 
       //清除溢出中断标志
       TIM_ClearFlag(TIM2, TIM_FLAG_Update);
       //禁止ARR预装载缓冲器
       TIM_ARRPreloadConfig(TIM2, DISABLE);
       //开启TIM2的中断
       TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
}
 
void NVIC_cfg()
{
       NVIC_InitTypeDef NVIC_InitStructure;
        //选择中断分组1
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        
        
        //选择TIM2的中断通道
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;      
        //抢占式中断优先级设置为0
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
       //响应式中断优先级设置为0
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        //使能中断
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}
 
void GPIO_cfg()
{
       GPIO_InitTypeDef GPIO_InitStructure;
 
      
       GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;                 //选择引脚5
       GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出频率最大50MHz
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //带上拉电阻输出
       GPIO_Init(GPIOB,&GPIO_InitStructure);
}
在stm32f10x_it.c中,我们找到函数TIM2_IRQHandler(),并向其中添加代码
void TIM2_IRQHandler(void)
{
       u8 ReadValue;
       //检测是否发生溢出更新事件
       if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
       {
              //清除TIM2的中断待处理位
              TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
              //将PB.5管脚输出数值写入ReadValue
              ReadValue = GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5);
             
              if(ReadValue == 0)
              {
                     GPIO_SetBits(GPIOB,GPIO_Pin_5);
              }    
              else
              {
                     GPIO_ResetBits(GPIOB,GPIO_Pin_5);      
              }
       }
 
}

本文转载自: 博客园 - 沉舟侧畔
声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有,如涉及侵权,请联系小编邮箱 demi@eetrend.com 进行处理。

围观 29
531

定时/计数器结构(T0和T1)
51单片机 | 定时/计数器原理及结构
16位寄存器T0、T1分别由TH0、TL0和TH1、TL1四个8位计数器组成

  • 定时器的区别:

    • T0可分成2个独立的8位定时器,而定时器1则不能;
    • T1可作为串口的波特率发生器,而定时器0则不能。
  • 工作原理

    • 用途:定时器和计数器
    • 核心:加1计数器
    • 原理:每来一个脉冲则加1计数器加1,当加到全1时再来一个脉冲使加1计数器归零,同时加1计数器的溢出使TCON寄存器中的TF0(或TF1)置1,向CPU发出中断请求
    • 脉冲来源:

      • 定时器:脉冲来源是由系统的时钟晶振器输出脉冲源提供
      • 计数器:脉冲来源是由T0或T1引脚(P3.4或P3.5)输入的外部脉冲源提供

注:T0或T1都不能同时既做定时器也做计数器

补充:

  • 计数器工作原理:

    用作计数器时,对T0或T1引脚的外部脉冲计数,如果前一个机器周期采样值为1,后一个机器周期采样值为0 ,则说明有一个脉冲,计数器加1。

    在每个机器周期的S5P2期间采样引脚输入电平。新的计数初值于下一个机器周期的S3P1期间装入计数器。

    此种方式需要两个机器周期来检测一个1->0负跳变信号,因此最高的计数频率为时钟频率的1/24。

  • S5P2:

    S5P2指的是第5个时钟周期的相位2。

    晶体振荡器的振荡信号从XTAL2端输入到片内的时钟发生器上,时钟发生器是一个二分频触发器电路,它将振荡器的信号频率除以2,向CPU提供了两相时钟信号P1和P2。时钟信号的周期称为机器状态时间S,它是振荡周期的2倍。在每个时钟周期(即机器状态时间S)的前半周期,相位1(即P1信号)有效,在每个时钟周期的后半周期,相位2(即P2信号)有效。

使用的寄存器

  • TCON控制寄存器:启动和停止定时/计数器的计数,并控制定时器的工作状态,不能按位寻址
  • 51单片机 | 定时/计数器原理及结构
  • TMOD方式寄存器:设置定时器的工作方式,选择定时或计数的功能,可以按位寻址。(和中断共用寄存器,高四位为定时计数器使用,低四位为中断使用)
  • 51单片机 | 定时/计数器原理及结构51单片机 | 定时/计数器原理及结构

    注:GATE逻辑结构此处略过

工作方式:

  • 方式0
    • 计算公式:
      51单片机 | 定时/计数器原理及结构
    • 最大计数:8192个机器周期
    • 工作原理:
      13位计数器,使用TL0的低5位和TH0的高8位组成,TL0的低5位溢出时向TH0进位。TH0溢出时发出中断请求。
      51单片机 | 定时/计数器原理及结构
  • 方式1
    • 计算公式:
      51单片机 | 定时/计数器原理及结构
    • 最大计数:65536个机器周期
    • 工作原理:
      16位计数器,TL0作为低8位,TH0作为高8位
      51单片机 | 定时/计数器原理及结构
  • 方式2:自动重装初值的8位计数方式
    • 计算公式:
      p.s.晶振频率必须选择12的整数倍,因为定时器的频率是晶振频率的1/12。
      51单片机 | 定时/计数器原理及结构
    • 最大计数:256个机器周期
    • 优点:
      适合做比较精准的脉冲信号发生器
    • 缺点:
      51单片机 | 定时/计数器原理及结构
    • 工作原理:
      计数器溢出后,计数器自动将上次设置的初值重装。
      51单片机 | 定时/计数器原理及结构
  • 方式3:p.s.只能用于定时/计数器T0,T0工作在方式3时,T1不要使用在有中断的场合。通常该种情况下T1用作串口波特率发生器
    • 工作原理:
      将T0分成两个独立的8位定时/计数器TL0和TH0。

      TL0为正常的8位定时/计数器,计数器溢出后置位TF0,申请中断,之后重装初值。

      TH0也是8位定时/计数器,但由于TL0占用了TF0和TR0,因此TH0占用定时器TF1和TR1(所以T1不能用)
      51单片机 | 定时/计数器原理及结构

时钟周期/机器周期计算:
51单片机 | 定时/计数器原理及结构

定时/计数器初始化

  • 对TMOD赋值,确定T0和T1的工作方式
  • 计算初值,并将其写入TH.x和TL.x
  • 使用中断方式时对IE寄存器赋值开发中断
  • 使TR0或TR1置位,启动定时/计数器

转自: hugh.dong

围观 7
1343

STM32F4系列定时器输出PWM频率计算

第一步,了解定时器的时钟多少:

STM32定时器输出PWM频率和步进电机控制速度计算

我们知道AHP总线是168Mhz的频率,而APB1和APB2都是挂在AHP总线上的。

(1)高级定时器timer1, timer8以及通用定时器timer9, timer10, timer11的时钟来源是APB2总线
(2)通用定时器timer2~timer5,通用定时器timer12~timer14以及基本定时器timer6,timer7的时钟来源是APB1总线

从STM32F4的内部时钟树可知:

当APB1和APB2分频数为1的时候,TIM1、TIM8~TIM11的时钟为APB2的时钟,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟;

而如果APB1和APB2分频数不为1,那么TIM1、TIM8~TIM11的时钟为APB2的时钟的两倍,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍。

因为系统初始化SystemInit函数里初始化APB1总线时钟为4分频即42M,APB2总线时钟为2分频即84M,所以TIM1、TIM8~TIM11的时钟为APB2时钟的两倍即168M,TIM2~TIM7、TIM12~TIM14的时钟为APB1的时钟的两倍即84M。

知道定时器的时钟源频率我们用定时器做延时就很方便了,只要设定合适的分频系数即可,附一下用中断实现延时的公式:(摘自原子的STM32F4开发指南)

Tout = ((arr+1)*(psc+1))/Tclk;

公式中psc就是分频系数,arr就是计数值,达到这个计数就会发生溢出中断,Tclk就是我上述分析的时钟源频率的倒数。

通过上面的公式我们就可以轻松计算出对应的定时器频率:但是这里我们需要将分频系数固定一个合适的值。设置成多大合适了,这里我们就要来分析一下我们控制系统的中步进电机的细分步距角和减速比了。

已经知道我们电机参数如下:步距角 = 1.8° 细分=16 减速比= 2mm

一圈360°需要的脉冲数 = 360/1.8*16 = 3200 pulse

又因为电机转一圈,对应的距离是2mm, 所以 电机带动轮子走1mm = 3200pulse / 2 = 1600pluse

#define MM_TO_PLUSE 1600//1mm对应的脉冲数

#define PLUSE_TO_MM (1/1600)//一个脉冲对应的距离

#define DIS_MM_TO_PLUSE(dis) ( MM_TO_PLUSE * (dis) ) //将以mm为单位的长度抓换成对应的脉冲数

#define SPEED_TO_PLUSE(speed) ( (speed) *MM_TO_PLUSE ) //将mm/s的速度转换成HZ

到此为止,电机之间脉冲和距离之间的关系已经搞明白了,那我们开始言归正传,如何计算出我们需要的定时器频率输出了?

假设我们系统需要达到30mm/s的速度而且我们用的是timer2,调用宏计算 30mm/s * 1600 = 48000HZ的频率 = 48KHZ。意思就是说们只要定时器输出的PWM能够满足48KHZ的频率就可以了。

将上面的公式换算成 输出频率 = 定时器的时钟频率(注意是时钟频率不是输出频率)/(分频系数 + 1)/( 计数值+1)

将psc = 0;分频系数为1 ,内部自动加1 ,带入上面的公式就可以计算出计数值 = 1000。就可以输出对应的速度了。

#define TIMER_CLK (48000000/1) //48Mhz 不分频

#define CALC_ARR(speed) (TIMER_CLK /(speed)*MM_TO_PLUSE )

知道速度值就可以调用CALC_ARR宏返回对应的ARR寄存器值啦,我们就可以根据机器的系统参数来控制了。注意,速度不能高于30000ms/s = 30m/s的速度。因为定时的的最大频率就是48MHZ 。

转自: wolf_man9999

围观 57
949

在MCU中(M16),定时器是独立的一个模块,M16有三个独立的定时器模块,即T/C0、T/C1和T/C2;其中T/C0和T/C2都是8位的定时器,而T/C1是一个16位的定时器。定时器的工作是独立于CPU之外自行运行的硬件模块。

1、定时器何时开始工作(或说计数)的?

当TCCR0!=0x00任何模式下,只要MCU一上电,T/C就开始计时工作。其实TCCR0主要是定时器的预分频和波形模式、比较匹配模式的设置,说到预分频,不得不提一下这个模块,这个模块是T/C0、T/C1共用的一个模块,但可以有不同的分频设置。

2、定时器是如何进行工作的:说到定时器的工作,不得不说三个个重要参数:TCNT0、OCR0,TIMSK,TCNT0是设置定时器的计时初始值,定时器开始工作后立即从TCNT0一直累加到0XFF,累加过程所消耗的时间就是我们需要的定时时间;OCR0是一个比较设定值,当TCNT0的值累计到OCR0时(TNCT0==OCR0),如果有开启比较匹配中断功能,那么此时就会产生比较中断,所以,OCR0的值一般都是设置在TCNT0初始值和0XFF之间,之外的任何值都不会产生比较中断。TIMSK是一个中断使能位设置,就是我们需要计时器溢出中断或是比较匹配中断功能或两者都要时就对TIMSK的相应寄存器位进行设置。

3、定时器的中断使用,一个定时器可以有两个中断资源可利用,一个只溢出中断,另一个是比较匹配中断,如上面2所说的。想说明的溢出中断子程序内一般要有重载TCNT0的初始值,否则,TCNT0就会从0X00开始累加计数到0XFF,所耗费的时间就不我们想要的时间。比较中断就是当TCNT0==OCR0时,发生比较匹配中断;所以,中断子程序中一般只插入少量的处理代码,否则,会发生所谓的中断套嵌的现象,由于M16不支持中断套嵌,这样会使得中断子程序中的部分代码无法执行,严重时会造成系统崩溃。

4、TCNT0和OCR0的值换算:对于8bit的计时器,TCNT0一般可以由下面的公式换算:

TCNT0=256-(TV*F)/N;
TV: 所想要设定的定时时间,单位,us
F: 晶振频率(MHz)
N: 分频因子

定时器是独立运行的,它不占用CPU的时间,不需要指令,只有调用对应的寄存器的时候才需要参与。

以AVR mega16为例,它有三个寄存器,timer0,timer1和timer2,T0和T2是8位定时器,T1是16位寄存器,T2为异步定时器,三个定时器都可以用于产生PWM。

以定时器T0来简单介绍定时器的操作方法,T0有三个寄存器可以被CPU访问,TCCR0,TCNT0,OCR0,下面看一段ICC生成的定时器初始化程序。

//TIMER0 initialize - prescale:8
// WGM: Normal
// desired value: 1KHz
// actual value: 1.000KHz (0.0%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0x83; //set count
OCR0 = 0x7D; //set compare
TCCR0 = 0x02; //start timer
}

TCCR0为控制寄存器,用于控制定时器的工作模式细节;
TCNT0为T/C 寄存器,它的值在定时器的每个工作周期里加一或减一,实现定时操作,CPU可以随时读写TCNT0;
OCR0:输出比较寄存器,它包含一个8 位的数据,不间断地与计数器数值TCNT0 进行比较。匹配事件可以用来产生输出比较中断,或者用来在OC0 引脚上产生波形。

这里说最简单的模式,TCNT一直加一,到达最大值0xFF然后清零,进入下一次计数,在上面的程序中。

TCCR0=0x00;关闭T0的时钟源,定时器停止工作。
TCNT0=0x83;设置T/C寄存器的初始值,及让定时器从TCNT0从0x83开始定时或计数。
OCR0 = 0x7D;设定比较匹配寄存器的值,这个程序里没有使用。
TCCR0 = 0x02;选择时钟源,来自时钟8分频,设置后定时器就开始工作。

初始化后定时器开始工作,TCNT0在每一个定时器时钟加一,当TCNT0等于OCR0的值时,T/C 中断标志寄存器- TIFR中的OCF0 置位,如果这时候TIMSK中OCIE0为1(即允许T0比较匹配中断),并且全局中断允许,比较匹配中断即运行。中断程序中可以对TCNT0和0CR0进行操作,对定时器进行调整。

TCNT0继续加一,当达到0xFF时,T/C 中断标志寄存器- TIFR中的TOV0置位,如果这时候TIMSK中TOIE0为1(即允许T0溢出中断),并且全局中断允许,溢出中断即运行。中断程序中可以对TCNT0和0CR0进行操作,对定时器进行调整。

和定时器相关的寄存器还有SREG和TIMSK,前者位1控制全局中段允许,后者位1(OCIE0)和位0(TOIE0)分别控制比较匹配中断和溢出比较匹配中断允许。

实际的过程中,定时器相关寄存器的操作非常灵活,可以在溢出中断中修改TCNT0的值,也可以在中断中修改OCR0的值,后面的实验中会讲到用定时器1修改OCR1A的方法实现1S精确定时。

转自: u010312937的博客

围观 22
677

页面

订阅 RSS - 定时器