时间路行者之 51单片机(STC89C52RC)第七章 定时器以及按键控制LED流水灯模式&定时器时钟 | 您所在的位置:网站首页 › 电脑上的定时器在哪 › 时间路行者之 51单片机(STC89C52RC)第七章 定时器以及按键控制LED流水灯模式&定时器时钟 |
定时器
定时器介绍: 51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 定时器作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作 (2) 替代长时间的Delay,提高CPU的运行效率和处理速度 定时器个数: 3个 (TO、T1、T2),TO和T1与传统的51单片机兼容T2是此型号单片机增加的资源不同的型号注意: 定时器的资源和单片机的型号是关联在一起的,可能会有不同的定时器个数和操作方式,但一般来说,TO和T1的操作方式是所有51单片机所共有的 定时器框图定时器在单片机内部就像一个小闹钟一样,根据时钟的输出信号每隔“一秒”,计数单元的数值就增加一,当计数单元数值增加到“设定的闹钟提醒时间”时,计数单元就会向中断系统发出中断申请产生“响铃提醒”,使程序跳转到中断服务函数中执行 STC89C52的TO和T1均有四种工作模式 模式0: 13位定时器/计数器 模式1: 16位定时器/计数器 (常用) 模式2: 8位自动重装模式 模式3: 两个8位计数器 工作模式1框图 SYSclk:系统时钟,即晶振周期,本开发板上的晶振为12MHZ 这是定时器 计数器 在单片机上看是T0处,用于接外界的计时器 P2口作为地址复用,P3口有第二功能引脚(这里面就有中断的相关引脚) IAP15中断源有21个 IAP里面的5个中断源 分时的操作(我在服务你的同时被中断后可以服务别人,这样就实现了服务对象的多样化); 实现实时处理(可以在编译的时候,中断的子程序); 进行故障的处理(例如:看门狗程序,进入死循环后,可以跳出并进行复位) (下面有可能是考点) 中断系统是为使CPU具有对外界紧急事件的实时处理能力而设置的. 当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作,这样的过程称为中断。实现这种功能的部件称为中断系统,请示CPU中断的请求源称为中断源。 微型机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为它服务的时候,这就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。 当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序) ,发生了另外一个优先级比它还高的中断源请求。如果CPU能够暂停对原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低级中断服务程序,这样的过程称为中断嵌套。这样的中断系统称为多级中断系统,没有中断嵌套功能的中断系统称为单级中断系统。 中断程序流程
中断源个数:8个(外部中断0、定时器0中断、外部中断1、定时器中断源个数:8个1中断、串口中断、外部中断2、外部中断3) 中断优先级个数:4个 中断号: 注意:中断的资源和单片机的型号是关联在一起的,不同的型号可能会有不同的中断资源,例如中断源个数不同、中断优先级个数不同等等 定时器和中断系统IAP15和89c52的中断系统图相同
IT0=0 电平触发 低电平触发 IT0=1 边沿触发分为 上升沿(低电平转高电平) 下降沿(高电平转低电平) IE0为中断标志位:是用来存储前面的触发源是否有效 (如果触发成功IE0=1,否则的等于0) EX0 中断允许:外部中断0的中断允许 EA为总的中断:集体关闭中断的允许,更加方便 PX0优先级:当PX0=1的时候为高优先级 (其中里面还有自然优先级的概念) TCON控制中断请求的控制寄存器 IE,IP也都同理 T0是靠内部的定时器进行溢出来触发请求 TF0是T0的中断标志位 TR0是控制定时器启动的 相关程序书写:1、将定时器0工作在模式1中: 想要让定时器0在模式1下工作,那么就需要将M0打开,所以M0的值为1,其余的都为0,所以得出二进制的数为0000 0001, GATE:为门控端,表示控制启动方、方式 GATE=0(为软启动)GATE=1(为硬启动) C/T:为0时,为定时器模式;为1的时候,为计数器模式 M0和M1:用于设置定时器的工作方式 00 01都是16位的计数器,方式00具有重复计数的功能,而00只能自己再写初值(写到中断函数中) 10 为一个8位的计数器(也具有自动重复计数功能)最多计数256个数 11 只有T0才有方式3,TL1和TH1就各自干各自的事情(这时候T1:可以继续计数,不能发送中断请求(被TH1借走了)了,这时候就辅助串口工作(给串口产生计时脉冲(波特率(是应该脉冲信号)))) 定时器结束后,就会向单片机发送中断请求(就会让TF0=1或TF1=1) 中断撤销:是自动撤销(TF0=0或TF1=0) 不可位寻址:表示不能控制位 可位寻址:可以控制每一位 计数器是8个为1位的,8个只能存256个 中断函数 //闹钟响了以后要调到这个指函数中,起到中断的作用 //初始化后大概一ms后会发生中断 //后面跟的小尾巴就是中断子程序 void Timer0_Routine() interrupt 1 { }这个中断系统可以用STC-ISP来进行配置(需要注意配置的时候选的频率等因素) 复制过来的代码中会少一个中断定时器(中断是是需要自己开的),开头的那个12T因为是新的版本,89C52的旧版是用不到的所以可以直接删掉 (太重要了,我听了3遍才知道的技巧) 中断系统的(完整代码)中断子程序是不能够被调用的, 中断子程序有固定的地址入口 #include /******************************* 初始化 *******************************/ void Timer0_Init(){ // TMOD=0;//选择定时器//0000 0001 //(利用“与或”的方法) //利用下面这两句代码来配置上面的那一句代码,可以保证在配置第四位的时候不影响高四位 TMOD&=0xF0;//把TMOD低四位清零,高四位保持不变(“与”清零) TMOD|=0x01;//把TMOD低位置1,高四位保持不变(“或”置1)(任何数或零都为任何数) TF0=0;//选0是因为防止中断,(TF0为中断艺术标志位) TR0=1;//TR0是判断定时器是否开启,如果想要让定时器开始工作,就赋值为1。 TH0=64535/256;//表示高位 TL0=64535%256;//表示存下了低位(高位和地位,相当于用两个盒子把数装进去) /******上面可以用stc-isp生成,下面的中断还是需要自己打开(其中如果单片机不是12T的可以将生成的第一条删除)*********/ //控制中断器的开关 ET0=1;//打开中断的第一个开关 EA=1;//打开第二个开关 PT0=0;//打开第三个开关 } /******************************* 中断函数 *******************************/ //闹钟响了以后要调到这个指函数中,起到中断的作用 //初始化后大概一ms后会发生中断 //后面跟的小尾巴就是中断子程序 unsigned int T0Count;//定义了一个新的函数,用来尝试计时一分钟 void Timer0_Routine() interrupt 1 { //计数器是同步计数,起始值是64536计时才是1ms。 TH0=64535/256; TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下 T0Count++;//来计中断的次数 if(T0Count>=1000){ T0Count=0;//将T0Count恢复原值 P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用 } } void main(){ Timer0_Init(); while(1){ } } static unsigned int T0Count;//定义静态变量,这样定义的话就不会丢失数字 流水灯用_crol_和_cror_来实现循环左移和循环右移 完整代码如下 //main.c #include #include "Timer0.h" #include "Key.h" #include unsigned char KeyNum,LEDMode;//LEDMode为流水灯模式 void main(){ P2=0xFE;//点亮最低位LED Timer0Init(); while(1){ KeyNum=Key();//给 KeyNumber赋值 if(KeyNum) { if(KeyNum==1) { LEDMode++; if(LEDMode>=2)LEDMode=0; } } } } ///******************************* //初始化 //*******************************/ //void Timer0_Init(){ TMOD=0;//选择定时器//0000 0001 // //(利用“与或”的方法) // //利用下面这两句代码来配置上面的那一句代码,可以保证在配置第四位的时候不影响高四位 // TMOD&=0xF0;//把TMOD低四位清零,高四位保持不变(“与”清零) // TMOD|=0x01;//把TMOD低位置1,高四位保持不变(“或”置1)(任何数或零都为任何数) // // TF0=0;//选0是因为防止中断,(TF0为中断艺术标志位) // TR0=1;//TR0是判断定时器是否开启,如果想要让定时器开始工作,就赋值为1。 // TH0=64535/256;//表示高位 // TL0=64535%256;//表示存下了低位(高位和地位,相当于用两个盒子把数装进去) // // /******上面可以用stc-isp生成,下面的中断还是需要自己打开(其中如果单片机不是12T的可以将生成的第一条删除)*********/ // 控制中断器的开关 // ET0=1;//打开中断的第一个开关 // EA=1;//打开第二个开关 // PT0=0;//打开第三个开关 // //} /******************************* 中断函数//一般都放在主函数中 *******************************/ //闹钟响了以后要调到这个指函数中,起到中断的作用 //初始化后大概一ms后会发生中断 //后面跟的小尾巴就是中断子程序 void Timer0_Routine() interrupt 1 { static unsigned int T0Count;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟 //计数器是同步计数,起始值是64536计时才是1ms。 TH0=0x18; TL0=0xfc;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下 T0Count++;//来计中断的次数 if(T0Count>=500){//每个500毫秒进来一次 T0Count=0;//将T0Count恢复原值 if(LEDMode==0){ P2=_crol_(P2,1); } if(LEDMode==1){ P2=_cror_(P2,1); } // P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用 } } //Timer0.c #include /** * @brief 定时器初始化,1毫秒@12.000MHz * @param 无 * @retval 无 */ //Timer0.c void Timer0Init(void) //1毫秒@12.000MHz { // AUXR &= 0x7F; //定时器时钟12T模式//这句话在旧版的89C52中是可以删去的 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;//定义静态变量//定义了一个新的函数,用来尝试计时一分钟 //计数器是同步计数,起始值是64536计时才是1ms。 TH0=64535/256; TL0=64535%256;//为了防止溢出过后,初始值会发生变化,所以在这里需要重置一下 T0Count++;//来计中断的次数 if(T0Count>=1000){ T0Count=0;//将T0Count恢复原值 P2_0=~P2_0;//表示在执行Timer0_Init()的时候,主函数中虽然没有写Timer0_Routine()但还是会点亮灯,这就说明中断起到了作用 } } */ //Timer0.h #ifndef __TIMER0_H__ #define __TIMER0_H__ void Timer0Init(void); //1毫秒@12.000MHz #endif //Key.c #include #include "Delay.h" /** * @brief 获取独立按键键码 * @param 无 * @retval 按下独立按键的键码,范围:0~4,无按键按下时值为0 */ unsigned char KeyNumber=0;//char的初值是不确定的 unsigned char Key(){ if(P3_1==0){Delay(20);while(P3_1);Delay(20);KeyNumber=1;} if(P3_0==0){Delay(20);while(P3_0);Delay(20);KeyNumber=2;} if(P3_2==0){Delay(20);while(P3_2);Delay(20);KeyNumber=3;} if(P3_3==0){Delay(20);while(P3_3);Delay(20);KeyNumber=4;} return KeyNumber; } //Key.h #ifndef __KEY_H__ #define __KEY_H__ unsigned char Key(); #endif1、触发中断:选择触发方式 开总中断 开对应的中断 选择设置自然优先级、 2、定义中断子程序函数 (中断关键词 interrupt 0~4) 3、主函数 while(1);(之后等着子程序被触发) 换灯的亮的案例 |
CopyRight 2018-2019 实验室设备网 版权所有 |