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