基于单片机倾角检测仪设计分享
目錄
【功能介紹】
【原理圖】
【PCB】?
【實(shí)物圖】
【元器件清單】
【源代碼】
【參考資料】
【參考文獻(xiàn)】
【功能介紹】
本設(shè)計(jì)利用51單片機(jī)為主控系統(tǒng),采用三軸加速度傳感器ADXL345進(jìn)行傾角測(cè)量,可以實(shí)現(xiàn)兩大功能:
- 實(shí)時(shí)顯示當(dāng)前測(cè)量的角度值;
- 可以設(shè)置角度報(bào)警值,到達(dá)設(shè)定角度進(jìn)行報(bào)警功能。
【原理圖】
????????原理圖中包含單片機(jī)最小系統(tǒng),按鍵電路,顯示模塊,電源模塊,蜂鳴器模塊,傾角檢測(cè)模塊等;如需詳細(xì)資料可私信作者或加微信biyezhan007
【PCB】?
【實(shí)物圖】
【元器件清單】
| 10uf電解電容 | 1 |
| 30pf瓷片電容 | 2 |
| 3mm 紅色led燈 | 1 |
| 小電源接口 | 1 |
| 自鎖開關(guān) | 1 |
| 自鎖按鍵 | 7 |
| 4針排針 | 1 |
| LCD1602液晶顯示屏+16P插座 | 1 |
| 8550 三極管 | 1 |
| 5V 有源蜂鳴器 | 1 |
| 103排阻 | 1 |
| 3K電阻 | 1 |
| 1K電阻 | 2 |
| 10K電阻 | 3 |
| ADXL345模塊+2*5P插座 | 1 |
| STC89C52 單片機(jī)+DIP40插座 | 1 |
| 12M晶振 | 1 |
【源代碼】
#include <reg52.H> //頭文件調(diào)用 #include "ADXL345.h" //調(diào)用傾角傳感器的控制程序函數(shù) #include "LCD1602.h" //調(diào)用LCD1602 的顯示控制函數(shù) #include "eeprom52.h" //調(diào)用LCD1602 的顯示控制函數(shù)#define uchar unsigned char //簡化宏定義 #define uint unsigned int //簡化宏定義sbit Key_1=P1^0; //校零按鍵定義IO口 sbit Key_2=P1^1; //絕對(duì)校零按鍵定義IO口sbit Key_3=P1^2; //暫停顯示控制按鍵sbit Key_4=P1^3; sbit Key_5=P1^4; sbit Key_6=P1^5;sbit Beep=P2^3; //蜂鳴器標(biāo)志位bit angle_flag=0; //判斷處于絕對(duì)角度還是相對(duì)角度 ,angle_flag=0絕對(duì)角度顯示 Absolute angle、 =1相對(duì)顯示 relative angleint xDat,yDat,zDat; //傾角度傳感器的暫存數(shù)據(jù)變量 int x,y,z; //角度數(shù)據(jù)濾波計(jì)算暫存變量 int xNum,yNum,zNum; //角度數(shù)據(jù)濾波計(jì)算暫存變量 int ShowDatx,ShowDaty,ShowDatz; //濾波后的角度數(shù)據(jù)變量 bit SysError,key1,key2,key3,key4,key5,key6,SysMode; //系統(tǒng)錯(cuò)誤標(biāo)志位,按鍵控制3個(gè)標(biāo)志位,系統(tǒng)顯示狀態(tài)標(biāo)志位 uint ButtonTime=0; //按鍵等待延時(shí)變量int AngleDat,Dat1AngleDat; //實(shí)時(shí)角度值暫存變量 int AngleDat_value=0;float AngleDatx,CalibrationDat; //實(shí)際角度值、校準(zhǔn)角度值uchar state,ms; //數(shù)據(jù)顯示變量,定時(shí)變量 bit s1,Beep1; //數(shù)據(jù)閃爍標(biāo)志位,蜂鳴器報(bào)警標(biāo)志位/*無論是什么單片機(jī),只要是用內(nèi)部存儲(chǔ)區(qū)域EEPROM基本使用都是這樣關(guān)于內(nèi)部存儲(chǔ)區(qū),EEPROM,不同的單片機(jī)使用流程基本一致,單片機(jī)內(nèi)部有很多存儲(chǔ)單元,或者說扇區(qū),每一個(gè)扇區(qū)下面有很多地址, 數(shù)據(jù)就是存儲(chǔ)在這些地址下面的。存儲(chǔ)函數(shù)的程序都是官方提供好的,這些程序,咱們只需要用三個(gè),一個(gè)是扇區(qū)擦除函數(shù),一個(gè)是 數(shù)據(jù)寫函數(shù),還有一個(gè)就是數(shù)據(jù)讀取函數(shù)。 扇區(qū)擦除函數(shù)------使用哪個(gè)扇區(qū),先對(duì)那個(gè)扇區(qū)進(jìn)行擦,函數(shù)里填寫要擦除扇區(qū)的首地址 例如 SectorErase(0x2000);就是說擦除首地址為0x2000的扇區(qū)數(shù)據(jù) 數(shù)據(jù)存儲(chǔ)----------扇區(qū)擦除之后,就可以使用這個(gè)扇區(qū)下的地址進(jìn)行存儲(chǔ)數(shù)據(jù) 例如 byte_write(0x2000,123); 就是說將123存儲(chǔ)在0x2000地址下 數(shù)據(jù)讀取----------直接調(diào)用即可,例如 Dat=byte_read(0x2000);就是說將0x2000地址下的數(shù)據(jù)讀取出來給 Dat另外---- //51單片機(jī)存儲(chǔ)區(qū)域是8位的,也就是說能夠存下的最大數(shù)據(jù)是 255,而我們存的數(shù)據(jù)一旦大于256就會(huì)出現(xiàn)一些問題 //所以,如果您的設(shè)計(jì)需要存儲(chǔ)的數(shù)據(jù)大于256,那就把數(shù)據(jù)拆開存 /256得到高位 %256得到低位,之所以是256,是因?yàn)?-255,256個(gè)數(shù) // 例如數(shù)據(jù)257 257/256=1 257%256=1 ,這就存進(jìn)去兩個(gè)1,讀取的時(shí)候,將高位數(shù)據(jù)乘以256加低位數(shù)據(jù),還原數(shù)據(jù)*///按鍵處理函數(shù),平常按鍵處理是,判斷按鍵按下,延時(shí)消抖,再次判斷,然后按鍵死循環(huán)等待釋放,但是這樣會(huì)有 //一些問題,就是如果我按鍵一直按下,不松開,就會(huì)一直等待按鍵釋放,程序就會(huì)死在那,所以就不用這種按鍵處理 //換了一種變量判斷形勢(shì)的,比如說我將一個(gè)變量在按鍵不按下的時(shí)候等于0,按鍵按下的時(shí)候進(jìn)行累加,當(dāng)數(shù)值累加到 //一定程度,再次判斷按鍵是否按下,如果按鍵真的按下,就執(zhí)行,這種思路 void ButtonCode() //系統(tǒng)按鍵控制函數(shù) {if(!Key_2) //恢復(fù)絕對(duì)零度的校準(zhǔn)值{CalibrationDat=0; //清除校0標(biāo)志位angle_flag=0;}if(!Key_1) //校準(zhǔn)零度 記錄在絕對(duì)零度下的 角度值 (重要){if(ButtonTime<1000) ButtonTime++; //變量累加if(!Key_1 && ButtonTime>4) //變量加到四之后,就進(jìn)行再次判斷按鍵是否按下{if(!key1) //是按鍵按下,只要這個(gè)變量等于1,就執(zhí)行一次按鍵操作,并且變量清零,確保執(zhí)行一次{key1=1;CalibrationDat=AngleDatx; //校零時(shí)記錄當(dāng)前系統(tǒng)的角度值angle_flag=1;}}else key1=0;}else if(!Key_3){if(ButtonTime<1000) ButtonTime++;if(!Key_3 && ButtonTime>4){if(!key3){key3=1;SysMode=!SysMode; //顯示角度鎖定狀態(tài)標(biāo)志位置位}}else key3=0;}else if(!Key_4) //校準(zhǔn)零度 記錄在絕對(duì)零度下的 角度值 (重要){if(ButtonTime<1000) ButtonTime++;if(!Key_4 && ButtonTime>4){if(!key4){key4=1;state=(state+1)%2;}}else key4=0;}else if(!Key_5){if(ButtonTime<1000) ButtonTime++;if(!Key_5 && ButtonTime>4){if(ButtonTime>80){ButtonTime=75;key5=0;}if(!key5){key5=1;if(state==1){if(Dat1AngleDat<180){Dat1AngleDat++; SectorErase(0x2000);byte_write(0x2000,Dat1AngleDat);}}}}else key5=0;}else if(!Key_6){if(ButtonTime<1000) ButtonTime++;if(!Key_6 && ButtonTime>4){if(ButtonTime>80){ButtonTime=75;key6=0;}if(!key6){key6=1;if(state==1){if(Dat1AngleDat>0){Dat1AngleDat--;SectorErase(0x2000);byte_write(0x2000,Dat1AngleDat);}}}}else key6=0;}else ButtonTime=0; }/*1602液晶,是常用的顯示器件,一共是16個(gè)管腳,其中有八個(gè)管腳是數(shù)據(jù)傳輸管腳,有三個(gè)管腳是數(shù)據(jù)命令使能端管腳,還有兩組電源管腳, 其中一組電源管腳是給整個(gè)液晶進(jìn)行供電的,還有一組電源是單純的背景光電源,還剩下的最后一個(gè)管腳是對(duì)比度調(diào)節(jié)管腳,一般接上一個(gè)3K電 阻再接地即可。 一般我們用的函數(shù),無非就是 LCD1602_write 和 LCD1602_writebyte LCD1602_write(x,y); 這個(gè)函數(shù)括號(hào)里面可以填寫兩個(gè)數(shù)據(jù),第一個(gè)數(shù)據(jù)只能是 0 1 ,是0就說明第二個(gè)數(shù)據(jù)對(duì)液晶來說就是命令,填1就說明 第二個(gè)數(shù)據(jù)對(duì)于液晶來說就是要顯示的數(shù)據(jù)。 LCD1602_writebyte(); 這個(gè)函數(shù)里面直接填上要顯示的字符串即可,自動(dòng)進(jìn)行顯示*/void ShowCode() //顯示控制函數(shù) {if(ShowDaty>=0) //判斷當(dāng)前系統(tǒng)設(shè)備當(dāng)前角度處于正半軸還是負(fù)半軸 //計(jì)算絕對(duì)零度時(shí)的 角度數(shù)據(jù){if(ShowDatz>=0) //判斷當(dāng)前角度是否為0°-90° / 還是90°-180°的飯{AngleDatx=(float)ShowDaty*90/257; //計(jì)算當(dāng)前角度值0-90 (當(dāng)前角度=Y周角度數(shù)據(jù)*90° / Y軸最大90°時(shí)對(duì)應(yīng)的角度數(shù)據(jù))}else{AngleDatx=((float)2570-ShowDaty)*90/257+900; //計(jì)算當(dāng)前角度值90-180 (當(dāng)前角度=Y周角度數(shù)據(jù)*90° / Y軸最大90°時(shí)對(duì)應(yīng)的角度數(shù)據(jù)+90°)-}}else{if(ShowDatz>=0) //判斷當(dāng)前角度是否為-0°→ -90° / 還是-90° → -180°的飯{AngleDatx=(float)ShowDaty*90/257; //計(jì)算當(dāng)前角度值0--90 (當(dāng)前角度=Y周角度數(shù)據(jù)*90° / Y軸最大90°時(shí)對(duì)應(yīng)的角度數(shù)據(jù))}else{AngleDatx=(float)((ShowDaty*-1)-2570)*90/257-900; //計(jì)算當(dāng)前角度值90-180 (當(dāng)前角度=Y周角度數(shù)據(jù)*90° / Y軸最大90°時(shí)對(duì)應(yīng)的角度數(shù)據(jù)-90°)-}}ButtonCode(); //調(diào)用按鍵控制程序AngleDatx=AngleDatx-CalibrationDat; //零點(diǎn)校準(zhǔn)部分程序if(AngleDatx>1800) //角度值劃分 超限制計(jì)算實(shí)際角度值{AngleDatx=-1800+(AngleDatx-1800); //角度值劃分 超限制計(jì)算實(shí)際角度值 }else if(AngleDat<-1800){AngleDatx=1800+(AngleDatx+1800); //角度值劃分 超限制計(jì)算實(shí)際角度值}AngleDat=(int) AngleDatx; //賦值當(dāng)前角度值并顯示if(state==0){LCD1602_write(0,0x80); // 81 95 90 -90if(angle_flag==0) LCD1602_writebyte(" Absolute angle ");else LCD1602_writebyte(" Relative angle ");LCD1602_write(0,0xC0); //顯示到第二行LCD1602_writebyte("DAT:"); //顯示當(dāng)前角度值if(SysMode==0){ AngleDat_value=AngleDat;if(AngleDat<0) //如果角度為負(fù)數(shù){LCD1602_writebyte("-"); //顯示對(duì)應(yīng)的數(shù)據(jù)LCD1602_write(1,0x30+AngleDat*-1/1000%10);LCD1602_write(1,0x30+AngleDat*-1/100%10); LCD1602_write(1,0x30+AngleDat*-1/10%10);LCD1602_writebyte("."); LCD1602_write(1,0x30+AngleDat*-1%10); }else{ //如果角度為正數(shù)LCD1602_writebyte(" ");LCD1602_write(1,0x30+AngleDat/1000%10); //顯示對(duì)應(yīng)的數(shù)據(jù)LCD1602_write(1,0x30+AngleDat/100%10); LCD1602_write(1,0x30+AngleDat/10%10);LCD1602_writebyte("."); LCD1602_write(1,0x30+AngleDat%10); }LCD1602_write(1,0xdf); //單位顯示符號(hào)if((Dat1AngleDat*10<AngleDat || Dat1AngleDat*-10>AngleDat) && Dat1AngleDat!=0) Beep1=1;else Beep1=0;}else {if(AngleDat_value<0) //如果角度為負(fù)數(shù){LCD1602_writebyte("-"); //顯示對(duì)應(yīng)的數(shù)據(jù)LCD1602_write(1,0x30+AngleDat_value*-1/1000%10);LCD1602_write(1,0x30+AngleDat_value*-1/100%10); LCD1602_write(1,0x30+AngleDat_value*-1/10%10);LCD1602_writebyte("."); LCD1602_write(1,0x30+AngleDat_value*-1%10); }else{ //如果角度為正數(shù)LCD1602_writebyte(" ");LCD1602_write(1,0x30+AngleDat_value/1000%10); //顯示對(duì)應(yīng)的數(shù)據(jù)LCD1602_write(1,0x30+AngleDat_value/100%10); LCD1602_write(1,0x30+AngleDat_value/10%10);LCD1602_writebyte("."); LCD1602_write(1,0x30+AngleDat_value%10); }}LCD1602_write(0,0xC0+11);if(SysMode==0) //顯示系統(tǒng)狀態(tài){LCD1602_writebyte(" ON ");}else{LCD1602_writebyte(" OFF");}}else{LCD1602_write(0,0x80);LCD1602_writebyte("Alarm Value:");if(state==1&&s1==1){LCD1602_writebyte(" "); }else{LCD1602_write(1,0x30+Dat1AngleDat/100%10); //顯示對(duì)應(yīng)的數(shù)據(jù)LCD1602_write(1,0x30+Dat1AngleDat/10%10); LCD1602_write(1,0x30+Dat1AngleDat%10); }LCD1602_write(1,0xdf); //單位顯示符號(hào) LCD1602_write(0,0xC0);LCD1602_writebyte(" ");} }void interrupt_Init(void) {TMOD=0x01; //定義兩個(gè)定時(shí)器TL0 = 0x00; //設(shè)置定時(shí)初值TH0 = 0x4C; //設(shè)置定時(shí)初值 EA=1; //開總中斷ET0=1;TR0=1; }void main() //系統(tǒng)主程序 { uchar IDDat,cs;interrupt_Init();LCD1602_cls(); //系統(tǒng)初始化, 液晶顯示初始化Dat1AngleDat=byte_read(0x2000);if(Dat1AngleDat>180 || Dat1AngleDat<0){ Dat1AngleDat=45;SectorErase(0x2000);byte_write(0x2000,Dat1AngleDat);}Init_ADXL345(); //初始化ADXL345IDDat=Single_Read_ADXL345(0X00); //讀出的數(shù)據(jù)為0XE5,表示正確if(IDDat!=0XE5) SysError=1; //判斷傳感器是否正常else SysError=0;while(1) //循環(huán){ if(SysError==0) //如果系統(tǒng)傳感器正常 則{if(cs<10) //讀取角度濾波計(jì)算函數(shù)部分 連續(xù)記錄10次X、Y、Z角度數(shù)據(jù){cs++;Multiple_Read_ADXL345(); //連續(xù)讀出數(shù)據(jù),存儲(chǔ)在BUF中 xDat=BUF[1]*256+BUF[0]; //連續(xù)讀取XYZ的實(shí)時(shí)角度距離yDat=BUF[3]*256+BUF[2];zDat=BUF[5]*256+BUF[4];xNum+=xDat; //記錄10次的XYZ總數(shù)據(jù)yNum+=yDat;zNum+=zDat;}else{x=x*0.7+xNum*0.3; //濾波計(jì)算函數(shù)部分y=y*0.7+yNum*0.3;z=z*0.7+zNum*0.3;ShowDatx= x; //得出濾波后的系統(tǒng)角度數(shù)據(jù)ShowDaty= y;ShowDatz= z;cs=0;xNum=yNum=zNum=0; //清除 記錄10次的XYZ總數(shù)據(jù)} } ShowCode(); //調(diào)用系統(tǒng)顯示計(jì)算角度函數(shù)} } //傳感器錯(cuò)誤void init_1() interrupt 1 //定時(shí)器0中斷服務(wù)程序 {TH0=0x3c; //重新賦值TL0=0xb0;ms++; //計(jì)時(shí)變量計(jì)時(shí)if(ms%2==0) //250ms定時(shí){if(Beep1==1) Beep=!Beep; //只要beep等于1,蜂鳴器就會(huì)滴滴滴滴的響else Beep=1; //否則就是不響}if(ms%10==0) //500ms定時(shí){ s1=!s1;}if(ms>19) //1s定時(shí){ms=0;} }本文介紹了在設(shè)計(jì)的過程的關(guān)鍵點(diǎn),供大家參考學(xué)習(xí),如果有錯(cuò)誤或者不明白的可以直接私信作者,或者添加微信biyezhan007。
【參考資料】
?? ? ? ?本文介紹了在設(shè)計(jì)的過程的關(guān)鍵點(diǎn),供大家參考學(xué)習(xí),如需獲取實(shí)物、或者下載鏈接失效、對(duì)其他單片機(jī)硬件設(shè)計(jì)感興趣、有不明白的或者錯(cuò)誤的,可以添加徽信biyezhan007?
鄭重聲明,此文章提供給大家做參考模板,杜絕一切不良學(xué)術(shù)不良行為。
??
?????????最后說一下,如果大家對(duì)硬件和編程感興趣,可以點(diǎn)擊牛客網(wǎng)這個(gè)連接看看,是個(gè)不錯(cuò)的學(xué)習(xí)網(wǎng)站,是學(xué)長推薦給我的,因?yàn)橹罢夜ぷ鞯臅r(shí)候沒有太多經(jīng)驗(yàn),也不知道怎么準(zhǔn)備,去哪里搜資源,走了很多彎路,所以推薦給大家,當(dāng)初在上面大量刷題還看了好多面試經(jīng)驗(yàn)等,反正上面有很多課程+刷題+面經(jīng)+求職+討論區(qū)等資源,關(guān)鍵里面的資源全部公開免費(fèi),不用花錢,希望能幫助家!????
【參考文獻(xiàn)】
[1]肖金球,馮翼.增強(qiáng)型51單片機(jī)與仿真技術(shù)[M].北京:清華大學(xué)出版社社,?
[2]肖金球.單片機(jī)原理與接口技術(shù)[M].北京:清華大學(xué)出版社,2004,17-128.?
[3]周鴻武.基于單片機(jī)的酒精濃度檢測(cè)儀設(shè)計(jì)[J].制造業(yè)自動(dòng)化2012,02.?
[4]?康華光.電子技術(shù)基礎(chǔ)模擬部分(第五版)[M].高等教育出版社,2006年
[5]?康華光.電子技術(shù)基礎(chǔ)數(shù)字部分(第五版)[M].高等教育出版社,2006年
[6]?紀(jì)宗南.單片機(jī)外圍器件使用手冊(cè)—輸入通道器件分冊(cè)[M].北京航空航天大學(xué)出版社,2005年?
[7]賈伯年.傳感器技術(shù)[M].東南大學(xué)出版社,2000年
[8]何希才.傳感器及其應(yīng)用[M].國防工業(yè)出版社,2001年
[9]鄭學(xué)堅(jiān).微型計(jì)算機(jī)原理及應(yīng)用[M].清華大學(xué)出版社,2006年
[10]張水利.?單片機(jī)原理及應(yīng)用.?黃河水利出版社,出版年:2008年8月?
[11]譚浩強(qiáng).?C程序設(shè)計(jì).?第三版.?清華大學(xué)出版社,出版年:2005年7月
未經(jīng)作者允許,不得抄襲轉(zhuǎn)載,轉(zhuǎn)載或有問題請(qǐng)私信或微信作者。
總結(jié)
以上是生活随笔為你收集整理的基于单片机倾角检测仪设计分享的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux卸载MariaDB
- 下一篇: 【机器学习实战】——常见函数积累