原理图
代码程序
main.c
#include "common.h"
task_t data tasks[]={
{display,1,0,TS_READY},
{timecount,1000,0,TS_READY},
{timeshow,50,0,TS_READY},
{keyalone,8,0,TS_READY},
};
code u8 tasks_size=sizeof(tasks)/sizeof(task_t); // 当前系统中的任务数量
void init_task(){
// 定义每个任务的句柄 handle
// 句柄的主要作是用来动态修改任务的属性。
// 通过动态改变任务的属性,你可以实现延时、刷新速度调整、任务禁用启用等功能。
display_h=tasks+0;
timecount_h = tasks + 1;
timeshow_h =tasks +2;
keyalone_h =tasks +3;
//将 timer2 设置为系统时钟。每毫秒加一
//timer0 init
TMOD=0X01;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC;
TF0 = 0;
TR0 = 1;
ET0=1;//打开定时器中断
EA=1;//打开总中断
}
//tick用来记录当前的开机时间。单位ms。
u32 tick = 0;
void Time0() interrupt 1
{
TL0 = 0x18; //每次溢出之后要手动进行一次初始化。
TH0 = 0xFC;
++tick;//
}
task_t data * get_nearest_task(){
u8 i;
task_t data * data task;
u32 timeout=u32_max;
for(i=0;i<tasks_size;++i){
if(tasks[i].t<timeout&&TS_READY==tasks[i].s){
task=tasks+i;
timeout=task->t;
}
}
return task;
}
void main()
{
init_task(); // 全局初始化。
// 使用 data 关键字修饰的目的是将频繁使用的变量编译在 data 段,以优化程序运行性能。
// 同理所有变量定义中的其它修饰关键字也可以去掉,比如 code data xdata 等。(但是程序性能会有部分影响,但是运行效果几乎没有区别)
for(;;){
static task_t data * data task; // 由于编译中寄存器优化问题,必须将 task_t 变量定义为 static。
task=get_nearest_task(); // 获取最近的就绪任务。
if(task->t>tick) // 判断是否已经到达该任务的下一次执行时间。
continue; // 如果没有没有到达,继续循环取出最近的任务判断。
task->s=TS_RUNNING; // 设置任务状态为运行中。(如果在程序中你不需要判断任务状态,就可以不用设置,省略掉)
((fun_t)(task->f))(); // 将任务函数 f 取出,强制转换为函数类型((fun_t)(task->f)),然后调用()。
task->s=TS_READY; // 设置任务状态为就绪中。(同上,可以省略)
task->t=tick+task->i; // 更新任务的下一次调用时间 (t=tick+i)。(下一次调用时间更新为当前时间加上调用时间间隔)
}
}
task.c
#include "common.h"
u8 code dsp_code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};//共阳段码表
u8 dsp_buff[]={0,0,0,0,0,0};
sbit k1= P2^6;
sbit k2=P2^7;
sbit k3=P3^0;
sbit k4=P3^1;
u8 show_stat=0;
u8 time_sec=54;
u8 time_min=59;
u8 time_hou=16;
u8 sec_flag=0;
u8 min_flag=0;
u8 ch_start=0;
u8 run_flag=1;
u8 temp=0;
/************************显示函数*********************/
task_t* display_h;
void display(){
static u8 dsp_com=0;
SEG_LE=1;
P0=0xff;
P0=dsp_code[dsp_buff[dsp_com]];
P2=(1<<dsp_com)|0xc0;
SEG_LE=0;
if(++dsp_com==6) dsp_com=0;
}
/***********************时钟计数********************/
task_t* timecount_h;
void timecount(){
if(run_flag==1){
if(++time_sec==60){
time_sec=0;
sec_flag=1;
}
if(sec_flag==1){
if(++time_min==60){
time_min=0;
min_flag=1;
}
sec_flag=0;
}
if(min_flag==1){
if(++time_hou==24){
time_hou=0;
}
min_flag=0;
}
}
}
/************************显示刷新*****************/
task_t* timeshow_h;
void timeshow(){
static u16 count=0;
static u8 blink=0;
if(show_stat==0){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else if(show_stat==1){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
}
else if(show_stat==2){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=time_hou/10;
dsp_buff[1]=10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
}
else if(show_stat==3){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
}
else if(show_stat==4){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
}
else if(show_stat==5){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=10;
dsp_buff[5]=time_sec%10;
}
}
else if(show_stat==6){
if(blink){
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=time_sec%10;
}
else{
dsp_buff[0]=time_hou/10;
dsp_buff[1]=time_hou%10;
dsp_buff[2]=time_min/10;
dsp_buff[3]=time_min%10;
dsp_buff[4]=time_sec/10;
dsp_buff[5]=10;
}
}
count+=50;
if(count>600){
blink=1;
}
else
blink=0;
if(count>1200)
count=0;
}
/****************************独立按键*************************/
task_t* keyalone_h;
void keyalone(){
static u8 key_stat=0;
u8 key_val=0;
if(k3==0)
key_val = 3;
else if(k1==0)
key_val = 1;
else if(k2==0)
key_val =2;
else if(k4==0)
key_val=4;
else
key_val=0;
switch(key_stat){
case 0:
if(key_val!=0)
key_stat=1;
break;
case 1:
if(key_val==0)
key_stat=0;
else{
key_stat=2;
if(key_val==1){
if(show_stat==1){
if(time_hou/10<2){
temp = (time_hou/10)+1;
time_hou=temp*10+time_hou%10;
}
}
else if(show_stat==2){
if(time_hou%10<9){
time_hou=time_hou + 1;
}
}
else if(show_stat==3){
if(time_min/10<5){
temp = (time_min/10)+1;
time_min=temp*10+time_min%10;
}
}
else if(show_stat==4){
if(time_min%10<9){
time_min=time_min + 1;
}
}
else if(show_stat==5){
if(time_sec/10<5){
temp = (time_sec/10)+1;
time_sec=temp*10+time_sec%10;
}
}
else if(show_stat==6){
if(time_sec%10<9){
time_sec=time_sec + 1;
}
}
}
else if(key_val==2){
if(show_stat==1){
if(time_hou/10>0){
temp = (time_hou/10)-1;
time_hou=temp*10+time_hou%10;
}
}
else if(show_stat==2){
if(time_hou%10>0){
time_hou=time_hou - 1;
}
}
else if(show_stat==3){
if(time_min/10>0){
temp = (time_min/10)-1;
time_min=temp*10+time_min%10;
}
}
else if(show_stat==4){
if(time_min%10>0){
time_min=time_min - 1;
}
}
else if(show_stat==5){
if(time_sec/10>0){
temp = (time_sec/10)-1;
time_sec=temp*10+time_sec%10;
}
}
else if(show_stat==6){
if(time_sec%10>0){
time_sec=time_sec - 1;
}
}
}
else if(key_val==3){//当k3被按下
switch(show_stat){
case 0:
show_stat=1;
run_flag=0;
break;
case 1:
show_stat=2;
run_flag=0;
break;
case 2:
show_stat=3;
run_flag=0;
break;
case 3:
show_stat=4;
run_flag=0;
break;
case 4:
show_stat=5;
run_flag=0;
break;
case 5:
show_stat=6;
run_flag=0;
break;
case 6:
show_stat=0;
run_flag=1;
break;
}
}
else if(key_val==4){//当k4被按下的时候
show_stat=0;
run_flag=1;
}
}
break;
case 2:
if(key_val==0)
key_stat=0;
break;
}
}
#ifndef __COMMON_H_
#define __COMMON_H_
#include<reg52.h>
#include "intrins.h"
sbit SEG_LE = P1^0;
sbit led2 = P1^1;
typedef unsigned char u8; // 定义u8类型,简写,加快开发速度。
typedef unsigned int u16;
typedef unsigned long u32;
#define u8_max ((u8)-1) // u8 最大值
#define u16_max ((u16)-1)
#define u32_max ((u32)-1)
#define true 1 // 同上
#define false 0
// 定义函数类型 相当于定义一个参数为空,返回值为空的函数类型。2byte
typedef void fun_t(void);
// 定义任务结构体
typedef struct{
u16 f; //function // 任务对应的函数,调用的时候需要将其强制转换为 fun_t 函数类型来调用。
u16 i; //interval // f 函数每隔多少毫秒调用一次。
u32 t; //timeout // f 函数下一次调用的时间。如果 (t<=tick) f 函数就会被调用,调用完成过后就会更新 (t=tick+i) (下一次调用时间更新为当前时间加上调用时间间隔)
u8 s; //state // 当前任务的状态 TS_DISABLE(禁用),TS_READY(就绪),TS_RUNNING(运行)
}task_t;
enum TS_STATE{TS_DISABLE,TS_READY,TS_RUNNING}; // TASK STATE 当前任务状态的枚举。
extern u32 tick;
/******************************全局变量区*******************************/
/******************************任务函数区********************************/
void display();//数码管显示
void timecount();//计数模块
void timeshow();
void keyalone();
/******************************任务控制块********************************/
extern task_t* display_h;//数码管显示
extern task_t* timecount_h;//计数模块
extern task_t* timeshow_h;
extern task_t* keyalone_h;
#endif