完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
温湿度检测设计。基于51单片机、ESP8266WiFi模块、温湿度DHT11传感器、Android APP完成。首先先展示一下设计好的实物,接下来将从系统方案、硬件设计、软件设计这三个方面来阐述。
1、系统方案 DHT11温湿度传感器采集数据传送给单片机,单片机将数据处理之后通过ESP8266WiFi模块将数据发送给手机App。WiFi模块有两个作用:一是串口转WiFi,单片机通过串口将数据发送给Wifi模块,对于单片机编程而言,与Wifi模块通信就相当于与串口通信,不必知道WiFi协议;二是WiFi模块当做WiFi 热点AP,手机搜索8266建立的WiFi名称就能与其连接。显然这种方式只是局域网通信,不能进行远程连接,远程连接需要服务器端的支持,现在常采用的方法是通过阿里云、机智云等,远程连接比较复杂,我们以后再研究。 2、硬件设计 整个设计电路图如下所示: ESP8266WiFi模块我们采用的是ESP-01S模组,安信可公司出品的,注意ESP-01S的电源是3.3V,而单片机电源是5V,所以需要一个5V转3.3V的模块,我们选用的是LM1117T-3.3V这个器件, LM1117这个器件管脚一定不要接错,否则会发热非常严重然后烧毁。我第一次焊接的时候把LM1117管脚焊错了,上电后用手触碰了一下差点把手烫伤,赶紧把电源拔掉。LM1117的接线如下所示: ESP8266的接线如下图所示: RX:模块串口通信的接收引脚,接到单片机的TX引脚。 GND:接地 TX:模块的发射端,接单片机的RX接口。 CH_PD / EN:接3.3v高电平。 VCC:接3.3V的高电平。 DHT11温湿度传感器负责采集环境中的温湿度数据,在单片机软件设计部分会详细的介绍该传感器的使用步骤。 引脚说明: VDD 供电3.3~5.5V DC DATA 串行数据,单总线 NC 空脚 GND 接地,电源负极 3.单片机软件设计 单片机程序主要是两个点,一是读取DHT11传感器的温湿度数据,二是串口通信。DHT11的官方文档写的很规范,有关于读取数据的详细步骤,文档更新也比较及时, DHT11采用单总线通信,单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。 传送数据位定义 DATA 管脚用于DHT11与单片机之间的通讯和同步,采用单总线数据格式,一次传送40 位数据,高位先出。 数据格式: 8bit 湿度整数数据+ 8bit 湿度小数数据+ 8bit 温度整数数据+ 8bit 温度小数数据+ 8bit 校验位。 注:其中湿度小数部分为0。 校验位数据定义 8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 = 8bit 校验位 如果以上等式成立,则本次传感器采集的数据有效,否则无效。 先看采集数据有效的示例,接收到的40 位数据为: 0011 0101 0000 0000 0001 1000 0000 0100 0101 0001 湿度高8 位 湿度低8 位 温度高8 位 温度低8 位 校验位 计算: 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,接收数据正确。 湿度:0011 0101(整数)=35H=53%RH 0000 0000(小数)=00H=0.0%RH =》53%RH + 0.0%RH = 53.0%RH 温度:0001 1000(整数)=18H=24℃ 0000 0100(小数)=04H=0.4℃ =》24℃ + 0.4℃ = 24.4℃ 采集数据无效的示例,接收到的40 位数据为: 0011 0101 0000 0000 0001 1000 0000 0100 0100 1001 湿度高8 位 湿度低8 位 温度高8 位 温度低8 位 校验位 计算: 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 不等于0100 1001,本次接收的数据不正确,放弃,重新接收数据。 通过以上两个示例可以清楚DHT11数据格式以及数据如何去校验有效性。 数据时序图 用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出40bit 的数据,并触发一次信采集。信号发送如图所示。这里的主机是指单片机,从机是指DHT11传感器。 下面这个图表罗列了时序图相关的参考时间,在读取数据的详细步骤中会用到这些数值。 根据时序图和表中的参考时间,我们可以得出读取传感器数据的步骤。 step1:单片机输出低电平保持20ms step2:单片机拉高电平保持13us等待DHT11传感器的低电平响应信号 step3:判断DHT11是否给出低电平响应,如果有低电平响应则进入步骤4,否则等待下一轮的尝试。 step4:通过while语句等待83us的低电平响应时间结束 step5:通过while语句等待87us的高电平响应时间结束 step6:计算温湿度数据 step7:单片机输出高电平结束一次数据采集的读取 step8:校验数据 在时序图中可以看到,数据读取是每次一位进行的,数据0位和数据1位的低电平时间是相同的,即54us。数据0位的高电平时间是24us,而数据1为的高电平时间是71us,通过高电平时间的差异我们就可以判断出是数据0还是数据1。所以单独写了一个函数用来计算数据0位和1位,由于温湿度的整数和小数部分分别是由8位表示的,我们定义该函数得到8位数据之后给出返回值。步骤6对应的函数computeData() 用来完成上述工作。我们对步骤6进行详细的描述: step 6.1:等待54us低电平结束 step 6.2:延时30us判断高电平是否结束,因为数据0位的电平最大时长是27us,如果超过27us之后高电平结束,则为数据0位,否则为数据1位。 step 6.3:通过while语句等待高电平结束 step 6.4:通过移位和或与的方式保存一个数据位 step 6.5:循环6.1到6.4步骤8次,得到一个字节的数据 //-------------------------------- //-----湿度读取子程序 ------------ //-------------------------------- //----以下变量均为全局变量-------- //----温度高8位== temperature_H------ //----温度低8位== temperature_L------ //----湿度高8位== humidity_H----- //----湿度低8位== humidity_L----- //----校验 8位 == checkdata----- //-------------------------------- void readData() { U8 humidity_H_temp,humidity_L_temp,temperature_H_temp,temperature_L_temp,checkdata_temp; //step1:单片机输出低电平保持20ms P2_0=0; delayms(20); //step2:单片机拉高电平保持13us等待DHT11传感器的低电平响应信号 P2_0=1; delay13us(); //step3:判断DHT11是否给出低电平响应,如果有低电平响应则进入步骤4,否则等待下一轮的尝试。 if(P2_0==0) { //step4:通过while语句等待83us的低电平响应时间结束 while(P2_0==0); //step5:通过while语句等待87us的高电平响应时间结束 while(P2_0==1); //step6:计算温湿度数据 humidity_H_temp = computeData(); humidity_L_temp = computeData(); temperature_H_temp = computeData(); temperature_L_temp = computeData(); checkdata_temp = computeData(); //step7:单片机输出高电平结束一次数据采集的读取 P2_0 = 1; //step8:校验数据 if(checkdata_temp == humidity_H_temp + humidity_L_temp + temperature_H_temp + temperature_L_temp) { humidity_H = humidity_H_temp; humidity_L = humidity_L_temp; temperature_H = temperature_H_temp; temperature_L = temperature_L_temp; checkdata = checkdata_temp; } } } /** *根据时序计算温湿度值 */ U8 computeData() { U8 i,U8comdata; for(i=0; i《8; i++) { //step 6.1:等待54us低电平结束 while(P2_0==0); //step 6.2:延时30us判断高电平是否结束 Delay_10us(); Delay_10us(); Delay_10us(); U8temp=0; if(P2_0==1) { U8temp=1; } //step 6.3:通过while语句等待高电平结束 while(P2_0==1); //step 6.4:通过移位和或与的方式保存一个数据位 U8comdata《《=1; U8comdata|=U8temp; } return U8comdata; } 温湿度数据读取完毕,接下来就是通过串口发送出去,串口发送数据的代码相对简单了,我们在主函数中对串口通信进行初始化,然后在一个while语句中每隔2s读取数据然后发送。 //---------------------------------------------- //main()功能描述: STC89C52RC 11.0592MHz 串口发送温湿度数据,波特率 9600 //---------------------------------------------- void main() { U8 i; TMOD=0x20; //定时器1工作在方式2 TH1 = 0xfd; //波特率9600 TL1 = 0xfd; SM0=0; //串口工作在方式1 SM1=1; EA = 1; //开总中断 REN = 1; //使能串口 TR1 = 1; //定时器1开始计时 delayms(1000); sendString(“AT+CWMODE=2rn”); //ap模式 delayms(1000); sendString(“AT+CIPMUX=1rn”); //允许多连接 delayms(1000); sendString(“AT+CIPSERVER=1rn”); //建立TCP Server delayms(1000); ES = 1; //开串口中断 while(1) { //调用温湿度读取子程序 readData(); str[0]=humidity_H; str[1]=humidity_L; str[2]=temperature_H; str[3]=temperature_L; str[4]=checkdata; //发送到串口 delayms(2); //发送温度数据 sendString( “AT+CIPSTART=1,”TCP“,”192.168.4.2“,5000rn”); delayms(2); sendString(“AT+CIPSEND=1,5rn”); delayms(2); for(i=0; i《5; i++) { sendOneChar(str); } //读取模块数据周期不易小于 2S delayms(2000); } } 至此,单片机端的主要代码就讲解完了,可以看到核心代码是如何读取DHT11的数据。 4.手机APP软件设计 APP是用Android Studio(AS)开发的,不建议初学者学习Eclipse结合ADT(Android Eclipse Tools)插件的方式开发Android APP,这种方式已经过时并且以后会被淘汰,Google在2016年底已经停止了对ADT的更新,我之前所在的公司已经将Eclispe的代码全部迁移到AS平台了,推荐使用Google自家的AS集成开发环境。AS有很多优点,但是在使用时也有问题,AS借助gradle进行项目构建,至于为什么Google利用gradle进行Android app项目构建,读者可以自行上网搜索。gradle插件版本要和AS版本相对应,不同的开发者的gradle版本可能不同,所以当你拿到另外一个开发者的代码在自己的AS运行时时有可能会构建失败。这个现象对于国外开发者而言不是一个问题,AS可以自动去下载所需要的gradle插件版本,但是在国内,由于众所周知的原因,如果不会科学上网那么AS直接尝试下载gradle插件时会失败,会令很多初学者不知所措。在以后有时间我会单独写一篇blog来讲解如何去解决这个问题。最近听到Google要重返中国市场,如果能回归成功,对于国内的很多开发者和学术研究者而言是个好消息。 言归正传,本设计APP的代码主要分成两个部分,一是WiFi数据的接收,二是图表显示。 在OnCreate()方法中进行控件的初始化,并开启一个温度数据接收线程来接收数据。 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //实例化控件 mTemperatureTv = findViewById(R.id.tv_temperature); mHumidityTv = findViewById(R.id.tv_humidity); mTemperatureAlert = findViewById(R.id.tv_temperature_alert); mHumidityAlert = findViewById(R.id.tv_humidity_alert); mTemperatureRangeTv = findViewById(R.id.tv_temperature_range); mHumidityRangeTv = findViewById(R.id.tv_humidity_range); mTemperatureRangeTv.setText(“(” + mTempLow + “ - ” + mTempHigh + “℃)”); mHumidityRangeTv.setText(“(” + mHumidityLow + “ - ” + mHumidityHigh + “%)”); mLineChart = findViewById(R.id.chart); //初始化图表属性 initChart(); //开启温度显示线程 new ReceiveDataThread().start(); } 单独开辟一个线程用来循环读取WiFi模块传输过来的数据,对于App而言单片机通过Wifi模块传输的数据相当与网络数据,用网络编程相关的就可以,线程的相关定义如下所示: /** * 温湿度数据接收线程 */ private class ReceiveDataThread extends Thread { private DataInputStream in; private byte[] receive; @Override public void run() { try { //在手机端建立一个ServerSocket,负责接收ESP8266发送的数据,端口为5000 serverSocket = new ServerSocket(5000); client = serverSocket.accept(); while (true) { //循环读取数据 in = new DataInputStream(client.getInputStream()); receive = new byte[5]; in.read(receive); String data = new String(receive); //刷新UI doUIRrefresh(data); } } catch (IOException e) { e.printStackTrace(); } } } |
|
|
|
只有小组成员才能发言,加入小组>>
2514 浏览 0 评论
1092浏览 2评论
703浏览 1评论
456浏览 0评论
200浏览 0评论
341浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 16:16 , Processed in 2.954952 second(s), Total 80, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号