前言
对于独立按键控制流水灯状态需要用到定时器以及相关中断的知识,所以我们首先需要了解什么是定时器?什么是中断?以及简单的运用中断和定时器的寄存器,配置定时器等相关知识。
一、定时器是什么?
定时器属于单片机的内部资源,在单片机的内核中,下面是定时器的简图:
定时器的作用:
代码语言:javascript复制 用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
代码语言:javascript复制代替长时间Delay,提高CPU的运行效率和处理速度。
定时器分为三个部分:时钟、计数单元、中断系统
对上述结构进行分析:
1:系统时钟,即晶振周期,本开发板的晶振为12MHz。注:时钟可长可短。 2:作用是分频,在2中它会把12兆的系统时钟进行分频,分频之后就是输出的频率就是1兆Hz输出的周期就是1微妙,每隔1微妙单片机的计数单元就记一个数。 3:也是一个分频的模式 4:时钟的来源一个是单片机的内部资源SYSclk另一个则是T0Pin,T0Pin是单片机的外部接口,由外部引脚来提供,当由外部引脚提供时,时钟就是一个计数器,相当于一个记脉冲的计数器。 5:TMOD的一个寄存器,当5配置0时,就表现为计时器,当5配置为1时就表现为计数器。 6:TCON的一个寄存器,高字节是TH,低字节是TL,左边的TH提供一个脉冲,右边的计时器就会 1,对于这个寄存器总共可以存储65535,当溢出时就会重置为0,并记一个标记位传给TF0,有了这个标记位就会申请中断。 7:TF0溢出标志位,也就是中断申请标志位。 8:与门,只要有一个输入端是0输出端就是0,两个输入端都是1,输出端才是1. 9:或门:两个输入端有一个是1输出端就是1,两个输入端都是0,输出端才是0. 10:TR0定时器控制寄存器。 11:门控端:GATE门控端是一种电子元件,主要用于控制电路的通断。在电路中,GATE门控端接收输入信号,根据输入信号的逻辑状态来决定输出信号的通断。常见的GATE门控端有与门、或门、非门等。 12:定时器控制寄存器 11右边的三角形:非门:非门的输入端输入0,输出端就输出1,输入端输入1,输出端就输出0.
时钟中用到的寄存器
二、中断系统是什么
1.概念
中断系统是为使CPU具有对外界紧急时间的实时处理能力而设置的。 当中央处理器CPU正在处理某件事的时候外界发生紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再 回到原来被中断的地方,继续原来的工作,这个过程称为中断。 在单片机中,定时器溢出就是一种中断源。 中断可以理解为下图:
当多个中断源出现时,就需要规定一个轻重缓急排队,规定每一个中断源的优先级别。CPU总是先响应优先级最高的中断请求。 当CPU正在处理一个中断源时,发生了一个优先级比他高的中断源请求,如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断源请求,处理完以后,再回到源优先级中断服务程序,这样的过程叫做中断源嵌套。 这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。 总结:高优先级的中断可以打断低优先级的中断。 注意:中断的资源和单片机的型号也是关联在一起的,不同型号可能会有不同的中断资源,例如中断源个数不同、中断优先级的个数不同等等。 89C52的中断源的个数是8个(外部中断0,定时器0中断,外部中断1,定时器1中断,串口中断,外部中断2,外部中断3) 中断优先级个数:4个 下图就是一个中断系统:
当中断系统接收到溢出时产生的中断申请标志位时,就会传到中断系统中,中断系统会根据中断优先级进行处理。 下面是中断系统中涉及到的寄存器
三、代码实现独立按键对流水灯控制
1. .c文件
Delay.c
代码语言:javascript复制void Delay(unsigned int xms) //@12.000MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
Key.c
代码语言:javascript复制#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @relval 按下按键的数字,返回:0~4,无按键按下时返回值为0
*/
unsigned char Key()
{
unsigned int Keynum=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);Keynum=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);Keynum=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);Keynum=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);Keynum=4;}
return Keynum;
}
main.c
代码语言:javascript复制#include <REGX52.H>
#include "timer0.h"
#include "Key.h"
#include <INTRINS.H>
unsigned char KeyNum,LEDMode;
unsigned char KeyNumber;
void main()
{
P2=0xfe;
Timer0_Init();//初始化
while(1)
{
KeyNumber=Key();
if(KeyNumber)
{
if(KeyNumber==1)
{
LEDMode ;
if(LEDMode>=2)LEDMode=0;
}
}
}
}
//时钟的中断
void timer0_Routine() interrupt 1//中断函数
{
static unsigned int T0Count;
TH0=64535/256;
TL0=64535%6;//
//每次定时器完了之后进入中断都会重置前面的计数单元,所以需要对计数单元进行人为的赋值
T0Count ;
if(T0Count>=500)
{
T0Count=0;
if(LEDMode==0)
{
P2=_crol_(P2,1);
}
if(LEDMode==1)
{
P2=_cror_(P2,1);
}
}
}
timer0.c
代码语言:javascript复制#include <REGX52.H>
/**
* @brief 定时器初始化,一毫秒12MHz
* @param 无
* @relval 无
*/
void Timer0_Init()
{
//配置TMOD
//前四个0是配置定时器1,后面四个数是配置定时器0
//0表示配置GATE,0表示配置C/T,最后两个数表示配置M1和M0
// TMOD=0x01;//0000 0001
TMOD&=0xF0;//把TMOD的低四位清零:高四位保持不变 与清零
TMOD|=0x01;//把TMOD的低四位置1,高四位保持不变 或置1
//&操作相当于
//配置中断溢出标志位
TF0=0;//清零防止刚打开就产生中断
TR0=1;
TH0=64535/256;//十进制数除以10相当于左移1位,二级制数除以256就相当于
//向左移8位,但是是/所以是取的高位,TH0就表示取高位
TL0=64535%6;//这里表示取余数取二进制余数取的低位
//配置中断
ET0=1;
EA=1;
PT0=0;//低优先级
}
/*
void timer0_Routine() interrupt 1//中断函数
{
static unsigned int T0Count;
TH0=64535/256;
TL0=64535%6;//
//每次定时器完了之后进入中断都会重置前面的计数单元,所以需要对计数单元进行人为的赋值
T0Count ;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
2. .h文件
Delay.h
代码语言:javascript复制#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int xms);
#endif
Key.h
代码语言:javascript复制#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
timer0.h
代码语言:javascript复制#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void );
#endif
四、总结
对于独立按键控制流水灯状态来说不是特别难,还可以继续发散更多好玩的