单片机温湿度采集主从机_基于51单片机温湿度系统采集 - CSDN
  • 51单片机DHT11温湿度传感器

    万次阅读 多人点赞 2016-08-28 15:23:36
    DHT11是一款有已校准数字信号输出的温湿度传感器。 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃。一.电路连接分析1.引脚图2.接线图DHT11 器件采用简化...由于它们是主从结极,只有主机呼叫从时,从

    DHT11是一款有已校准数字信号输出的温湿度传感器。 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃。

    一.电路连接分析

    1.引脚图

    这里写图片描述

    2.接线图

    DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约 5.1kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

    这里写图片描述

    二.数据采集分析

    1.数据总时序

    用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,幵触发一次信采集

    这里写图片描述

    2.主机发送起始信号

    单片机连接DHT11的DATA引脚的I/O口输出低电平,且低电平保持时间不能小于 18ms,然后等待 DHT11 作出应答信号。

    这里写图片描述

    3.检测从机应答信号

    DHT11 的 DATA 引脚检测到外部信号有低电平时, 等待外部信号低电平结束, 延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据。

    这里写图片描述

    4.接收数据
    (1)数据判定规则
    位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。

    接收数据时可以先等待低电平过去,即等待数据线拉高,再延时60us,因为60us大于28us且小于70us,再检测此时数据线是否为高,如果为高,则数据判定为1,否则为0。

    这里写图片描述

    (2)数据格式

    一次传送 40 位数据,高位先出

    8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。

    (3)数据校正
    判断“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”的结果是否等于8bit 校验位。如果等于则数据接收正确,否则应该放弃这一次的数据,重新接收。

    三.驱动程序

    #include<reg51.h>
    #include<intrins.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit Data=P3^6;   //定义数据线
    uchar rec_dat[9];   //用于显示的接收数据数组
    
    void DHT11_delay_us(uchar n)
    {
        while(--n);
    }
    
    void DHT11_delay_ms(uint z)
    {
       uint i,j;
       for(i=z;i>0;i--)
          for(j=110;j>0;j--);
    }
    
    void DHT11_start()
    {
       Data=1;
       DHT11_delay_us(2);
       Data=0;
       DHT11_delay_ms(20);   //延时18ms以上
       Data=1;
       DHT11_delay_us(30);
    }
    
    uchar DHT11_rec_byte()      //接收一个字节
    {
       uchar i,dat=0;
      for(i=0;i<8;i++)    //从高到低依次接收8位数据
       {          
          while(!Data);   等待50us低电平过去
          DHT11_delay_us(8);     //延时60us,如果还为高则数据为1,否则为0 
          dat<<=1;           //移位使正确接收8位数据,数据为0时直接移位
          if(Data==1)    //数据为1时,使dat加1来接收数据1
             dat+=1;
          while(Data);  //等待数据线拉低    
        }  
        return dat;
    }
    
    void DHT11_receive()      //接收40位的数据
    {
        uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; 
        DHT11_start();
        if(Data==0)
        {
            while(Data==0);   //等待拉高     
            DHT11_delay_us(40);  //拉高后延时80us
            R_H=DHT11_rec_byte();    //接收湿度高八位  
            R_L=DHT11_rec_byte();    //接收湿度低八位  
            T_H=DHT11_rec_byte();    //接收温度高八位  
            T_L=DHT11_rec_byte();    //接收温度低八位
            revise=DHT11_rec_byte(); //接收校正位
    
            DHT11_delay_us(25);    //结束
    
            if((R_H+R_L+T_H+T_L)==revise)      //校正
            {
                RH=R_H;
                RL=R_L;
                TH=T_H;
                TL=T_L;
            } 
            /*数据处理,方便显示*/
            rec_dat[0]='0'+(RH/10);
            rec_dat[1]='0'+(RH%10);
            rec_dat[2]='R';
            rec_dat[3]='H';
            rec_dat[4]=' ';
            rec_dat[5]=' ';
            rec_dat[6]='0'+(TH/10);
            rec_dat[7]='0'+(TH%10);
            rec_dat[8]='C';
        }
    }
    
    /*这里使用lcd1602来显示采集到的数据,lcd1602驱动程序在博主的51单片机系列博文中有详细讲解*/
    void main()
    {
       uchar i;   
       lcd_init();   //lcd1602初始化
       while(1)
       {   
           DHT11_delay_ms(1500);    //DHT11上电后要等待1S以越过不稳定状态在此期间不能发送任何指令
           DHT11_receive();
           lcd_write_command(0x80);   //从lcd1602第一行第一个位置开始显示
           for(i=0;i<9;i++)
           lcd_write_data(rec_dat[i]);   //显示数据                      
       }
    }
    展开全文
  • 基于Android的温湿度采集系统

    万次阅读 热门讨论 2018-01-15 16:24:16
    本次设计结合日常生活中的需要,应用单片机技术、蓝牙通信技术和Android手机APP开发技术,设计了一种以Android智能手机作为指令传送和数据接收终端,获取实时温湿度信息的系统。系统整体框架如图所示。 整体...

          本次设计结合日常生活中的需要,应用单片机技术、蓝牙通信技术和Android手机APP开发技术,设计了一种以Android智能手机作为指令传送和数据接收终端,获取实时温湿度信息的系统。系统整体框架如图所示。


    整体设计包含硬件与软件两大部分,硬件提供数据支持,软件用于数据显示,数据传送的桥梁HC-05蓝牙模块,它支持Socket蓝牙通信协议,这种协议与4.0低功耗蓝牙通信协议有很大的区别,具体可以自己去上网查资料,这里仅介绍传统的蓝牙通信协议。程序流程如下图所示。


    下面我将从硬件和软件两个方面对本系统进行详细的介绍。

    1.软件部分

    软件开发用的是eclipse工具,在文章结束时将一并给出手机端与硬件端完整源代码。

    1.1添加蓝牙权限

    在设计主程序之前,首先需要在AndroidManifest.xml文件中添加操作蓝牙的权限。

    <uses-permissionandroid:name="android.permission.BLUETOOTH"/>  //允许程序连接到已配对的蓝牙设备。

    <uses-permissionandroid:name="android.permission.BLUETOOTH_ADMIN"/>  //允许程序发现和配对蓝牙设备。

    1.2打开蓝牙并连接设备

    打开蓝牙使用的是eclipse系统自带的蓝牙适配器BluetoothAdapter,通过实例化该对象,运用条件语句判断是否打开蓝牙,具体代码如下:

    if (!mBluetoothAdapter.isEnabled())

    {  //蓝牙未代开时会执行此语句,提示是否打开蓝牙

    IntentenableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);

                  startActivityForResult(enableIntent,REQUEST_ENABLE_BT);

    }

    当用户选择打开蓝牙时,程序会执行条件里的语句,跳转至蓝牙设备选择界面

    用户点击页面底下的扫描设备时,程序会首先注册一个广播接收机制,监听蓝牙设备的变化,每搜索一个设备就会发送一个广播,当全部搜索完之后会发送该广播,注册广播接收机制的代码如下:

    privatefinal BroadcastReceiver mReceiver = new BroadcastReceiver()

    @Override 

      public void onReceive(Context context, Intent intent)

    String action =intent.getAction();  // When discoveryfinds a device 

    if (BluetoothDevice.ACTION_FOUND.equals(action))

    BluetoothDevicedevice = intent.getParcelableExtra(BluetoothDevice.EXTRA _DEVICE); 

                if (device.getBondState() !=BluetoothDevice.BOND_BONDED)  

    {  //设备绑定状态

    mNewDevicesArrayAdapter.add(device.getName()+ "\n" + device.getAddress()); 

                } 

              }

    else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))

                setProgressBarIndeterminateVisibility(false); 

             setTitle(R.string.select_device); 

             if(mNewDevicesArrayAdapter.getCount() == 0)

                       { 

                    String noDevices =getResources().getText(R.string.none_found.toString();

                 mNewDevicesArrayAdapter.add(noDevices); 

             }

           }

    }

    };   

    系统扫描完所有的可用蓝牙设备后,用户点击其中一个设备,程序会根据点击的设备通过getAdress方法获取该设备地址,该地址将会通过putExtra方法传递给下一个界面。同时运用getName方法获取设备名告知用户。

    1.3线程建立连接

    当用户从设备选择界面返回至主界面时,首先会调用onActivityResult方法,该方法中有三个参数,第一个是请求码,即一开始调用startActivityForResult的传递过去的值,第二个参数为结果码,结果码用于标识返回数据来自哪个新Activity,第三个是Intent对象,通过getExtra获取蓝牙设备的地址。获取地址后,通过BluetoothAdapter对象中的getRemote

    Device方法生成一个BluetoothDevice对象device。重要代码如下:

    String address = data.getExtras().getString(DeviceListActivity.EXTRA_DEVICE _AD DRESS); //获取地址

    BluetoothDevice device =mBluetoothAdapter.getRemoteDevice(address); //创建bluetoothDevice对象

    建立一个线程,创建BluetoothDevice类型的局部变量,生成一个构造器方法将上面的device对象传递过来。蓝牙4.0及以下运用的是BluetoothSocket蓝牙通信协议。建立连接的代码如下:

    tmp =device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));  //创建客户端蓝牙ClientSocket

    这个线程执行后,就可以与蓝牙之间互相通信了,我们还需要建立一个线程,用于与蓝牙之间数据的传递,为了完成这一操作,我们需要创建一个输入与输出流,用于数据的发送与接收。发送指令时,规定发送一个字符型的“a”,转换为字节流型数据后发送出去,硬件识别该指令后,会调取温湿度采集模块采集周围环境的温湿度并向客户端发送该数据。客户端接收时,先通过输入流读取数据,然后进行数据类型的转换。这一部分重要代码如下:

    String str="a";

    mmOutStream.write(str.getBytes());  //写入该指令

    bytes = mmInStream.read(buffer);   //读取数据

    synchronized (mBuffer) {  //List<Integer> mBuffer

    for (int i = 0;i < bytes; i++) {

    mBuffer.add(buffer[i]& 0xFF);  //字节数组转换成整形变量

                  }

    }

    1.4数据显示

    在显示之前,我们想要接收的数据是完整的,还需要加一个延迟,这里,我加了一个线程等待时间0.1秒。这样便可达到我们的目的。

    Thread.currentThread().sleep(100);

    最后,通过split方法将温度和湿度数据分隔开,运用TextView组件就可以将数据展示给用户了

    String[] temp=receiveData.substring(0,21).split("-");

    tv_data.setText("当前温度:"+temp[0]+"℃"+"\n"+"当前湿度:"+temp[1]+"%"+"\n");

    最终效果如图所示。












    2.硬件部分

    2.1主控模块

    本系统主控采用ATmel公司生产的ATmega16单片机,ATmega16是基于增强的AVRRISC结构的低功耗8 CMOS微控制器。由于其先进的指令集以及单时钟周期指令执行时间,ATmega16数据吞吐率高达1 MIPS/MHz,从而可以减缓系统在功耗和处理速度之间的矛盾。ATmega16AVR内核具有丰富的指令集和32 个通用工作寄存器。所有的寄存器都直接与运算逻单元(ALU) 相连接,使得一条指令可以在一个时钟周期内同时访问两个独立的寄存器。这种结构大大提高了代码效率,并且具有比普通的CISC微控制器最高至10 倍的数据吞吐率。

    ATmega16有如下特点:16K字节的系统内可编程Flash(具有同时读写的能力,即RWW),512 字节EEPROM,1K 字节SRAM,32 个通用I/O 口线,32 个通用工作寄存器,用于边界扫描的JTAG接口,支持片内调试与编程,三个具有比较模式的灵活的定时器/ 计数器(T/C),片内/外中断,可编程串行USART,有起始条件检测器的通用串行接口,8路10位具有可选差分输入级可编程增益(TQFP封装) 的ADC,具有片内振荡器的可编程看门狗定时器,一个SPI 串行端口,以及六个可以通过软件进行选择的省电模式。

    ATmega16为主控的最小系统图如下图所示,它包含复位电路,滤波电路和晶振电路


    2.2采集模块

    本系统温湿度采集模块采用的是SHT30,传感器将传感元件和信号处理电路集成在一块微型电路板上,输出完全标定的数字信号。传感器采用专利的CMOSens技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容性聚合体测湿敏感元件、一个用能隙材料制成的测温元件,并在同一芯片上,与14 位的A/D转换器以及串行接口电路实现无缝连接。因此,该产品具有品质卓越、响应迅速、抗干扰能力强、性价比高等优点。该传感器属于低成本版本的数字型温湿度传感器,其可通过IIC总线即可与单片机进行通信,电压范围较宽为2.4-5.5V且功耗低每次测量只需4.8uw,其湿度测量范围为0-100%,温度测量范围为-40-+125℃。该传感器属于电容式传感器具有精确度高,感应速度快等特点,为了防止氧化该传感器采用了电极分布和镀膜技术,使得传感器不仅不会被氧化,还能很快吸收水分子,从而提高了稳定性。

    SHT30工作流程:首先,选择供电电压后将传感器通电,上电速率不能低于1V/ms。通电后传感器需要11ms进入休眠状态,在此之前不允许对传感器发送任何命令。用一组“启动传输”时序,来完成数据传输的初始化。它包括:当SCK时钟高电平时DATA翻转为低电平,紧接着SCK变为低电平,随后是在SCK时钟高电平时DATA翻转为高电平。布一组测量命令(‘00000101’表示相对湿度RH,‘00000011’表示温度T)后,控制器要等待测量结束。这个过程需要大约20/80/320ms,分别对应8/12/14bit测量。确切的时间随内部晶振速度,最多可能有-30%的变化。 SHT1x通过下拉DATA至低电平并进入空闲模式,表示测量的结束。控制器在再次触发SCK时钟前,必须等待这个“数据备妥”信号来读出数据。检测数据可以先被存储,这样控制器可以继续执行其它任务在需要时再读出数据。SHT30外形图如下图所示。


    2.3无线蓝牙模块

    本系统采用的蓝牙模块为支持蓝牙协议2.0的HC-05,该模块为无线透传的主从一体模块,采用AT指令可将其设置为主模块和从模块,该模块具有低功耗,高性能的特点,波特率范围较宽为4800-1382400,并且完全兼容3.3V/5V的单片机系统,其与设备进行连接时可以取代串口线通讯的应用,改为无线蓝牙通讯。与单片机通讯时连接方式如下所示,单片机与蓝牙模块之间通过串口进行通信,即单片机的TXD与蓝牙模块的RXD相连,单片机的RXD与蓝牙模块的TXD相连;只需要四根线就能轻松实现数据的无线传输,非常简单可靠。


    2.4 PCB设计

    本系统原理图与PCB采用AltiumDesigner10软件进行设计,由于该板所用元器件不是很多,故在设计时采用双层板即顶层(TopLayer)和底层(BottomLayer),双层板在走线时信号线与电源线采用了不同宽度的线以降低外界对电源的干扰,PCB图如下图所示。


    在本系统PCB走线过程中学习到以下几点:

    (1)PCB布线方向:从焊接面看,组件的排列方位尽可能保持与原理图相一致,布线方向最好与电路图走线方向相一致,因生产过程中通常需要在焊接面进行各种参数的检测,故这样做便于生产中的检查,调试及检修(在满足电路性能及整机安装与面板布局要求的前提下)。
        (2)各组件排列,分布要合理和均匀,力求整齐,美观,结构严谨的工艺要求。

    (3)相关联的两引线端不要距离太大,一般为2~3/10英寸左右较合适。进出线端尽可能集中在1至2个侧面,不要太过离散。

    4设计布线图时要注意管脚排列顺序,组件脚间距要合理。

    (5在保证电路性能要求的前提下,设计时应力求走线合理,少用外接跨线,并按一定顺充要求走线,力求直观,便于安装,高度和检修

    (6设计布线图时走线尽量少拐弯,力求线条简单明了布线条宽窄和线条间距要适中,电容器两焊盘间距应尽可能与电容引线脚的间距相符;设计应按一定顺序方向进行,例如可以由左往右和由上而下的顺序进行。


    最终实物图如图所示


    硬件与手机端源码链接: http://download.csdn.net/download/caicai19930805/10206496

    展开全文
  • 标题:51单片机温湿度测控系统设计 一,器材目录 51单片机最小系统板,DHT11温湿度传感器三个(求取平均温湿度),继电器,水泵,排气扇,加热片,PNP三极管8550(驱动继电器工作),LCD1602显示温湿度值,发光二极管...

    标题:51单片机温湿度测控系统设计

    一,器材目录
    51单片机最小系统板,DHT11温湿度传感器三个(求取平均温湿度),继电器,水泵,排气扇,加热片,PNP三极管8550(驱动继电器工作),LCD1602显示温湿度值,发光二极管。
    二,实现要求
    三个温湿度传感器DHT11采集温湿度显示到LCD1602上,通过四个按键实现屏幕切换设置恒温值,温度上下限,湿度上下限,K1具有设置和确定功能,K2增加,K3减少,K4返回,如果温度低于设定恒温值时,调用PID算法控制加热设备,温度高于设定恒温值时,停止加热,如果当前温湿度高于或者低于所设置的温湿度上下限时,蜂鸣器报警提示,并且开启相应的除湿或加湿设备工作,当按键设定完恒温值,温湿度上下限时,可以随时查看所设定值的大小。
    三,PROTEUS仿真电路图
    由于在仿真中找不到水泵,排气扇,加热片这些器件,直接用发光二极管替代!
    在这里插入图片描述四,DHT11温湿度传感器接线图
    DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。单总线通常要求外接一个约 5.1kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。
    在这里插入图片描述五,DHT11数据采集分析
    1.数据总时序
    用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11 发送响应信号,送出 40bit 的数据,幵触发一次信采集。
    在这里插入图片描述2.主机发送起始信号
    单片机连接DHT11的DATA引脚的I/O口输出低电平,且低电平保持时间不能小于 18ms,然后等待 DHT11 作出应答信号。
    在这里插入图片描述3.检测从机应答信号
    DHT11 的 DATA 引脚检测到外部信号有低电平时, 等待外部信号低电平结束, 延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据。
    在这里插入图片描述4.接收数据
    (1)数据判定规则
    位数据“0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“1”的格式为: 50 微秒的低电平加 70微秒的高电平。
    接收数据时可以先等待低电平过去,即等待数据线拉高,再延时60us,因为60us大于28us且小于70us,再检测此时数据线是否为高,如果为高,则数据判定为1,否则为0。
    在这里插入图片描述(2)数据格式
    一次传送 40 位数据,高位先出。
    8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。
    (3)数据校正
    判断“8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据”的结果是否等于8bit 校验位。如果等于则数据接收正确,否则应该放弃这一次的数据,重新接收。
    六,LCD1602操作时序
    (1),RS,RW操作时序
    在这里插入图片描述在这里插入图片描述(2),指令集
    LCD_1602 初始化指令小结:
    0x38 设置 162 显示,57 点阵,8 位数据接口
    0x01 清屏
    0x0F 开显示,显示光标,光标闪烁
    0x08 只开显示
    0x0e 开显示,显示光标,光标不闪烁
    0x0c 开显示,不显示光标
    0x06 地址加 1,当写入数据的时候光标右移
    0x02 地址计数器 AC=0;(此时地址为 0x80) 光标归原点,但
    是 DDRAM 中断内容不变
    七,程序代码

    #include <reg52.h>
    #include <intrins.h>
    #include <string.h>
    #define uchar unsigned char
    #define uint unsigned int
    sbit RS=P2^7;//LCD1602 RS口
    sbit RW=P2^6;//LCD1602 RW口
    sbit EN=P2^5;//LCD1602 EN口
    sbit AddHeat=P2^2;//加热控制口
    sbit AddHum=P2^3;//加湿控制口
    sbit DelHum=P2^4;//除湿控制口
    sbit Data1=P1^0;//1号DHT11 数据输出口
    sbit Data2=P1^1;//2号DHT11 数据输出口
    sbit Data3=P1^2;//3号DHT11 数据输出口
    sbit Buzzer=P1^3;//蜂鸣器控制口
    sbit SetSure=P1^4;//设置和确认键
    sbit Add=P1^5;//数据加
    sbit Sub=P1^6;//数据减
    sbit Back=P1^7;//返回键
    uchar table[6];//存入三个传感器的温湿度值
    uint FinData[2];//温湿度平均值
    uchar table1[]={" NowTem: "};
    uchar table2[]={" NowHum: "};
    uchar high_time,low_time;//定义调节时间变量
    uchar ConTem=0;//温度恒定值
    uchar TemH=0;//温度上限值
    uchar TemL=0;//温度下限值
    uchar HumH=0;//湿度上限值
    uchar HumL=0;//湿度下限值
    uchar count=0,time=0;//设定值变量,记录按键次数变量
    uchar count1=0;//定时器中使用
    uchar Flag1=0,Flag2=1;//标志位
    void FirDHT11_receive();//声明函数
    void SecDHT11_receive();
    void ThDHT11_receive();
    struct PID
    {
        uint SetPoint;// 设定目标
        uint Proportion;// 比例常数
        uint Integral;// 积分常数
        uint Derivative;// 微分常数
        uint LastError;//当前误差
        uint PrevError;//前次误差
        uint SumError;//误差和
    };
    struct PID spid;//定义PID变量
    unsigned int rout;//累计误差值
    void PIDInit(struct PID*pp)//PID初始化
    {
        memset(pp,0,sizeof(struct PID)); //PID参数初始化全部设置为0
    }
    uint PIDCalc(struct PID*pp,uint NextPoint)//PID误差计算
    {
        uint dError,Error ;
        Error=pp->SetPoint-NextPoint;// 偏差
        pp->SumError+=Error;// 积分
        dError=pp->LastError-pp->PrevError;//当前微分
        pp->PrevError=pp->LastError ;
        pp->LastError=Error ;
        return(pp->Proportion*Error+pp->Integral*pp->SumError+pp->Derivative*dError);//比例积分项微分项
    }
    void compare_temper()//温度比较
    {
        uchar i ;
        float temper=FinData[1]/10;//当前温度值
        float set_temper=ConTem;//设定温度值
        if(set_temper>temper)
        {
            if(set_temper-temper>1)
            {
                high_time=100 ; //大于1°不进行PID运算
                low_time=0 ;
            }
            else
            {   //在1°范围内进行PID运算
                for(i=0;i<10;i++)
                {
                    FirDHT11_receive();
                    SecDHT11_receive();
                    ThDHT11_receive();
                    FinData[1]=(table[1]+table[3]+table[5])/3*10;
                    rout=PIDCalc(&spid,FinData[1]/10); //执行PID运算
                }
                if(high_time<=100) //限制最大值
                    high_time=(uchar)(rout/800);
                else
                    high_time=100;
                low_time=(100-high_time);
            }
        }
        else//当实际温度大于设置温度时
        {
                high_time=0;//停止加热
                low_time=100;
        }
    }
    void PIDBEGIN()
    {
        TMOD=0x01;
        TH0=0x63;//定时100us
        TL0=0xC0;
        EA=1;//打开总中断
        ET0=1;//允许T0中断
        TR0=1;//运行定时器0
        high_time=50;//加热时间记录次数
        low_time=50;//停止加热时间记录次数
        PIDInit(&spid);//PID初始化
        spid.Proportion=10;//比例系数
        spid.Integral=8;//积分系数
        spid.Derivative=6;//微分系数
        spid.SetPoint=ConTem;//设定温度值   
    }
    void delay(uint n)//毫秒延时函数
    { 
      uint x,y; 
      for(x=n;x>0;x--) 
          for(y=110;y>0;y--); 
    } 
    void LCD_WriteCom(uchar com)//LCD1602写指令函数
    {
    	RS=0;                        
      P0=com;
      delay(5);
      EN=1;                        
      delay(5);
      EN=0;                      
    }
    void LCD_WriteData(uchar dat)//LCD1602写数据函数
    {
      RS=1;                         
      P0=dat;
      delay(5);
      EN=1;
      delay(5);
      EN=0;
    }
    void LCD_Init()//LCD1602初始化
    {
      EN=0;
      RW=0;
      LCD_WriteCom(0x38);          
      LCD_WriteCom(0x0c);         
      LCD_WriteCom(0x06);         
      LCD_WriteCom(0x01);
    }
    void DHT11_delay_us(uchar n)//微妙延时函数
    {
        while(--n);
    }
    void DHT11_delay_ms(uint z)//毫秒延时函数
    {
       uint i,j;
       for(i=z;i>0;i--)
          for(j=110;j>0;j--);
    }
    void FirDHT11_start()//1号DHT11起始信号
    {
       Data1=1;//数据口先拉高
       DHT11_delay_us(2);//短暂延时
       Data1=0;//数据口拉低
       DHT11_delay_ms(30); //延时18ms以上  
       Data1=1;//重新拉高
       DHT11_delay_us(30);//延时
    }
    uchar FirDHT11_rec_byte()//接收一个字节      
    {
       uchar i,dat=0;
      for(i=0;i<8;i++)    
       {          
          while(!Data1);//等待50us低电平过去   
          DHT11_delay_us(8);//延时60us左右  
          dat<<=1;           
          if(Data1==1)//此时数据口仍然为1,则数据为1    
             dat+=1;
          while(Data1);//等待数据口重新拉低     
        }  
        return dat;//返回8位数据
    }
    void FirDHT11_receive()//数据接收函数   
    {
        uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; 
        FirDHT11_start();//发送起始信号
        if(Data1==0)//如果为0,则DHT11应答
        {
            while(Data1==0);//等待80us低电平过去      
            DHT11_delay_us(40); //等待80us高电平过去
            R_H=FirDHT11_rec_byte();//湿度整数8位 
            R_L=FirDHT11_rec_byte(); //湿度小数8位
            T_H=FirDHT11_rec_byte(); //温度整数8位
            T_L=FirDHT11_rec_byte(); //温度小数8位
            revise=FirDHT11_rec_byte(); //校验位
            DHT11_delay_us(25);    
            if((R_H+R_L+T_H+T_L)==revise)//校验验证      
            {
                RH=R_H;
                RL=R_L;
                TH=T_H;
                TL=T_L;
            }  
            table[0]=RH+RL/10*0.1+RL%10*0.01;//温湿度存入数组中
            table[1]=TH+TL/10*0.1+TL%10*0.01;
        }
    }
    
    void SecDHT11_start()//2号DHT11原理与1号相同
    {
       Data2=1;
       DHT11_delay_us(2);
       Data2=0;
       DHT11_delay_ms(30);   
       Data2=1;
       DHT11_delay_us(30);
    }
    uchar SecDHT11_rec_byte()      
    {
       uchar i,dat=0;
      for(i=0;i<8;i++)    
       {          
          while(!Data2);   
          DHT11_delay_us(8);    
          dat<<=1;           
          if(Data2==1)    
             dat+=1;
          while(Data2);     
        }  
        return dat;
    }
    void SecDHT11_receive()     
    {
        uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; 
        SecDHT11_start();
        if(Data2==0)
        {
            while(Data2==0);       
            DHT11_delay_us(40);  
            R_H=SecDHT11_rec_byte();  
            R_L=SecDHT11_rec_byte(); 
            T_H=SecDHT11_rec_byte(); 
            T_L=SecDHT11_rec_byte(); 
            revise=SecDHT11_rec_byte(); 
            DHT11_delay_us(25);    
            if((R_H+R_L+T_H+T_L)==revise)      
            {
                RH=R_H;
                RL=R_L;
                TH=T_H;
                TL=T_L;
            }  
            table[2]=RH+RL/10*0.1+RL%10*0.01;
            table[3]=TH+TL/10*0.1+TL%10*0.01;
        }
    }
    
    void ThDHT11_start()//3号DHT11原理与1号相同
    {
       Data3=1;
       DHT11_delay_us(2);
       Data3=0;
       DHT11_delay_ms(30);   
       Data3=1;
       DHT11_delay_us(30);
    }
    uchar ThDHT11_rec_byte()      
    {
       uchar i,dat=0;
      for(i=0;i<8;i++)    
       {          
          while(!Data3);   
          DHT11_delay_us(8);    
          dat<<=1;           
          if(Data3==1)    
             dat+=1;
          while(Data3);     
        }  
        return dat;
    }
    void ThDHT11_receive()     
    {
        uchar R_H,R_L,T_H,T_L,RH,RL,TH,TL,revise; 
        ThDHT11_start();
        if(Data3==0)
        {
            while(Data3==0);       
            DHT11_delay_us(40);  
            R_H=ThDHT11_rec_byte();  
            R_L=ThDHT11_rec_byte(); 
            T_H=ThDHT11_rec_byte();
            T_L=ThDHT11_rec_byte();
            revise=ThDHT11_rec_byte(); 
            DHT11_delay_us(25);    
            if((R_H+R_L+T_H+T_L)==revise)      
            {
                RH=R_H;
                RL=R_L;
                TH=T_H;
                TL=T_L;
            }  
            table[4]=RH+RL/10*0.1+RL%10*0.01;
            table[5]=TH+TL/10*0.1+TL%10*0.01;
        }
    }
    void KeyScan()//按键扫描函数
    {
        if(SetSure==0)//设置-确认键按下
        {
            delay(2);//消抖
            if(SetSure==0)//再次确认按下
            {
                count=0;//count值初始化为0
                time++;//time为1表示为设置键,否则为确认键
                Flag1=1;//Fla1标志位置为1,
                if(time>=2)
                  Flag2++;//Flag2表示所要设置的对象
            }
            while(SetSure==0);//等待按键松开
        }
        if(Add==0)//按键加按下
        {
            delay(2);//延时消抖
            if(Add==0)//再次确定按键按下
            {
                count++;//数值加1
                if(Flag2==1) ConTem=count;//Flag2为1,表示设置对象为恒温值
                else if(Flag2==2) TemH=count;//Flag2为2,表示设置对象为温度上限
                else if(Flag2==3) TemL=count;//Flag2为3,表示设置对象为温度下限
                else if(Flag2==4) HumH=count;//Flag2为4,表示设置对象为湿度上限
                else if(Flag2==5) HumL=count;//Flag2为5,表示设置对象为湿度下限
                while(Add==0);//等待按键松开
            }
        }
        if(Sub==0)//按键减按下
        {
            delay(2);//延时消抖
            if(Sub==0)//再次确认按下
            {
                count--;//数据减1
                if(Flag2==1) ConTem=count;//Flag2为1,表示设置对象为恒温值
                else if(Flag2==2) TemH=count;//Flag2为2,表示设置对象为温度上限
                else if(Flag2==3) TemL=count;//Flag2为3,表示设置对象为温度下限
                else if(Flag2==4) HumH=count;//Flag2为4,表示设置对象为湿度上限
                else if(Flag2==5) HumL=count;//Flag2为5,表示设置对象为湿度下限
                while(Sub==0);//等待按键松开
            }
        }
        if(Back==0)//返回按键按下
        {
            delay(2);//延时消抖
            if(Back==0)//再次确定按键按下
            {
                Flag1=0;//跳出屏幕切换
                Flag2=1;//Flag2重新初始为1
                time=0;//time 初始为0
                while(Back==0);//等待按键松开
            }
        }
    }
    void SwitchDisplay()//切换屏幕显示
    {
        LCD_WriteCom(0x80);//第一行显示
        LCD_WriteData('C');//显示字符C:,表示恒温
        LCD_WriteData(':');
        LCD_WriteData(ConTem/10+0x30);//显示恒温十位
        LCD_WriteData(ConTem%10+0x30);//显示恒温个位
        LCD_WriteData(' ');//显示空格
        LCD_WriteData('T');//显示温度上限字符TH:
        LCD_WriteData('H');
        LCD_WriteData(':');
        LCD_WriteData(TemH/10+0x30);//显示温度上限十位
        LCD_WriteData(TemH%10+0x30);//显示温度上限个位
        LCD_WriteData(' ');//显示空格
        LCD_WriteData('T');//显示温度下限字符TL:
        LCD_WriteData('L');
        LCD_WriteData(':');
        LCD_WriteData(TemL/10+0x30);//显示温度下限十位
        LCD_WriteData(TemL%10+0x30);//显示温度下限个位
        LCD_WriteCom(0x80+0x40);//第二行显示
        LCD_WriteData('R');//显示湿度上限字符RH:
        LCD_WriteData('H');
        LCD_WriteData(':');
        LCD_WriteData(HumH/10+0x30);//显示湿度上限十位
        LCD_WriteData(HumH%10+0x30);//显示湿度上限个位
        LCD_WriteData(' ');//显示空格
        LCD_WriteData('R');//显示湿度下限字符RL:
        LCD_WriteData('L');
        LCD_WriteData(':');
        LCD_WriteData(HumL/10+0x30);//显示湿度下限十位
        LCD_WriteData(HumL%10+0x30);//显示湿度下限个位
        LCD_WriteData(' ');//显示空格
        LCD_WriteData('F');//显示字符Flag2:
        LCD_WriteData('g');
        LCD_WriteData(':');
        LCD_WriteData(Flag2%10+0x30);//显示标志位Flag2
    }   
    void Lcd_DisPlay()//正常显示
    {
        uchar i;
        FirDHT11_receive();//1号DHT11接收数据
        SecDHT11_receive();//2号DHT11接收数据
        ThDHT11_receive();//3号DHT11接收数据
        FinData[0]=(table[0]+table[2]+table[4])/3*10;//平均湿度
        FinData[1]=(table[1]+table[3]+table[5])/3*10;//平均温度
        LCD_WriteCom(0x80);//以下为显示程序
        for(i=0;i<9;i++)
            LCD_WriteData(table1[i]);
        LCD_WriteData(FinData[1]/100+0x30);
        LCD_WriteData(FinData[1]/10%10+0x30);
        LCD_WriteData('.');
        LCD_WriteData(FinData[1]%10+0x30);
        LCD_WriteData('^');
        LCD_WriteData('C');
        LCD_WriteData(' ');
        LCD_WriteCom(0x80+0x40);
        for(i=0;i<9;i++)
            LCD_WriteData(table2[i]);
        LCD_WriteData(FinData[0]/100+0x30);
        LCD_WriteData(FinData[0]/10%10+0x30);
        LCD_WriteData('.');
        LCD_WriteData(FinData[0]%10+0x30);
        LCD_WriteData('%');
        LCD_WriteData(' ');
        LCD_WriteData(' ');
    }
    void AddDelHum_Alarm()//加湿除湿和报警函数
    {
        if(FinData[0]/10<HumL)//湿度小于湿度下限值
        {
            AddHum=0;//开启加湿设备
            //Buzzer=0;//蜂鸣器报警
        }
        else if(FinData[0]/10>HumH)//湿度大于湿度上限值
        {
            DelHum=0;//开启除湿设备
            //Buzzer=0;//蜂鸣器报警
        }
        else if(FinData[1]/10<TemL||FinData[1]/10>TemH)//温度低于温度下限或高于温度上限
            Buzzer=0;//蜂鸣器报警
        else
        {
            AddHum=DelHum=1;//关闭设备
            //Buzzer=1;//关闭蜂鸣器
        }
    }   
    int main()
    {
       AddHeat=AddHum=DelHum=1;//初始化关闭设备
       Buzzer=1;//关闭蜂鸣器
       LCD_Init();//LCD1602初始化
       PIDBEGIN();//开启PID
       while(1)
       {
         KeyScan();//按键扫描
         Lcd_DisPlay();//LCD1602显示温湿度
         compare_temper();//温度比较
         AddDelHum_Alarm();//湿度调节和报警
         while(Flag1==1)//进入分屏模式
         {
             KeyScan();//按键扫描
             SwitchDisplay();//分屏显示
         }
       }
    }
    void Timer0() interrupt 1
    {
        count1++;
        if(count1<=(high_time))//加热设备开启时间
             AddHeat=0;
        else if(count1<=100)//加热设备关闭时间
        {
            AddHeat=1;
        }
        else
            count1=0 ;
        TH0=0x63;//定时器重新赋值
        TL0=0xC0;
    }
    

    八,现象结果
    (1)初始上电显示平均温湿度值
    在这里插入图片描述(2)分屏设置恒温值,温湿度上下限
    在这里插入图片描述C代表恒温值,TH代表温度上限,TL代表温度下限,RH代表湿度上限,RL代表湿度下限,Fg为1代表设置恒温值大小,Fg为2代表设置温度上限值大小,Fg为3代表设置温度下限值大小,Fg为4代表设置湿度上限值大小,Fg为5代表设置湿度下限值大小。
    其他具体的一些调节现象大家可以自行演示一下哈哈。
    九,总结心得
    疫情在家状态自然没有在学校好了,但也写了一些程序了嘿嘿,程序方面有了一定提升,越努力越幸运,真的很感谢老师们,没有他们的教导,实践能力上不会有当前这么大的一个提升,很感激。
    再有一个就是第一次用PID算法写了调节温度的程序,之前也只是了解,现在动手实践上了,心里还是挺兴奋的。
    博观而约取,厚积而薄发。
    祝大家都能够学有所成!

    展开全文
  • ESP8266笔记—DHT11温湿度传感器

    千次阅读 2020-05-11 14:13:27
    它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC 测温元件,并与一个高性能8位单片机相连接。 典型电路 典型应用电路中建议...

    参考文档

    技小新:https://www.jixin.pro/bbs/topic/5013

    产品概述

    DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个NTC 测温元件,并与一个高性能8位单片机相连接。

    典型电路

    DHT11典型电路图

    1. 典型应用电路中建议连接线长度短于5m时用4.7K上拉电阻,大于5m时根据实际情况降低上拉电阻的阻值。
    2. 使用3.3V电压供电时连接线尽量短,接线过长会导致传感器供电不足,造成测量偏差。
    3. 每次读出的温湿度数值是上一次测量的结果,欲获取实时数据,需连续读取2次,但不建议连续多次读取传感器,每次读取传感器间隔大于2秒即可获得准确的数据。
    4. 电源部分如有波动,会影响到温度。如使用开关电源纹波过大,温度会出现跳动。

    标题串行通信说明(单线双向)

    单总线说明 DHT11器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏枀开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

    单总线传送数据位定义

    DATA用于微处理器与DHT11之间的通讯和同步,采用单总线数据格式,一次传送40位数据,高位先出。
    数据格式: 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据 + 8bit校验位。
    注:其中湿度小数部分为0。

    校验位数据定义

    “8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度整数数据 + 8bit温度小数数据”
    8bit校验位等于所得结果的末8位。
    单总线格式定义
    数据时序图:
    用户主机(MCU)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信采集。信号发送如图所示。数据时序图
    注:主机从DHT11读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值。

    外设读取步骤

    步骤一:
    DHT11上电后(DHT11上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时 DHT11的DATA数据线由上拉电阻拉高一直保持高电平;此时 DHT11的 DATA 引脚处于输入状态,时刻检测外部信号。
    步骤二:
    微处理器的I/O设置为输出同时输出低电平,且低电平保持时间不能小于18ms(最大不得超过30ms),然后微处理器的I/O设置为输入状态,由于上拉电阻,微处理器的I/O即DHT11的DATA数据线也随之变高,等待DHT11作出回答信号,发送信号如图所示:
    主机发送起始信号
    步骤三:
    DHT11的DATA引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后DHT11的DATA引脚处于输出状态,输出 83微秒的低电平作为应答信号,紧接着输出 87 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11回应信号)后,等待87微秒的高电平后的数据接收,发送信号如图所示:
    从机响应信号
    步骤四:
    由DHT11的DATA引脚输出40位数据,微处理器根据I/O电平的变化接收40位数据,位数据“0”的格式为: 54 微秒的低电平和 23-27 微秒的高电平,位数据“1”的格式为: 54 微秒的低电平加68-74微秒的高电平。位数据“0”、“1”格式信号如图所示:
    在这里插入图片描述
    结束信号:
    DHT11的DATA引脚输出40位数据后,继续输出低电平54微秒后转为输入状态,由于上拉电阻随之变为高电平。但DHT11内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
    单总线信号特性
    注:为保证传感器的准确通讯,用户在读取信号时,请严格按照表10和图21 中的参数和时序进行设计。

    展开全文
  • 它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电容式感湿元件和一个高精度测温元件,并与一个高性能的8位单片机相连。因此该产品具有品质卓越、超快...
  • 它应用专用的数字模块采集技术和温湿度传感器技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。它具有成本低,性能稳定,抗干扰...
  • RS485温湿度传感器与modbus协议一、modbus协议介绍二、modbus与RS485的关系三、传感器使用3.1传感器介绍3.1 PC与传感器3.2 单片机与传感器三、modbus RTU常用功能码 一、modbus协议介绍 Modbus协议是应用于 电子...
  • 针对广阔空间环境温度采集系统对功耗及成本的要求,设计了基于无线传感网络技术的多点温度采集系统.以CC2430 为主 控芯片,选用DS18B20 作为温度采集节点的传感器,基于ZigBee 协议栈构建无线网络实现主从节点之间...
  • 1、DHT11和DHT21传感器 ...它应用专用的数 字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一 个电容式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单...
  • 协议栈构建无线网络实现主从节点之间数据的采集与传输,利用串口通信技术与PC 通信,并编程实现数据处理、存储与显示。  1 引言  随着生产技术的提高, 环境温度指标越来越多的影响到生产效率、能源
  • 本文介绍了以AT89C51/55单片机为核心的主从机温湿度自动巡回监测系统;此系统主要由单片机、传感器、多路开关和信号处理、A/D转换子系统等组成,其中多路信号选择由CD4051和CD4052完成,电路简单可靠。
  • 3.1 智能型温湿度传感器的研究 3.2 ZZ 995X系列传感器的特性及应用 3.3 用电容式阵列传感器实现触觉的测量 3.4 组成智能传感器的接口芯片 3.5 传感器实时自校准/自补偿技术研究 3.6 几种...
  • 4.5 温湿数据采集实验 一、实验目的 了解智能传感器DHT11的原理与应用 掌握智能传感器DHT11的编程与操作方法 理解微处理器与湿度传感器DHT11之间的通讯 二、实验材料 具有USB 串口通讯的PC 1 台 ADS1.2 ...
  • 前言: 近期在做个小项目是在dragonboard410c的平台上,其中需要使用到DHT11温湿度传感器模块来实时显示当前环境的温湿度,由此...它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的
  • 传感器的学习

    2020-09-01 20:23:59
    DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。DHT11是一款温湿度传感器。 其测量精度为:...
  • 温湿数据采集实验

    2019-08-06 14:02:42
    三、实验原理 振动传感器实验环境由PC(安装有Windows XP操作系统、ADS1.2集成开发环境和J-Link-ARM-V410i仿真器)、J-Link-ARM...1. 温湿度传感器简介 1.1温度、湿度的相关概念 由于温度与湿度不管是从由于温...
  • 本系统设计是从低成本、低功耗、高效率等概念出发,采用32位单片机STM32F103C8T6为处理核心,在数据采集节点端控制一系列的传感器(如DS18B20、DHT11、MQ-135、光敏二极管、雨滴传感器、土壤水分传感器等)来采集...
  • 该课题是毕业时做的一个远程数据采集课题,今天无意翻看到这份报告,不禁勾起满满的怀念。重新看了一遍报告,感觉做的确实是挺low的,但想起当时自己查了无数的资料,才完成这个设计,尤其是人在学校,然后通过...
  • Overall:内置TCP协议栈的433MHz无线局域网1) 传输距离高达200+米,穿透4层实心的水泥墙后仍然稳定通讯2) 接收电流26mA,发射电流140mA,休眠电流。可动态控制功耗3) 提供子无线节点,无线基站(网桥)和高增益...
1 2
收藏数 36
精华内容 14
关键字:

单片机温湿度采集主从机