21ic中很多帖子给我很多启示。 #include <at89x52.h>
sbit turnLin = P1^0;//转向灯信号输入,接车头开关,低电平有效 sbit shuju = P1^1;//595共用数据线 sbit shizhong = P1^2;//时速屏595时钟线 sbit gengxin = P1^3;//时速屏595更新线 sbit shizhong2 = P1^4;//里程屏时钟线 sbit turnRin = P1^5;//转向灯信号输入,接车头开关,低电平有效 sbit turnleft = P1^6;//左转弯灯驱动信号 sbit turnright = P1^7;//右转弯灯驱动信号
sbit beep = P0^0;//喇叭信号输出 sbit beepin = P2^0;//喇叭控制信号输入 sbit ultrasound=P2^1;//超声波驱动输出
unsigned char sled1,sled2,sled3,sled4,sztj,lztj,valupd,xxd,datacount,roadblock;//串行LED扫描数据,状态机,更新缓冲用 unsigned char lichen1,lichen2,lichen3,lichen4,zxd,beepdly,beepf,up_down,bepfw;//里程数据 unsigned int T1_ISR_count,speed,reboundtime;//T1定时器溢出计数,速度变量 unsigned long plusewidth,plusecount,distance,totalwidth;//脉冲宽度值,单位微秒 unsigned char code sledsg[]={0x28,0xEB,0x32,0xA2,0xE1,0xA4,0x24,0xEA, 0x20,0xA0,0x61,0x7f,0xF7,0xff};//串行LED段码 void init(void) //初始化函数,就是开机首先要做的事情,init是自己起的名字 { TMOD=0x11; //两个定时器工作于方式1 PX0=1; //计时定时器中断优先 TR1=1; //定时器1启动 TR0=1; //定时器0启动 IT0=1; //外部中断0下降沿有效 IE=0x8B; //允许定时器及外部0中断 beepf=25; //喇叭频率设置 } //这段程序启动了芯片中的两个定时器
void send595(unsigned char dat) //595发送数据子程序,扫描程序调用 { shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x80;//将最高位(MSB)放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x40;//将第6位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x20;//将第5位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x10;//将第4位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x08;//将第3位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x04;//将第2位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x02;//将第1位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x01;//将第0位数据放到数据线上 shizhong=1; //产生上升沿,将数据移入595 shizhong=0; //拉低时钟线,传输完成 }
void sendlic(unsigned char dat)//里程屏发送数据子程序,扫描程序调用 { shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x80;//将最高位(MSB)放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x40;//将第6位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x20;//将第5位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x10;//将第4位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x08;//将第3位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x04;//将第2位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x02;//将第1位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,好准备产生上升沿 shuju=dat&0x01;//将第0位数据放到数据线上 shizhong2=1; //产生上升沿,将数据移入595 shizhong2=0; //拉低时钟线,传输完成 }
void sledscan(void) //时速LED模块扫描子程序,定时器调用 { switch(sztj) //切换状态机 { case 0: gengxin=0; //锁定595输出 send595(0x03); //发送共阳控制值 send595(sledsg[sled1]); //发送要显示的数据 gengxin=1; //打开更新 gengxin=0; //锁定595输出 sztj=1; //转移状态 break; case 1: gengxin=0; //锁定595输出 send595(0x0c); //第二位LED共阳控制值 send595(sledsg[sled4]); //发送要显示的数据 gengxin=1; //更新595输出 gengxin=0; //锁定595输出 sztj=2; //转移状态 break; case 2: gengxin=0; send595(0x30); send595(xxd&sledsg[sled3]); //与0xdf,加上小数点 gengxin=1; gengxin=0; //锁定595输出 sztj=3; break; case 3: gengxin=0; send595(0xc0); send595(sledsg[sled2]); gengxin=1; gengxin=0; //锁定595输出 sztj=0; break; default: sztj=0; //异常时捕获状态机 break; } }
void lichenscan(void) //里程LED模块扫描子程序,定时器调用 { switch(lztj) //切换状态机 { case 0: gengxin=0; //锁定595输出 sendlic(0x03); //发送共阳控制值 sendlic(sledsg[lichen1]); //发送要显示的数据 gengxin=1; //打开更新 gengxin=0; //锁定595输出 lztj=1; //转移状态 break; case 1: gengxin=0; //锁定595输出 sendlic(0x0c); //第二位LED共阳控制值 sendlic(sledsg[lichen4]); //发送要显示的数据 gengxin=1; //更新595输出 gengxin=0; //锁定595输出 lztj=2; //转移状态 break; case 2: gengxin=0; sendlic(0x30); sendlic(xxd&sledsg[lichen3]); //与0xdf,加上小数点 gengxin=1; gengxin=0; //锁定595输出 lztj=3; break; case 3: gengxin=0; sendlic(0xc0); sendlic(sledsg[lichen2]); gengxin=1; gengxin=0; //锁定595输出 lztj=0; break; default: lztj=0; //异常时捕获状态机 break; } }
void speedtobcd(unsigned int spd)//速度到BCD码,传递参数:速度 { sled1=sled2=sled3=sled4=0; while(spd>=10000) { sled4++; spd=spd-10000; } while(spd>=1000) { sled3++; spd=spd-1000; } while(spd>=100) { sled2++; spd=spd-100; } while(spd>=10) { sled1++; spd=spd-10; } }
void getspeed(void) //取得数据函数,主循环调用 { if(T1_ISR_count>=100) //100*65536us都没有脉冲,则说明太慢 { speed=0; //太慢,速度置零 } else { speed=495599760/totalwidth*datacount;//计算速度,速度=距离常数/总脉冲宽度*脉冲数量 totalwidth=0;//总脉冲宽度复位 datacount=0;//脉冲数量复位 } speedtobcd(speed);//转换速度值到BCD码 if(sled4==0){sled4=13;} //无效零消隐 }
void distancetobcd(unsigned long disdata)//距离到BCD码,传递参数:距离 { lichen1=lichen2=lichen3=lichen4=0;//原值置零 while(disdata>=1000000000) { lichen4++; disdata=disdata-1000000000; } while(disdata>=100000000) { lichen3++; disdata=disdata-100000000; } while(disdata>=10000000) { lichen2++; disdata=disdata-10000000; } while(disdata>=1000000) { lichen1++; disdata=disdata-1000000; } }
void getdistance() { distance=plusecount*6883; //计算里程 distancetobcd(distance); //转换成BCD码 }
void int0int(void) interrupt 0 using 1 //外中断0函数,下降沿触发,霍尔信号 { EA=0; //关闭外部中断 TR1=0; //冻结定时器值 ((unsigned char *)&plusewidth)[0]=((unsigned char *)&T1_ISR_count)[0];//使用指针 ((unsigned char *)&plusewidth)[1]=((unsigned char *)&T1_ISR_count)[1];//快速拼合 ((unsigned char *)&plusewidth)[2]=TH1;//拼合低十六位 ((unsigned char *)&plusewidth)[3]=TL1;//拼合最低8位 datacount++;//计算收到了多少个脉冲 totalwidth=totalwidth+plusewidth;//总脉冲宽度=原总脉冲宽度+本次脉冲宽度 TL1=0;//定时器复位 TH1=0;//定时器复位 TR1=1;//重新启动定时器 T1_ISR_count=0;//溢出计数复位 plusecount++;//计算脉冲总数,用于计算行驶里程 EA=1;//开中断 }
void timer0 (void) interrupt 1 using 2 //定时器中断程序,定时时间到,自动运行此程序 { TH0=(65536-9984)/256; //这两行的数值代表每10000us运行一次此程序 TL0=(65536-9984)%256; //置定时值,每次时间到都要重新置定时值 sledscan(); //扫描时速LED模块,122个周期 lichenscan(); //扫描里程LED模块,122个周期 valupd++; //延时辅助变量,1个周期 if(!turnRin|!turnLin) //判断转向灯开关是否合上,6个周期 { zxd++; //转向灯闪烁延时变量自增 if(zxd>=25) //判断时间是否到250ms { zxd=0; //延时变量复位 if(!turnRin) //右转向开关合上吗 { turnright=!turnright; //闪烁 } if(!turnLin) //左转向灯开关合上吗 { turnleft=!turnleft; //闪烁 } } } }
void int1int(void) interrupt 2 using 3 //外中断1函数,下降沿触发,超声波信号 { TR2=0;//冻结定时器2 ((unsigned char *)(&reboundtime))[0]=TH2; ((unsigned char *)(&reboundtime))[1]=TL2;//使用指针快速读取T2定时值 roadblock=6800000/reboundtime; //路障距离计算:路障=声速×2÷回弹时间 TH2=0x00; TL2=0x00;//定时器值复位 }
void timer1 (void) interrupt 3 //定时器中断程序 { T1_ISR_count++; //定时器溢出计数 }
void timer2 (void) interrupt 5 { TR2=0;//65536ms还没有收到回波,停止定时器 TH2=0xff; TL2=0xff;//将65535值存入定时器 }
void hi(void) //开机动画程序 { unsigned char de1=20,de2,de3; //延时函数用临时变量 xxd=0xff; //关闭小数点 lichen1=lichen4=sled1=sled4=12; //显示"-Hi-" lichen2=sled2=11; //显示"-Hi-" lichen3=sled3=10; //显示"-Hi-" while(--de1) while(--de2) while(--de3); //延时 sled1=sled2=sled3=sled4=0; //测试0000-9999 de1=10; //测试0000-9999 while(--de1) { sled1=sled2=sled3=++sled4; //测试0000-9999 lichen1=lichen2=sled1; lichen3=lichen4=sled1; while(--de2) while(--de3); //延时 } xxd=0xdf; //打开小数点 } void main(void) //主函数 { init(); //初始化 hi(); //开机动画 while(1) { //判断模式是显示时速还是里程 if(valupd>=50) //时间到,计算速度 { getspeed(); //计算速度,占用2432个周期 getdistance(); //计算里程,占用2438个周期 valupd=0; //更新延时变量复位,占用2个周期 } if(turnLin) //转向灯控制信号,低电平有效 { turnleft=0; //开关未合上,关闭转向灯 } if(turnRin) //转向灯控制信号,低电平有效 { turnright=0; //开关未合上,关闭转向灯 } if(!beepin) //判断喇叭控制信号是否有效 { beepdly++; //延时辅助变量 if(beepdly>=beepf) //时间到 { beep=!beep; //输出方波 beepdly=0; //辅助变量复位 bepfw++; //扫频延时辅助变量 if(bepfw>=5) //控制扫频速度 { bepfw=0; //扫频辅助变量复位 if(up_down==0) //判断扫频方向 { beepf--; //增加频率 if(beepf<=10){up_down=1;} //到达阈值,反向 } else { beepf++; //降低频率 if(beepf>=40){up_down=0;} //到达阈值,反向 } } else{beep=1;} //喇叭控制信号无效,IO置1 } } } } |