目录
【功能介绍】
【原理图】
【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月
未经作者允许,不得抄袭转载,转载或有问题请私信或微信作者。