51单片机——定时器和中断

1.中断系统

1.中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的;当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。

2.定时器

1.作用

(1)用于计时系统,可实现软件计时,或使程序每隔一段时间完成完成一项操作。

(2)替代长时间的Delay,提高CPU的运行效率和处理速度。

2.个数

传统的STC89C52单片机的定时器只有T0和T1两种定时器。

3.模式

STC89C52单片机的T0与T1均有4种模式

(模式0):13位定时器/计数器

(模式1):16位定时器/计数器(常用)

(模式2):8位自动重装模式

(模式3):两个8位计数器

51单片机——定时器和中断_第1张图片

4. 定时器如何定时?

原理:每经过一个机器周期计数器就+1:寄存器。

晶振:是数字电路的“心脏”,所有工作都离不开时钟。

时钟周期:晶振上面写的频率的倒数,一般是11.0592MHZ,也就是1/11.0592,时钟周期相当于人类时间的秒,时钟周期是最小的时间单位。

机器周期:也称CPU周期,为了方便管理,常把一条指令的执行过程划分为诺干个阶段(如取指,译码,执行等),每一阶段完成一个基本操作所需的时间称为机器周期,一般情况下,一个机器周期由诺干个时钟周期组成。

加1经历的时间:

(1)11.0592MHZ=11059.2KHZ=11059200HZ;

  (2)  跳一次的时间等于一个机器周期;

(3)一个机器周期等于12个时钟周期(T就是时钟周期;计速频率:时钟模式分为12T和6T,这里我们选用12T)————也就是每过12时钟周期,就+1,也就是机器周期+1;

(4)一个时钟周期等于晶振的倒数:1/11059200s;

(5)跳一下=12/11059200s=12000000/11059200us=1.085us(1s=1000ms,1ms=1000us,1s=1000000us)

51单片机——定时器和中断_第2张图片

5.定时器与中断系统有什么关联?

(1)像闹钟一样,,根据时钟的输出信号,每隔一秒,计数单元的数字增一,当计数单元数值增加到设定的提醒时间时,计数单元会自动向系统发出中断申请,产生闹铃提醒,使程序跳转到中断服务函数去执行。

(2)TF0或者TF1是计时器溢出标志,TR0或者TR1是计时器开始计时标志位,爆表后如果是定时器T0,TCON的bit5——TF0会置1,如果是定时器1,TCON的bit7——TF1会置1,如果是定时器查询的方式(无中断),需要手动用软件清0,如果定时器爆表用硬件中断方式,则不需要手动清0。

51单片机——定时器和中断_第3张图片

 51单片机——定时器和中断_第4张图片

 6.如何设置定时10ms?(定时器0模式1—16位)

10ms=10000us    10000us/1.085us=9216下

定时器的初值不让寄存器从0数到9216下,因为这样子想设置10ms就爆表然后中断,设置不了,因为要到65536下才爆表,所以让寄存器从65535-9216=56320下开始数起,51单片机是向上计数法,从56320一直+1到65535然后爆表就中断,56320换成十六进制就是0xDC00,TH0和TL0是高八位和低八位的意思,他们两个组成就是十六位,也就是0xDC00,TH0和TL0是记录定时器初值的,也就是记录一开始从第几下开始跳的;所以TH0=0xDC,TL0=0x00。

7.定时器模式

51单片机——定时器和中断_第5张图片

 按位操作时:(1)需要清0则位逻辑与0,不需要的不会改变则位逻辑与1。

                       (2)需要置1则位逻辑与1,不需要的不会改变则位逻辑或0。

GATE:门控位,当GATE=0时,TCON寄存器中的TR0或者TR1为1,才能启动定时器工作。当GATE为1时,TCON寄存器中的TR0或者TR1为1,且需要外部引脚为高电平,定时器才能工作。

C/T:为0时为定时器模式,为1时为计时模式。

M1,M0:选定工作方式,一般为16位计时计数器。

8.定时器模式配置

假设现在需要用到定时器0,稍后在用定时器1,为了不影响定时器1的值,所以不能改变定时器1的值,则TMOD&=0xF0(1111 0000),TMOD|=0x01。

三.中断系统打开配置

51单片机——定时器和中断_第6张图片

51单片机——定时器和中断_第7张图片

 51单片机——定时器和中断_第8张图片

由图可知,定时器0触发条件是溢出(爆表),中断开关ET0=1时则打开,ET0=0时则关闭,总中断开关EA=1时则打开,EA=0时则关闭(打开就是开关闭合);外部中断0触发的条件是:当IT0=0时,单片机的IO口则由低电平触发,当IT0=1时,单片机的IO口则由低电平触发,单片机上面会标注外部中断的IO口。

51单片机——定时器和中断_第9张图片

四.定时器控制led亮灭(无中断)——查询方式(软件)

#include 

sbit led=P2^4;


void Time0Init(void)
{
	//配置定时器0工作模式16位计时
	TMOD&=0xF0;
    TMOD|=0x01;
	//给初值,定制10ms
	TL0=0x00;
	TH0=0xDC;
	
	TR0=1;//开始计时
	TF0=0;
}

void main()
{
	int cnt=0;
	led=1;
	
	Time0Init();
	
	while(1)
	{
		if(TF0==1)//爆表时硬件会修改bit5(TF0)位上面的数据,改成1
		{
			TF0=0;//软件清0,因为不用中断
			cnt++;//cnt++用来记录第一次爆表,cnt是1次
			//重新给初值
			TL0=0x00;
			TH0=0xDC;
			if(cnt==100)//爆表100次,经过1s,led就亮
			{
				cnt=0;//当1s时,让count从0开始,计算下一次的1s
				led=!led;//每经过1s,翻转led状态
			}
		}
	}
}

五.定时器中断方式控制led亮灭——硬件

#include 

sbit led=P2^4;

int cnt=0;

void Time0Init(void)
{
	//配置定时器0工作模式16位计时
	TMOD&=0xF0;
    TMOD|=0x01;
	//给初值,定制10ms
	TL0=0x00;
	TH0=0xDC;
	
	TR0=1;//开始计时
	TF0=0;
	
	//打开定时器0中断
	ET0=1;
	//打开总中断
	EA=1;
}

void main()
{
	
	led=1;
	
	Time0Init();
	
	while(1)
	{
		//当在看电视的时候,如果爆表就中断跳到TimeRountime() interrupt 1中,然后重新初值以后又回到了这里,
	}
}

void Time0Rountime()  interrupt 1
{
			cnt++;//cnt++用来记录第一次爆表,cnt是1次
			//重新给初值
			TL0=0x00;
			TH0=0xDC;
			if(cnt==100)//爆表100次,经过1s,led就亮
			{
				cnt=0;//当1s时,让count从0开始,计算下一次的1s
				led=!led;//每经过1s,翻转led状态
			}
}

六.震动传感器通过外部中断方式控制led亮灭

//由震动传感器通过外部中断控制led亮灭,震动传感器DO接单片机P3^2口
#include 
#include 

sbit led4=P2^3;

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void EX0_init()
{
	EA=1;
	EX0=1;
	IT0=0;//低电平触发,震动时就是低电平
}

void main()
{
	EX0_init();
	
	while(1)
	{
		led4=1;
	}
}

void EX0_Rountime()  interrupt 0
{
	led4=0;
	Delay1000ms();
}

七.按键通过外部中断方式控制led亮灭

//51普中开发板按键k3和k4连着单片机IO口P3^2和P3^3,也就是外部中断口IT0和IT1
#include 

sbit led4=P2^3;

void EX0_init()
{
	EA=1;
	EX0=1;
	IT0=0;//低电平触发,按键按下时就是低电平
}

void EX1_init()
{
	EA=1;
	EX1=1;
	IT1=0;//低电平触发,按键按下时就是低电平
}

void main()
{
	EX0_init();
	EX1_init();
	while(1);
}

void EX0_Rountime()  interrupt 0//按下k3
{
	led4=0;
}

void EX1_Rountime()  interrupt 2//按下k4
{
	led4=1;
}
//按键按下k3,led亮,一秒后led灭
#include 
#include 

sbit led4=P2^3;

void EX0_init()
{
	EA=1;
	EX0=1;
	IT0=0;//低电平触发,按键按下时就是低电平
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void main()
{
	EX0_init();
	while(1)
	{
		led4=1;//灭
	}
}

void EX0_Rountime()  interrupt 0//按下k3亮一s就灭
{
	led4=0;
	Delay1000ms();
}

八.定时器做闹钟(LCD1602显示)

#include 
#define LCE_Dataport P0

sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;


unsigned char Sec,Min,Hour;


void LCD_WriteCommand(unsigned char Command)//写指令
{
	LCD_RS=0;
	LCD_RW=0;
	LCE_Dataport=Command;
	LCD_EN=1;
	Delay(1);
	LCD_EN=0;
	Delay(1);
}

void LCD_WriteData(unsigned char Data)//写数据
{
	LCD_RS=1;
	LCD_RW=0;
	LCE_Dataport=Data;
	LCD_EN=1;
	Delay(1);
	LCD_EN=0;
	Delay(1);
}

void LCD_Init(void)//初始化
{
	LCD_WriteCommand(0x38);
	LCD_WriteCommand(0x0C);
	LCD_WriteCommand(0x06);
	LCD_WriteCommand(0x01);
}

void LCD_Setcursor(unsigned char line,unsigned char column)
{
	if(line==1)//设置光标位置
	{
		//第一列是数字1,但是位置是0x00,要把数字1转换0x00,就把数字1-1就0,所以转十六进制就是0x00
		LCD_WriteCommand(0x80|(column-1));
	}
	else
	{
		//第二行的第一列是从0x40开始,第二列是0x41,相当于0x40+0x01,0x01就是与上面一致
		LCD_WriteCommand(0x80|(column-1)+0x40);
	}
}

void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string)//line行,column列,string字符串
{//显示字符串,字符串直接等于指针,不用数组形式等于字符串,在等于指针形式,那传给指针的就是字符串的第一个字符的地址,然后string【i】一直往下就可以知道字符串,数组是连续的,如果baby的b在第一行第一列,那a就会在第一行,第二列。
	unsigned char i;
	LCD_Setcursor(line,column);		
	for(i=0;string[i]!='\0';i++)
	{
		LCD_WriteData(string[i]);//字符串本身就是地址,所以传进来的字符串用指针string来接
	}
}

int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i0;i--)
	{
		LCD_WriteData('0'+number/LCD_Pow(10,i-1) %10);
	}
}

void main()
{
 LCD_Init();
 Timer0_Init();
 LCD_Showstring(1,1,"Clock");
 LCD_Showstring(2,1,"  :  :");
 while(1)
 {
		 LCD_Shownum(2,1,Hour,2);
		 LCD_Shownum(2,4,Min,2);
		 LCD_Shownum(2,7,Sec,2);
 }
}

void Time0_Rountime() interrupt 1
{
 static unsigned int count=0;//不加static的话函数调用后退出时自动销毁
 count++;//爆表一次就中断一次
 TH0=0xDC;
 TL0=0x00;
 if(count==100)
 {
  count=0;
  Sec++;
  if(Sec>=60)
  {
   Sec=0;
   Min++;
   if(Min>=60)
   {
    Min=0;
    Hour++;
    if(Hour>=24)
    {
     Hour=0;
    }
   }
  }
 }
}

补充知识:_nop_()是延时函数,一个nop延时就是一个机器指令周期,延时的时间由晶振决定,如果晶振是11.0592MHZ,那么一个nop就是1.085us,如果是12MHZ,一个nop约为1us。

你可能感兴趣的:(51单片机,单片机,嵌入式硬件)