赞
踩
目录
51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 定时器
作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
(2)替代长时间的Delay,提高CPU的运行效率和处理速度
(…)
定时器个数:3个(T0、T1、T2),T0和T1与传统的51单片机兼容,T2是此型号单片机增加的资源 注意:定时器的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的定时器个数和操作方式,但一般来说,T0和T1的操作方式是所有51单片机所共有的
STC89C52系列单片机的定时器0和定时器1,与传统8051的定时器完全兼容,当在定时器1做波特率发生器时,定时器0可以当两个8位定时器用。
STC89C52系列单片机内部设置的两个16位定时器/计数器TO和T1都具有计数方式和定时方式两种工作方式。对每个定时器/计数器(TO和T1),在特殊功能寄存器TMOD中都有一控制位-C/T来选择TO或T1为定时器还是计数器。定时器/计数器的核心部件是一个加法(也有减法)的计数器,其本质是对脉冲进行计数。只是计数脉冲来源不同: 如果计数脉冲来自系统时钟,则为定时方式,此时定时器/计数器每12个时钟或者每6个时钟得到一个计数脉冲,计数值加1:如果计数脉冲来自单片机外部引脚(TO为P3.4,T1为P3.5),则为计数方式,每来一个脉冲加1.
当定时器/计数器工作在定时模式时,可在烧录用户程序时在STC-ISP编程器中设置(如下图所示)是系统时钟一12还是系统时钟一6后让TO和T1进行计数。当定时器/计数器工作在计数模式时,对外部脉冲计数不分频。
定时器/计数器:0有4种工作模式: 模式0(13位定时器/计数器),模式1(16位定时器/计数器模式这个模式是最常使用的模式), 模式2(8位自动重装模式),模式3(两个8位定时器/计数器)。定时器/计数器1除模式3外,其他工作模式与定时器/计数器0相同,T1在模式3时无效,停止计数。
TCON: 定时器/计数器中断控制寄存器(可位寻址) 可位寻址-----可以单独给每一位赋值
TCON为8位寄存器,控制中断源的开启,可以位寻址。高4位控制定时器0/1,低4位控制外部中断。
①TR0:定时器0控制位。 TR1:定时器1控制位。
②TF0:定时器0溢出位,置1时申请中断 TF1:定时器1溢出位,置1时申请中断
- TCON一般赋值以下的这两个位
- TF0 = 0; //清除TF0标志
- TR0 = 1; //启动定时器0
不可位寻址----只能整体给8位赋值
A:GATE=0仅有运行控制位TRx来控制定时/计数器的开启; 当启动控制为1时关闭(通路), 0打开(断路)
B:GATE=1 置1时受外部中断引脚和TCON控制器控制
配置TMOD打开定时器0 (下面这中写法只在开启一个定时器时有用, 开启动多个会覆盖)
- //TMOD打开定时器0
- TMOD=0x01 //0000 0001 GATE=0 C/T=0,选择定时器模式 01->16位定时器
开多个定时器下面这个写法
- //TMOD是不可位寻址,必须8位同时赋值 TMOD=0000 0001
-
- TMOD &= 0xF0; //设置定时器模式 TMOD=TMOD & 1111 0000 TMOD的低四位清零,高四位保持不变;
- TMOD |= 0x01; //设置定时器模式 TMOD=TMOD | 0000 0001 TMOD的最低位置1,高四位保持不变;
-
-
- /*
- TMOD的低四位清零,高四位保持不变;
- TMOD=1010 0011
- 1010 0011 & 1111 0000(0xF0)= 1010 0000
- */
-
- /*
- TMOD的最低位置1,高四位保持不变;
- TMOD=1010 0000
- 1010 0000 | 0000 0001(0x01)= 1010 0001
- */
- void Timer0Init(void) //1毫秒@12.000MHz
- {
- //TMOD配置
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- //设置定时器(计算)初值(TH0,TL0)因为打开的是0计时器
- TL0 = 0x18; //设置定时初值 定时器0的高低位
- TH0 = 0xFC; //设置定时初值 定时器0的高8位
- //TCON配置
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- }
定时器配置大致完成
- //改造下给传传递延长时间
- #include <REGX52.H>
- void Delay(unsigned int xms) //
- {
- unsigned char i, j;
- while(xms)
- {
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- xms--;
- }
- }
我们使用的是16位定时器, 并且没有自动装载, 所以在写中断函数的时需要手动写装载
在16位全部变为1111 1111 1111 1111 (16进制)也就是65536每隔1us加1 (10进制)启动中断
如果我们不设置初值它会从0开始加到了65536(10进制)每隔1us加1; 也就是65.536ms启动中断
一般情况的使用我们会设置初值(TH0,TL0)它从初值开始加,加到65536启动中断(每隔1us加1),我们使用的是16位,并且没有自动装载的,所以需要手动在中断函数把TH0,TL0在写一遍
TH0:定时器0的高8位 TH1:定时器1的高8位
TL0:定时器0的低8位 TL01:定时器1的低8位
我们想每隔1ms让程序中断,进入中断函数,只需要将初值设置为64536既可以
- //16进制
- TH0=(65536-1000)/256 //定时器0的高8位
- TLO=(65536-1000)%256 //定时器0的低8位
解释
- //10进制
- 125/100=1
- 125%10=25
具体的应用在下面的实例代码的1:定时器点亮LED灯
中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的。
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。 实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。
当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序) ,发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。
A:打开中断时必须打开全局中断 (EA=1)
B:打开对应的中断允许位
C:中断开的少,可以不用管中断优先级这个
中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器1中断、串口中断、定时器2中断、外部中断2、外部中断3) 中断优先级个数:4个
中断号: 中断函数名可以改但是不建议
注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等
大置流程TMOD-->TCON-->计数器初值-->中断配置
- void Timer0Init(void) //1毫秒@12.000MHz
- {
- //定时器配置 (可以使用STC生成)
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- //中断配置
- ET=1; //打开中断允许位
- EA=1; //使能总开关
-
- }
mian.c
- #include <REGX52.H>
- #include "time.h"
-
- void main(){
- Init_time();
- while (1){
-
- }
- }
time.c
- #include <REGX52.H>
-
- //一般来说&是清零;|是置1
- unsigned int count=0;
-
- sbit LED_D1= P2^0;
- void Init_time() //1微秒@12.000MHz
- {
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- //中断配置
- ET0=1; //打开中断允许位
- EA=1; //使能总开关
- LED_D1=1;
- }
-
- void Timer0_Routine() interrupt 1
- {
-
- //每隔1微秒启动中断函数
- count++;
- /*因为它是16位,没有自动装载\
- 每次进去中断函数都会从0开始计数.计数到65536在中断
- 所以加上 TL0 = 0x18;TH0 = 0xFC;让它从64536计数
- 这个就是手动装载
- */
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
-
- if (count==1000)
- {
- count=0;
- LED_D1=~ LED_D1;
-
- }
-
-
- }
- //每隔1微秒启动中断,然后自动打开中断函数
-
time.h
- #ifndef __TIME_H__
- #define __TIME_H__
- void Init_time();
- void Timer0_Routine();
- #endif
main.c
- #include <REGX52.H>
- #include "LCD1602.h"
- #include "Delay.h"
- #include "Timer.h"
- unsigned char Sec,Min,Hour;
-
- void main()
- {
- //初始化lcd和定时器
- LCD_Init();
- Timer0Init();
- 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 Timer0_Routine() interrupt 1
- {
- static unsigned int T0Count;
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- T0Count++;
- if(T0Count>=1000) //定时器分频,1s
- {
- T0Count=0;
- Sec++; //1秒到,Sec自增
- if(Sec>=60)
- {
- Sec=0; //60秒到,Sec清0,Min自增
- Min++;
- if(Min>=60)
- {
- Min=0; //60分钟到,Min清0,Hour自增
- Hour++;
- if(Hour>=24)
- {
- Hour=0; //24小时到,Hour清0
- }
- }
- }
- }
- }
-
Timer.c
- #include <REGX52.H>
-
- /**
- * @brief 定时器0初始化,1毫秒@12.000MHz
- * @param 无
- * @retval 无
- */
- void Timer0Init(void)
- {
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0=1;
- EA=1;
- PT0=0;
- }
-
- /*定时器中断函数模板
- void Timer0_Routine() interrupt 1
- {
- static unsigned int T0Count;
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- T0Count++;
- if(T0Count>=1000)
- {
- T0Count=0;
-
- }
- }
- */
Timer.h
- #idndef __TIMER_H__
- #define __TIMER_H__
- void Timer0Init(void);
- #endif
Delay.c
- void Delay(unsigned int xms)
- {
- unsigned char i, j, k;
-
- while (xms--)
- {
- i = 6;
- j = 157;
- k = 59;
- do
- {
- do
- {
- while (--k);
- } while (--j);
- } while (--i);
- }
- }
Delay.h
- #ifndef __DELAY_H__
- #define __DELAY_H__
- void Delay(unsigned int xms);
-
- #ednif
LCD1602.c
- #include <REGX52.H>
-
- //引脚配置:
- sbit LCD_RS=P2^6;
- sbit LCD_RW=P2^5;
- sbit LCD_EN=P2^7;
- #define LCD_DataPort P0
-
- //函数定义:
- /**
- * @brief LCD1602延时函数,12MHz调用可延时1ms
- * @param 无
- * @retval 无
- */
- void LCD_Delay()
- {
- unsigned char i, j;
-
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- }
-
- /**
- * @brief LCD1602写命令
- * @param Command 要写入的命令
- * @retval 无
- */
- void LCD_WriteCommand(unsigned char Command)
- {
- LCD_RS=0;
- LCD_RW=0;
- LCD_DataPort=Command;
- LCD_EN=1;
- LCD_Delay();
- LCD_EN=0;
- LCD_Delay();
- }
-
- /**
- * @brief LCD1602写数据
- * @param Data 要写入的数据
- * @retval 无
- */
- void LCD_WriteData(unsigned char Data)
- {
- LCD_RS=1;
- LCD_RW=0;
- LCD_DataPort=Data;
- LCD_EN=1;
- LCD_Delay();
- LCD_EN=0;
- LCD_Delay();
- }
-
- /**
- * @brief LCD1602设置光标位置
- * @param Line 行位置,范围:1~2
- * @param Column 列位置,范围:1~16
- * @retval 无
- */
- void LCD_SetCursor(unsigned char Line,unsigned char Column)
- {
- if(Line==1)
- {
- LCD_WriteCommand(0x80|(Column-1));
- }
- else if(Line==2)
- {
- LCD_WriteCommand(0x80|(Column-1+0x40));
- }
- }
-
- /**
- * @brief LCD1602初始化函数
- * @param 无
- * @retval 无
- */
- void LCD_Init()
- {
- LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
- LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
- LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
- LCD_WriteCommand(0x01);//光标复位,清屏
- }
-
- /**
- * @brief 在LCD1602指定位置上显示一个字符
- * @param Line 行位置,范围:1~2
- * @param Column 列位置,范围:1~16
- * @param Char 要显示的字符
- * @retval 无
- */
- void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
- {
- LCD_SetCursor(Line,Column);
- LCD_WriteData(Char);
- }
-
- /**
- * @brief 在LCD1602指定位置开始显示所给字符串
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param String 要显示的字符串
- * @retval 无
- */
- void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=0;String[i]!='\0';i++)
- {
- LCD_WriteData(String[i]);
- }
- }
-
- /**
- * @brief 返回值=X的Y次方
- */
- int LCD_Pow(int X,int Y)
- {
- unsigned char i;
- int Result=1;
- for(i=0;i<Y;i++)
- {
- Result*=X;
- }
- return Result;
- }
-
- /**
- * @brief 在LCD1602指定位置开始显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~65535
- * @param Length 要显示数字的长度,范围:1~5
- * @retval 无
- */
- void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:-32768~32767
- * @param Length 要显示数字的长度,范围:1~5
- * @retval 无
- */
- void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
- {
- unsigned char i;
- unsigned int Number1;
- LCD_SetCursor(Line,Column);
- if(Number>=0)
- {
- LCD_WriteData('+');
- Number1=Number;
- }
- else
- {
- LCD_WriteData('-');
- Number1=-Number;
- }
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以十六进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~0xFFFF
- * @param Length 要显示数字的长度,范围:1~4
- * @retval 无
- */
- void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i,SingleNumber;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- SingleNumber=Number/LCD_Pow(16,i-1)%16;
- if(SingleNumber<10)
- {
- LCD_WriteData(SingleNumber+'0');
- }
- else
- {
- LCD_WriteData(SingleNumber-10+'A');
- }
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以二进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~1111 1111 1111 1111
- * @param Length 要显示数字的长度,范围:1~16
- * @retval 无
- */
- void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
- }
- }
LCD1602.h
- #ifndef __LCD1602_H__
- #define __LCD1602_H__
-
- //用户调用函数:
- void LCD_Init();
- void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
- void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
- void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
- void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
- void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
- void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
-
- #endif
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。