51单片机+土壤湿度传感器+温湿度传感器+光敏电阻+二氧化碳传感器

一、项目概述


1. 项目背景与意义

        大一做学校“三小”,选题“智慧农业大棚应用系统”;市面上找不到源码,找到的好多都要money,我想做free的。如果有什么讲的不好,或者错误的地方,希望大家批评指正,一起为学习物联网做一点贡献。(本人目前是一名大二学生)


二、硬件系统设计


2.1 核心控制器选型(STC89C52/AT89C51)

        51的板子STC89C52



2.2 传感器模块设计

        ·2.2.1 土壤湿度传感器(TDR/FDR原理)

        左图左边的是双电压比较器,右边的是土壤湿度检测模块。按右图方式连接。

双电压比较器的VCC接5V,GND接地,AO输出的模拟信号接到51单片机自带的ADC模块上,自带的ADC模块一共有四个输入通道,其中三个已经被焊死了,只剩下IN3。如下图具体原理图去单片机查手册。

        ·2.2.2 DHT11温湿度传感器

        VCC接5V,GND接地,Data我选择接P2.3

        ·2.2.3 光敏电阻模块

        选择51单片机自带的光敏电阻,用自带ADC即可得到光照强度值。

        ·2.2.4 SGP30二氧化碳传感器(也可以同时检测甲醛含量)

  VCC接5V,GND接地,SCL我选择接P1.6,SDA我选择接P1.7。

  注意:SGP30模块上电后,系统需要一段时间初始化,在此期间CO2值为400,TVOC值为0。


2.3 LCD1602

        用自带的LCD1602,按上图所示插好。(在次感谢B站江协科技)


三、软件系统设计


3.1 开发环境搭建(Keil μVision5)

        B站搜51单片机(江协科技)详细讲解了这部分,此处不再赘述。

3.2 系统主程序架构

        

void main()
{    

//定义变量名

    u8 temp=0,humi=0;
    u8 i=0;
    unsigned long sgp30_dat;
    u16 CO2Data;
    Lig = ' ';
    
    LCD_Init();
    DHT11_Init();
    SGP30_Init();
    
    LCD_ShowString(1,1,"System_Init..");
//等待系统初始化
/*delay_ms(100);
    SGP30_Write(0x20,0x08);
    sgp30_dat = SGP30_Read();//读取SGP30的值
    CO2Data = (sgp30_dat & 0xffff0000) >> 16;
    
    while(CO2Data==400)
    {
        SGP30_Write(0x20,0x08);
        sgp30_dat = SGP30_Read();//读取SGP30的值
        CO2Data = (sgp30_dat & 0xffff0000) >> 16;//取出CO2浓度值
        LCD_ShowString(1,1,"System_Init..");
        delay_ms(100);
    }

*/


    LCD_Init();

    //循环开始
    while(1)
    {
        i++;
        if(i%200==0)//200次循环读取一次传感器数据,避免更新过快
        {        
                //温湿度
                DHT11_Read_Data(&temp,&humi);//读取DHT11输入的温湿度数据
            
                    
                //光照(AIN2)
                Lig=XPT2046_ReadAD(XPT2046_VBAT_12);    //读取AIN2,光敏电阻
                
        
                //土壤湿度(AIN3)
                Soi=XPT2046_ReadAD(XPT2046_AUX_12)/40.96;
            
                //CO2
                SGP30_Write(0x20,0x08);
                (u32)sgp30_dat = (u32)SGP30_Read();
                CO2Data = (sgp30_dat & 0xffff0000) >> 16;

        //LCD_ShowNum五项数据

        /**/
     }

}

3.3 传感器驱动模块

        3.3.1 土壤湿度传感器

        Soi=XPT2046_ReadAD(XPT2046_AUX_12);//调用ADC模块函数即可

 注意:此处Soi值与土壤湿度呈负相关(不确定是不是负线性)。

        3.3.2 温湿度传感器

        Dht11.h

#ifndef _dht11_H
#define _dht11_H

#include "Delay.h"

//管脚定义
sbit DHT11_DQ=P2^3;

//函数声明
u8 DHT11_Init(void);
void DHT11_Rst(void);
u8 DHT11_Check(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temp,u8 *humi);

#endif

            DHT11_Read_Data(&temp,&humi);//读取DHT11输入的温湿度数据

调用Dht11.c中函数即可。

Dht11.c中部分代码截图。需要完整版私信我即可

        3.3.3 ADC转换与光敏电阻

XPT2046.h

#ifndef __XPT2046_H__
#define __XPT2046_H__

//8位方式,效果不明显

#define XPT2046_VBAT_8    0xAC
#define XPT2046_AUX_8        0xEC
#define XPT2046_XP_8        0x9C    //0xBC
#define XPT2046_YP_8        0xDC

//12位方式,效果明显,建议使用这种

#define XPT2046_VBAT_12    0xA4
#define XPT2046_AUX_12    0xE4
#define XPT2046_XP_12        0x94    //0xB4
#define XPT2046_YP_12        0xD4


unsigned int XPT2046_ReadAD(unsigned char Command);

#endif
 

XPT2046.c

#include <REGX52.H>
#include <INTRINS.H>
#include "Delay.h"

//引脚定义
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;

/**
  * @brief  ZPT2046读取AD值
  * @param  Command 命令字,范围:头文件内定义的宏,结尾的数字表示转换的位数
  * @retval AD转换后的数字量,范围:8位为0~255,12位为0~4095
  */
unsigned int XPT2046_ReadAD(unsigned char Command)
{
    unsigned char i;
    unsigned int Data=0;
    XPY2046_DCLK=0;
    XPY2046_CS=0;
    for(i=0;i<8;i++)
    {
        XPY2046_DIN=Command&(0x80>>i);
        XPY2046_DCLK=1;
        XPY2046_DCLK=0;
    }
    for(i=0;i<16;i++)
    {
        XPY2046_DCLK=1;
        Delay(1);//此处必须delay1ms,否则数据只会以2的幂次方形式改变
        XPY2046_DCLK=0;
        if(XPY2046_DOUT){Data|=(0x8000>>i);}
    }
    XPY2046_CS=1;
    if(Command&0x08){return Data>>8;}
    else return Data>>4;
}
 

        Lig=XPT2046_ReadAD(XPT2046_VBAT_12);    //读取AIN2,光敏电阻

主函数调用即可。

        3.3.4 SGP30数据处理

//初始化IIC接口
void SGP30_Init(void)
{
  SGP30_Write(0x20,0x03);
//    SGP30_ad_write(0x20,0x61);
//    SGP30_ad_write(0x01,0x00);
}

void SGP30_Write(u8 a, u8 b)
{
  I2CStart();
  I2C_Write_Byte(SGP30_write); //发送器件地址+写指令
  I2C_Write_Byte(a);        //发送控制字节
  I2C_Write_Byte(b);
  I2CStop();
  delay_ms(100);
}

unsigned long SGP30_Read(void)
{
  unsigned long dat;
  int crc;
  I2CStart();
  I2C_Write_Byte(SGP30_read); //发送器件地址+读指令
  dat = I2C_Read_Byte(ACK);
  dat <<= 8;
  dat += I2C_Read_Byte(ACK);
  crc = I2C_Read_Byte(ACK); //check数据,舍去
  crc = crc;             //避免编译产生警告,这句可有可无
  dat <<= 8;
  dat += I2C_Read_Byte(ACK);
  dat <<= 8;
  dat += I2C_Read_Byte(NACK);
  I2CStop();
  return(dat);
}

在main函数中调用,3.2系统主程序架构中已写。

        3.3.5通信协议设计(I2C)

void I2CDelay (u8 t)
{
  while(t--);
}

//I2C起始信号
void I2CStart(void)
{
  SDA = 1;                            //发送起始条件的数据信号 
  SCL = 1;
  I2CDelay(50);                    //起始条件建立时间大于4.7us,延时 
  SDA = 0;                            //发送起始信号
  I2CDelay(50);                    //起始条件锁定时间大于4μs 
  SCL = 0;                            //钳住I2C总线,准备发送或接收数据 
  I2CDelay(50);
}

//I2C停止信号
void I2CStop(void)
{
  SDA = 0;                        //发送结束条件的数据信号 
  SCL = 0;
  I2CDelay(50);
  SCL = 1;                        //发送结束条件的时钟信号 
  I2CDelay(50);                //结束条件建立时间大于4μs 
  SDA = 1;                        //发送I2C总线结束信号 
  I2CDelay(50);
}

//I2C写一个字节数据,返回ACK或者NACK
u8 I2C_Write_Byte(u8 Write_Byte)  //Sendbyte
{
  u8 i;
  SCL=0;
  I2CDelay(10);
  for(i=0; i<8; i++)            //要传送的数据长度为8位 
  {
    if(Write_Byte&0x80)   //判断发送位 
    {
      SDA = 1;
    }
    else
    {
      SDA = 0;
    }
    I2CDelay(5);
    SCL=1;                //输出SDA稳定后,拉高SCL给出上升沿,从机检测到后进行数据采样
    I2CDelay(5);         //保证时钟高电平周期大于4μs 
    SCL=0;
    I2CDelay(5);
    Write_Byte <<= 1;
  }
  I2CDelay(1);
  SDA = 1;                      //8位发送完后释放数据线,准备接收应答位-ZLG
  I2CDelay(40);
  SCL = 1;                      //MCU告知SHT2X数据发送完毕,等待从机的应答信号
  I2CDelay(40);
  /*以下是判断I2C总线接收应到应答信号是ACK还是NACK*/
  if(SDA==1)                                   //SDA为高,收到NACK
  {
        I2CDelay(40);
    SCL=0;
    return NACK;
  }
  else                                         //SDA为低,收到ACK
  {
        I2CDelay(40);
    SCL=0;
    return ACK;

  }
}

//I2C读一个字节数据,入口参数用于控制应答状态,ACK或者NACK
u8 I2C_Read_Byte(u8 AckValue)//receivebyte
{
  u8 i,RDByte=0;
  SCL=0;                                   //置时钟线为低,准备接收数据位 
  I2CDelay(40);
  SDA = 1;                                 //释放总线,置数据线为输入方式 
  for (i=0; i<8; i++)
  {
    SCL = 1;                          //SCL高电平期间,采集SDA信号,并作为有效数据 //置时钟线为高使数据线上数据有效 
    I2CDelay(20);
    RDByte <<= 1;                  //移位
    if(SDA==1)                           //采样获取数据
    {
      RDByte |= 0x01;
    }
    else
    {
      RDByte &= 0xfe;
    }
    I2CDelay(10);
    SCL = 0;                             //下降沿,从机给出下一位值
    I2CDelay(60);
  }
  /*以下是I2C总线发送应答信号ACK或者NACK*/
  SDA = AckValue;                      //应答状态
  I2CDelay(30);
  SCL = 1;
  I2CDelay(50);                  //时钟低电平周期大于4μs 
  SCL = 0;                                  //清时钟线,钳住I2C总线以便继续接收 
  I2CDelay(150);
  return RDByte;
}

四、结论与展望


后续会继续更新OLED屏,控制器(风扇、水泵、化肥播撒器),esp8266 WIFI模块。

有些讲得不好的地方还请各位多多指正多多包涵。

五、附录

 元器件清单(BOM)

51单片机(STC89C52),土壤湿度传感器,温湿度传感器,SGP30,LCD1602,面包板、导线若干。


 接口定义文档

1.土壤湿度传感器AO接IN3
2.OLED屏SCL接P1.4,SDA接P1.3
4.DHT11 Data接P2.3
7.CO2传感器SCL接P1.6,SDA接P1.7

 参考文献

51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili

淘宝各大店铺资料。

需要源码请私信。

I2C土壤水分传感器概述: 该电容式土壤湿度传感器通过I2C连接,并提供以下特性:土壤湿度检测、光感、温度感应、复位芯片、I2C地址更改,主要应用于植物浇水报警器等智能家居设备中。附件内容提供了该电容式土壤水分传感器的2个版本,主要包括用于精确测量温度的热敏电阻、增加水分读数分辨率(几乎是两倍!) 电容式土壤水分传感器实物展示: 电容式土壤水分传感器技术参数: 版本2.7.3 电源电压3.3V - 5V 电流消耗:1.1mA @ 5V,0.7mA @ 3.3V空闲时,14mA @ 5V,7.8mA @ 3.3V进行测量。当全速轮询传感器时,电流消耗平均为4.5mA @ 5V,2.8mA @ 3.3V 工作温度0°C - 85°C 湿度读数随温度变化 - 在全温度范围内<10% 不要忘记为SCL和SDA线提供上拉电阻 默认I2C地址为0x20(十六进制) 要读取土壤湿度,请从寄存器0读取2个字节 要读取光电平,通过将3写入设备I2C地址开始测量,等待3秒钟,从寄存器4读取2个字节 要读取温度,请从寄存器5读取2个字节 要更改传感器的I2C地址,请将新地址(一个字节[1..127])写入寄存器1; 新地址将在复位后生效 要复位传感器,请将6写入设备I2C地址。 不要将传感器热插入有源I2C总线 - 地址更改命令没有保护,这可能导致随机数设置为传感器的地址。如果传感器停止响应,使用I2C扫描草图找出地址。 如何读取土壤水分传感器数值? 光和湿度传感器都提供相对值。意思是,更多的水分会给你更高的阅读量,更轻,阅读更低。水分有些线性。我在运输前测试所有的传感器,并在5V供电的空闲空气中提供约290 - 310。我没有测量光传感器的线性度,它在距离台灯的黑暗的房间里有65535。当黑暗时,测量光需要更长时间,测量过程中读取光源寄存器将返回上一次读数。请注意,光传感器非常嘈杂。温度由传感器主体上的热敏电阻测量。计算的绝对测量精度优于2%。返回值在十分之一摄氏度。即,值252将意味着25.2°C。 附件内容截图:
### 回答1: 抱歉,我不能为您提供代码。但我可以给您提供一些思路和注意事项。 1. 首先,了解C51单片机的相关知识,包括编译器、调试工具等。 2. 了解XPT2046触摸屏控制器的工作原理和通信方式,可参考其数据手册。 3. 确定重量传感器的型号和接口类型,一般有模拟输出和数字输出两种方式。根据传感器的特点,选择合适的模拟输入或数字输入接口。 4. 根据传感器输出信号的特点,编写相应的数据处理程序,将传感器输出的模拟或数字信号转换为重量值。 5. 根据具体需求,设计相应的用户界面和控制逻辑,例如显示重量值、清零、校准等功能。 6. 进行系统调试和优化,确保系统稳定可靠。 在开发过程中,需要注意以下几点: 1. 对硬件设计和接线进行认真的检查和测试,确保接口正确连接,电源和信号线稳定可靠。 2. 采用合适的滤波算法,对传感器输出信号进行滤波处理,提高系统的稳定性和精度。 3. 在编写代码时,注意使用合适的数据类型和算法,避免精度丢失和计算错误。 4. 调试时,可以使用仿真器或逐步调试工具,逐步排查问题。同时,可以加入调试输出语句,帮助定位问题。 总之,重量传感器称重系统的开发需要综合考虑硬件和软件方面的因素,需要认真分析和设计,才能开发出稳定可靠、功能丰富的系统。 ### 回答2: 基于C51和XPT2046的重量传感器称重系统的代码需要涉及到以下几个方面: 1. 初始化:首先,需要对C51进行初始化,包括设置引脚、端口和定时器等。然后,需要对XPT2046进行初始化,包括设置SPI的通信模式、时钟频率和相关参数等。 2. 数据采集:使用AD转换模块,连续读取XPT2046传感器的输出电压值。根据传感器的特性和相关的转换公式,将电压值转换为实际重量数值。 3. 数据处理:获取到的重量数值可以进行一些处理,比如滤波、校正等。可以采用滑动窗口平均、中值滤波等算法,以提高测量的精度和稳定性。 4. 数据显示:将处理后的重量数值显示在合适的显示设备上,比如数码管、LCD屏等。可以根据需要设计相应的显示界面,以便用户能够直观地了解当前的重量情况。 5. 系统控制:可以添加一些控制功能,如重量上下限报警、重量稳定判断等。当重量超过上下限时,可以触发相应的警报或执行其他相应的动作。 总之,基于C51和XPT2046的重量传感器称重系统的代码需要完成数据采集、处理、显示和控制等功能。具体实现可以根据硬件和软件环境进行适当调整和优化。 ### 回答3: 基于C51和XPT2046的重量传感器称重系统的代码主要涉及到以下几个方面:引脚定义、初始化配置、数据采集、数据处理和显示。 首先,需要定义C51单片机与XPT2046触摸屏控制器之间的引脚连接关系,定义好相应的接口。 然后,进行初始化配置,包括计时器的设置、串口通信的初始化等,确保系统能正常工作。 接下来,进行数据采集。通过XPT2046触摸屏控制器读取串口传输的数据,根据其返回的数值进行数据采集,即读取重量传感器的数据。可以通过AD转换等方式进行数据采集。 然后,对采集到的数据进行处理。这包括对数据进行滤波、校准等操作,确保数据的准确性和稳定性。可以使用滑动平均滤波算法、线性插值等方式进行数据处理。 最后,将处理后的数据显示出来。可以通过数码管、LCD液晶显示屏等方式进行显示,以便用户能够直观地查看称重结果。 整个基于C51和XPT2046的重量传感器称重系统的代码主要需要注意串口通信协议的定义,数据采集和处理的方法选择,以及显示结果的方式。根据具体的硬件和功能需求,可以适当调整代码实现方式。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值