超级给力,为发扬电子DIY精神,方便大家制作,公开本制作的程序了,希望大家多多支持!
       占楼拉票了,ysjabcd的速度里程计,清新不落俗套,独一无二,可以做成产品哦!
       带单次里程显示,方便计算任意两地间路程.带时间显示,红外调时,解决了机械按键不能密闭防水的缺点,也可移植到不方便近距离调时的时钟。
       做一个这家伙装在您的自行车上,随时掌握速度时间,还是您自己动手制作的,那是相当的有面子!
       更多精彩http://forum.eepw.com.cn/thread/205904/1
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ISP_BYTE_READ    1  //ISP字节读
#define ISP_BYTE_PROGRAM 2  //ISP直接编程
#define ISP_SECTOR_ERASE 3  //ISP扇区擦除
/*以下是配置STC单片机的寄存器*/
/*相关资料在STC89C51RC的PDF的第35页开始*/
sfr ISP_DATA  = 0xE2;
sfr ISP_ADDRH = 0xE3;
sfr ISP_ADDRL = 0xE4;
sfr ISP_CMD   = 0xE5;
sfr ISP_TRIG  = 0xE6;
sfr ISP_CONTR = 0xE7;
uchar code table[]="km/h       km";
uchar code table1[]="        km";
sbit rs=P2^4;   // 液晶
sbit rw=P2^5;   // 液晶
sbit en=P2^6;   // 液晶
uint aa,time,s1,s11;
uchar num,bb,a,b,up,down;
uchar IRCOM[7];//红外数组
unsigned long int quan,s2,s21;     //
sbit ACC0 = ACC^0;    //1302
sbit ACC7 = ACC^7;    //1302
sbit IRIN = P3^2;         //红外接收器数据线
sbit T_CLK = P3^6; /*实时时钟时钟线引脚 */
sbit T_IO = P3^4; /*实时时钟数据线引脚 */
sbit T_RST = P3^5; /*实时时钟复位线引脚 */
uchar flag;
uchar sec, min, hour;
void Write_DS1302Init(void);
void display();
void delayhw(uchar x);  //x*0.14MS 红外延时
void delay(uint z);//液晶延时
/********************************************************************
* 功能 : EEPROM的扇区擦除
* 输入 : Address(擦除扇区的地址)
***********************************************************************/
void ISP_ERASE(Address)
{
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
 ISP_CONTR = 0x81;    
 ISP_CMD = ISP_SECTOR_ERASE; 
 ISP_TRIG = 0x46; //PDF手册中说先像 ISP_TRIG 中写入 0x46, 然后写入 0xb9
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_(); 
}
/********************************************************************
* 输入 : Address(想要读取EEPROM的地址)
*********************************************************************/
uint ISP_READ(Address)
{
 uchar Read_Data;
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
// EA = 0; 
 ISP_CONTR = 0x81;
 ISP_CMD = ISP_BYTE_READ;
 ISP_TRIG = 0x46;
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_();
 Read_Data = ISP_DATA;
 return Read_Data; 
}
/********************************************************************
* 输入 : Address为编程的地址,Data_temp为想要编程的值
***********************************************************************/
void ISP_PROGRAM(Address, Data_temp)
{
 ISP_DATA = Data_temp;
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
 ISP_CONTR = 0x81;
 ISP_CMD = ISP_BYTE_PROGRAM;
 ISP_TRIG = 0x46;
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_();  
}
void delay(uint z) //液晶延时
{
 uint x,y;
 for(x=110;x>0;x--)
  for(y=z;y>0;y--); 
}
void write_com(uchar com) //液晶写命令
{
 rs=0;
 P0=com;
 delay(1);
 en=1;
 delay(1);
 en=0; 
}
void write_data(uchar date) //液晶写数据
{
 rs=1;
 P0=date;
 delay(1);
 en=1;
 delay(1);
 en=0;
}
void init()
{
 quan=0;
 en=0;
 rw=0;
 aa=0;
 up=0;
 down=0;
 flag=0;
 write_com(0x38);
 write_com(0x0c);
 write_com(0x06);
 EA=1;    //开总中断
 EX0=1;    //开外部中断0
 IT0=1;    //外部中断设为下降沿触发
 ET0=1;     // 开定时器0中断
 TMOD=0x11;//定时器0设定为定时器模式
 TH0=(65536-5000)/256;
 TL0=(65536-5000)%256; //定时器0装初值5ms
 TR0=1;//启动定时器0 
 EX1=1;  //开外部中断1
 IT1=1;               //外部中断1设为下降沿触发
 flag=0;
}
void v_RTInputByte(uchar ucDa)  //往DS1302写入1Byte数据
{
 uchar i;
 ACC = ucDa;
 T_RST = 1;
 for(i=8; i>0; i--)
 {
  T_IO = ACC0;
  T_CLK = 1;
  T_CLK = 0;
  ACC = ACC >> 1;
 }
}
uchar uc_RTOutputByte(void)  //读取1byte数据
{
 uchar i;
 T_RST = 1;
 for(i=8; i>0; i--)
 {
  ACC = ACC >>1;
//  T_IO=1;
  ACC7 = T_IO;
  T_CLK = 1;
  T_CLK = 0;
 }
 return(ACC);
}
void v_W1302(uchar ucAddr, uchar ucDa) //输入   :   ucAddr: DS1302地址, ucDa: 要写的数据
{
 T_RST = 0;
 T_CLK = 0;
 T_RST = 1;
 v_RTInputByte(ucAddr);   // 写地址 
 _nop_();
 _nop_();
 v_RTInputByte(ucDa);     // 写1Byte数据
 T_CLK = 1;
 T_RST = 0;
}
uchar uc_R1302(uchar ucAddr)  // 读取DS1302某地址的数据
{
 uchar ucDa;
 T_RST = 0;
 T_CLK = 0;
 T_RST = 1;
 v_RTInputByte(ucAddr);    //写地址,命令
 _nop_();
 _nop_();
 ucDa = uc_RTOutputByte(); //读1Byte数据
 T_CLK = 1;
 T_RST = 0;
 return(ucDa);
}
void keyscan()      //设置时钟的键盘扫描程序
{
 if(flag!=0)
 {
  while(flag)
  {
   if(flag==1)
   {
    write_com(0x80+0x47);
    write_com(0x0f);
   }
   if(flag==2)
   {
    write_com(0x80+0x44);
   }
   if(flag==3)
   {
    write_com(0x80+0x41);
   }       //
    if(up==1)
    {
     if(flag==1)
     {
      sec++;
      if(sec==60)
       sec=0;
     }
     if(flag==2)
     {
      min++;
      if(min==60)
       min=0;
     }
     if(flag==3)
     {
      hour++;
      if(hour==24)
      hour=0;
     }
     up=0;
     display();
    }
 
    if(down==1)
    {
     if(flag==1)
     {
      sec--;
      if(sec==255)
       sec=59;
     }
     if(flag==2)
     {
      min--;
      if(min==255)
       min=59;
     }
     if(flag==3)
     {
      hour--;
      if(hour==255)
      hour=23;
     }
     down=0;
     display();
    }
//      display();
  }
 Write_DS1302Init();    
 }
}
uchar dectobcd(uchar dec)//  DEC码转换为BCD码
{
 uchar bcd;
 bcd = 0;
 while(dec >= 10)
 {              
  dec -= 10;                         
  bcd++;
 } 
 bcd <<= 4;
 bcd |= dec;
 return bcd;
}
uchar bcdtodec(uchar bcd)  // BCD码转换为DEC码
{
 uchar data1;
 data1 = bcd & 0x0f;     //取BCD低4位
 bcd = bcd & 0x70;       //剔除BCD的最高位和低4位。
 data1 += bcd >> 1;
 data1 += bcd >> 3;      //用位移代替乘法运算
 return data1;
}
void Write_DS1302Init(void)
{
 sec=dectobcd(sec);
 min=dectobcd(min);
 hour=dectobcd(hour);
 v_W1302(0x8e,0);
 v_W1302(0x80,sec); //写入秒;
 v_W1302(0x82,min); //写入分
 v_W1302(0x84,hour); //写入小时
}
void display()    //1302显示
{
 uchar hourshi,hourge,minshi,minge,secshi,secge;
 hourshi=hour/10;
 hourge=hour%10;
 minshi=min/10;
 minge=min%10;
 secshi=sec/10;
 secge=sec%10;
 write_com(0x80+0x40);
 write_data(0x30+hourshi);
 write_data(0x30+hourge);
 write_data(0x3a);
 write_data(0x30+minshi);
 write_data(0x30+minge);
 write_data(0x3a);
 write_data(0x30+secshi);
 write_data(0x30+secge);  
}
void Run_DS1302(void)   // 读出DS1302中的数据,并在液晶上进行显示
{ uchar dd;
    for(dd=10;dd>0;dd--)   //加入循环,防止速度变化太快,不方便度数
 {
   sec = bcdtodec(uc_R1302(0x81));    //读出DS1302中的秒;
   min = bcdtodec(uc_R1302(0x83));    //读出DS1302中的分
   hour = bcdtodec(uc_R1302(0x85));   //读出DS1302中的小时
   if(hour==0)         //时间校准,每天0:30:30减少15s
   {           
    if(min==30)
    {
     if(sec==45)
     {
       while(sec)
      {
      sec = bcdtodec(uc_R1302(0x81));
      }
      sec=46;
      Write_DS1302Init();
     }
    }
   }
   display();
   keyscan();
   }
} 
void write_su(uint dat)//速度显示
{
 uchar shi,ge;
 shi=dat%100/10;
 ge=dat%10;
 write_com(0x80);
 write_data(0x20);
 write_com(0x81);
 write_data(0x30+shi);
 write_data(0x30+ge);
}
void write_s1(uint s1)//一次里程显示
{
 uchar bai,shi,ge,dian;
// wan=s1/10000;     //s1为一次路程,一般不会超过几百km,故无万千位
// qian=s1%10000/1000; 
 bai=s1%10000/1000;
 shi=s1%1000/100;
 ge=s1%100/10;
 dian=s1%10;
 write_com(0x89);
 write_data(0x30+bai);       
 write_data(0x30+shi);
 write_data(0x30+ge);
 write_data(0x2e);
 write_data(0x30+dian);
}
void write_s2(uint s2)//总里程显示
{
 uchar wan,qian,bai,shi,ge,dian;
 wan=s2%1000000/100000;
 qian=s2%100000/10000;
 bai=s2%10000/1000;
 shi=s2%1000/100;
 ge=s2%100/10;
 dian=s2%10;
 write_com(0x80+0x49);
 write_data(0x30+wan);
 write_data(0x30+qian);
 write_data(0x30+bai);
 write_data(0x30+shi);
 write_data(0x30+ge);
 write_data(0x2e);
 write_data(0x30+dian);
}
void main()
{
 init();
 write_com(0x83);
 for(num=0;num<13;num++)    //先显示固定的km/h       km
 {
  write_data(table[num]);
  delay(2);
 }
 write_com(0x80+0x46);
 for(num=0;num<10;num++)       //先显示固定的km
 {
  write_data(table1[num]);
  delay(2);
 }
//   ISP_ERASE(0x2000);     //
//   ISP_PROGRAM(0x2000, 0x05);
//   ISP_ERASE(0x2c01);
//   ISP_PROGRAM(0x2c01, 0x40);
 a=ISP_READ(0x2003);
 delay(20);
 b=ISP_READ(0x2207);   
 s21=a*256+b;   //读出的两个八位合成一个十六位
// s21=248;   //要改,用来清空第一次写入eeprom的数据
 write_s2(s21); //显示开机总里程
 while(1)
 {
  s1=quan*0.65;   //s1为一次路程 这里一圈按0.65m算
  if(s11!=s1)        //如果s1发生了变化
  {
   s2=s21+s1;     //s2为总里程 ,s21为开机读出的里程
   a=s2/256;     //s2为16位,把其分为两个八位分别写入存储器
   b=s2%256;
   ISP_ERASE(0x2003);     // 扇区擦除。无字节擦除
   ISP_PROGRAM(0x2003, a);
   delay(20);
   ISP_ERASE(0x2207);
   ISP_PROGRAM(0x2207, b);  // 将两组数据写向不同扇区
   write_s2(s2);
  }
  s11=s1;
  write_s1(s1);  // 一次路程显示
  delay(100);
  write_com(0x81); //换行
  write_su(bb);   //速度显示
  bb=0;
  Run_DS1302(); 
 } 
}
void timer0() interrupt 1
{ 
 TH0=(65536-5000)/256;
 TL0=(65536-5000)%256; //定时器0装初值5ms
 aa++;
}
void exter1() interrupt 2
{
 if(aa>=200)//即车轮转一圈时间超过1秒,认为速度为零
  bb=0;
 if(aa<200)
 {
  time=aa*5;//定时器为5ms,为避免带小数点,此乃为正常时间的1000倍
  bb=65*36/time;//65为车圈周长的100倍,单位为米,bb为整型变量,舍掉速度小数点
 }
 aa=0;
 quan++;    
} 
void exter0() interrupt 0
{
     unsigned char j,k,N=0;
     EX1 = 0;   
  delayhw(15);
  if (IRIN==1) 
     { EX1 =1;
    return;
   } 
                           //确认IR信号出现
  while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
    {delayhw(1);}
 for (j=0;j<4;j++)         //收集四组数据
 { 
  for (k=0;k<8;k++)        //每组数据有8位
  {
   while (IRIN)            //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
     {delayhw(1);}
    while (!IRIN)          //等 IR 变为高电平
     {delayhw(1);}
     while (IRIN)           //计算IR高电平时长
      {
    delayhw(1);
    N++;           
    if (N>=30)
  { EX1=1;
  return;}                  //0.14ms计数过长自动离开。
      }                        //高电平计数完毕                
     IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
     if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}  //数据最高位补“1”
     N=0;
  }//end for k
 }//end for j
   
   if (IRCOM[2]!=~IRCOM[3])
   { EX1=1;
     return; }
   IRCOM[5]=IRCOM[2] & 0x0F;     //取键码的低四位
   IRCOM[6]=IRCOM[2] >> 4;       //右移4次,高四位变为低四位
   if(IRCOM[5]>9)
    { IRCOM[5]=IRCOM[5]+0x37;}
   else
   IRCOM[5]=IRCOM[5]+0x30;
   if(IRCOM[6]>9)
    { IRCOM[6]=IRCOM[6]+0x37;}
   else
   IRCOM[6]=IRCOM[6]+0x30;    
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x35)
   {
     flag=flag+1;
     if(flag==4)
     {
     write_com(0x0c);
      flag=0;
      }
   }
  }
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x34)
   {
    down=1;
   }
  }  
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x30)
   {
     up=1;
   }
  }
     EX1 = 1;
  return;
}
void delayhw(unsigned char x)    //x*0.14MS  红外延时
{
 unsigned char i;
  while(x--)
 {
  for (i = 0; i<13; i++) {}
 }
}#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ISP_BYTE_READ    1  //ISP字节读
#define ISP_BYTE_PROGRAM 2  //ISP直接编程
#define ISP_SECTOR_ERASE 3  //ISP扇区擦除
/*以下是配置STC单片机的寄存器*/
/*相关资料在STC89C51RC的PDF的第35页开始*/
sfr ISP_DATA  = 0xE2;
sfr ISP_ADDRH = 0xE3;
sfr ISP_ADDRL = 0xE4;
sfr ISP_CMD   = 0xE5;
sfr ISP_TRIG  = 0xE6;
sfr ISP_CONTR = 0xE7;
uchar code table[]="km/h       km";
uchar code table1[]="        km";
sbit rs=P2^4;   // 液晶
sbit rw=P2^5;   // 液晶
sbit en=P2^6;   // 液晶
uint aa,time,s1,s11;
uchar num,bb,a,b,up,down;
uchar IRCOM[7];//红外数组
unsigned long int quan,s2,s21;     //
sbit ACC0 = ACC^0;    //1302
sbit ACC7 = ACC^7;    //1302
sbit IRIN = P3^2;         //红外接收器数据线
sbit T_CLK = P3^6; /*实时时钟时钟线引脚 */
sbit T_IO = P3^4; /*实时时钟数据线引脚 */
sbit T_RST = P3^5; /*实时时钟复位线引脚 */
uchar flag;
uchar sec, min, hour;
void Write_DS1302Init(void);
void display();
void delayhw(uchar x);  //x*0.14MS 红外延时
void delay(uint z);//液晶延时
/********************************************************************
* 功能 : EEPROM的扇区擦除
* 输入 : Address(擦除扇区的地址)
***********************************************************************/
void ISP_ERASE(Address)
{
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
 ISP_CONTR = 0x81;    
 ISP_CMD = ISP_SECTOR_ERASE; 
 ISP_TRIG = 0x46; //PDF手册中说先像 ISP_TRIG 中写入 0x46, 然后写入 0xb9
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_(); 
}
/********************************************************************
* 输入 : Address(想要读取EEPROM的地址)
*********************************************************************/
uint ISP_READ(Address)
{
 uchar Read_Data;
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
// EA = 0; 
 ISP_CONTR = 0x81;
 ISP_CMD = ISP_BYTE_READ;
 ISP_TRIG = 0x46;
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_();
 Read_Data = ISP_DATA;
 return Read_Data; 
}
/********************************************************************
* 输入 : Address为编程的地址,Data_temp为想要编程的值
***********************************************************************/
void ISP_PROGRAM(Address, Data_temp)
{
 ISP_DATA = Data_temp;
 ISP_ADDRL = Address;
 ISP_ADDRH = Address >> 8;
 ISP_CONTR = 0x81;
 ISP_CMD = ISP_BYTE_PROGRAM;
 ISP_TRIG = 0x46;
 ISP_TRIG = 0xb9;
 _nop_();
 _nop_();  
}
void delay(uint z) //液晶延时
{
 uint x,y;
 for(x=110;x>0;x--)
  for(y=z;y>0;y--); 
}
void write_com(uchar com) //液晶写命令
{
 rs=0;
 P0=com;
 delay(1);
 en=1;
 delay(1);
 en=0; 
}
void write_data(uchar date) //液晶写数据
{
 rs=1;
 P0=date;
 delay(1);
 en=1;
 delay(1);
 en=0;
}
void init()
{
 quan=0;
 en=0;
 rw=0;
 aa=0;
 up=0;
 down=0;
 flag=0;
 write_com(0x38);
 write_com(0x0c);
 write_com(0x06);
 EA=1;    //开总中断
 EX0=1;    //开外部中断0
 IT0=1;    //外部中断设为下降沿触发
 ET0=1;     // 开定时器0中断
 TMOD=0x11;//定时器0设定为定时器模式
 TH0=(65536-5000)/256;
 TL0=(65536-5000)%256; //定时器0装初值5ms
 TR0=1;//启动定时器0 
 EX1=1;  //开外部中断1
 IT1=1;               //外部中断1设为下降沿触发
 flag=0;
}
void v_RTInputByte(uchar ucDa)  //往DS1302写入1Byte数据
{
 uchar i;
 ACC = ucDa;
 T_RST = 1;
 for(i=8; i>0; i--)
 {
  T_IO = ACC0;
  T_CLK = 1;
  T_CLK = 0;
  ACC = ACC >> 1;
 }
}
uchar uc_RTOutputByte(void)  //读取1byte数据
{
 uchar i;
 T_RST = 1;
 for(i=8; i>0; i--)
 {
  ACC = ACC >>1;
//  T_IO=1;
  ACC7 = T_IO;
  T_CLK = 1;
  T_CLK = 0;
 }
 return(ACC);
}
void v_W1302(uchar ucAddr, uchar ucDa) //输入   :   ucAddr: DS1302地址, ucDa: 要写的数据
{
 T_RST = 0;
 T_CLK = 0;
 T_RST = 1;
 v_RTInputByte(ucAddr);   // 写地址 
 _nop_();
 _nop_();
 v_RTInputByte(ucDa);     // 写1Byte数据
 T_CLK = 1;
 T_RST = 0;
}
uchar uc_R1302(uchar ucAddr)  // 读取DS1302某地址的数据
{
 uchar ucDa;
 T_RST = 0;
 T_CLK = 0;
 T_RST = 1;
 v_RTInputByte(ucAddr);    //写地址,命令
 _nop_();
 _nop_();
 ucDa = uc_RTOutputByte(); //读1Byte数据
 T_CLK = 1;
 T_RST = 0;
 return(ucDa);
}
void keyscan()      //设置时钟的键盘扫描程序
{
 if(flag!=0)
 {
  while(flag)
  {
   if(flag==1)
   {
    write_com(0x80+0x47);
    write_com(0x0f);
   }
   if(flag==2)
   {
    write_com(0x80+0x44);
   }
   if(flag==3)
   {
    write_com(0x80+0x41);
   }       //
    if(up==1)
    {
     if(flag==1)
     {
      sec++;
      if(sec==60)
       sec=0;
     }
     if(flag==2)
     {
      min++;
      if(min==60)
       min=0;
     }
     if(flag==3)
     {
      hour++;
      if(hour==24)
      hour=0;
     }
     up=0;
     display();
    }
 
    if(down==1)
    {
     if(flag==1)
     {
      sec--;
      if(sec==255)
       sec=59;
     }
     if(flag==2)
     {
      min--;
      if(min==255)
       min=59;
     }
     if(flag==3)
     {
      hour--;
      if(hour==255)
      hour=23;
     }
     down=0;
     display();
    }
//      display();
  }
 Write_DS1302Init();    
 }
}
uchar dectobcd(uchar dec)//  DEC码转换为BCD码
{
 uchar bcd;
 bcd = 0;
 while(dec >= 10)
 {              
  dec -= 10;                         
  bcd++;
 } 
 bcd <<= 4;
 bcd |= dec;
 return bcd;
}
uchar bcdtodec(uchar bcd)  // BCD码转换为DEC码
{
 uchar data1;
 data1 = bcd & 0x0f;     //取BCD低4位
 bcd = bcd & 0x70;       //剔除BCD的最高位和低4位。
 data1 += bcd >> 1;
 data1 += bcd >> 3;      //用位移代替乘法运算
 return data1;
}
void Write_DS1302Init(void)
{
 sec=dectobcd(sec);
 min=dectobcd(min);
 hour=dectobcd(hour);
 v_W1302(0x8e,0);
 v_W1302(0x80,sec); //写入秒;
 v_W1302(0x82,min); //写入分
 v_W1302(0x84,hour); //写入小时
}
void display()    //1302显示
{
 uchar hourshi,hourge,minshi,minge,secshi,secge;
 hourshi=hour/10;
 hourge=hour%10;
 minshi=min/10;
 minge=min%10;
 secshi=sec/10;
 secge=sec%10;
 write_com(0x80+0x40);
 write_data(0x30+hourshi);
 write_data(0x30+hourge);
 write_data(0x3a);
 write_data(0x30+minshi);
 write_data(0x30+minge);
 write_data(0x3a);
 write_data(0x30+secshi);
 write_data(0x30+secge);  
}
void Run_DS1302(void)   // 读出DS1302中的数据,并在液晶上进行显示
{ uchar dd;
    for(dd=10;dd>0;dd--)   //加入循环,防止速度变化太快,不方便度数
 {
   sec = bcdtodec(uc_R1302(0x81));    //读出DS1302中的秒;
   min = bcdtodec(uc_R1302(0x83));    //读出DS1302中的分
   hour = bcdtodec(uc_R1302(0x85));   //读出DS1302中的小时
   if(hour==0)         //时间校准,每天0:30:30减少15s
   {           
    if(min==30)
    {
     if(sec==45)
     {
       while(sec)
      {
      sec = bcdtodec(uc_R1302(0x81));
      }
      sec=46;
      Write_DS1302Init();
     }
    }
   }
   display();
   keyscan();
   }
} 
void write_su(uint dat)//速度显示
{
 uchar shi,ge;
 shi=dat%100/10;
 ge=dat%10;
 write_com(0x80);
 write_data(0x20);
 write_com(0x81);
 write_data(0x30+shi);
 write_data(0x30+ge);
}
void write_s1(uint s1)//一次里程显示
{
 uchar bai,shi,ge,dian;
// wan=s1/10000;     //s1为一次路程,一般不会超过几百km,故无万千位
// qian=s1%10000/1000; 
 bai=s1%10000/1000;
 shi=s1%1000/100;
 ge=s1%100/10;
 dian=s1%10;
 write_com(0x89);
 write_data(0x30+bai);       
 write_data(0x30+shi);
 write_data(0x30+ge);
 write_data(0x2e);
 write_data(0x30+dian);
}
void write_s2(uint s2)//总里程显示
{
 uchar wan,qian,bai,shi,ge,dian;
 wan=s2%1000000/100000;
 qian=s2%100000/10000;
 bai=s2%10000/1000;
 shi=s2%1000/100;
 ge=s2%100/10;
 dian=s2%10;
 write_com(0x80+0x49);
 write_data(0x30+wan);
 write_data(0x30+qian);
 write_data(0x30+bai);
 write_data(0x30+shi);
 write_data(0x30+ge);
 write_data(0x2e);
 write_data(0x30+dian);
}
void main()
{
 init();
 write_com(0x83);
 for(num=0;num<13;num++)    //先显示固定的km/h       km
 {
  write_data(table[num]);
  delay(2);
 }
 write_com(0x80+0x46);
 for(num=0;num<10;num++)       //先显示固定的km
 {
  write_data(table1[num]);
  delay(2);
 }
//   ISP_ERASE(0x2000);     //
//   ISP_PROGRAM(0x2000, 0x05);
//   ISP_ERASE(0x2c01);
//   ISP_PROGRAM(0x2c01, 0x40);
 a=ISP_READ(0x2003);
 delay(20);
 b=ISP_READ(0x2207);   
 s21=a*256+b;   //读出的两个八位合成一个十六位
// s21=248;   //要改,用来清空第一次写入eeprom的数据
 write_s2(s21); //显示开机总里程
 while(1)
 {
  s1=quan*0.65;   //s1为一次路程 这里一圈按0.65m算
  if(s11!=s1)        //如果s1发生了变化
  {
   s2=s21+s1;     //s2为总里程 ,s21为开机读出的里程
   a=s2/256;     //s2为16位,把其分为两个八位分别写入存储器
   b=s2%256;
   ISP_ERASE(0x2003);     // 扇区擦除。无字节擦除
   ISP_PROGRAM(0x2003, a);
   delay(20);
   ISP_ERASE(0x2207);
   ISP_PROGRAM(0x2207, b);  // 将两组数据写向不同扇区
   write_s2(s2);
  }
  s11=s1;
  write_s1(s1);  // 一次路程显示
  delay(100);
  write_com(0x81); //换行
  write_su(bb);   //速度显示
  bb=0;
  Run_DS1302(); 
 } 
}
void timer0() interrupt 1
{ 
 TH0=(65536-5000)/256;
 TL0=(65536-5000)%256; //定时器0装初值5ms
 aa++;
}
void exter1() interrupt 2
{
 if(aa>=200)//即车轮转一圈时间超过1秒,认为速度为零
  bb=0;
 if(aa<200)
 {
  time=aa*5;//定时器为5ms,为避免带小数点,此乃为正常时间的1000倍
  bb=65*36/time;//65为车圈周长的100倍,单位为米,bb为整型变量,舍掉速度小数点
 }
 aa=0;
 quan++;    
} 
void exter0() interrupt 0
{
     unsigned char j,k,N=0;
     EX1 = 0;   
  delayhw(15);
  if (IRIN==1) 
     { EX1 =1;
    return;
   } 
                           //确认IR信号出现
  while (!IRIN)            //等IR变为高电平,跳过9ms的前导低电平信号。
    {delayhw(1);}
 for (j=0;j<4;j++)         //收集四组数据
 { 
  for (k=0;k<8;k++)        //每组数据有8位
  {
   while (IRIN)            //等 IR 变为低电平,跳过4.5ms的前导高电平信号。
     {delayhw(1);}
    while (!IRIN)          //等 IR 变为高电平
     {delayhw(1);}
     while (IRIN)           //计算IR高电平时长
      {
    delayhw(1);
    N++;           
    if (N>=30)
  { EX1=1;
  return;}                  //0.14ms计数过长自动离开。
      }                        //高电平计数完毕                
     IRCOM[j]=IRCOM[j] >> 1;                  //数据最高位补“0”
     if (N>=8) {IRCOM[j] = IRCOM[j] | 0x80;}  //数据最高位补“1”
     N=0;
  }//end for k
 }//end for j
   
   if (IRCOM[2]!=~IRCOM[3])
   { EX1=1;
     return; }
   IRCOM[5]=IRCOM[2] & 0x0F;     //取键码的低四位
   IRCOM[6]=IRCOM[2] >> 4;       //右移4次,高四位变为低四位
   if(IRCOM[5]>9)
    { IRCOM[5]=IRCOM[5]+0x37;}
   else
   IRCOM[5]=IRCOM[5]+0x30;
   if(IRCOM[6]>9)
    { IRCOM[6]=IRCOM[6]+0x37;}
   else
   IRCOM[6]=IRCOM[6]+0x30;    
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x35)
   {
     flag=flag+1;
     if(flag==4)
     {
     write_com(0x0c);
      flag=0;
      }
   }
  }
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x34)
   {
    down=1;
   }
  }  
 if(IRCOM[6]==0x34)
  {
    if(IRCOM[5]==0x30)
   {
     up=1;
   }
  }
     EX1 = 1;
  return;
}
void delayhw(unsigned char x)    //x*0.14MS  红外延时
{
 unsigned char i;
  while(x--)
 {
  for (i = 0; i<13; i++) {}
 }
}