|
基于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.1 89C52引腳圖 本設計使用的是單片機的最小系統,其中電路包括下載口電路、復位電路和晶振電路。復位電路中,電阻在下接地,電容在上接高電平,中間為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 引腳排列 表4 ADC0832引腳說明 通常情況下的單片機和ADC0832的接口的數據線應為4條,分別是 CS、CLK、DO、DI。由于ADC0832的數據信號輸入輸出口與單片機具有雙向接口通信,輸入輸出口也不同時使用,所以可以將數據信號輸入輸出口并聯后當一條數據線進行使用。它們的硬件接口電路與單片機連接的原理如圖4.7所示。 最后將以上的惠思登電橋、放大器、ADC0832轉換器和STC89C52單片機連接起來,就組成了系統的采集模塊。 圖4.7 ADC0832 與單片機的接口電路 報警模塊本系統要實現一旦檢測到車輛超載超限,就會立刻鳴笛報警,通過操作人員的檢查處理后,解除報警。本設計選用蜂鳴器作為發聲裝置,蜂鳴器可利用三極管來進行放大驅動。該接口電路如圖4.15所示: 圖4.15 報警接口電路 - 1 -
5. 系統的軟件設計
5.1 主程序設計當系統上電復位后,系統開始初始化,包括端口等;初始化完畢后,調用串口輸出提示語,開始準備串口輸出電壓;準備完畢后,調用串口輸出電壓值,開始從串口輸出電壓值;輸出完畢后,調用串口輸出換行值;最后開始延時200ms。根據系統方案,設計出本設計的主程序流程,可以用框圖表示。 圖5.1 主程序流程圖 5.3 ADC0832軟件設計首先要將芯片開始使能,即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.2 ADC0832轉換流程圖 表7 AD0832功能項 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.4 LCD顯示程序設計首先設置顯示模式,設置第(x,y)個字符的DDRAM的地址,為15×2顯示,因為液晶顯示為15列,所以x位置的范圍是0到15,同理,因為顯示2行,所以y位置的范圍是0到1。顯示程序如下: void Lcd_Pos(uchar yPos,uchar xPos) { uchar tmp; xPos &= 0x0f; //x位置范圍是0~15,因為顯示15列 yPos &= 0x01; //y位置范圍是0~1,因為顯示2行 if(yPos==0) //顯示第一行 { tmp = xPos; } else { tmp = xPos + 0x40; //顯示第二行 } tmp |= 0x80; Write_com(tmp); } 5.5 主函數軟件主要分成四個部分:串口配置,ADC0832的初始化,等待接受數據和輸出數據。程序如下: void main(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(); //采集電壓并發送 } } }
單片機系統部分硬件原理圖單片機程序
- #include "reg52.h"
- #include "My_type.h" //數據類型頭文件
- #include <intrins.h>
-
- #define nop() _nop_()
- #define uchar unsigned char
- #define uint unsigned int
-
- sbit Lcd_rs=P2^0;
- sbit Lcd_rw=P2^1;
- sbit Lcd_en=P2^2;
-
- sbit key1 = P3^5;
- sbit key2 = P3^6;
- sbit key3 = P3^7;
-
- sbit Beep = P2^7;
- sbit Led = P2^6;
- sbit CS=P1^3; //使能
- sbit CLK=P1^1; //時鐘
- sbit Do=P1^2; // 數據輸出
- sbit Di=P1^2; //數據輸入
-
- #define first_channel 0x02 //通道1
- #define second_channel 0x03 //通道2
- uchar CH = first_channel;
-
- #define Fclk 11059200UL /*使用11.0592M晶體*/
- #define BitRate 9600UL /*波特率定義為9600*/
- uint8 Sending; //發送標志
-
- code uint16 AD_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};
-
- uint8 temp_zheng;
- float temp_xiao;
-
- uint8 flag10ms = 0;
- uint8 flag50ms = 0;
- uint8 get10s = 0;
- uint8 flagget10s = 0;
- uint8 Alarmflag = 1;
- uint16 sum = 0;
- uint8 count5ms = 0;
- uint8 Wh = 40;
- uint8 Wl = 20;
-
- void Delay_lcd1602(uint dly)
- {
- uint i;
- for(; dly>0; dly--)
- for(i=0; i<100; i++);
- }
-
- bit Lcd_busy()
- {
- bit result;
- Lcd_rw = 1;
- Lcd_rs = 0;
- Lcd_en = 1;
- nop();nop();nop();nop();
- result = (bit)(P0&0x80);
- Lcd_en = 0;
- return(result);
- }
-
- void Write_com(uchar com)
- {
- while(Lcd_busy()); //LCD忙等待
- Lcd_rs = 0;
- Lcd_rw = 0;
- P0 = com;
- Delay_lcd1602(5);
- Lcd_en = 1;
- Delay_lcd1602(5);
- Lcd_en = 0;
- }
- void Write_data(uchar date)
- {
- while(Lcd_busy()); //LCD忙等待
- Lcd_rs = 1;
- Lcd_rw = 0;
- P0 = date;
- Delay_lcd1602(5);
- Lcd_en = 1;
- Delay_lcd1602(5);
- Lcd_en = 0;
- }
- void Lcd_init()
- {
- Lcd_en = 0;
- Write_com(0x38);
- Delay_lcd1602(5);
- Write_com(0x0c);
- Delay_lcd1602(5);
- Write_com(0x04);
- Delay_lcd1602(5);
- Write_com(0x01);
- Delay_lcd1602(5);
- }
- void Lcd_Pos(uchar yPos,uchar xPos) //設置第(xPos,yPos)個字符的DDRAM地址
- {
- uchar tmp;
- xPos &= 0x0f; //x位置范圍是0~15,因為顯示15列
- yPos &= 0x01; //y位置范圍是0~1,因為顯示2行
- if(yPos==0) //顯示第一行
- {
- tmp = xPos;
- }
- else
- {
- tmp = xPos + 0x40; //顯示第二行
- }
- tmp |= 0x80;
- Write_com(tmp);
- }
-
- void Write_char(uchar c,uchar xPos,uchar yPos) //定義Write_Char函數
- {
- Lcd_Pos(xPos,yPos);
- Write_data(c);
- }
-
-
-
- void Write_String(uchar *s,uchar xPos,uchar yPos) //定義Write_String函數
- {
- uchar i = 0;
- Lcd_Pos(xPos,yPos);
- while(*s)
- {
- Write_data(*(s++));
- if(++i>16) break;
- }
- }
-
-
- void InitUART(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; //允許中斷
- }
- void UartISR(void) interrupt 4
- {
- if(RI) //收到數據
- {
- RI=0; //清中斷請求
- }
- else //發送完一字節數據
- {
- TI=0;
- Sending=0; //清正在發送標志
- }
- }
- void PutChar_to_Uart(uint8 d)
- {
- Sending=1;
- SBUF=d;
- while(Sending);
- }
- void Prints(uint8 *pd)
- {
- while((*pd)!='\0')
- {
- PutChar_to_Uart(*pd);
- pd++;
- }
- }
-
-
- unsigned char ADconv(void)
- {
- unsigned char i;
- unsigned int data_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;
- return data_f;
- }
- /*
- void delay_ms(unsigned int x)
- {
- unsigned int i,j;
- i=0;
- for(i=0;i<x;i++)
- {
- j=108;
- while(j--);
- }
- }
-
-
-
-
-
- */
-
- void DispVal(uint8 pdat, uint8 x, uint8 y)
- {
- /*
- 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);
- }
-
-
- void Process10ms(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 (key2==0)
- {
- while (!key2);
- Wl++;
- if (Wl >=Wh)
- {
- Wl = 20;
- }
- }
- if (key3==0)
- {
- while (!key3)
- Alarmflag = ~Alarmflag;
- }
- }
- }
-
- /*
- void Process50ms(void)
- {
- if (flag50ms == 1)
- {
- flag50ms = 0;
- Led = ~Led;
-
-
- }
- }
- */
-
- void CheckProcess()
- {
- uint16 Wig, SetH, SetL;
- Wig = (uint16)temp_zheng*100 + (uint16)(temp_xiao*100);
- SetH = (uint16)Wh*100;
- SetL = (uint16)Wl*100;
- if ((Wig>SetH) && (Alarmflag==1))
- {
- Beep = 0;
- }
- else if ((Wig<SetL) && (Alarmflag==1))
- {
- Beep = 0;
- }
- else if (Alarmflag == 0)
- {
- Beep = 1;
- }
- else
- {
- Beep = 1;
- }
-
- }
- /*
- uchar Get10sAD(void)
- {
- uchar i;
- uint sum = 0;
-
- for (i=0; i<10; i++)
- {
- sum = sum + ADconv();
- delay_ms(10);
- }
- sum = sum/10;
- return sum;
- }
-
-
- */
- void Get_temp(uint ad_temp)
- {
- uint8 n = 0;
- while(1)
- {
- if ((ad_temp >= AD_Tab[n]) && (ad_temp <= AD_Tab[n+1]))
- {
- temp_zheng = n + 10;
- temp_xiao = (1.0*(ad_temp - AD_Tab[n]))/(AD_Tab[n+1] - AD_Tab[n]);
- break;
- }
- n++;
- if (n>40)
- {
- break;
- }
- }
- }
-
- void Disp_Voltage(void)
- {
- uchar temp;
- temp = (uchar)(temp_xiao * 100);
- Prints("Weight:"); //提示語
- PutChar_to_Uart(temp_zheng/100 + 0x30);
- PutChar_to_Uart(temp_zheng%100/10 + 0x30);
- PutChar_to_Uart(temp_zheng%100%10 + 0x30);
- PutChar_to_Uart('.');
- PutChar_to_Uart(temp/10 + 0x30);
- PutChar_to_Uart(temp%10 + 0x30);
- PutChar_to_Uart('T');
- PutChar_to_Uart(0x0d); //換行
- PutChar_to_Uart(0x0a); //換行
- Write_char(temp_zheng/100 + 0x30, 0, 8);
- Write_char(temp_zheng%100/10 + 0x30, 0, 9);
- Write_char(temp_zheng%100%10 + 0x30, 0, 10);
- Write_char('.', 0, 11);
- Write_char(temp/10 + 0x30, 0, 12);
- Write_char(temp%10 + 0x30, 0, 13);
- Write_char('T', 0, 14);
- }
-
-
- void main(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(); //采集電壓并發送
- }
-
- }
- }
-
- void Timer0() interrupt 1
- {
- static uint8 count1ms = 0;
- TH0 = (65535 - 1000)/256;
- TL0 = (65535 - 1000)%256;
- count1ms ++;
- if (count1ms == 10)
- {
- count1ms = 0;
- flag10ms = 1;
- }
-
- }
復制代碼
完整的Word格式文檔51黑下載地址:
|