📄 060305.c
字号:
//几点说明:关机可以让单片机真正休眠进入真正低功耗状态,但是由于液晶一直有电供应且不知其功耗,故能省多少电并不知道,当然可以通过一个管脚通过
//控制三极管的基极来给液晶供电,关机时给其断电
#include <at89x52.h>
#include"LCD1602.h"
#include"I2C.h"
sfr P1Port = 0x90;
sbit led1=P3^7;
sbit led2=P3^6;
sbit led3=P3^5;
sbit led4=P3^4;
sbit lcd_on=P2^7;//P2^7控制lcd的开关
//######################################################################################################################################
//I2C程序
//######################################################################################################################################
unsigned char wheel_radi;
unsigned short sec_add1;
unsigned char second1;
unsigned char minute;
unsigned char hour;
unsigned short sec_add2; //ms
unsigned int cal_sec_add2; //
unsigned int mil_temp;
unsigned int miles; //最大值为65536,即655.36km
unsigned int speed;
unsigned int max_speed;
unsigned int time_round; //保存一个时间里面包含了几个36ms
unsigned int temp_radi;
unsigned int totalmile=0;
unsigned int wspeed;//存放圈速度
unsigned char butt_down;
bit speedflag;
bit firstime_flag;//消除速度第一次效应
unsigned char timearray[]={0x30,0x30,0x3a,0x30,0x30,0x3a,0x30,0x30,0xff};
unsigned char speedarray[]={0x30,0x30,0x2e,0x30,0x6b,0x6d,0x2f,0x68,0xff};
unsigned char milesarray[]={0x30,0x30,0x30,0x2e,0x30,0x30,0x6b,0x6d,0xff};
unsigned char wspeedarray[]={0x30,0x30,0x30,0x72,0x2f,0x6d,0x69,0x6e,0xff};
void Delay1ms(unsigned char count)
{
unsigned char i,j;
for(i=0;i<count;i++)
for(j=0;j<33;j++);
}
void inttial_reg()
{
max_speed=0;
speedflag=0;
firstime_flag=0;
sec_add1=0;
second1=0;
minute=0;
hour=0; //时、分、秒、毫秒计数器,用来寄存行驶时间
sec_add2=0;
cal_sec_add2=0;
mil_temp=0;
miles=0;
speed=0;
time_round=0;
temp_radi=180*wheel_radi;
}
void initiall()
{
//warm up 延时
lcd_on=1;
Delay1ms(60);
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x02);
ack();
sta();
wri_one_char(0xa1);
ack();
wheel_radi=read();
no_ack();
stop();
inttial_reg();
TMOD=0x11;
TL0=0xb0;
TH0=0x3c;
TL1=0x30;
TH1=0xf8; //打开外中断0,定时器0和定时器1、总中断的中断允许
TCON=0x01; //将外中断0设置为跳变触发方式
//下面从外部存储器中读入车轮周长的值
//将中断设为下降沿,定时器模式设为1
//将定时器0用来计时,定时器1用来计相邻脉冲的时间间隔
//如果下一脉冲还没有到来而已经经过很长时间,则可以将速度置零
//$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
LCD_Initial();
}
void timer0 (void) interrupt 1 //计时程序,时间数据输出到LCD上
{
TL0=0xb0;
TH0=0x3c;
if (sec_add1==19) //定时时长50ms
{
sec_add1=0;
if (second1==59)
{
second1=0;
if (minute==59)
{
minute=0;
if (hour==9)
{
hour=0;
}
else
{
hour++;
}
}
else
{
minute++;
}
}
else
{
second1++;
}
}
else
{
sec_add1++;
}
}
void timer1 (void) interrupt 3 //定时器1的中断,对转一圈的时间进行计时
{
TL1=0x30;
TH1=0xf8; //定时时长2ms
sec_add2++;
if(sec_add2>2500){speed=0;wspeed=0;speedflag=1;}
else{speedflag=0;}
}
void pulse_in (void) interrupt 0
{
//将当前寄存器数值保存并置零,同时开启定时器
//Delay1ms(100);
mil_temp+=wheel_radi; //因为wheel_radi是以厘米为单位的,而且我们的显示精度到0.01km(即10m),故要和1000进行比较
if (mil_temp>=1000)
{
mil_temp-=1000;
miles++; //这里miles也是取的整数,单位也是10m,尽管最后在lcd上显示的是km/s
}
cal_sec_add2=sec_add2;
sec_add2=0;
if(speedflag==0)
{
speed=temp_radi/cal_sec_add2;
wspeed=30000/cal_sec_add2;
} //*************#########################*******************由于简化运算,这里的精度不可能很高,
else {
speed=0;
wspeed=0;
} //这里速度的单位是:百米/小时
if(firstime_flag==0){firstime_flag=1;speed=0;wspeed=0;}//消除速度第一次效应
if(speed>max_speed) max_speed=speed;
IE0=0; //清中断标志
}
//时间格式: hour(1bit) : minute (int) : second1 (int)
//速度: speed(3bits) 百米/小时------->**.*
//里程: miles 十米------>km .**
//这里很重要的一件事情就是将数据形式转换为可以送去显示的形式
void display()
{
timearray[1]=hour+0x30;
timearray[3]=minute/10+0x30;
timearray[4]=minute%10+0x30;
timearray[6]=second1/10+0x30;
timearray[7]=second1%10+0x30;
speedarray[0]=speed/100+0x30;
speedarray[1]=(speed/10)%10+0x30;
speedarray[3]=speed%10+0x30;
milesarray[0]=miles/10000+0x30;
milesarray[1]=(miles/1000)%10+0x30;
milesarray[2]=(miles/100)%10+0x30;
milesarray[4]=(miles/10)%10+0x30;
milesarray[5]=miles%10+0x30;
wspeedarray[0]=wspeed/100+0x30;
wspeedarray[1]=(wspeed/10)%10+0x30;
wspeedarray[2]=wspeed%10+0x30;
}
unsigned int cal_total_miles()
{
unsigned int stoa=0;
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x00);
ack();
sta();
wri_one_char(0xa1);
ack();
stoa=read();
no_ack();
stop();
stoa=stoa<<8;
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x01);
ack();
sta();
wri_one_char(0xa1);
ack();
stoa+=read();
no_ack();
stop();
stoa+=(miles/10);
return stoa;
}
void stoa_miles()
{
unsigned int stoa=0;
unsigned char stob;
stoa=cal_total_miles();
//上面程序将数据从存储器中读出加上当前里程,下面将数据回存到存储器中
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x01);
ack();
stob=stoa&0x00ff;
wri_one_char(stob);
ack();
stop();
Delay1ms(100);
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x00);
ack();
stob=stoa>>8;
wri_one_char(stob);
ack();
stop();
Delay1ms(100);
}
void disp_MILES_MSpeed() //显示最大速度以及总里程
{
unsigned int MilTemp;
unsigned char chartemp[9];
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
MilTemp=cal_total_miles();
chartemp[8]=0xff;
chartemp[4]=0x2e;
chartemp[6]=0x6b;
chartemp[7]=0x6d;
chartemp[5]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[3]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[2]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[1]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[0]=MilTemp%10+0x30;
GotoXY(4,0);
Print(chartemp);
//上面一段显示了总里程,下面一段将显示行驶中的最大速度
Delay1ms(100);
MilTemp=max_speed;
chartemp[8]=0xff;
chartemp[2]=0x2e;
chartemp[4]=0x6b;
chartemp[5]=0x6d;
chartemp[6]=0x2f;
chartemp[7]=0x68;
chartemp[3]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[1]=MilTemp%10+0x30;
MilTemp/=10;
chartemp[0]=MilTemp%10+0x30;
GotoXY(4,1);
Print(chartemp);
}
void disp_wheel_radi()
{
unsigned char tempchar2;
unsigned char tempchatable[]={0x47,0x52,0x49,0x54,0x48,0x3a,0xff};
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏
Delay1ms(100);
GotoXY(5,0);
Print(tempchatable);
tempchar2=wheel_radi;
tempchatable[2]=tempchar2%10+0x30;
tempchar2/=10;
tempchatable[1]=tempchar2%10+0x30;
tempchar2/=10;
tempchatable[0]=tempchar2%10+0x30;
tempchatable[3]=0x63;
tempchatable[4]=0x6d;
tempchatable[5]=0xff;
GotoXY(5,1);
Print(tempchatable);
}
void chan_radi() //改变车轮周长
{
bit changed_flag=0;
disp_wheel_radi();
//将当前周长显示在lcd上
EA=0;
do
{
if(!(P1Port&0x04))//如果发现UP键被按下
{
Delay1ms(100);//延时进行前沿消抖
if(!(P1Port&0x04))//确认UP键确实被按下一次
{
while(!(P1Port&0x04));//等待UP按键弹起
Delay1ms(100);//后沿消抖
wheel_radi++; //车轮周长增加1
changed_flag=1;//判断车轮周长变化了的标志
if(wheel_radi>230) wheel_radi=180;
if(wheel_radi<180) wheel_radi=180;//限制车轮周长在180~230cm之间
disp_wheel_radi();//将车轮周长在lcd上显示出来
}
}
if(!(P1Port&0x02))//判断MODE键是否被按下
{
Delay1ms(100);
led1=1;
if(!(P1Port&0x02))
{
while(!(P1Port&0x02));
Delay1ms(100);
break;
}
}
}while(1);
if(changed_flag)
{
changed_flag=0;
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x02);
ack();
wri_one_char(wheel_radi);
ack();
stop();
Delay1ms(100);
miles=0x0000;
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x00);
ack();
wri_one_char(0x00);
ack();
stop();
Delay1ms(100);
sta();
wri_one_char(0xa0);
ack();
wri_one_char(0x01);
ack();
wri_one_char(0x00);
ack();
stop();
inttial_reg();
}
EA=1;
}
void main (void)
{
bit dispflag1;
bit dispflag2;
bit MODE2flag;
unsigned int to_time;
initiall();
//led1=0;//测试用句
//led2=0;//测试用句
//led3=0;//测试用句
//led4=0;//测试用句
MODE2flag=0;
IE=0x8f; //开中断
TR0=1;
Delay1ms(1);
TR1=1;
do{
if(second1%2==0) dispflag1=0;
else dispflag1=1;
if(dispflag1!=dispflag2)
{
dispflag2=dispflag1;
display();
GotoXY(0,0);
Print(wspeedarray);
GotoXY(8,0);
Print(timearray);
GotoXY(0,1);
Print(speedarray);
GotoXY(8,1);
Print(milesarray);
}
butt_down=P1Port;
if(!(P1Port&0x01))//关机程序
{
EA=0;
for(to_time=6000;to_time>0;to_time--);
if(P1Port&0x01)break;
else{
stoa_miles();
LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏 shut down lcd
LCD_Write(0x08,1);//显示关
PCON+=0x02;//进入掉电方式
}
}
else if(!(P1Port&0x02))//判断是否MODE键被按下第一次,若是则进入下一步×××××××××××××××××××××××××
{
Delay1ms(100);//延时10ms,软件消除前沿抖动
if(P1Port&0x02)break;//再次判断,若MODE键没有被按下了第一次则退出
else{ //确实MODE键被按下了第一次
while(!(P1Port&0x02));//等待第一次按键弹起后,再处理
Delay1ms(100);//延时10ms,软件消除后沿抖动
disp_MILES_MSpeed();//显示总里程和本次骑行最大速度
for(to_time=120;to_time>0;to_time--)//延时一段时间,同时在本段时间内判断MODE键有没有第二次被按下
{
Delay1ms(100);
if(!(P1Port&0x02))//这后面的过程基本重复×××××××××××××××××××××××××的过程
{
Delay1ms(100);
if(P1Port&0x02)break;
else{ //若确实MODE键被按下了第二次
while(!(P1Port&0x02));//等待第二次按键弹起
MODE2flag=1;
Delay1ms(100);//软件消除后沿抖动
break;
}
}
}
}
}
if(MODE2flag){MODE2flag=0;chan_radi();}
}while(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -