2018-05-19 00:38:28 qrsxtkf 阅读数 1224
  • 定时器和计数-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    1963 人正在学习 去看看 朱有鹏

单片机的定时器是作为片外资源,开启定时器需要设置相关的寄存器,当然,这些寄存器是可以位寻址的,怎么位寻址?在头文件中reg52.h中已经预定义好了。不用担心,你只需要学会设置就好了:

TMOD=0X01;    //定时器0工作在方式1(16位计数器)

TH0=0xfe;

TL0=0x33;

EA=1;

ET0=1;

TR0=1;

以上6条语句,已经将定时器设置好了,现在协议个led的项目来时间一下:

#include<reg52.h>

#define uint unsigned int
#define uchar unsigned char
uint count=0;     //5000微秒的次数,用于在中断中加1,count有多少,定时count*5ms
sbit led=P1^0;


int main()

{
TMOD=0X01;    //定时器0工作在方式1(16位计数器)
TH0=0xfe;    //赋初值
//TH0=(65536-5000)/256;   //假设赋初值为60536,从60536开始,每隔1微秒,计数器加1,(高8位),计满为              5000微秒(5ms),之后产生中断
TL0=0x33;
////TH0=(65536-5000)%256;   //赋初值为60536,从60536开始,每隔1微秒,计数器加1,(低8位)
EA=1;     //开总中断
ET0=1;    //开T0中断
TR0=1;    //启动T0开始计数

while(1)//大循环,循环执行里面的程序
{
if(count==20)//判断:如果定时20*0.5=10ms,10ms亮灭一次led
{
count=0;  //重新赋成0
led=~led; //led状态取反一次
}
}

void timer0() interrupt 1  //中断函数
{
TH0=0xfe;    //,重新赋值
//TH0=(65536-5000)/256;   //赋初值为60536,从60536开始,每隔1微秒,计数器加1,(高8位)
TL0=0x33;
////TH0=(65536-5000)%256;   //赋初值为60536,从60536开始,每隔1微秒,计数器加1,(低8位)
count++;//0.5ms的次数加1

}

注意:这里使用到了中断,有时无需使用到中断:

#include<reg52.h>

#define uint unsigned int
#define uchar unsigned char
uint count=0;     //5000微秒的次数,用于在中断中加1,count有多少,定时count*5ms
sbit led=P1^0;


int main()

{
TMOD=0X01;    //定时器0工作在方式1(16位计数器)
TH0=0xfe;    //赋初值
//TH0=(65536-5000)/256;   //假设赋初值为60536,从60536开始,每隔1微秒,计数器加1,(高8位),计满为              5000微秒(5ms),之后产生中断
TL0=0x33;
////TH0=(65536-5000)%256;   //赋初值为60536,从60536开始,每隔1微秒,计数器加1,(低8位)
EA=1;     //开总中断
ET0=1;    //开T0中断
TR0=1;    //启动T0开始计数

while(1)//大循环,循环执行里面的程序

{

          if(TF0==1)//每次产生中断的时候,TFx(0或1)都会置位

           {

                 TF0=0;

                 count++;

           }

          if(count==20)//判断:如果定时20*0.5=10ms,10ms亮灭一次led

{
count=0;  //重新赋成0
led=~led; //led状态取反一次
}
}




2017-08-03 11:04:05 mcuwangzai 阅读数 20571
  • 定时器和计数-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    1963 人正在学习 去看看 朱有鹏
               **菜鸟关于51类单片机的定时器初值计算问题的计算**

首先先来介绍单片机的几个周期:   

1、时钟周期,也称为振荡周期:定义为时钟脉冲的倒数,在单片机中也就等于晶振的倒数。
51单片机中把一个时钟周期定义为一个节拍(用P表示),2个节拍定义为状态周期(用S表示)
时钟周期是单片机中最小的时间单位。
eg:12M晶振的单片机,时钟周期=振荡周期=1/12 us。

2、机器周期:定义为完成一项基本操作所需要的时间,称为机器周期。
在计算机中,为了方便管理,把一条指令的执行过程分为若干个阶段,每个阶段去执行一项基本操作。
如:取指令,存储器读,存储器写等。
在51单片机中1个机器周期由6个状态周期组成,也就是12个时钟周期=12 x 1/12 us =1 us
定义机器周期是因为时钟周期时间太短,根本做不了什么。

3、指令周期:定义为执行一条指令所需的时间。
通常,包含一个机器周期的指令称为单周期指令,比如 MOV指令,CLR指令等。
包含两个机器周期的指令称为双周期指令。
另外还有四周期指令。

小伙伴们看完了上面的周期是不是看懵了………hahahahahahaha

不要慌,其实我们这节课要用到的就一句话—— 在51单片机中1个机器周期由6个状态周期组成,也就是12个时钟周期=12 x 1/12 us =1 us

这里我们知道了一个机器周期的时间是1us,所以如果我们要延时1ms就是1000个机器周期;
可能大家我们刚开始了解定时器的时候都会与疑惑,为什么要用定时器这么麻烦的东西,自己用delay()慢慢调一个合适的参数就可以了。 其实如果深入了解定时器真的比delay() 强大太多我先列举几点:
1.就如上面所说用定时器定时1ms,这里就要注意了,这个1ms不是和delay延时1ms一样哦,这个1ms是精确的1ms哦,越往后学需要的定时就要求越高,所以定时器是一定要搞定的。

2.相比于delay计时,delay是要直接让单片机做空循环,死等。而定时器则是利用定时器的溢出间隔,如果时间上不够,可以在溢出中断中配合软件计数器来实现。 前者浪费cpu,后者更高效。

言归正传,现在来计算初值了,直接用例子说明,就比如用定时器0延时50ms

一言不合,先上代码

void main()
{
TOMD|=0x01;         //设置TMOD工作方式寄存器的M0M1为01,对照表格即为定时器/计数器的4种模式中的16位定时器/计数器模式
    TH0=(65536-46080)/256; //装初值11.0592M晶振定时50ms数为46080
    TL0=(65536-46080)%256;
    EA=1;    //中断总开关
    ET0=1;   //开启定时器/计数器的中断允许位置为1
    TR0=1;   //
    return 0;
}
void T0_time() interrupt 1
{
    TH0=(65536-46080)/256;
    TL0=(65536-46080)%256;
    num++;
    if(num==20)
    {
        num=0;
    }
}
首先一个机器周期=12*一个时钟周期=12*(1/晶振)  一般的51晶振频率为11.0592M

    则一个机器周期= 1.085069444444444 us     单位是微秒

所以如果要定时50ms 则要50 000/1.085069444444444~=46080个机器周期

    又因为TOMD|=0x01选择了16位的模式,就是TH0高八位 TL0低八位,所以最大到溢出就是65536

    故初值设为65536-46080即程序运行了大约46080个机器周期即50ms

    而后面的/256 %256就是划分低八位和高八位的

这是我的第一篇博客,就是希望大家有所帮助(虽然有些地方都可以有问题haha),自己的对玩单片机更加的理解,利己利彼。学单片机学acm的都知道,一个点想不清楚的时候网上找到一个好的解答是多么的珍贵。所以希望大家一起加油,在单片机中找到更多的乐趣。。。。。。

2013-12-17 21:54:17 csuyishuan 阅读数 29
  • 定时器和计数-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    1963 人正在学习 去看看 朱有鹏

                                         单片机定时器中断

    51单片机内部共有两个16位的可编程的定时器/计数器T0、T1,而52单片机内部多了一个T2定时器/计数器。通过设置相关的特殊功能寄存器,就可以选择启用定时或计数功能。

    需要注意的是,定时器系统是单片机内部一个独立的硬件部分,它与cpu和晶振通过内部某些控制线连接并相互作用,cpu一旦设置开启定时功能,定时器便在晶振的作用下自动开始计时,当定时器计数计满后,会溢出产生中断,并通知cpu作相应的处理。

    T0、T1实质是加一计数器,由高8位和低8位两个寄存器组成。TMOD是定时/计数器工作方式寄存器,确定工作方式和共

2016-03-15 09:02:22 a1314521531 阅读数 1276
  • 定时器和计数-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    1963 人正在学习 去看看 朱有鹏

单片机——定时器

 

宗旨:技术的学习是有限的,分享的精神是无限的。

 

1、定时器和计数器

时钟周期:单片机时序中的最小单位,集体计算的放法就是时钟源分之一

机器周期:单片机完成一个操作的最短时间,=12个时钟周期

定时器:打开定时器后,定时器“存储寄存器”的值经过一个机器周期自动加1,也就是说,机器周期是定时器的计数周期。

 

2、定时器的寄存器

 

 

TMOD —— 工作模式选择寄存器——常用模式1和模式2.

TCON —— 控制寄存器(TRn定时器开关)

TH/TL —— 定时计数器

 

3、定时器应用

第一步:设置特殊功能寄存器 TMOD,配置好工作模式。
第二步:设置计数寄存器TH0TL0的初值。
第三步:设置TCON,通过TR0 1来让定时器开始计数。
第四步:判断TCON 寄存器的TF0 位,监测定时器溢出情况。

写程序之前,我们要先来学会计算如何用定时器定时时间。我们的晶振是 11.0592M,时钟周期就是 1/11059200,机器周期是12/11059200,时器定时值最大也就是 71ms 左右。

(65536-N)*12/11.0592M = time ---计算出N转换成十六进制

1ms的例子:

TMOD = 0X01;

TH0 = 0XFC;

TL0 = 0X67;

TR0 = 1; 

#include<reg52.h>

typedef unsigned char uchar;

sbit LED = P0^0;

int  main(void)
{
  uchar cnt = 0;  //定义一个计数变量,记录T0溢出次数

  TMOD = 0x01;  //设置T0为模式1
  TH0 = 0xFC;  //为T0赋初值0xB800
  TL0 = 0x67;
  TR0 = 1;     //启动T0

  while (1)
  {
    if (1 == TF0)        //判断T0是否溢出
    {
      TF0 = 0;         //T0溢出后,清零中断标志
      TH0 = 0xFC;      //并重新赋初值
      TL0 = 0x67;
      cnt++;           //计数值自加1
      if (cnt >= 1000)   //判断T0溢出是否达到50次
      {
        cnt = 0;     //达到50次后计数值清零
        LED = ~LED;  //LED取反:0-->1、1-->0
      }
    }
  }

  return 0;
}

 

4、数码管

 

共阴与共阳数码管 ——8个LED灯

位选——控制选择多个数码管中的哪一个

段选——选择数码管显示的值

 

// 秒定时器:
#include<reg52.h>

typedef unsigned int uint;
typedef unsigned char uchar;

uchar code count[] =
{
  0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
  0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

int main(void)
{
  uchar cnt = 0;  //记录T0中断次数
  uchar sec = 0;  //记录经过的秒数

  TMOD = 0x01;  //设置T0为模式1
  TH0 = 0xFC;  //为T0赋初值0xB800
  TL0 = 0x67;
  TR0 = 1;     //启动T0

  while (1)
  {
    if (TF0 == 1)        //判断T0是否溢出
    {
      TF0 = 0;         //T0溢出后,清零中断标志
      TH0 = 0xFC;      //并重新赋初值
      TL0 = 0x67;
      cnt++;           //计数值自加1
      if (cnt >= 1000)   //判断T0溢出是否达到1000次
      {
        cnt = 0;            //达到1000次后计数值清零
        P0 = count[sec];  //当前秒数对应的真值表中的值送到P0口
        sec++;              //秒数记录自加1
        if (sec >= 16)      //当秒数超过0x0F(15)后,重新从0开始
        {
          sec = 0;
        }
      }
    }
  }

  return 0;
}

 

 

 

2019-12-03 12:41:05 pangyinglong 阅读数 88
  • 定时器和计数-第1季第10部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第10个课程,主要内容是51单片机的定时器和计数器,本课程的学习目标是对定时器的作用和意义有深入理解,掌握通过操作寄存器来操作硬件的思路和方法。

    1963 人正在学习 去看看 朱有鹏

1、单片机定时器中断后计数器是否还会计数

解决:单片机定时器中断后计数器还是会计数的,如果重新赋值,会按照设置的时间进行计时。如果没有,则从0开始。

2、单片机在执行定时器中断时,是否在没执行当前中断情况再次执行定时器中断(中断嵌套?)

解决:中断在执行时,如果又有一个中断产生,将不会进入中断函数,知道当前中断执行结束后,才允许下一个新的中断进入。

总结:定时器中断在执行中断过程中,计数器一直计数,但是产生的中断不能进入中断函数。只有上一个中断结束后,才会发生新的中断进入。

测试:

单片机:stc12c5a60s2

软件:keil

串口软件:stc-isp

思路:在定时中断执行函数中使用串口打印0-9,采用两次打印,它们之间间隔1s,定时中断时间是10ms。通过查看串口发送的数据,如果是相同的数字两两相邻,表示延迟1s过程中中断没有再次进入;如果数字是连续而且很快显示出来的,表示在延迟1s的过程中多次进入了中断。

代码:

void time0_inter() interrupt 1{
	//2msʱ¼ä
	TF0 = 0;
	TH0 = 0xF8;
  TL0 = 0x30;
	adc.transFlag++;
	if(adc.transFlag>=10){
		adc.transFlag=0;
	}
	uart0_send_byte('0'+adc.transFlag);
	//²âÊÔ¶¨Ê±ÖжÏʱÊÇ·ñ»á¼ÌÐø¼Æʱ
	delay1s();
	uart0_send_byte('0'+adc.transFlag);
	
	//´ò¿ªADC
	adc_switch(ADC_OPEN);
}

结果:

                                     

由结果可以看出:定时器在延迟1s的过程中没有多次进行定时中断函数执行。

可以得出的结论是:

如果在定时中断执行函数中处理的时间超过定时时间,那么会出现中断丢失的问题,即需要进行中断处理时,由于上一个中断还未结束,失去这个时间点需要处理执行指令的机会。

如果中断函数执行处理的时间小于定时中断时间,那么就能够在下一次中断到来之前结束本次中断,这样新来的中断就能够执行需要的处理指令。

没有更多推荐了,返回首页