写一个C语言标准库keil,计时程序
keil下的c编写的多功能计时器
#include <aduc848.h> #include <KeyScan.h> //自定义头文件,KeyScan用于键盘扫描。 #include <I2C.h> //用于I2C总线。 #define uchar unsigned char #define uint unsigned int unsigned char b[7]={50,58,9,1,15,6,15},clock1[2]={0,12},clock2[2]={0,0}; //b[7]的元素含义:秒,分,时,星期,日,月,年 clock的元素含义:分,时。 code unsigned char tab[11]={0x03,0xf3,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0x00}; //数码管0-9的编码列表,0x00点亮全部管。 code unsigned char tab2[2]={0x6d,0xff}; //ox6d: 表示三横图标。 unsigned char time[7]; //时间设置函数的参数。 void delay(unsigned int cnt); //延时函数声明。 unsigned char getkey1(); //unsigned char getkey2(); //读键盘函数声明。 void tim(void); //中断函数声明。 void KeyDelay(unsigned int KeyJsTime); //键盘扫描延时函数声明。 void display(uchar bit7,uchar bit6,uchar bit5,uchar bit4, uchar bit3,uchar bit2,uchar bit1,uchar bit0); //数码管显示函数。 void ReadTime(unsigned char TIME[7]); //DS1307读时间函数。 void SetTime(unsigned char TIME[7]); //设置时间初值函数。 void SwitchRTC(unsigned char SWITCH); //时间修改的使能函数:SWITCH=1禁止修改时间,SWITCH=0可以修改时间。 uchar dis_num_h; //显示记录数据的组别十位 uchar dis_num_l; //显示记录数据的组别个位 uchar dis_min_h; //要显示的分的十位; uchar dis_min_l; //要显示的分的个位; uchar dis_sec_h; //要显示的秒的十位; uchar dis_sec_l; //要显示的秒的个位; uchar dis_dsec; //要显示的0.1秒; uchar min=0x00; //防止意外,赋初值。分······· uchar sec=0x00; //秒 uchar dsec=0x00; //十分之一秒。 uchar en,i,clocken1=0,clocken2=0; main() { unsigned char quzhi,xianshi,symbol=0x55,set,set1=0x55,ce; unsigned char c[30]; unsigned char num,num1,j,k,stop=1; //注意stop必须先赋初值1。 PLLCON&=0xf8; //设置频率为12.582912MHz TMOD=0x01; //选定定时器及其工作模式。 TH0=0xce; //赋初值:52736,则总共的计数次数为:65536-52736=12800,即12.8毫秒。 TL0=0x00; IE=0x82; //中断控制,10000010,EA=1开总中断,ET0=1:定时器0中断允许。0x82:1000 0010 I2CCON=0xE8; //开启I2C总线通信,具体含义参阅ADuC848英文版说明资料。 SetTime(b); //设定初始时间。 SwitchRTC(1); //调用时间保持函数。 while(1) //设置死循环,实现循环执行。 { ReadTime(time); //调用读时间函数,读取当前的时间,并保留在time数组中。 if(((clock1[0]==time[1])&&(clock1[1]==time[2])&&(clocken1==0)&&stop)||((clock2[0]==time[1])&&(clock2[1]==time[2])&&(clocken2==0)&&stop)) //stop 作为控制闹钟闹铃的标志位。 { PWM0H=205;PWM1L=500;PWMCON=0x21; //蜂鸣器响 KeyDelay(333); //延时约为90毫秒。 PWM1H=0;PWM1L=0;PWMCON=0x00; KeyDelay(333); if(getkey1()==12) { stop=0; } } if((time[1]==clock1[0]+1)||(time[1]==clock2[0]+1)) stop=1; //实现响一分钟之后停止的功能,同时修改闹钟的标志位。 if((time[0]==0)&&(time[1]==0)) //实现整点报时功能,检测时间的分钟位和秒钟位。 { i=1; //设置标志位,注意i是全局变量。 while(i) { PWM0H=50;PWM1L=100;PWMCON=0x21; //蜂鸣器响 KeyDelay(333); //延时约为90毫秒。 PWM1H=0;PWM1L=0;PWMCON=0x00; //蜂鸣器停止响。 KeyDelay(333); i++; if(i==23) //整点报时总共响23次。 { i=0; } } } en=getkey1(); //调用键盘扫描函数。 if((en==0x80)||(en==0x55)) //此条件即为无按键按下。 { en=symbol; //symbol作为标志位使用,是全局变量。 } if(xianshi==8) //xianshi是主函数里的局部变量,作为显示的标志位。 { display(dis_num_h,dis_num_l,dis_min_h,dis_min_l, dis_sec_h,dis_sec_l,0xff,dis_dsec) ; //调用显示函数,显示已存储的秒表时间值 } //////////////////////////////////////////////////////////////////////////////////// if(en==1) //按下按键1,显示北京时间:年月日星期 { symbol=1; //标志位计数。 display(tab[time[6]/10],tab[time[6]],tab[time[5]/10],tab[time[5]], tab[time[4]/10],tab[time[4]],0xff,tab[time[3]]); } //////////////////////////////////////////////////////////////////////////////////// if(en==2) //按下按键2,显示北京时间:时分秒 { symbol=2 ; display(tab2[clocken1],tab2[clocken2],tab[time[2]/10],tab[time[2]],tab[time[1]/10],tab[time[1]],tab[time[0]/10],tab[time[0]]); } //////////////////////////////////////////////////////////////////////////////////// else if(en==3) //按下按键3,秒表进入正常工作模式。 { min=0; //因为是正计时,去先清零。 sec=0; dsec=0; symbol=3; //标志位计数。 while(1) { quzhi=getkey1(); if(num<11) //num是主函数里的局部变量,用于记录计时的组数。 display(dis_min_h,dis_min_l,0xff,0xff,dis_sec_h,dis_sec_l,0xff,dis_dsec); //这里确定了记录的计时数组的显示格式。 else display(0x71,0x83,0xe3,0xe3,0xff,0xff,0xff,0xff); //显示单词“FULL",表示计数的组数已满。 if(quzhi==5) //5号键用于启动正计时。 { quzhi=0x55; //取消键值,为下一次扫描做准备。 num=1; //启动计时后,数据自动存入第一组。 if(TR0==1) TR0=0; else TR0=1; } else if(quzhi==6) //按键6,用于秒表读值。 { quzhi=0x55; //消去quzhi的记录值,为下一次的键值记录做准备。 c[3*(num-1)+2]=dsec; //读出的值放在c[]中 c[3*(num-1)+1]=sec; //每四位为一段,依次时取值的顺序、分、秒、0.1秒 c[3*(num-1)+0]=min; num++; } else if(quzhi==7) //按键7按下,表示计时结束 { TR0=0; num1=1; symbol=0x55; min=0; sec=0; dsec=0; break; } } } ////////////////////////////////////////////////////////////////////////////////////// else if(en==4) //秒表倒计时 { symbol=4; j=0; for(i=0;i<=30;i++) c[i]=0; while(1) { display(dis_min_h,dis_min_l,0xff,0xff,dis_sec_h,dis_sec_l,0xff,dis_dsec); set=getkey1(); while(j<5) { ce=getkey1(); //ce是全局变量。 display(tab[c[0]],tab[c[1]],0xff,0xff,tab[c[2]],tab[c[3]],0xff,tab[c[4]]); if((ce!=0x55)&&(ce!=0x80)) { if(ce>9) ce=0; c[j]=ce; j++; } min=c[0]*10+c[1]; sec=c[2]*10+c[3]; dsec=c[4]; } dis_min_h=tab[min/10]; //分、秒及0.1秒显示值的处理 dis_min_l=tab[min]; dis_sec_h=tab[sec/10]; dis_sec_l=tab[sec]; dis_dsec=tab[dsec]; if(set==5) { set=0x55; TR0=1; TF0=1; } if((min==0)&&(sec==0)&&(dsec==0)) { while(i) { PWM0H=50;PWM1L=100;PWMCON=0x21; //蜂鸣器响 KeyDelay(333); //延时 PWM1H=0;PWM1L=0;PWMCON=0x00; KeyDelay(333); i++; if(i==200) { i=0; break; } } } if(set==7) { symbol=0x55; min=0; sec=0; dsec=0; for(i=0;i<30;i++) c[i]=0; //c数组,全局变量,可以有30个元素。 ce=0x55; break; } } } else if(en==8) { symbol=0x55; xianshi=8; dis_num_h=tab[num1/10]; dis_num_l=tab[num1]; dis_min_h=tab[c[(num1-1)*3+0]/10]; dis_min_l=tab[c[(num1-1)*3+0]]; dis_sec_h=tab[c[(num1-1)*3+1]/10]; dis_sec_l=tab[c[(num1-1)*3+1]]; dis_dsec=tab[c[(num1-1)*3+2]]; num1++; if(num1>num) { xianshi=0x55; } } else if(en==9) { symbol=0x55; j=0; for(i=0;i<=6;i++)b[i]=0; for(i=0;i<=30;i++)c[i]=0; while(1) { while(j<=13) { ce=getkey1(); if(j<=5) display(tab[b[2]/10],tab[b[2]],0xff,tab[b[1]/10], tab[b[1]],0xff,tab[b[0]/10],tab[b[0]]); else if(j<=13) display(tab[b[6]/10],tab[b[6]],tab[b[5]/10], tab[b[5]],tab[b[4]/10],tab[b[4]],0xff,tab[b[3]]); if(ce==10)break; else if((ce!=0x55)&&(ce!=0x80)) { if(ce>9) ce=0; c[j]=ce; j++; } b[2]=c[0]*10+c[1]; b[1]=c[2]*10+c[3]; b[0]=c[4]*10+c[5]; b[6]=c[6]*10+c[7]; b[5]=c[8]*10+c[9]; b[4]=c[10]*10+c[11]; b[3]=c[12]; } ReadTime(time); c[13]=time[2]/10; c[14]=time[2]; c[15]=time[1]/10; c[16]=time[1]; c[17]=time[0]/10; c[18]=time[0]; c[19]=time[6]/10; c[20]=time[6]; c[21]=time[5]/10; c[22]=time[5]; c[23]=time[4]/10; c[24]=time[4]; c[25]=time[3]; for(k=j;k<=12;k++) { c[k]=c[k+13]; } b[2]=c[0]*10+c[1]; b[1]=c[2]*10+c[3]; b[0]=c[4]*10+c[5]; b[6]=c[6]*10+c[7]; b[5]=c[8]*10+c[9]; b[4]=c[10]*10+c[11]; b[3]=c[12]; SetTime(b); break; } }else if(en==13) { if(clocken1==0) clocken1=1; else if(clocken1==1) clocken1=0; }else if(en==14) { symbol=0x55; j=0; for(i=0;i<=30;i++)c[i]=0; while(1) { while(j<=4) { ce=getkey1(); display(tab[clock1[1]/10],tab[clock1[1]],0xff,0xff, tab[clock1[0]/10],tab[clock1[0]],0xff,0xff); if((ce!=0x55)&&(ce!=0x80)) { if(ce>9)ce=0; c[j]=ce; j++; } clock1[1]=c[0]*10+c[1]; clock1[0]=c[2]*10+c[3]; } break; } }else if(en==15) { if(clocken2==0) clocken2=1; else if(clocken2==1) clocken2=0; }else if(en==0) { symbol=0x55; j=0; for(i=0;i<=30;i++)c[i]=0; while(1) { while(j<=4) { ce=getkey1(); display(tab[clock2[1]/10],tab[clock2[1]],0xff,0xff, tab[clock2[0]/10],tab[clock2[0]],0xff,0xff); if((ce!=0x55)&&(ce!=0x80)) { if(ce>9)ce=0; c[j]=ce; j++; } clock2[1]=c[0]*10+c[1]; clock2[0]=c[2]*10+c[3]; } break; } } } } /********************************/ /* 延时函数程序 */ /********************************/ void delay(unsigned int cnt) //用于动态扫描数码管的延时程序 { while(--cnt); } /********************************/ /* 数码管显示函数 */ /********************************/ void display(uchar bit7,uchar bit6,uchar bit5,uchar bit4,uchar bit3,uchar bit2,uchar bit1,uchar bit0) { P2=0x08; P0=bit7; delay(500); P2=0x04; P0=bit6; delay(500); P2=0x02; //显示秒表计时的时间 P0=bit5; delay(500); P2=0x10; P0=bit4; delay(500); P2=0x00; //关闭P2控制的数码管,即高三位(最左边三位),可以实现消影。 P3=0x80; P0=bit3; delay(500); P3=0x40; P0=bit2; delay(500); P3=0x20; P0=bit1; delay(500); P3=0x08; P0=bit0; delay(500); P3=0x00; //关闭右边五位数码管,消影。 } /****************************************/ /* 定时中断函数程序 */ /****************************************/ void tim(void) interrupt 1 using 1 //靠计时器0计时溢出触发中断。 { unsigned int count; TH0=0x3c; //重新赋初值:15360,计数次数:65536-15360=50176,约为47.8515625毫秒,1/200秒定时 TL0=0x00; IE=0x82; //中断控制,EA=1开总中断,ET0=1:定时器0中断允许 TR0=1; //启动计时器。 count++; //计数次数标志。 if(en==3) //按键3按下,正计时计数 { if(count>=20) //这里的时间:21×47.8515625毫秒 { count=0; dsec++; //每隔约0.1秒,最后一位加一。 if(dsec==10) { dsec=0; sec++; if(sec==60) { sec=0; //实现进位。 min++; if(min==60) //计时满60分钟,自动清零,即计时最大到60分钟。 { min=0; } } } } } else //倒计时 { if(count>=20) { count=0; dsec--; if(dsec==-1) { dsec=9; sec--; if(sec==-1) { sec=59; min--; if(min==-1) { min=59; } } } } if((min==0)&&(sec==0)&&(dsec==0)) //倒计时结束的处理方案。 { TR0=0; en=0x55; i=1; //注意这里将i置1。 } } dis_min_h=tab[min/10]; //分、秒及0.1秒显示值的处理 dis_min_l=tab[min]; dis_sec_h=tab[sec/10]; dis_sec_l=tab[sec]; dis_dsec=tab[dsec]; } /*****************************************/ /* 读时间程序 **/ /*******************************************/ void ReadTime(unsigned char TIME[7]) { bit EATemp; unsigned char temp; EATemp=EA; CFG848|=0x01;//使用片内xram iicstart(); iicwriteda(0xd0); iicreadack(); iicwriteda(0x00); iicreadack(); iicstop(); iicdelay(1); iicstart(); iicwriteda(0xd1); iicreadack(); TIME[0]=iicreadda(); iicack(); TIME[1]=iicreadda(); iicack(); TIME[2]=iicreadda(); iicack(); TIME[3]=iicreadda(); iicack(); TIME[4]=iicreadda(); iicack(); TIME[5]=iicreadda(); iicack(); TIME[6]=iicreadda(); iicnack(); iicstop(); iicdelay(1); TIME[0]=((TIME[0]&0x7f)>>4)*10+(TIME[0]&0x0f); //second TIME[1]=((TIME[1]&0x7f)>>4)*10+(TIME[1]&0x0f); //minute if(TIME[2]&0x40) { if(TIME[2]&0x20)temp=0x80;else temp=0x40; TIME[2]=((TIME[2]&0x1f)>>4)*10+(TIME[2]&0x0f); //hour TIME[2]|=temp; } else { TIME[2]=((TIME[2]&0x3f)>>4)*10+(TIME[2]&0x0f); } TIME[3]=TIME[3]&0x07; //week TIME[4]=((TIME[4]&0x3f)>>4)*10+(TIME[4]&0x0f); //date TIME[5]=((TIME[5]&0x1f)>>4)*10+(TIME[5]&0x0f); //month TIME[6]=(TIME[6]>>4)*10+(TIME[6]&0x0f); //year EA=EATemp; } /*****************************************/ /* 设置时间程序 **/ /*******************************************/ void SetTime(unsigned char TIME[7]) //函数参数设为一个7元素数组 { bit EATemp; unsigned char temp=0; unsigned char TimeTemp[7]; EATemp=EA; //EA是开总中断的关键字。 CFG848|=0x01; //使用片内xram,CFG848查阅ADuC848英文说资料第25页。 for(temp=0;temp<7;temp++) TimeTemp[temp]=TIME[temp]; temp=0; //将初值归零,为循环调用此函数做准备。 TimeTemp[6]=((TimeTemp[6]/10)<<4)+(TimeTemp[6]); //转换成BCD码,为I2C总线的传输做准备。 TimeTemp[5]=((TimeTemp[5]/10)<<4)+(TimeTemp[5]); TimeTemp[4]=((TimeTemp[4]/10)<<4)+(TimeTemp[4]); TimeTemp[3]=((TimeTemp[3]/10)<<4)+(TimeTemp[3]); if((TimeTemp[2]&0xc0)==0x00) //Timetemp[2]是时的设置,由于有12小时制和24小时制,故分类讨论。 { TimeTemp[2]=((TimeTemp[2]/10)<<4)+(TimeTemp[2]); } else { if((TimeTemp[2]&0xc0)==0x01) //这里的条件恐怕永远都不能满足吧。 temp=0x40; else temp=0x60; //24小时计数的算法。 TimeTemp[2]&=0x3f; //不修改低6位的值。 TimeTemp[2]=((TimeTemp[2]/10)<<4)+(TimeTemp[2]); TimeTemp[2]|=temp; } TimeTemp[1]=((TimeTemp[1]/10)<<4)+(TimeTemp[1]); TimeTemp[0]=((TimeTemp[0]/10)<<4)+(TimeTemp[0]); TimeTemp[0]&=0x7f; //0x7f:关闭修改时间的参数。详见资料DS1307。 iicstart(); iicwriteda(0xd0); //0xd0:这是DS1307在总线上的物理地址。详见资料DS1307。 iicreadack(); //调用读应答函数。 iicwriteda(0x00); //0x00:这是接下来传送的数据存储到DS1307的物理地址。详见资料DS1307。这是传送方式规定的。 iicreadack(); //调用读应答函数。 iicwriteda(TimeTemp[0]); //进行时间设置数据的传送。 iicreadack(); iicwriteda(TimeTemp[1]); iicreadack(); iicwriteda(TimeTemp[2]); iicreadack(); iicwriteda(TimeTemp[3]); iicreadack(); iicwriteda(TimeTemp[4]); iicreadack(); iicwriteda(TimeTemp[5]); iicreadack(); iicwriteda(TimeTemp[6]); iicreadack(); iicstop(); //关闭总线通信。 iicdelay(1); //总线延时。 EA=EATemp; //与前面的语句呼应,确保EA的值保持不变。 } /******************************/ /* 时间设置使能函数 */ /******************************/ void SwitchRTC(unsigned char SWITCH) //SWITCH:1,禁止修改时间;0,可以修改时间。 { unsigned char temp; bit EATemp; EATemp=EA; //与后面的呼应,确保EA的值在执行下面的程序前后不被改变。 CFG848|=0x01; //使用片内xram,CFG848查阅ADuC848英文说资料第25页。 iicstart(); //打开I2C总线,准备通信。 iicwriteda(0xd0); iicreadack(); iicwriteda(0x00); iicreadack(); iicstop(); iicstart(); iicwriteda(0xd1); iicreadack(); temp=iicreadda(); //将I2C总线读取的数据赋给temp进行保存。 iicnack(); //关闭总线响应。 iicstop(); if(SWITCH) temp&=0x7f; else temp|=0x80; iicstart(); iicwriteda(0xd0); iicreadack(); iicwriteda(0x00); iicreadack(); iicwriteda(temp); iicreadack(); iicstop(); EA=EATemp; }