有趣生活

当前位置:首页>科技>单片机定时器计数器四种工作方式单片机应用实践篇之定时

单片机定时器计数器四种工作方式单片机应用实践篇之定时

发布时间:2026-07-21阅读(1)

导读上节分享了单片机定时/计数器实现数码管动态刷新的程序代码,本节利用定时/计数器以及外部中断实现一简单的电子时钟功能。对应的视频课程为:单片机应用实践篇之定时....

上节分享了单片机定时/计数器实现数码管动态刷新的程序代码,本节利用定时/计数器以及外部中断实现一简单的电子时钟功能。对应的视频课程为:单片机应用实践篇之定时/计数器实现按键可调电子时钟,视频链接:https://www.ixigua.com/6840071457402257928。此处把视频课程中的程序代码重新整理了下,按照模块化进行了简单的处理,分为main.c,display.c,display.h,time.c,time.h,exit.c,exit.h。此处的按键可调电子时钟功能比较简单,主要是为了给初学单片机的同学介绍一个综合的应用实例,同时,也考虑下状态机的编程思路,及程序的框架处理。程序当然有许多需要改进和优化的地方,此处只是采用了4位数码管进行程序的功能演示,大家如果做实物的话,可以考虑采用时钟专用数码管,另外程序为了演示效果,当前界面是显示的分钟:秒,小时并没有显示,大家可以根据自己的需求,进行相应的界面设计及修改。如果在此代码的基础上,适当的增加些小算法代码就可以实现一个万年历的功能,如果有网友有想要实现万年历的功能代码的话,可以留言,我后面可以进行分享以前调试的一个代码。话不多说,代码撸起来。

//main.c/***********************************************************程序功能:按键可调电子时钟的设计 四位数码管显示 分钟:秒(可根据需要调整显示界面) KEY1 外部中断0 状态切换KEY2 外部中断1 参数调整产生时间基准 定时器0 数码管动态刷新 定时器1*************************************************************/#include <reg51.h>#include "display.h"#include "time.h"#include "exit.h"void showNormal();void showSec();void showMin();void showHour();//状态变量unsigned char state = 0;void main(){EX0_Init();EX1_Init();Timer1Init();Timer0Init();EA = 1;while(1){switch(state){case 0:TR0 = 1;showNormal();break;//正常时钟状态case 1:showSec();break;//调秒case 2:showMin();break;//调分case 3:showHour();break;//调时default:break;}}}//正常时钟显示界面void showNormal(){LEDBuf[0] = min/10;LEDBuf[1] = min;LEDBuf[2] = sec/10;LEDBuf[3] = sec;}//调秒显示界面void showSec(){LEDBuf[0] = 23;//关LEDBuf[1] = 23;//关LEDBuf[2] = sec/10;LEDBuf[3] = sec;}//调分显示界面void showMin(){LEDBuf[0] = min/10;LEDBuf[1] = min;LEDBuf[2] = 23;//关LEDBuf[3] = 23;//关}//调时显示界面void showHour(){LEDBuf[0] = hour/10;LEDBuf[1] = hour;LEDBuf[2] = 23;//关LEDBuf[3] = 23;//关}

//time.c#include "time.h"#include "display.h"//全局变量定义unsigned char timerCnt;unsigned char sec;unsigned char min;unsigned char hour;void Timer0Init(void)//50毫秒@12.000MHz{TMOD &= 0xF0;//设置定时器模式TMOD |= 0x01;//设置定时器模式TL0 = 0xB0;//设置定时初值TH0 = 0x3C;//设置定时初值TF0 = 0;//清除TF0标志ET0 = 1;}void Timer1Init(void)//1毫秒@12.000MHz{TMOD &= 0x0F;//设置定时器模式TMOD |= 0x10;//设置定时器模式TL1 = 0x18;//设置定时初值TH1 = 0xFC;//设置定时初值TF1 = 0;//清除TF1标志ET1 = 1;TR1 = 1;//定时器1开始计时}/*************************************1、中断服务函数一定是一个没有返回值的函数2、中断服务函数一定是没有参数的函数3、中断服务函数函数名后跟关键字 interrupt 4、interrupt n 0 - 4 5个中断源 8*n 0003H 0003H INT0 000BH T0 0013H INT1 001BH T1 0023H ES5、中断服务函数不能被主程序或其他程序所调用6、 n 后面 跟 using m (0 - 3 )工作寄存器组***************************************/void timer0_ISR(void) interrupt 1{timerCnt ;if(timerCnt >= 20)//20次50ms中断,即1S时间到{timerCnt = 0;sec ;if(sec >= 60){sec = 0;min ;if(min >= 60){min = 0;hour ;if(hour >= 24){hour = 0;}}}}TL0 = 0xB0;//设置定时初值TH0 = 0x3C;//设置定时初值}void timer1_ISR(void) interrupt 3{TR1 = 0;Display();TL1 = 0x18;//设置定时初值TH1 = 0xFC;//设置定时初值TR1 = 1;}

//time.h#ifndef __TIME_H__#define __TIME_H__#include <reg51.h>extern unsigned char sec;extern unsigned char min;extern unsigned char hour;void Timer0Init(void);void Timer1Init(void);#endif

//exti.c#include "exit.h"#include "time.h"//外部变量声明extern unsigned char state;void EX0_Init(){IT0 = 1;EX0 = 1;}void EX1_Init(){IT1 = 1;EX1 = 1;}void EX0_ISR() interrupt 0{TR0 = 0;state ;if(state >3 )state = 0;}void EX1_ISR() interrupt 2{switch(state){case 0:break;case 1:sec ;if(sec >= 60) sec = 0;break;case 2:min ;if(min >= 60) min = 0;break;case 3:hour ;if(hour >= 24) hour = 0;break;default:break;}}

//exti.h#ifndef __EXIT_H__#define __EXIT_H__#include <reg51.h>void EX0_Init();void EX1_Init();#endif

//display.c#include "display.h"unsigned char code leddata[]={ //数码管的段码表 0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 };unsigned char LEDBuf[] = {22,22,22,22};//数据显示缓冲区unsigned char code PLACE_CODE[] = {0xfe,0xfd,0xfb,0xf7};//位选信号void Display(){static unsigned char i = 0;//1、送段码//2、送位选//3、延时 //4、消隐switch(i){case 0:GPIO_DIG = 0x00;GPIO_DIG = leddata[LEDBuf[0]]; GPIO_PLACE = PLACE_CODE[0];i ;break;case 1:GPIO_DIG = 0x00;GPIO_DIG = leddata[LEDBuf[1]]; GPIO_PLACE = PLACE_CODE[1];i ;break;case 2:GPIO_DIG = 0x00;GPIO_DIG = leddata[LEDBuf[2]]; GPIO_PLACE = PLACE_CODE[2];i ;break;case 3:GPIO_DIG = 0x00;GPIO_DIG = leddata[LEDBuf[3]]; GPIO_PLACE = PLACE_CODE[3];i = 0;break;default:break;}}

//display.h#ifndef __DISPLAY_H__#define __DISPLAY_H__#include <reg51.h>//IO的声明#define GPIO_DIG P0 //段码 IO#define GPIO_PLACE P2 //位选 IO#define N 4 //数码管个数unsigned char code leddata[];extern unsigned char LEDBuf[];void Display();#endif

执行代码后,通过Proteus仿真的显示界面如下:

正常时钟显示界面(分钟:秒)

调秒显示界面

调分显示界面

调时显示界面

程序代码仅供初学的同学参考学习,代码可以根据自己的风格进行相应的优化处理,仅供参考。

Copyright © 2024 有趣生活 All Rights Reserve吉ICP备19000289号-5 TXT地图HTML地图XML地图