目录
1、资料内容
2、整体架构流程
3、主控单元设计
4、LCD液晶显示
5、仿真图
6、程序
资料下载地址:基于51单片机的智能晾衣架设计资料(论文+源码+仿真)
1、资料内容
2、整体架构流程
为了实现晾衣自身能够完成对外界数据的采集与分析,集成控制环节我们采用了ATMEL公司生产的AT89C52单片机,与市面上的其他嵌入式控制单元相比较在体积与功耗方面都相当出色。此次设计主要突破在于设计合理的控制电路单元,同时结合采用的主控编写高质量的源码并使系统在实际与应用中能够发挥出色的稳定性和参考价值。本次将围绕主控单元设计合理的电路,结合SHT11温湿度采集单元、感光原件单元、LCD显示单元、模式控制单元使晾衣架能够得到外界的实时数据并作出相应的调整。在设定合适的温湿度及感光度的条件下能够自动控制电机驱动滑杆实现自动量晒与回收衣物,结合光线角度进行上下左右调整。主要框架如下图所示:
3、主控单元设计
为了使智能晾衣架在使用时满足嵌入式系统功耗、抗干扰、适用空间等要求,设计之初除了上述因素也考虑到成本因素。通过比较我们选择了51系列中的AT89C52芯片作为主控制单元。无论是功耗还是处理速度上都有着不错的表现,与CONTEX-M3系列单片机相比较处理上稍微慢点,但本次设计对分时处理的要求不是特别高,同时52系列具有简单高效的指令集和,大大减少设计难度,结合SHT11与ADC0804精准的完成数采集与电机控制。
我们常见的主控封装形式有40脚的DIP直插的也有PQFP类型的贴片封装,在proteus中仿真的时候选择DIP类型,方便自主设计与搭建外围电路单元。从产品角度和制版工艺上面来讲贴片能够节省空间。这次采用的主控制芯片是8位CMOS工艺的单片机,内部有八位CPU和FlASH,在工控领域有着广泛的用途,脱机运行性能稳定,相比较51有着更大的存储和定时器资源,其主要内部参数与引脚分布见下图:
指令集和
兼容MCS-51产品
FLASH
8个字节重复擦写
擦写周期
1000次重复擦写
静态操作
0HZ –- 24MHZ
编程I/O
32个可编程I/O
功耗模式
低功耗和掉电模式
中断源个数
8个中断控制单元
定时器个数
3个16位定时/计数器
4、LCD液晶显示
主控单元在上电之后会对液晶屏幕进行初始化,直观的显示出各项参数,结合独立按键显示控制模式,给用户提供良好的人机交互。常见的显示屏幕有很多尺寸,市面上的电容、电阻屏也数不胜数,这里我们选用户LCD1602作为液晶显示,同样的考虑到功耗与显示区间等因素。1602有着八个数据端口,体积很小亮度饱和能够直观简单的显示ASCII码与字符,与单片机的接口连接简单,控制屏幕上的液晶分子显示出字符,不同的电压控制不同区域上下两行能够分别显示16个字符,不具备汉字现实的能力,这点上不如12864,但完成设计的时候能够带来更稳定的显示,较强的抗干扰能力。实际硬件分为有无背光源,带背光的厚度稍微大点,会有更好的显示效果且调节背光源之间的滑变能够显示效果。常用的有16个管脚,分为电源区、指令控制区、数据区、背光区。实际外观尺寸见下图:
可以看到上图中有两行显示区域,左上角有1-16个外围引脚可以用,用来驱动屏幕显示想要的数据与字符,先简单说下管脚分布和功能:1管脚与2管脚用来接工作电源;3管脚通过VCC与分压电阻控制屏幕的对比度且会随着电压的变化而增加减少,对比度过高会出现阴影不清晰等现象,因此需要条调节合适的对比度以满足正常显示,可以外接10K电阻进行调整;4管脚RS控制端用来告诉模块当前是发送/读写数据还是指令,在实际现实过程中参与控制时序,高的电平信号控制数据控制寄存器、低电平信号控制指令寄存器;5管脚为W/R读写控制端,与4管脚结合起来可以实现数据/命令&读/写功能;6管脚作为EN使能控制端用来控制液晶的工作状态;7管脚到14管脚为数据线,用来读写数据;15与16管脚控制背光,根据实际情况考虑是否需要接入电路中。
对控制端口有一定的了解后,还需要掌握读写时序图从而根据时序去设计软件驱动,这里以写数据时序图为例子说下原理过程:
上图中RS决定当前是要启用命令寄存器还是数据寄存器,写数据的过程中RS要保持高电平信号,写命令的过程要保持低电平信号。当往液晶上写字符的时候,首先要将RS拉低,R/W保持低电频信号,随后有个上升沿将RS拉成高电位,也就是上图RS对应的第二条信号线。图中tsp_x、tR、tHD_x等间距在设计过程中都可以采用延时实现时序同步。我们可以看到valid data是有效地数据段,只有当RS = 1、R/W = 0、DB0-DB7发送数据、EN使能等状态都满足的时候才能实现数据从I/O写入到液晶。这种时序图在液晶操作与与不同工控领域的传感器数据采集中经常会用到,因此软件设计过程中要严格遵守时序从而获得准确有效地数据值。关于读写命令及读写数据的操作时序就不一一说明了,在下表中根据逻辑时序已经归出控制区域I/O的工作状态,方便开发使用。
读状态
输入
RS=L,R/W=H,E=H
输出
D0—D7=状态字
写指令
输入
RS=L,R/W=L,D0—D7=指令码,E=高脉冲
输出
无
读数据
输入
RS=H,R/W=H,E=H
输出
D0—D7=数据
写数据
输入
RS=H,R/W=L,D0—D7=数据,E=高脉冲
输出
无
上面也有提到16个显示区域,它们也是有对应的基带地址,要在固定的地址上显示字符就需要发送对应的地址指令,第一行地址起始地址为0x00,第二行起始地址为0x40,后续的地址参考图3.2.3。设计时如果没有用到屏幕滚动的话可以不考虑虚拟地址。也就是说从0x10以后到0x27以及0x50到0x67需要开启其滚动显示才能显示出该地址空间上的数据。
关于常见的操作指令可以参考手册中的指令集部分。
详细内容请下载资料。
5、仿真图
6、程序
#include<reg52.h>
#include <intrins.h>
#include <math.h>
#include <stdio.h>
#include <1602.h>
#include <sht11.h>
#include <24c02.h> #define uchar unsigned char
#define uint unsigned int
#define W_cmd 0xa0 //24c02写指令
#define R_cmd 0xa1
uint temp,humi;
value humi_val,temp_val; //定义两个共同体,一个用于湿度,一个用于温度
uchar error; //用于检验是否出现错误
uchar checksum; //CRCuchar TEMP_data[7]; //用于记录实测的温度
uchar HUMI_data[6]; //用于记录实测的湿度
uchar LIGH_data[4]; //用于记录实测光感度uchar show_temp[5]; //显示设定的温度
uchar show_humi[4]; //显示设定的湿度uchar data temp_humi_cache[4]; //温湿度设置缓存
uchar temp_set; //保存温度变量
uchar humi_set; //保存湿度变量
uchar presskeynum; //按键次数变量
uchar nn; //用于蜂鸣器
uchar code word1[]={" a product of "};
uchar code word2[]={"UNITED ELECTRONS"};
uchar code word3[]={" Welcome........"};
sbit k1=P2^0; //选择按键
sbit k2=P2^1; //增加按键
sbit k3=P2^2; //减小按键
sbit k4=P2^3;// 确认按键
sbit led1=P1^4; //温度过低指示灯
sbit led2=P1^5; //温度过高
sbit led3=P1^6; //湿度低于下限值,报警,加湿。
sbit led4=P1^7; //湿度过高,报警,不调湿
sbit motor1=P3^4;
sbit motor2=P3^5;
sbit motor3=P3^6;
sbit motor4=P3^7;
sbit P2_6=P2^6;//********延时函数*********
void delay(uint z) //z为毫秒数{int a,b;for(a=z;a>0;a--)for(b=120;b>0;b--);
}
void key()
{uchar m;if (k1==0) //调整按键检测{delay(5);if (k1==0){presskeynum++;if(presskeynum==3)presskeynum=0;while(k1==0); //若一直按下,循环LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏}}if(presskeynum==1)//温度设置{if(k2==0) // 加{delay(300);temp_set++;if (temp_set>30)temp_set=30;while(k2==0); //加上此句必须松按键才处理}if(k3==0)//减{delay(300);temp_set--;if (temp_set<18)temp_set=18;while(k3==0); //加上此句必须松按键才处理}}if(presskeynum==2)//湿度设置{if(k2==0)// 加{delay(300);humi_set++;if (humi_set>99)humi_set=99;while(k2==0);}if(k3==0)//减{delay(300);humi_set--;if (humi_set<1)humi_set=1;
// while(k3==0); //这句是调试加入的}}if(k4==0)// 退出键 //设置完初始值以后通过IIC写入24c02并清屏 {delay(10);if(k4==0){while(k4==0);presskeynum=0;temp_humi_cache[0]=temp_set/10;temp_humi_cache[1]=temp_set%10;temp_humi_cache[2]=humi_set/10;temp_humi_cache[3]=humi_set%10;for(m=0;m<4;m++){ WriteIIC(W_cmd,0x00+m,temp_humi_cache[m]); //设定值写入24c02}LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏}}
}//主函数void main()
{ uchar t;uchar temp_adc;k1=k2=k3=k4=1;motor1=motor2=motor3=motor4=0;P2_6=0;for (t=0;t<4;t++)temp_humi_cache[t]=ReadIIC(W_cmd,0x00+t,R_cmd); //读入24c02设定的值temp_set=temp_humi_cache[0]*10+temp_humi_cache[1]; //设置温度humi_set=temp_humi_cache[2]*10+temp_humi_cache[3]; //设置湿度LCD_Initial(); //液晶初始化GotoXY(0,0);Print_slow(word1);GotoXY(0,1);Print_slow(word2);LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏GotoXY(0,0);Print_slow(word3);LCD_Write(LCD_COMMAND,LCD_CLEAR_SCREEN); //清屏 //完成系统初始化 while(1){key();P1 = 0xff; //P1口初始化temp_adc = P1; //读取光敏值,8位精度最大256if(presskeynum==0) //测量温湿度{ s_connectionreset(); //启动连接复位error=0; //初始化error=0,即没有错误error+=s_measure((unsigned char*)&temp_val.i,&checksum,TEMP); //温度测量值返回到temp.val.ierror+=s_measure((unsigned char*)&humi_val.i,&checksum,HUMI); //湿度测量值返回到humi_val.iif(error!=0)s_connectionreset(); //如果发生错误,系统复位else{ humi_val.f=(float)humi_val.i; //转换为浮点数temp_val.f=(float)temp_val.i; //转换为浮点数calc_sth10(&humi_val.f,&temp_val.f); //修正相对湿度及温度,误差弥补temp=temp_val.f*10;humi=humi_val.f*10;GotoXY(0,0); //选择温度显示位置Print("Temp: C --- "); //5格空格GotoXY(0,1); //选择湿度显示位置Print("Humi: % "); //5格空格 GotoXY(5,0); //设置温度显示位置TEMP_data[0]=temp/1000+'0'; //温度百位 if (TEMP_data[0]==0x30) //ASCLL = 0TEMP_data[0]=0x20; //对应的ASCLL位空格TEMP_data[1]=temp%1000/100+'0'; //温度十位 if (TEMP_data[1]==0x30 && TEMP_data[0]!=0x30) TEMP_data[1]=0x20;TEMP_data[2]=temp%100/10+'0'; //温度个位TEMP_data[3]=0x2e; //小数点TEMP_data[4]=temp%10+'0'; //温度小数点后第一位 TEMP_data[5]=0xdf; //显示温度符号℃书上是第248TEMP_data[6]='\0'; //实际上0xdf对应的是小圆圈Print(TEMP_data); //输出温度 GotoXY(5,1); HUMI_data[0]=humi/1000+'0'; //湿度百位 if (HUMI_data[0]==0x30)HUMI_data[0]=0x20;HUMI_data[1]=humi%1000/100+'0'; //湿度十位 HUMI_data[2]=humi%100/10+'0'; //湿度个位HUMI_data[3]='.' ; //小数点HUMI_data[4]=humi%10+'0'; //湿度小数点后第一位 HUMI_data[5]='\0';Print(HUMI_data); //输出湿度GotoXY(13,1);LIGH_data[0] = temp_adc%1000/100+'0';
// if(LIGH_data[0] == 0x30)
// LIGH_data[0] = 0x20;LIGH_data[1] = temp_adc%100/10+'0';LIGH_data[2] = temp_adc%10+'0';LIGH_data[3] = '\0';Print(LIGH_data); if ((temp/10)<temp_set) {motor1=1;motor2=0; }else if ((temp/10)>=temp_set){motor2=1;motor1=0;}if ((humi/10)<humi_set){motor3=1;motor4=0;}else if ((humi/10)>=humi_set){ motor4=1;motor3=0;}} //else} //ifif(presskeynum==1) //设定温度时显示的内容{show_temp[0]=temp_set/10+0x30;show_temp[1]=temp_set%10+0x30;show_temp[2]=0xdf;show_temp[3]='C';show_temp[4]='\0';GotoXY (0,0);Print("SET TEMP:");GotoXY (0,1);Print(show_temp);} if(presskeynum==2) //设定湿度时显示的内容{show_humi[0]=humi_set/10+0x30;show_humi[1]=humi_set%10+0x30;show_humi[2]='%';show_humi[3]='\0';GotoXY (0,0);Print("SET HUMI:");GotoXY (0,1);Print(show_humi);}}//while
} //mian