基于51单片机的称重系统设计说明.docx
《基于51单片机的称重系统设计说明.docx》由会员分享,可在线阅读,更多相关《基于51单片机的称重系统设计说明.docx(30页珍藏版)》请在冰点文库上搜索。
基于51单片机的称重系统设计说明
单片机作业
学院计算机与控制工程学院
专业自动化132
学号2013022030
王伟
基于51单片机的称重系统
一动态称重
所谓动态称重是指通过分析和测量车胎运动中的力,来计算该运动车辆的总重量、轴重、轮重和部分重量数据的过程。
动态称重系统按经过车辆行驶的速度划分,可分为低速动态称重系统与高速动态称重系统。
因为我国高速公路的限速最高是120,所以高速动态称重系统在理论上可对5到120之间时速通过称量装置的车辆进行动态称重。
而低速动态称重系统则一定要限制通过车辆的行驶速度,要想有较高的测量精度,理论要求车辆在5km/h以下时速匀速通过。
在我国,车辆动态称重一般都使用低速动态称重来完成,在很多收费站和车辆检测站都有应用,国家也出台了相关的测量标准。
与传统意义上的静态称重相比,动态称重可以在车辆缓慢运动情况下直接进行称重,这样动态称重的高效率、测量时间短、能流畅交通等主要特点就凸显出来了。
动态称重的问世,不但使车辆的管理上有了很大的促进作用,而且还对我国的公路管理和维护起到了至关重要的作用。
二系统总体结构及其功能
设计总体结构是以51单片机为处理器的系统,如图3.1所示。
图3.1
本设计要求能判断出车辆是否超载,如果车辆超载,本系统能够提供该车辆的超载信息并发出警报。
本设计采用STC89C52单片机作为系统的处理核心,利用桥式称重传感器采集到车辆重量并转换成电压信号,然后通过放大电路将电压信号进行放大处理后,传送到A/D转换器中转换为数字信号,再经过单片机处理、传输到接口电路,最后送到上位机,该数据可以与上位机里用键盘事先输入设定的总重量作比较并判断出该车辆是否超载,如果超载,则可通过显示器、蜂鸣器作显示超载信息并报警,当然,键盘的作用除了输入设定值还可以解除和开启警报。
三动态称重系统的组成
动态称重系统主要由车辆重量(含超载、偏载检测)检测子系统、货车长、宽、高三维尺寸超限检测子系统、自动触发摄像拍照子系统、车辆类型自动判别子系统、系统配置及系统维护子系统、行驶车辆速度测量子系统、数据统计、报表处理子系统和单据输出打印子系统这几部分组成。
该系统组成完善,部件考虑周全,能很好的完成称重任务。
四动态称重系统的主要功能
(1)动态检测出通过车辆的轴数、轴重、轴距、轮数、车速等;
(2)能自动检测出车辆的高、宽、长等外围尺寸是否超出最大标准,并能给出超出部位的具体位置和具体数据;
(3)拍摄机器在车辆经过时能自行对要被检测的车辆进行拍照,该机器能对车牌、车辆种类进行识别,最终作为图像证据;
(4)可以将不合格车辆的处理记录、超限情况进行打印,根据车辆超限的程度来计算罚款数额并打印收据或罚款单;
(5)检测到的数据全部存入数据库中,并对被监测到的数据进行分析、统计。
便于汇总上报、日常管理和进行查询。
五单片机的选用
本设计采用的是INTEL公司研究开发生产的STC89C52单片机,其部置有256字节的部数据存储器、8位中央处理单元、8K片程序存储器、3个16位定时/计数器、32个双向I/O口和一个片时钟振荡电路,全双工串行通信口,5个两级中断结构。
89C52的引脚图如图4.1所示。
图4.189C52引脚图
本设计使用的是单片机的最小系统,其中电路包括下载口电路、复位电路和晶振电路。
复位电路中,电阻在下接地,电容在上接高电平,中间为RST。
复位电路工作原理是:
通电时,由于电流很大,从而相当于电容被短路,这样RST引脚上处于高电平,这时的单片机为禁止工作状态。
如果要使单片机正常工作,就要使RST端电压慢慢下降并到一定程度,也就是RST端为低电平,这就需要通过电源对电容进行充电。
复位电路复位的方式有手动复位、上电复位两种。
所谓上电复位,就是通电瞬间,由于电流很大,从而相当于电容被短路,这样RST引脚上处于高电平,自动复位;相反,通过对改变电容电流,当电流很小的时候,我们就可以把电容当做开路状态,RST端就处于低电平,程序就能正常的运行。
而手动复位要在上电复位的基础上,按下复位按键,使VCC直接与RST相连,电容处于放电状态,以高电平形成复位;松开复位按键,RST仍旧是高电平,这时充电电流作用于电阻上,VCC给电容进行充电,还是复位状态,充电结束后,RST为低电平,能够正常工作。
A/D转换器
A/D转换器根据输出的信号格式有并行A/D和串行A/D两种。
ADC0832是一种具有双通道A/D转换芯片和8位分辨率。
它的优点有体积小,兼容性强,性价比高,从而深受个人的欢迎和企业的认可,目前在世界上也已经有了较高的使用率。
ADC0832具有能够进行双通道A/D转换,分辨率高达8位;当供电电源为5V时,输入电压能稳定的保持在0~5V之间;TTL/CMOS与输出输入电平兼容;功耗很低,只有15mW;转换工作时间只有32μS,也就是频率仅有250KHZ等特点。
其引脚功能图如图4.6所示,芯片引脚接口说明如表4所示。
图4.6引脚排列
表4ADC0832引脚说明
接口
说明
CS
片选使能,输入低电平能使芯片工作
CH1
模拟的输入通道1,或作为IN+/-使用
CH0
模拟的输入通道0,或作为IN+/-使用
GND
接地
DO
转换数据输出,数据信号输出
DI
选择通道控制,数据信号输入
CLK
芯片时钟脉冲输入
Vcc/REF
5V参考电压输入和电源输入
通常情况下的单片机和ADC0832的接口的数据线应为4条,分别是CS、CLK、DO、DI。
由于ADC0832的数据信号输入输出口与单片机具有双向接口通信,输入输出口也不同时使用,所以可以将数据信号输入输出口并联后当一条数据线进行使用。
它们的硬件接口电路与单片机连接的原理如图4.7所示。
最后将以上的惠思登电桥、放大器、ADC0832转换器和STC89C52单片机连接起来,就组成了系统的采集模块。
图4.7ADC0832与单片机的接口电路
报警模块
本系统要实现一旦检测到车辆超载超限,就会立刻鸣笛报警,通过操作人员的检查处理后,解除报警。
本设计选用蜂鸣器作为发声装置,蜂鸣器可利用三极管来进行放大驱动。
该接口电路如图4.15所示:
图4.15报警接口电路
5.系统的软件设计
5.1主程序设计
当系统上电复位后,系统开始初始化,包括端口等;初始化完毕后,调用串口输出提示语,开始准备串口输出电压;准备完毕后,调用串口输出电压值,开始从串口输出电压值;输出完毕后,调用串口输出换行值;最后开始延时200ms。
根据系统方案,设计出本设计的主程序流程,可以用框图表示。
图5.1主程序流程图
5.3ADC0832软件设计
首先要将芯片开始使能,即CS使能端置于低电平,然后通过DI和DO的同一数据输入端口,可实现通道功能的选择,再调用通道初始化程序,初始化完毕后,在8个时钟边沿获得正序和反序8位数据,最后返回数据。
根据此方案,设计出本设计中A/D转换程序流程,如图5.2所示。
当两位数据都为0时,CH1作为负输入端IN-,而CH0就作为正输入端IN+来进行相关输入。
当此两位数据都为1时,CH1进行单通道转换而CHO不转换。
当两位数据分别为0和1时,CH1作为正输入端IN+,CH0作为负输入端IN-来进行相关输入。
当两位数据为分别为1和0时,CH0进行单通道转换而CH1不转换。
ADC0832的功能项如表7所示。
图5.2ADC0832转换流程图
表7AD0832功能项
MUXAddress
Channe#
SGL/DIF
ODD/SIGN
0
1
1
0
+
1
1
+
0
0
+
_
0
1
_
+
ADC0832没有工作时,DO/DI和CLK的电平可高可低,但CS的输入端口应必须显示高电平,此时芯片处于禁用状态。
当A/D转换进行时,CS端口必须处于低电平并且一直将低电平保持到转换全部结束。
当芯片转换工作开始,芯片的CLK端口会接收到处理器传送来的一时钟脉冲,DO/DI并联端口将使用数据输入信号的DI端口。
第一个时钟脉冲的下沉出现之前,DI端口一定要是高电平,表示启始信号的发出,在第二、三个脉冲的下沉出现之前,DI端口要输入两位数据来选择通道。
第三个脉冲出现下沉之后,DI端口就不再起任何作用,此后DO/DI并联端口则是被DO端口占领进行读取转换数据。
第四个下沉脉冲出现开始,DO端口输出最高位的转换数据DATA7,接下来每个脉冲下沉之后DO端口都会输出下一位的转换数据。
直到发出最低位数据DATA0,也就是由第十一个脉冲发出的数据之后,这样一个字节的数据输出就完成了。
再从第十一个脉冲下沉开始从DATD0开始输出下一个相反数据字节。
然后一直到第十九个脉冲完成数据的输出,这样一次A/D转换才结束。
最后,要想将转换后的数据进行相关处理就必须将芯片禁用,也就是将CS端口输入高电平。
5.4LCD显示程序设计
首先设置显示模式,设置第(x,y)个字符的DDRAM的地址,为15×2显示,因为液晶显示为15列,所以x位置的围是0到15,同理,因为显示2行,所以y位置的围是0到1。
显示程序如下:
voidLcd_Pos(ucharyPos,ucharxPos)
{
uchartmp;
xPos&=0x0f;//x位置围是0~15,因为显示15列
yPos&=0x01;//y位置围是0~1,因为显示2行
if(yPos==0)//显示第一行
{
tmp=xPos;
}
else
{
tmp=xPos+0x40;//显示第二行
}
tmp|=0x80;
Write_(tmp);
}
5.5主函数
软件主要分成四个部分:
串口配置,ADC0832的初始化,等待接受数据和输出数据。
程序如下:
voidmain(void)
{
InitUART();//串口初始化
Lcd_init();
Write_String("Weight:
",0,0);
Write_String("H=",1,0);
Write_String("L=",1,6);
Beep=1;
while
(1)
{
Process10ms();
DispVal(Wh,1,2);
DispVal(Wl,1,8);
CheckProcess();
if(flagget10s==1)
{
flagget10s=0;
Get_temp(sum*100);
ET0=1;
TR0=1;
Disp_Voltage();//采集电压并发送
}
}
}
参考文献
[1]周杏鹏,传感器与检测技术,清华大学,2010
[2]燕,传感器原理及应用,大学,2009
[3]王幸之、钟爱琴、王雷、王闪,AT89系列单片机原理与接口技术,航天大学,2004
[4]高玉芹,单片机原理与应用及C51编程技术,机械工业,2011
[5]毅刚、喜元、宇,单片机原理与应用,高等教育,2010
[6]小成、吴清、夏春明,单片机原理及C51应用,华东理工大学,2009
[7]国务院全国治理车辆超限超载领导工作小组,全国治理车辆超限超载工作简报[Z],2004
(1)
[8]勇、吴文兵、竹生、雨,汽车轮重动态检测中的单片机,汽车科技,2004(3)
[9]积东,单片机51/98开发与应用,电子工业,1994
[10]周航慈,单片机程序设计基础,航空航天大学,1997
单片机系统部分硬件原理图
单片机程序
#include"reg52.h"
#include"My_type.h"//数据类型头文件
#include
#definenop()_nop_()
#defineucharunsignedchar
#defineuintunsignedint
sbitLcd_rs=P2^0;
sbitLcd_rw=P2^1;
sbitLcd_en=P2^2;
sbitkey1=P3^5;
sbitkey2=P3^6;
sbitkey3=P3^7;
sbitBeep=P2^7;
sbitLed=P2^6;
sbitCS=P1^3;//使能
sbitCLK=P1^1;//时钟
sbitDo=P1^2;//数据输出
sbitDi=P1^2;//数据输入
#definefirst_channel0x02//通道1
#definesecond_channel0x03//通道2
ucharCH=first_channel;
#defineFclk11059200UL/*使用11.0592M晶体*/
#defineBitRate9600UL/*波特率定义为9600*/
uint8Sending;//发送标志
codeuint16AD_Tab[41]={512,2048,2970,3840,4659,5581,
6349,7117,7782,8397,9165,9830,
10291,11162,11520,11981,12749,13210,
13926,14490,15206,15821,16538,17357,
17971,18842,19814,20838,21760,22477,
23091,23603,23962,24371,24678,24883,
25037,25190,25293,25395,25600};
uint8temp_zheng;
floattemp_xiao;
uint8flag10ms=0;
uint8flag50ms=0;
uint8get10s=0;
uint8flagget10s=0;
uint8Alarmflag=1;
uint16sum=0;
uint8count5ms=0;
uint8Wh=40;
uint8Wl=20;
voidDelay_lcd1602(uintdly)
{
uinti;
for(;dly>0;dly--)
for(i=0;i<100;i++);
}
bitLcd_busy()
{
bitresult;
Lcd_rw=1;
Lcd_rs=0;
Lcd_en=1;
nop();nop();nop();nop();
result=(bit)(P0&0x80);
Lcd_en=0;
return(result);
}
voidWrite_(uchar)
{
while(Lcd_busy());//LCD忙等待
Lcd_rs=0;
Lcd_rw=0;
P0=;
Delay_lcd1602(5);
Lcd_en=1;
Delay_lcd1602(5);
Lcd_en=0;
}
voidWrite_data(uchardate)
{
while(Lcd_busy());//LCD忙等待
Lcd_rs=1;
Lcd_rw=0;
P0=date;
Delay_lcd1602(5);
Lcd_en=1;
Delay_lcd1602(5);
Lcd_en=0;
}
voidLcd_init()
{
Lcd_en=0;
Write_(0x38);
Delay_lcd1602(5);
Write_(0x0c);
Delay_lcd1602(5);
Write_(0x04);
Delay_lcd1602(5);
Write_(0x01);
Delay_lcd1602(5);
}
voidLcd_Pos(ucharyPos,ucharxPos)//设置第(xPos,yPos)个字符的DDRAM地址
{
uchartmp;
xPos&=0x0f;//x位置围是0~15,因为显示15列
yPos&=0x01;//y位置围是0~1,因为显示2行
if(yPos==0)//显示第一行
{
tmp=xPos;
}
else
{
tmp=xPos+0x40;//显示第二行
}
tmp|=0x80;
Write_(tmp);
}
voidWrite_char(ucharc,ucharxPos,ucharyPos)//定义Write_Char函数
{
Lcd_Pos(xPos,yPos);
Write_data(c);
}
voidWrite_String(uchar*s,ucharxPos,ucharyPos)//定义Write_String函数
{
uchari=0;
Lcd_Pos(xPos,yPos);
while(*s)
{
Write_data(*(s++));
if(++i>16)break;
}
}
voidInitUART(void)
{
EA=0;
TMOD|=0x21;//定时器1工作在模式2
SCON=0x50;//串口工作在模式1
TCON=0x05;
TH1=256-Fclk/(BitRate*12*16);
TL1=256-Fclk/(BitRate*12*16);
TH0=(65535-1000)/256;
TL0=(65535-1000)%256;
ET0=1;
TR0=1;
PCON=0x80;//串口波特率加倍
ES=1;//串行中断允许
TR1=1;//启动定时器1
REN=1;//允许接收
EA=1;//允许中断
}
voidUartISR(void)interrupt4
{
if(RI)//收到数据
{
RI=0;//清中断请求
}
else//发送完一字节数据
{
TI=0;
Sending=0;//清正在发送标志
}
}
voidPutChar_to_Uart(uint8d)
{
Sending=1;
SBUF=d;
while(Sending);
}
voidPrints(uint8*pd)
{
while((*pd)!
='\0')
{
PutChar_to_Uart(*pd);
pd++;
}
}
unsignedcharADconv(void)
{
unsignedchari;
unsignedintdata_f=0,data_c=0;
ET0=0;
TR0=0;
Di=1;
CS=1;
_nop_();
CS=0;
Di=1;;//芯片使能之前的初始化。
第一个下降沿
CLK=1;
_nop_();
_nop_();
CLK=0;//确定通道模式、第2个下降沿
_nop_();
_nop_();
CLK=1;
Di=(bit)(0x02&CH);//设定通道初始化
_nop_();
CLK=0;
_nop_();
_nop_();
CLK=1;
Di=(bit)(0x01&CH);//设定通道初始化.第3个下降沿
_nop_();
_nop_();
CLK=0;//AD转化的初始化完成。
Di=1;
CLK=1;
_nop_();
_nop_();
CLK=0;
_nop_();
CLK=1;
for(i=8;i>0;i--)//得到一个正常排序的8位数据
{
data_f|=Do;
data_f<<=1;
CLK=1;
_nop_();
_nop_();
CLK=0;
_nop_();
}
for(i=8;i>0;i--)//得到一个反序排列的8位数据
{
data_c<<=1;
data_c|=Do;
_nop_();
CLK=1;
_nop_();
_nop_();
CLK=0;
_nop_();
}
CLK=0;
_nop_();
_nop_();
CLK=1;
_nop_();
_nop_();
CLK=0;
_nop_();
_nop_();
CLK=1;
_nop_();
CS=1;
_nop_();
_nop_();
ET0=1;
TR0=1;
returndata_f;
}
/*
voiddelay_ms(unsignedintx)
{
unsignedinti,j;
i=0;
for(i=0;i{
j=108;
while(j--);
}
}
*/
voidDispVal(uint8pdat,uint8x,uint8y)
{
/*
PutChar_to_Uart(pdat/100+0x30);
PutChar_to_Uart(pdat%100/10+0x30);
PutChar_to_Uart(pdat%100%10+0x30);
*/
Write_char(pdat/100+0x30,x,y);
Write_char(pdat%100/10+0x30,x,y+1);
Write_char(pdat%100%10+0x30,x,y+2);
}
voidProcess10ms(void)
{
if(flag10ms==1)
{
flag10ms=0;
count5ms++;
if(count5ms==5)
{
count5ms=0;
flag50ms=1;
}
get10s++;
sum=sum+ADconv();
if(get10s==10)
{
get10s=0;
ET0=0;
TR0=0;
flagget10s=1;
sum=sum/10;
}
if(key1==0)
{
while(!
key1);
Wh++;
if(Wh>=51)
{
Wh=40;
}
}
if