功能:
0.本项目采用STC89C52作为单片机系统的控制MCU
1.LCD1602液晶分三种显示模式
a)显示实时速度和本次里程
b)显示当前时间
c)显示报警速度和总里程
2.超过报警速度将声光报警
3.功能按键介绍
a显示状态下:
'上’键——电机速度+1 '下’键——电机速度-1
'设置’键——电机启动/暂停
'切换’键——切换显示状态
b显示状态下:
'设置’键——进入时间设置
'切换’键——切换显示状态
*时间设置状态
'上’键——加1 '下’键——减1
'左’键/'右’键——更改设置坐标
'切换’键——确定
c显示状态下:
'设置’键——进入速度设置
'切换’键——切换显示状态
*报警速度设置状态
'上’键——加1 '下’键——减1
'左’键/'右’键——更改设置选项
'切换’键——确定
*总里程设置状态
'上’键/'下’键——清零
'左’键/'右’键——更改设置选项
'切换’键——确定
4.采用DC002作为电源接口可直接输入5V给整个系统供电
原理图:
PCB :
主程序:
#include <reg52.h>
#include "main.h"
#define DIAMETER 20 //直径,单位mm
float distance = 0; //单位m
float totalDistBuf = 0; //单位m
float rate = 0; //单位km/h
float totalDist = 0; //单位km
unsigned char rateAlarm = 30; //单位km/h
unsigned char second = 0;
unsigned char minute = 0;
unsigned long pulseCnt = 0;
bit dispFlag = 1;
bit setTimeFlag = 0;
bit setAlarmFlag = 0;
bit motorFlag = 0;
bit refreshFlag = 0;
bit writeFlag = 0;
bit isNewFlag = 1;
unsigned char pwmValue = 3;
unsigned char setIndex = 0;
enum{
DISP_RATE_MODE, DISP_TIME_MODE, SET_ALARM_MODE
} dispMode;
void main()
{
//初始化
LCD_Init();
DS1302_Init();
EEPROM_Init();
//EEPROM_WriteByte(IS_NEW_ADDR, 1); //将芯片设为新芯片
ReadEEPROM();
if (isNewFlag != 0) //新芯片
{
EEPROM_WriteByte(IS_NEW_ADDR, 0);
//给出初始值
rateAlarm = 30;
totalDist = 0;
WriteEEPROM();
}
DS1302_ReadTime();
Timer0_Init();
Timer1_Init();
EXT1_Init();
//开机显示
LCD_DispStr(0, 0, " Welcome! ");
DelayS(2);
LCD_Clear();
while(1)
{
//每秒钟更新数据
if (refreshFlag == 1)
{
distance = distance + DIAMETER * 2 * 3.14 * (float)pulseCnt / 1000 ; //单位m
totalDist = totalDist + DIAMETER * 2 * 3.14 * (float)pulseCnt / 1000; //单位km
rate = 3.6 * DIAMETER * 2 * 3.14 * (float)pulseCnt / 1000; //单位km/h
pulseCnt = 0;
EX1 = 1;
refreshFlag = 0;
}
//每分钟写一次EEPROM
if (writeFlag == 1)
{
if (totalDist != totalDistBuf) //里程是否发生变化
{
WriteEEPROM();
}
totalDistBuf = totalDist;
writeFlag = 0;
}
//显示函数
if (dispFlag == 1)
{
if (dispMode == DISP_RATE_MODE)
{
DispRate();
}
else if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 0)
{
DS1302_ReadTime();
DispTime(setIndex, setTimeFlag);
}
}
else if (dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag == 0)
{
// ReadEEPROM();
if (totalDist != totalDistBuf)
{
WriteEEPROM();
}
totalDistBuf = totalDist;
DispAlarm(setIndex, setAlarmFlag);
}
}
}
//超速报警
if (rate > rateAlarm)
{
BUZZER = 0;
}
else
{
BUZZER = 1;
}
KeyProcess();
}
}
void ReadEEPROM(void)
{
isNewFlag = EEPROM_ReadByte(IS_NEW_ADDR);
rateAlarm = EEPROM_ReadByte(IS_NEW_ADDR + 1);
totalDist = EEPROM_ReadByte(IS_NEW_ADDR + 2);
totalDist = ((unsigned int)totalDist << 8) | EEPROM_ReadByte(IS_NEW_ADDR + 3);
}
void WriteEEPROM(void)
{
EEPROM_WriteByte(IS_NEW_ADDR + 1, rateAlarm);
EEPROM_WriteByte(IS_NEW_ADDR + 2, (((unsigned int)totalDist & 0xFF00) >> 8));
EEPROM_WriteByte(IS_NEW_ADDR + 3, ((unsigned int)totalDist & 0x00FF));
}
void DispAlarm(unsigned char setIndex, bit setAlarmFlag)
{
static unsigned char xdata dispRow0[16];
static unsigned char xdata dispRow1[16];
if (setAlarmFlag == 1)
{
LCD_WriteCommand(0x0F, 0);
}
else
{
LCD_WriteCommand(0x0C, 0);
LCD_WriteCommand(0x0C, 0);
}
sprintf(dispRow0, "Alarm:%6.2fkm/h", (float)rateAlarm);
sprintf(dispRow1, "Total:%8.2fkm", (float)totalDist / 1000);
LCD_DispStr(0, 0, dispRow0);
LCD_DispStr(0, 1, dispRow1);
switch (setIndex)
{
case 1: LCD_LocateXY(8, 0); break;
case 2: LCD_LocateXY(13, 1); break;
default: ;
}
}
void DispRate()
{
static unsigned char xdata dispRow0[16];
static unsigned char xdata dispRow1[16];
sprintf(dispRow0, "Rate:%7.2fkm/h", rate);
sprintf(dispRow1, "Dist:%9.2fkm", distance / 1000);
LCD_DispStr(0, 0, dispRow0);
LCD_DispStr(0, 1, dispRow1);
}
void DispTime(unsigned char setIndex, bit setTimeFlag)
{
static unsigned char xdata dispRow0[] = " / / ";
static unsigned char xdata dispRow1[] = " : : ";
if (setTimeFlag == 1)
{
LCD_WriteCommand(0x0F, 0);
}
else
{
LCD_WriteCommand(0x0C, 0);
LCD_WriteCommand(0x0C, 0);
}
dispRow0[0] = timeBufDec[1] / 10 +'0';
dispRow0[1] = timeBufDec[1] % 10 +'0';
dispRow0[3] = timeBufDec[2] / 10 +'0';
dispRow0[4] = timeBufDec[2] % 10 +'0';
dispRow0[6] = timeBufDec[3] / 10 +'0';
dispRow0[7] = timeBufDec[3] % 10 +'0';
dispRow1[4] = timeBufDec[4] / 10 +'0';
dispRow1[5] = timeBufDec[4] % 10 +'0';
dispRow1[7] = timeBufDec[5] / 10 +'0';
dispRow1[8] = timeBufDec[5] % 10 +'0';
dispRow1[10] = timeBufDec[6] / 10 +'0';
dispRow1[11] = timeBufDec[6] % 10 +'0';
LCD_DispStr(0, 0, dispRow0);
LCD_DispStr(0, 1, dispRow1);
switch (timeBufDec[7])
{
case 1: LCD_DispStr(10, 0, " Sun. "); break;
case 2: LCD_DispStr(10, 0, " Mon. "); break;
case 3: LCD_DispStr(10, 0, " Tue. "); break;
case 4: LCD_DispStr(10, 0, " Wed. "); break;
case 5: LCD_DispStr(10, 0, "Thur. "); break;
case 6: LCD_DispStr(10, 0, " Fri. "); break;
case 7: LCD_DispStr(10, 0, " Sat. "); break;
default: ;
}
switch (setIndex)
{
case 1: LCD_LocateXY(1 , 0); break;
case 2: LCD_LocateXY(4 , 0); break;
case 3: LCD_LocateXY(7 , 0); break;
case 4: LCD_LocateXY(14, 0); break;
case 5: LCD_LocateXY(5 , 1); break;
case 6: LCD_LocateXY(8 , 1); break;
case 7: LCD_LocateXY(11, 1); break;
default: ;
}
}
void KeyProcess()
{
if (!KEY_SET) //设置键按下
{
DelayMs(10);
if (!KEY_SET)
{
if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 0)
{
setTimeFlag = 1;
setIndex = 1;
DispTime(setIndex, setTimeFlag);
}
}
else if(dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag == 0)
{
setAlarmFlag = 1;
setIndex = 1;
DispAlarm(setIndex, setAlarmFlag);
}
}
else
{
motorFlag = ~motorFlag;
}
}
while (!KEY_SET)
;
}
if (!KEY_UP) //上键按下
{
DelayMs(150);
if (!KEY_UP)
{
if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 1)
{
switch (setIndex)
{
case 1:
{
timeBufDec[1]++;
if (timeBufDec[1] >= 100)
{
timeBufDec[1] = 0;
}
break;
}
case 2:
{
timeBufDec[2]++;
if (timeBufDec[2] >= 13)
{
timeBufDec[2] = 1;
}
break;
}
case 3:
{
timeBufDec[3]++;
if (timeBufDec[3] >= YDay(timeBufDec[1], timeBufDec[2]) + 1)
{
timeBufDec[3] = 1;
}
break;
}
case 4:
{
timeBufDec[7]++;
if (timeBufDec[7] > 7)
{
timeBufDec[7] = 1;
}
break;
}
case 5:
{
timeBufDec[4]++;
if (timeBufDec[4] >= 24)
{
timeBufDec[4] = 0;
}
break;
}
case 6:
{
timeBufDec[5]++;
if (timeBufDec[5] >= 60)
{
timeBufDec[5] = 0;
}
break;
}
case 7:
{
timeBufDec[6]++;
if (timeBufDec[6] >= 60)
{
timeBufDec[6] = 0;
}
break;
}
default:;
}
DispTime(setIndex, setTimeFlag);
}
}
else if (dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag)
{
switch (setIndex)
{
case 1:
rateAlarm++;
if (rateAlarm > 200)
{
rateAlarm = 200;
}
break;
case 2:
totalDist = 0;
break;
}
DispAlarm(setIndex, setAlarmFlag);
}
}
else
{
if (pwmValue <= 11)
{
pwmValue++;
}
}
}
//while (!KEY_UP);
}
if (!KEY_DOWN) //下键按下
{
DelayMs(150);
if (!KEY_DOWN)
{
if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 1)
{
switch (setIndex)
{
case 1:
{
if (timeBufDec[1] == 0)
{
timeBufDec[1] = 100;
}
timeBufDec[1]--;
break;
}
case 2:
{
timeBufDec[2]--;
if (timeBufDec[2] < 1)
{
timeBufDec[2] = 12;
}
break;
}
case 3:
{
timeBufDec[3]--;
if (timeBufDec[3] < 1)
{
timeBufDec[3] = YDay(timeBufDec[1], timeBufDec[2]);
}
break;
}
case 4:
{
timeBufDec[7]--;
if (timeBufDec[7] < 1)
{
timeBufDec[7] = 7;
}
break;
}
case 5:
{
if (timeBufDec[4] == 0)
{
timeBufDec[4] = 24;
}
timeBufDec[4]--;
break;
}
case 6:
{
if (timeBufDec[5] == 0)
{
timeBufDec[5] = 60;
}
timeBufDec[5]--;
break;
}
case 7:
{
if (timeBufDec[6] == 0)
{
timeBufDec[6] = 60;
}
timeBufDec[6]--;
break;
}
default:;
}
DispTime(setIndex, setTimeFlag);
}
}
else if (dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag)
{
switch (setIndex)
{
case 1:
if (rateAlarm > 0)
{
rateAlarm--;
}
break;
case 2:
totalDist = 0;
break;
}
DispAlarm(setIndex, setAlarmFlag);
}
}
else
{
if (pwmValue > 3)
{
pwmValue--;
}
}
}
//while (!KEY_DOWN);
}
if (!KEY_LEFT) //左键按下
{
DelayMs(10);
if (!KEY_LEFT)
{
if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 1)
{
setIndex--;
if (setIndex < 1)
{
setIndex = 7;
}
DispTime(setIndex, setTimeFlag);
}
}
else if (dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag)
{
setIndex--;
if (setIndex < 1)
{
setIndex = 2;
}
DispAlarm(setIndex, setAlarmFlag);
}
}
}
while (!KEY_LEFT)
;
}
if (!KEY_RIGHT) //右键按下
{
DelayMs(10);
if (!KEY_RIGHT)
{
if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 1)
{
setIndex++;
if (setIndex > 7)
{
setIndex = 1;
}
DispTime(setIndex, setTimeFlag);
}
}
if (setAlarmFlag)
{
setIndex++;
if (setIndex > 2)
{
setIndex = 1;
}
DispAlarm(setIndex, setAlarmFlag);
}
}
while (!KEY_RIGHT)
;
}
if (!KEY_ENTER) //确认键按下
{
DelayMs(10);
if (!KEY_ENTER)
{
if (dispMode == DISP_RATE_MODE)
{
dispMode = DISP_TIME_MODE;
setTimeFlag = 0;
setIndex = 0;
}
else if (dispMode == DISP_TIME_MODE)
{
if (setTimeFlag == 1)
{
setTimeFlag = 0;
setIndex = 0;
DS1302_WriteTime();
DispTime(setIndex, setTimeFlag);
}
else
{
dispMode = SET_ALARM_MODE;
setIndex = 0;
}
}
else if (dispMode == SET_ALARM_MODE)
{
if (setAlarmFlag == 1)
{
setAlarmFlag = 0;
setIndex = 0;
WriteEEPROM();
DispAlarm(setIndex, setAlarmFlag);
}
else
{
dispMode = DISP_RATE_MODE;
setIndex = 0;
}
}
}
while (!KEY_ENTER)
;
}
}
void EXT1_Init()
{
IT1 = 1; //下降沿触发
EX1 = 1; //使能外部中断0
EA = 1; //打开总中断
}
void EXT1_Interrupt() interrupt 2 using 1
{
pulseCnt++;
}
void Timer0_Init(void)
{
TMOD &= 0xF0; //定时器模式0
TMOD |= 0x01;
PT0 = 1; //设置T0为高优先级
TH0 = RH_10MS(3); //10ms
TL0 = RL_10MS(3);
TR0 = 1; //启动T0计时
ET0 = 1; //打开T0中断
EA = 1; //打开总中断
}
void Timer0_Intterupt(void) interrupt 1 using 0
{
static unsigned int cnt=0;
static unsigned char IN1Count = 0;
// TH0 = 0xF8; //设置定时初值
// TL0 = 0xCD; //设置定时初值 2ms
TH0 = 0xFC; //设置定时初值
TL0 = 0x66; //设置定时初值 1ms
IN1Count++;
cnt++;
if (motorFlag == 1)
{
if (IN1Count < pwmValue) //占空比调节
{
MOTOR = 0;
}
else if ((IN1Count >= pwmValue) && (IN1Count <= 11)) //关闭时间段
{
MOTOR = 1;
}
else
{
IN1Count = 0; //一个周期结束
}
}
else
{
MOTOR = 1;
}
if (cnt >= 250) //500ms
{
dispFlag = ~dispFlag;
cnt = 0;
}
}
void Timer1_Init(void)
{
TMOD &= 0x0F; //定时器模式1
TMOD |= 0x10;
TH1 = RH_10MS(5); //50ms
TL1 = RL_10MS(5);
TR1 = 1; //开启T1计时
ET1 = 1; //打开T1中断
EA = 1; //打开总中断
}
void Timer1_Intterupt(void) interrupt 3 using 2
{
static unsigned int cnt=0;
TH1 = RH_10MS(5); //50ms
TL1 = RL_10MS(5);
cnt++;
if (cnt >= 20) //1s
{
EX1 = 0;
if (second >= 60)
{
second = 0;
minute++;
if (minute == 1)
{
writeFlag = 1;
minute = 0;
}
}
else
{
second++;
}
refreshFlag = 1;
cnt = 0;
}
}
仿真演示视频:
https://www.bilibili.com/video/BV13R4y1G7k4/
实物演示视频:
https://www.bilibili.com/video/BV1iY411G7AJ/