定时器作用:
(1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作
(2)替代长时间的Delay,提高CPU的运行效率和处理速度
(…)
(相当于cpu可以在原本delay的时候同时进行其他任务)
定时器:时钟发出脉冲,计数单元进行计数,当计数值达到时,产生一个TF0(T0溢出中断标志),让中断系统产生中断,执行定时任务。
SYSclk:系统时钟,即晶振周期; T0 Pin:外部引脚,从外界接受脉冲
中断系统:使CPU具有对外界紧急事件的实时处理能力而设置,要求CPU正在处理某件事发生紧急事件请求后,去转而处理这个事件,处理完后再回去继续处理原来的工作。一般允许多个中断源,规定每个有个优先级别。(&中断嵌套)
寄存器:单片机通过配置寄存器来控制内部线路的链接。在单片机中寄存器就是一段特殊的RAM存储器,一方面,寄存器可以存储和读取数据,另一方面,每一个寄存器背后都连接了一根导线,控制着电路的连接方式。寄存器相当于一个复杂机器的“操作按钮”。
M0,M1:1,1--停止计数
0,1--16位
C/T:置0定时器,置1计数器
#include
/**
* @brief 定时器0初始化 1毫秒@11.0592MHz
* @param 无
* @retval 无
*/
void Timer0Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
void Timer0Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
TMOD=0x01 ;
TCOM不可位寻址,只能整体赋值。
这里取0000 0001,只启用定时器0。GATE取0,让或门为1,这样与门只由TR0的值控制。而C/T取0意味控制是否打开定时器0,M1,M0取0,1启用16位定时器。
TMOD=TMOD&0xF0;
TMOD=TMOD|0x01;
把TMOD低四位清零,高四位不变:不影响同时使用定时器1和定时器0。1010 0000&1111 0000=1010 0000
把TMOD最低位置1,高四位不变。1010 0000|0000 0001=1010 0001.
这种赋值法你可以想改那个就改那个,因为都说了不可位寻址,只能通过这种方式更改位。直接赋值是必须8位一起赋,如果只想改变四位,就必须要与或。
TF0=0;//清零,使中断器溢出中断为0
TR0=1;//让定时器开始工作
TCON可位寻址,可以每一位单独赋值
配置TL0,TH0
0~65535,每隔1us计数加一,总共定时时间65535.赋初值为64535,离计数器溢出差值为100,所以计时为1ms。寄存器是八个为一位,所以要把两个八位寄存器拼在一起才能存65535这么多
TH0=64535/256;
TL0=64535%256;
相当于256进制。类比于十进制123中123/10=1,123%10=23。和十进制一样,除以10是小数点左移一位。除以256在二进制里就是小数点左移8位。两个寄存器TH0、TL0为二进制八位,单独可计256次,低八位计满256次后高八位进1,合并在一起就是所赋的初始值。所以除以256可得高八位得次数,取余就是低八位的次数。然而我们这种会少一微秒,所以
TH0=64535/256;
TL0=64535%256+1;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
ET0=1;
EA=1;
PT0=0;
interrupt 1就是中断子函数。
void Timer_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
这样设置中断函数,使它每一次过了1s都执行一下
T0Count=0;
P2_0=~P2_0;
然后TL0,TH0重新赋初值,使其恢复到原位。
这样就设置好了定时器和中断函数。然后我们针对我们的目的写代码:按下独立按键,使流水灯的方向发生改变。然后我们定义独立函数的模块:(需注意,这里要用到Delay)
#include
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键键码,范围:0~4,无按键按下时返回值为0
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
回到主函数,我们定义一个LEDMode变量,如果按键被按下,就让LEDMode的值在0和1之间变化。这样如果LEDMode值仍然为0,那么流水灯方向保持向1-8方向;为1,则为8-1方向。这里使用了crol(字符循环左移)和cror(字符循环右移)
顾名思义,循环移位函数是一个函数操作,可以对一个数据进行循环移位操作,循环的意思是移出位的那位二进制数,不是进行舍弃,而是又从另外一端补位进来。
循环移位函数有两个参数,格式为_xxx_(c,b)。c为要移位的数据,b为移动的位数。移位函数一共有6个:
_crol_: 字符循环左移
_cror_: 字符循环右移
_irol_: 整数循环左移
_iror_: 整数循环右移
_lrol_: 长整数循环左移
_lror_: 长整数循环右移
————————————————
版权声明:本文为CSDN博主「一只爬爬虫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_72963799/article/details/127313328
timer:
#include
/**
* @brief 定时器0初始化 1毫秒@11.0592MHz
* @param 无
* @retval 无
*/
void Timer0Init(void) //1毫秒@11.0592MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=0;
}
/*定时器中断函数模板
void Timer_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
}
}
*/
key:
#include
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @retval 按下按键键码,范围:0~4,无按键按下时返回值为0
*/
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
main:
#include
#include "Timer0.h"
#include "Key.h"
#include
unsigned char KeyNum,LEDMode;
void main()
{
P2=0xFE;//1111 1110
Timer0Init();
while(1)
{
KeyNum=Key();
if(KeyNum)
{
LEDMode++;
if(LEDMode>=2)LEDMode=0;
}
}
}
void Timer_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x66; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=500)
{
T0Count=0;
if(LEDMode==0)
P2=_crol_(P2,1);
if(LEDMode==1)
P2=_cror_(P2,1);
}
}
独立按键控制LED流水灯