基于单片机的电动车里程记录仪的设计Word文档格式.docx
《基于单片机的电动车里程记录仪的设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《基于单片机的电动车里程记录仪的设计Word文档格式.docx(26页珍藏版)》请在冰豆网上搜索。
同时,AT89C52可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。
空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。
掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。
引脚如图2.1所示。
振荡器反相放大器如图2.2所示。
图2.1AT89C52引脚图
XTAL1:
振荡器反相放大器的及内部时钟发生器的输入端。
XTAL2:
振荡器反相放大器的输出端。
中断:
AT89C52共有6个中断向量:
两个外中断(INT0和INT1),3个定时器中断(定时器0,1,2)和串行口中断。
所有这些中断源可通过分别设置专用寄存器IE的置位或清0来控制每一个中断的允许或禁止。
IE也有一个总禁止位EA,它能控制所有中断的允许或禁止。
2.2存储电路
SCK串行时钟:
AT24C02串行时钟输入管脚用于产生器件所有数据发送或接收的时钟。
SDA串行数据/地址:
CAT24WC02双向串行数据/地址管脚用于器件所有数据的发送或接收,是一个开漏输出管脚可与其它开漏输出或集电极开路输出进行线或(wire-OR)。
WP写保护:
如果WP管脚连接到Vcc所有的内容都被写保护,只能读。
当WP管脚连接到Vss或悬空,允许器件进行正常的读/写操作。
本次设计采用的24C02是为了防止掉电时里程数据的丢失,由于24C02C的数据线和地址线是复用的,采用串口的方式传输数据,所以只用两根线SCK和SDA与单片机传输数据。
在软件编程时采用
程序包来控制24C02C发送或接受数据。
2.3 时钟电路
时钟是单片机的心脏,单片机各功能部件的运行都是以时钟频率为基准,有条不紊地一拍一拍地工作。
因此,时钟频率直接影响单片机的速度,时钟电路的质量也直接影响单片机系统的稳定性。
AT89C52片内由一个反相放大器构成振荡器,可以由它产生时钟。
常用的时钟电路有两种方式,一种是内部时钟方式,另一种为外部时钟方式。
本设计采用前者。
单片机内部有一个用于构成振荡器的高增益反相放大器,该高增益反相放大器的输入为芯片引脚XTAL1,输出端为引脚XTAL2。
这两个引脚跨接石英晶体振荡器和电容,就构成一个稳定的自激振荡器。
电路中的电容C1和C2常选择为30P左右。
对外接电容的值虽然没有严格的要求,但电容的大小会影响振荡器的高低、振荡器的稳定性、起振的快速性和温度的稳定性。
而外接晶体的振荡频率的大小,主要取决于单片机的工作频率范围,每一种单片机都有自己的最大工作频率,外接的晶体振荡频率不大于单片机的最大工作频率即可。
此外,如果单片机有串行通信,则应该选择振荡频率除以串行通信频率可以除尽的晶体。
本设计晶振采用12MHz,则计数周期为
S
2.4 复位电路
AT89C52单片机的复位输入引脚RET为AT89C52提供了初始化的手段。
有了它可以使程序从指定处开始执行,即从程序存储器中的0000H地址单元开始执行程序。
在89C52的时钟电路工作后,只要在RET引脚上出现两个机器周期以上的高电平时,单片机内部则初始复位。
只要RET保持高电平,则89C52循环复位。
只有当RET由高电平变成低电平以后,89C52才从0000H地址开始执行程序。
本系统的复位电路是采用按键复位的电路,如图2.12所示,是常用复位电路之一。
单片机复位通过按动按钮产生高电平复位称手动复位。
上电时,刚接通电源,电容C相当于瞬间短路,+5V立即加到RET/VPD端,该高电平使89C52全机自动复位,这就是上电复位;
若运行过程中需要程序从头执行,只需按动按钮即可。
按下按钮,则直接把+5V加到了RET/VPD端从而复位称为手动复位。
复位后,P0到P3并行I/O口全为高电平,其它寄存器全部清零,只有SBUF寄存器状态不确定。
工作原理:
通电瞬间,RC电路充电,RST引脚出现高电平,只要RST端保持10ms以上高电平,就能使单片机有效地复位。
2.5 显示电路
1602液晶显示模块可以和单片机AT89C51直接接口,1602的驱动程序11条指令,
(1)voidClear_display();
//清显示屏指令
(2)voidReturn_home();
//光标归位指令
(3)voidEntry_mode_set();
//输入模式设置指令
(4)voidDisplay_on_or_off();
//显示屏的开关控制指令
(5)voidCursor_or_Display_shift();
//设定显示屏或光标移动方向指令
(6)voidFunction_set();
//功能设定指令
(7)voidSet_character_address();
//设定CGRAM地址指令
(8)voidSet_display_address();
//设定DDRAM地址指令
(9)voidRead_busy_flag();
//读取忙信号或AC地址指令
(10)voidWrite_data();
//将数据写入DDRAM或CGRAM指令
(11)voidRead_data();
//从CGRAM或DDRAM读出数据的指令
2.6 报警电路
当速度超过30时,蜂鸣器报警,速度可以设定
第3章软件的设计与调试
3.1子程序和主函数的设计
一、子程序的设计
设汽车轮子半径为r,脉冲数为n,t=50毫秒,一个脉冲的时间为time,速度为v(km/h),路程为s(km),pi=3.14。
子程序按模块化的思路编写。
各子程序如下:
1.初始化:
设置T0计时器工作方式1,输入口为p3.2
开总中断。
打开外中断0中断控制位.
设置外部中断0优先级控制位。
设置外部中断0触发方式为边沿触发方式。
打开T0中断允许。
2.外部中断:
当P3.2口有脉冲时进入外部中断0。
time=sec+t*0.05,记一个脉冲的时间。
tab_v[5]=0.9*pi*r/time,计算速度并放入数组中。
高低速的判断,当V>
=5时为高速,并用flag=0,记高速标志位,
flag=1,记低速标志位;
for(i=0;
i<
6;
i++)
tab_v[i]=tab_v[i+1];
//数组移数据
关闭T0,给T0赋50毫秒初值。
开启T0,当来一个脉冲n++;
当n==50000时,n清零n=0;
3.定时器0中断:
当来一个脉冲进入定时器0中断,给T0定时器赋50毫秒初值,当记满50毫秒t++。
4.处理函数:
计算速度分高速和低速。
速度计算公式:
tab_v[5]=0.9*pi*r/time;
(单位km/h)
低速时:
v=tab_v[5],即显示第五个速度值。
高速时:
v+=tab_v[i];
计算五个速度之和。
v=v/5;
求得平均速度。
路程公式:
s=0.00025*pi*r*n,随着脉冲n的增加s不断累加。
3.2 PROTEUS仿真过程
一、电路原理图如下图:
图3.1车速里程表原理图
二、生成HEX文件如下图4.2。
图3.2 生成文件
三、编译结果如下图4.3。
图3.3 编译结果
仿真结果没有错误和警告,编译通过。
四、仿真结果如下图
仿真结果一表示:
速度为0,路程也为0。
仿真结果二表示:
速度为16km/h,行驶里程为4公里。
图3.4仿真结果一
图3.5仿真结果二
参考文献
[1]万福君,潘松峰,刘芳,吴贺荣,王秀梅.MCS-51单片机原理、系统应用[M].
清华大学出版社,2008.
[2]张迎新.单片机原理及应用(第二版)[M].电子工业出版社,2009.
[3]宋文绪,杨帆.自动检测技术(第三版)[M].高等教育出版社,2008.
[4]郭天祥.新概念51单片机C语言教程[M].电子工业出版社,2009.
[5]陈忠平,曹巧媛曹琳琳,刘琼,申晓龙.单片机原理及接口[M].清华大学出版社,2007.
附录一硬件设计原理图
附录二程序清单
//速度超过30KM/H报警
#include<
reg52.h>
stdio.h>
intrins.h>
#defineuintunsignedint
#defineucharunsignedchar
uintzd;
ucharb,i,count,temp2;
unsignedlongtime;
uintspeed,c,allc;
//速度里程总里程
#defineL50
sbitbeep=P3^7;
//speak端口
//-----------24c02----------------------
#defineC02_write0xa0//写
#defineC02_read0xa1//读
sbitSCL=P1^4;
//时钟
sbitSDA_EEPROM=P1^5;
//数据
bitack;
bitdd;
ucharNew[2]="
"
;
//使用者密码
ucharOld[2]="
//IIC密码
//------------24c02---------------------
sbitS1=P3^0;
//Pin4
/***********************************************************************/
voiddelay1(ucharMS);
unsignedcharReadTemperature(void);
voidInit_DS18B20(void);
unsignedcharReadOneChar(void);
voidWriteOneChar(unsignedchardat);
/************************************************************************/
sbitRS=P2^4;
sbitRW=P2^5;
//Pin5
sbitE=P2^6;
//Pin6
sbitout=P1^0;
#defineDataP0//数据端口
chardataTimeNum[]="
"
chardataTest1[]="
voidDelay(uintz)
{
uintx,y;
for(x=z;
x>
0;
x--)
for(y=110;
y>
y--);
}
/******************************************************************/
/*函数声明*/
/******************************************************************//***************************************************************/
voidDelayUs(unsignedcharus)//delayus
unsignedcharuscnt;
uscnt=us>
>
1;
/*Crystalfrequencyin12MHz*/
while(--uscnt);
voidDelayMs(unsignedcharms)//delayMs
while(--ms)
{
DelayUs(250);
}
voidWriteCommand(unsignedcharc)
DelayMs(5);
//shortdelaybeforeoperation
E=0;
RS=0;
RW=0;
_nop_();
E=1;
Data=c;
/****************************************************************/
voidWriteData(unsignedcharc)
//shortdelaybeforeoperation
RS=1;
/*********************************************************************/
voidShowChar(unsignedcharpos,unsignedcharc)
unsignedcharp;
if(pos>
=0x10)
p=pos+0xb0;
//是第二行则命令代码高4位为0xc
else
p=pos+0x80;
//是第二行则命令代码高4位为0x8
WriteCommand(p);
//writecommand
WriteData(c);
//writedata
/*************************************************************************/
voidShowString(unsignedcharline,char*ptr)
unsignedcharl,i;
l=line<
<
4;
for(i=0;
16;
ShowChar(l++,*(ptr+i));
//循环显示16个字符
voidInitLcd()
DelayMs(15);
WriteCommand(0x38);
//displaymode
WriteCommand(0x06);
//显示光标移动位置
WriteCommand(0x0c);
//显示开及光标设置
WriteCommand(0x01);
//显示清屏
////////////////////2402///////////////////////////////////
//---------------------------------------------------------
voiddelay_ms(uchari)
ucharj;
for(;
i>
i--)
for(j=124;
j>
j--);
voidI2C_start(void)
SDA_EEPROM=1;
SCL=1;
SDA_EEPROM=0;
SCL=0;
voidI2C_stop(void)
voidI2C_ackownledge(void)
voidI2C_no_ackownledge(void)
voidI2C_sendB(ucharbyte)
ucharcounter;
for(counter=0;
counter<
8;
counter++)
if(byte&
0x80)SDA_EEPROM=1;
elseSDA_EEPROM=0;
_nop_();
SCL=1;
SCL=0;
byte<
=1;
if(SDA_EEPROM==0)ack=1;
elseack=0;
ucharI2C_receiveB(void)
uchartemp;
temp=0;
if(SDA_EEPROM==1)temp=(temp<
1)|0x01;
elsetemp=temp<
return(temp);
/*bitI2C_write_byte(ucharbyte,ucharaddress)
I2C_sendB(address);
if(ack=0)
I2C_stop();
return(0);
elseI2C_sendB(byte);
*/
//存UserPassword
bitI2C_send_string(ucharno,ucharaddress)
no;
I2C_start();
I2C_sendB(C02_write);
if(ack==0)return(0);
I2C_sendB(address+counter);
I2C_sendB(New[counter]);
delay_ms(20);
return
(1);
//读EEPROMPassword
bitI2C_receive_string(ucharno,ucharaddress)
I2C_sendB(C02_read);
Old[co