目录
资料下载地址:基于51单片机的出租车计价器
一、项目功能
1、1602显示时间、日期、行驶距离、当前金额、和总价等信息
2、按键设置时间、日期、起步金额、历史数据查看等功能
3、通过霍尔传感器计算电机转速
二、原理图
三、仿真
系统刚上电,显示时间
点击开始按钮系统显示行驶公里、时间、费用、司机等待时间
通过霍尔传感器计算电机转速,从而计算出行驶路程
按下设置时间可以依次更改年月日、时分秒。
按下设置金额,可以对价格进行设置
四、程序
/*
1602液晶,是常用的显示器件,一共是16个管脚,其中有八个管脚是数据传输管脚,有三个管脚是数据命令使能端管脚,还有两组电源管脚,
其中一组电源管脚是给整个液晶进行供电的,还有一组电源是单纯的背景光电源,还剩下的最后一个管脚是对比度调节管脚,一般接上一个3K电
阻再接地即可。
*/
/*
数据显示的时候一般的处理:
首先,无论是数码管显示还是液晶显示,进行显示的时候绝对都是一个一个进行显示的,那么,比如说一个数据123,一百二十三,
进行显示的时候,要先显示1,然后是2,然后是3,那么怎么把数据提取出来??
提取百位 123/100=1
提取十位 123/10=12 12%10=2 “%”是取余的意思,像这个,就是12对10取余,换句话说,12除以10,然后取余数,就是2
提取个位 123%10=3 解释同上
取余的用法也有很多种,大家只要知道出现这个的时候,一般都是进行数据提取的就行
然后
如果您是数码管显示数据,将提取的数据放到段码数组里面送给IO即可,
如果是液晶显示,需要将数据转化成字符,因为液晶是字符屏,只能显示字符数据,数据0对应的字符是0x30,数据1对应的字符是0x31,
所以将提取出的数据直接加上0x30送给液晶即可,或者加上'0' 也是一样的
*/
void Display()
{
if(Page==0)
{
LCD1602_write(0,0x80);
LCD1602_writebyte("20");
if(state==1&&s0) LCD1602_writebyte(" ");
else
{
LCD1602_write(1,0x30+time_data_1[5]/10);
LCD1602_write(1,0x30+time_data_1[5]%10); //显示年
}
LCD1602_writebyte("/");
if(state==2&&s0) LCD1602_writebyte(" "); //显示月
else
{
LCD1602_write(1,0x30+time_data_1[4]/10);
LCD1602_write(1,0x30+time_data_1[4]%10);
}
LCD1602_writebyte("/");
if(state==3&&s0) LCD1602_writebyte(" "); //显示日
else
{
LCD1602_write(1,0x30+time_data_1[3]/10);
LCD1602_write(1,0x30+time_data_1[3]%10);
}
LCD1602_writebyte(" ");
switch(Conver_week(time_data_1[5],time_data_1[4],time_data_1[3]))
{
case 0: LCD1602_writebyte(" Sun"); break;
case 1: LCD1602_writebyte(" Mon"); break;
case 2: LCD1602_writebyte(" Tue"); break;
case 3: LCD1602_writebyte(" Wed"); break;
case 4: LCD1602_writebyte(" Thu"); break;
case 5: LCD1602_writebyte(" Fri"); break;
case 6: LCD1602_writebyte(" Sat"); break; //星期
}
LCD1602_write(0,0xC0);
LCD1602_writebyte(" ");
if(state==4&&s0) LCD1602_writebyte(" "); //显示时
else
{
LCD1602_write(1,0x30+time_data_1[2]/10);
LCD1602_write(1,0x30+time_data_1[2]%10);
}
LCD1602_writebyte(":");
if(state==5&&s0) LCD1602_writebyte(" "); //显示分
else
{
LCD1602_write(1,0x30+time_data_1[1]/10);
LCD1602_write(1,0x30+time_data_1[1]%10);
}
LCD1602_writebyte(":");
if(state==6&&s0) LCD1602_writebyte(" "); //显示分
else
{
LCD1602_write(1,0x30+time_data_1[0]/10);
LCD1602_write(1,0x30+time_data_1[0]%10);
}
LCD1602_writebyte(" ");
}
else if(Page==1||Page==2) //Page等于 1 2 代表的是,接客界面,1,开始计费,2,停止计费
{
LCD1602_write(0,0x80);
LCD1602_writebyte("S:");
LCD1602_write(1,0x30+Mileage/100000%10);
LCD1602_write(1,0x30+Mileage/10000%10);
LCD1602_write(1,0x30+Mileage/1000%10); //显示里程界面
// LCD1602_write(1,0x30+Mileage/100%10);
// LCD1602_write(1,0x30+Mileage/10%10);
// LCD1602_write(1,0x30+Mileage%10); //屏蔽这块是千米下数据,显示的时候直接显示千米数据了,千米下就不显示了
if(DJ_Star==0&&s0==0) LCD1602_writebyte("Km :");
else LCD1602_writebyte("Km Wt:"); //在电机停止的时候,根据s0变量进行闪烁
if((Waiting_Time/60)>9) LCD1602_write(1,0x30+(Waiting_Time/60)/10%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+(Waiting_Time/60)%10); //显示等待时间
LCD1602_writebyte("Min");
LCD1602_write(0,0xC0);
LCD1602_write(1,0x30+(Driving_time/60)/10%10);
LCD1602_write(1,0x30+(Driving_time/60)%10);
LCD1602_writebyte(":");
LCD1602_write(1,0x30+(Driving_time%60)/10%10);
LCD1602_write(1,0x30+(Driving_time%60)%10); //系统运行时间
LCD1602_writebyte(" ");
if(Page==2) LCD1602_writebyte("Off ");
else LCD1602_writebyte("On "); //Page等于 1 是 开始计费, 2 是不计费,这里显示On Off
LCD1602_write(1,0x5c);
if(Unit_price>999) LCD1602_write(1,0x30+Unit_price/1000%10);
else LCD1602_writebyte(" ");
if(Unit_price>99) LCD1602_write(1,0x30+Unit_price/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Unit_price/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Unit_price%10); //显示单价,该数据的个位数实际是小数位,这里注意一下
}
else if(Page==3||Page==4||Page==5||Page==6) //Page 等于 3 4 5 6 代表的是,设置,等待金额,白天价格,晚上价格还有起步价
{
LCD1602_write(0,0x80);
LCD1602_writebyte("Wp:"); //显示等待金额
if(Page==3&&s0) LCD1602_writebyte(" ");
else
{
if(Waiting_amount>99) LCD1602_write(1,0x30+Waiting_amount/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Waiting_amount/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Waiting_amount%10);
}
LCD1602_writebyte(" ");
LCD1602_writebyte("pD:"); //显示白天单价
if(Page==4&&s0) LCD1602_writebyte(" ");
else
{
if(Daytime_price>99) LCD1602_write(1,0x30+Daytime_price/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Daytime_price/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Daytime_price%10);
}
LCD1602_write(0,0xC0);
LCD1602_writebyte("Sp:"); //显示 起步价
if(Page==5&&s0) LCD1602_writebyte(" ");
else
{
if(Starting_price>99) LCD1602_write(1,0x30+Starting_price/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Starting_price/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Starting_price%10);
}
LCD1602_writebyte(" ");
LCD1602_writebyte("pN:"); //显示夜晚单价
if(Page==6&&s0) LCD1602_writebyte(" ");
else
{
if(Night_price>99) LCD1602_write(1,0x30+Night_price/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Night_price/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Night_price%10);
}
}
else if(Page==7) //Page等于7,代表的是
{
LCD1602_write(0,0x80);
LCD1602_writebyte("The total monney:"); //总金额
LCD1602_write(0,0xC0);
LCD1602_writebyte(" ");
LCD1602_write(1,0x5c); //显示人民币符号
if(Total_amount>9999) LCD1602_write(1,0x30+Total_amount/10000%10);
else LCD1602_writebyte(" ");
if(Total_amount>999) LCD1602_write(1,0x30+Total_amount/1000%10);
else LCD1602_writebyte(" ");
if(Total_amount>99) LCD1602_write(1,0x30+Total_amount/100%10);
else LCD1602_writebyte(" ");
LCD1602_write(1,0x30+Total_amount/10%10);
LCD1602_writebyte(".");
LCD1602_write(1,0x30+Total_amount%10); //显示总金额数据
LCD1602_writebyte(" ");
}
}
void read_time1() //实时读取DS1302中的时间数据
{
uchar i;
if(state==0) //等于 0 ,正常显示的时候,读取时间数据
{
time_data[0]=ds1302read(0x81);
time_data[1]=ds1302read(0x83);
time_data[2]=ds1302read(0x85);
time_data[3]=ds1302read(0x87);
time_data[4]=ds1302read(0x89);
time_data[5]=ds1302read(0x8D);
time_data_1[0]=time_data[0]/16*10+time_data[0]%16;
time_data_1[1]=time_data[1]/16*10+time_data[1]%16;
time_data_1[2]=time_data[2]/16*10+time_data[2]%16;
time_data_1[3]=time_data[3]/16*10+time_data[3]%16;
time_data_1[4]=time_data[4]/16*10+time_data[4]%16;
time_data_1[5]=time_data[5]/16*10+time_data[5]%16;
if(time_data_1[0]>59||time_data_1[0]<0)
{
ds1302write(0x8e,0x00);
ds1302write(0x80,0x80);
ds1302write(0x80,0);
ds1302write(0x8e,0x80);
}
}
else //否则就是写时间,将时间数据实时写进DS1302,修改数据
{
ds1302write(0x8e,0x00);
ds1302write(0x80,0x80);
for(i=0;i<7;i++)
{
time_data_2[i]=time_data_1[i]/10;
time_data_3[i]=time_data_1[i]%10;
}
for(i=0;i<7;i++){time_data_4[i]=time_data_2[i]*16+time_data_3[i];}
ds1302write(0x80,time_data_4[0]);
ds1302write(0x82,time_data_4[1]);
ds1302write(0x84,time_data_4[2]);
ds1302write(0x86,time_data_4[3]);
ds1302write(0x88,time_data_4[4]);
ds1302write(0x8C,time_data_4[5]);
}
}
/*按键操作的方式多种多样,在学校里学到的普遍都是判断按键按下,延时等待一下再次判断按键按
下,进行消抖,然后确定按键按下之后执行所要执行的,再死循环等待按键释放。这样写按键自然也
行,但是有一个弊端,就是按键如果不松开,程序就会一直卡在那里,所以这里我换了一种书写方
式,标志位的方式---> 按键松开的时候,将标志位置一,按键按下之后,不进行延时消抖再次判断,
而是判断标志位是否为 1 ,如果是 1 ,就说明在你按下之前按键是松开的,将标志位清零,执行一下
所要执行的操作,下面就算你按键是一直按着不松开的,因为标志位是 0 ,他也不会再次执行所要执
行的操作了,只有当按键松开之后将标志位置一。*/
void Key_Dispose1() //按键处理函数
{
if(!key1) //按键 1
{
if(key1_flag==1)
{
key1_flag=0;
if(Page<3)
{
Page=(Page+1)%3; //界面累加,等于 1 开始计费,2,停止计费
if(Page==1) //界面为 1 时,说明要开始计费了
{
DJ_Star=1; //开电机
Mileage = 0;
Mileage_float = 0 ; //清里程
Waiting_Time = 0 ;
Driving_time = 0 ; //清计时时间
Night_Temporary = 0 ;
Day_Temporary = 0 ;
}
if(Page==2)
{
Total_amount = Total_amount+Unit_price; //停止计费的时候,总金额累加一下
Memory_flag=1;
}
}
}
}
else key1_flag = 1;
if(!key2) //按键 2 ,停止电机按钮
{
if(key2_flag==1)
{
key2_flag=0;
DJ_Star=0;
}
}
else key2_flag = 1;
if(!key3) //按键 3 ,启动电机按钮
{
if(key3_flag==1)
{
key3_flag=0;
DJ_Star=1;
}
}
else key3_flag = 1;
if(!key4) //按键 4 设定时间按钮
{
if(key4_flag==1)
{
key4_flag=0;
if(Page==0) //只有当主界面的时候,设置时间按钮才是可以按下的
{
state=(state+1)%7; // 设置的有 年月日 时分秒
}
}
}
else key4_flag = 1;
if(!key5) //按键五是切换到设置金额的界面
{
if(key5_flag==1)
{
key5_flag=0;
if(Page<3)
{
if(Page==0&&state==0) Page = 3; //只有在待机界面,并且没有设置时间数据的时候,进行切换到该界面
}
else //页面不小于 3 ,那就是 3 4 5 6
{
if(Page<6) Page++; //累加
else
{
if(Page!=7) Page = 0; //当Page等于 6 的时候,该变量会被清零,返回主界面,这里加一个判断不等于 7 ,界面 7 是总金额显示
}
}
}
}
else key5_flag = 1;
if(!key6) //修改数据的有,时间数据,计费数据
{
if(key6_flag==1)
{
key6_flag=0;
if(Page==0) //判断修改时间部分,另外该按钮还是切换显示总金额按钮
{
if(state==0) //这里说明此时在主界面,并且没有进入设置时间状态,就切换显示总金额界面
{
Page=7; //直接等于 7 ,切换到显示总金额界面
}
else
{
switch(state)
{
case 0:break;
case 1:if(time_data_1[5]<99) time_data_1[5]++; break;
case 2:if(time_data_1[4]<12) time_data_1[4]++; break;
case 3:
if(time_data_1[4]==1||time_data_1[4]==3||time_data_1[4]==5||time_data_1[4]==7||time_data_1[4]==8||time_data_1[4]==10||time_data_1[4]==12)
{
if(time_data_1[3]<31) time_data_1[3]++;
}
else if(time_data_1[4]==4||time_data_1[4]==6||time_data_1[4]==9||time_data_1[4]==11)
{
if(time_data_1[3]<30) time_data_1[3]++;
}
else if((time_data_1[5]%4==0&&time_data_1[5]%100!=0)||(time_data_1[5]%400==0))
{
if(time_data_1[3]<29) time_data_1[3]++;
}
else
{
if(time_data_1[3]<28) time_data_1[3]++;
}
break;
case 4:if(time_data_1[2]<23) time_data_1[2]++; break;
case 5:if(time_data_1[1]<59) time_data_1[1]++; break;
case 6:if(time_data_1[0]<59) time_data_1[0]++; break;
}
}
}
else if(Page==3||Page==4||Page==5||Page==6) //这几个界面就是设置等待时间、白天价格、起步价、晚上价格
{
switch(Page)
{
case 0:break;
case 3:if(Waiting_amount<999) Waiting_amount++; break;
case 4:if(Daytime_price<999) Daytime_price++; break;
case 5:if(Starting_price<999) Starting_price++; break;
case 6:if(Night_price<999) Night_price++; break;
}
Memory_flag = 1;
}
else if(Page==7) //当处于总金额界面的时候,就去跳转到主界面待机
{
Page=0; //等于 0
}
}
}
else key6_flag = 1;
if(!key7) //设置 数据减 ,还有是在总金额界面的时候,清零数据按钮
{
if(key7_flag==1)
{
key7_flag=0;
if(Page==0)
{
if(state==0)
{
}
else
{
switch(state)
{
case 0:break;
case 1:if(time_data_1[5]>0) time_data_1[5]--; break;
case 2:if(time_data_1[4]>1) time_data_1[4]--; break;
case 3:if(time_data_1[3]>1) time_data_1[3]--; break;
case 4:if(time_data_1[2]>0) time_data_1[2]--; break;
case 5:if(time_data_1[1]>0) time_data_1[1]--; break;
case 6:if(time_data_1[0]>0) time_data_1[0]--; break;
}
}
}
else if(Page==3||Page==4||Page==5||Page==6) //这几个界面就是设置等待时间、白天价格、起步价、晚上价格
{
switch(Page)
{
case 0:break;
case 3:if(Waiting_amount>0) Waiting_amount--; break;
case 4:if(Daytime_price>0) Daytime_price--; break;
case 5:if(Starting_price>0) Starting_price--; break;
case 6:if(Night_price>0) Night_price--; break;
}
Memory_flag = 1;
}
else if(Page==7)
{
Memory_flag = 1;
Total_amount = 0 ; //在总金额界面,就清零该按钮
}
}
}
else key7_flag = 1;
}