2025年3月22日 星期六 甲辰(龙)年 月廿一 设为首页 加入收藏
rss
您当前的位置:首页 > 电子 > 单片机

基于51单片机+SHT30设计的环境温度与湿度检测设备(IIC模拟时序)

时间:11-08来源:作者:点击数:15

一、项目介绍

当前文章介绍基于51单片机和SHT30传感器设计的环境温度与湿度检测设备。设备采用IIC模拟时序通信协议,能够实时监测环境的温度和湿度,并将数据通过LCD显示屏显示出来;可以广泛应用于室内环境监测、气象观测、农业温室监测等领域。

在本项目中,使用了51单片机作为主控芯片,SHT30传感器作为温湿度传感器,LCD显示屏作为数据显示模块。通过51单片机的GPIO口模拟IIC通信协议,实现了与SHT30传感器的数据通信。

image-20230618123229983

二、硬件设计

2.1 硬件构成

本次设计所需的硬件主要包括以下部分:

  • STC89C52单片机
  • SHT30温湿度传感器
  • 串口通信模块
  • LCD1602显示屏
  • 电源模块
  • 杜邦线等连接线

2.2 硬件接口及信号

本次设计使用51单片机通过IIC总线与SHT30传感器进行通信,同时使用串口与上位机进行数据传输,并使用液晶显示屏显示当前温湿度值。

具体接口和信号定义如下:

(1) 51单片机与SHT30传感器之间的IIC接口:

端口 功能 说明
P2.0 SDA 数据线
P2.1 SCL 时钟线
P2.2 RESET 复位线

(2) 51单片机与串口通信模块之间的接口:

端口 功能 说明
P3.0 TXD 发送线
P3.1 RXD 接收线
P3.2 GND 地线

(3) 51单片机与液晶屏之间的接口:

端口 功能 说明
P1.0-P1.7 DB0-DB7 数据线
P0.0 RS 指令/数据选择线
P0.1 RW 读/写选择线
P0.2 E 使能线
P0.3 CS 片选线
VCC 电源正极 5V
GND 电源地

三、软件设计

3.1 SHT30传感器代码

下面代码读取SHT30传感器的值并通过串口打印。

  • #include <REG52.h>
  • #include <stdio.h>
  • #define uchar unsigned char
  • #define uint unsigned int
  • sbit SDA=P2^0;
  • sbit SCL=P2^1;
  • void delay(int n)
  • {
  • int i;
  • while(n--)
  • {
  • for(i=0; i<120; i++);
  • }
  • }
  • void start()
  • {
  • SDA = 1;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SDA = 0;
  • _nop_();
  • SCL = 0;
  • _nop_();
  • }
  • void stop()
  • {
  • SDA = 0;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SDA = 1;
  • _nop_();
  • }
  • void ack()
  • {
  • SDA = 0;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SCL = 0;
  • _nop_();
  • SDA = 1;
  • _nop_();
  • }
  • void nack()
  • {
  • SDA = 1;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SCL = 0;
  • _nop_();
  • }
  • void write_byte(uchar dat)
  • {
  • uchar i;
  • for(i=0; i<8; i++)
  • {
  • SDA = dat & 0x80;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SCL = 0;
  • _nop_();
  • dat <<= 1;
  • }
  • ack();
  • }
  • uchar read_byte()
  • {
  • uchar i, dat;
  • for(i=0; i<8; i++)
  • {
  • dat <<= 1;
  • SCL = 1;
  • _nop_();
  • dat |= SDA;
  • SCL = 0;
  • _nop_();
  • }
  • return dat;
  • }
  • void init_sht30()
  • {
  • start();
  • write_byte(0x80);
  • if(read_byte() != 0x5A)
  • {
  • stop();
  • return;
  • }
  • write_byte(0xBE);
  • if(read_byte() != 0x08 || read_byte() != 0x00)
  • {
  • stop();
  • return;
  • }
  • stop();
  • }
  • float measure_temp(void)
  • {
  • uchar temp_h, temp_l, crc;
  • float temp;
  • start();
  • write_byte(0x80); // 主机发送写地址
  • write_byte(0x2C); // 选择开始温度测量命令
  • write_byte(0x06);
  • stop();
  • delay(15); // 延时等待温度测量完成
  • start();
  • write_byte(0x81); // 主机发送读地址
  • temp_h=read_byte();
  • ack();
  • temp_l=read_byte();
  • ack();
  • crc=read_byte();
  • stop();
  • temp = ((temp_h<<8)+temp_l)*175.0/0xffff - 45.0; // 温度值转换公式
  • return temp;
  • }
  • float measure_humi(void)
  • {
  • uchar humi_h, humi_l, crc;
  • float humi;
  • start();
  • write_byte(0x80); // 主机发送写地址
  • write_byte(0x2C); // 选择开始湿度测量命令
  • write_byte(0x06);
  • stop();
  • delay(15); // 延时等待湿度测量完成
  • start();
  • write_byte(0x81); // 主机发送读地址
  • humi_h=read_byte();
  • ack();
  • humi_l=read_byte();
  • ack();
  • crc=read_byte();
  • stop();
  • humi = ((humi_h<<8)+humi_l)*100.0/0xffff; // 湿度值转换公式
  • return humi;
  • }
  • void main()
  • {
  • float temp, humi;
  • init_sht30(); // SHT30 初始化
  • TMOD=0x20; // 定时器0工作方式2,8位定时器,用于波特率设置
  • TH1=0xfd; // 波特率9600
  • TL1=0xfd;
  • TR1=1; // 启动定时器0
  • SCON=0x50; // 设置串口工作方式1,允许接收,允许接收中断
  • ES=1; // 允许串口中断
  • while(1)
  • {
  • temp = measure_temp();
  • humi = measure_humi();
  • printf("Temperature: %.1fC, Humidity: %.1f%\n", temp, humi);
  • delay(500); // 间隔时间500ms
  • }
  • }
  • void ser() interrupt 4 using 2
  • {
  • if(RI) // 接收到数据
  • {
  • RI=0; // 清除标志位
  • }
  • if(TI) // 发送完毕
  • {
  • TI=0; // 清除标志位
  • }
  • }

在上面的代码中,定义了两个函数 measure_temp 和 measure_humi,分别用于测量温度和湿度值,并返回结果。在主函数中,利用这两个函数得到当前的温湿度值,然后通过串口打印出来。

3.2 LCD1602显示屏代码

下面代码是LCD1602驱动代码,完成数字字符显示。

  • #include <REG52.h>
  • #define LCD1602_DB P0
  • sbit RS = P2^5;
  • sbit RW = P2^6;
  • sbit E = P2^7;
  • void delay(int n)
  • {
  • int i;
  • while(n--)
  • {
  • for(i=0; i<120; i++);
  • }
  • }
  • void main()
  • {
  • //LCD 初始化
  • delay(1000);
  • LCD1602_DB = 0x38;
  • E = 1;
  • delay(5);
  • E = 0;
  • delay(500);
  • LCD1602_DB = 0x08;
  • E = 1;
  • delay(5);
  • E = 0;
  • delay(500);
  • LCD1602_DB = 0x01;
  • E = 1;
  • delay(5);
  • E = 0;
  • delay(500);
  • LCD1602_DB = 0x06;
  • E = 1;
  • delay(5);
  • E = 0;
  • delay(500);
  • LCD1602_DB = 0x0C;
  • E = 1;
  • delay(5);
  • E = 0;
  • while(1)
  • {
  • //向LCD中写入数字12345
  • RS = 0; //选择指令寄存器
  • LCD1602_DB = 0x80; //设置地址为第一行的第一个字符位置(0x80 + 0x00)
  • E = 1;
  • delay(5);
  • E = 0;
  • RS = 1; //选择数据寄存器
  • LCD1602_DB = 0x31; //写入数字1
  • E = 1;
  • delay(5);
  • E = 0;
  • LCD1602_DB = 0x32; //写入数字2
  • E = 1;
  • delay(5);
  • E = 0;
  • LCD1602_DB = 0x33; //写入数字3
  • E = 1;
  • delay(5);
  • E = 0;
  • LCD1602_DB = 0x34; //写入数字4
  • E = 1;
  • delay(5);
  • E = 0;
  • LCD1602_DB = 0x35; //写入数字5
  • E = 1;
  • delay(5);
  • E = 0;
  • delay(500); //间隔时间为500ms
  • }
  • }

在上面的代码中,定义了函数 delay 用于延时等待,并且实现了LCD1602的初始化和写入操作。在主函数中,执行LCD1602的初始化操作,然后循环不断向LCD中写入数字12345,并且间隔时间为500ms。

3.3 完整代码

  • #include<reg52.h>
  • #include<intrins.h>
  • #define uchar unsigned char
  • #define uint unsigned int
  • sbit SDA = P2^0; //定义SDA引脚
  • sbit SCL = P2^1; //定义SCL引脚
  • sbit CS = P0^3; //定义液晶屏片选引脚
  • sbit RW = P0^1; //定义液晶屏读/写引脚
  • sbit RS = P0^0; //定义液晶屏指令/数据引脚
  • sbit E = P0^2; //定义液晶屏使能引脚
  • void delay(int n) //延时函数,n为延时时间
  • {
  • int i;
  • while(n--)
  • {
  • for(i=0; i<120; i++);
  • }
  • }
  • void start() //开始信号
  • {
  • SDA = 1; //数据线高电平
  • _nop_();
  • SCL = 1; //时钟线高电平
  • _nop_();
  • SDA = 0; //数据线低电平
  • _nop_();
  • SCL = 0; //时钟线低电平
  • _nop_();
  • }
  • void stop() //结束信号
  • {
  • SDA = 0; //数据线低电平
  • _nop_();
  • SCL = 1; //时钟线高电平
  • _nop_();
  • SDA = 1; //数据线高电平
  • _nop_();
  • }
  • void ack() //应答信号
  • {
  • SDA = 0; //数据线低电平
  • _nop_();
  • SCL = 1; //时钟线高电平
  • _nop_();
  • SCL = 0; //时钟线低电平
  • _nop_();
  • SDA = 1; //数据线高电平
  • _nop_();
  • }
  • void nack() //非应答信号
  • {
  • SDA = 1; //数据线高电平
  • _nop_();
  • SCL = 1; //时钟线高电平
  • _nop_();
  • SCL = 0; //时钟线低电平
  • _nop_();
  • }
  • void write_byte(uchar dat) //写一个字节
  • {
  • uchar i;
  • for(i=0; i<8; i++)
  • {
  • SDA = dat & 0x80;
  • _nop_();
  • SCL = 1;
  • _nop_();
  • SCL = 0;
  • _nop_();
  • dat <<= 1;
  • }
  • ack();
  • }
  • uchar read_byte() //读一个字节
  • {
  • uchar i, dat;
  • for(i=0; i<8; i++)
  • {
  • dat <<= 1;
  • SCL = 1;
  • _nop_();
  • dat |= SDA;
  • SCL = 0;
  • _nop_();
  • }
  • return dat;
  • }
  • void init_sht30() //SHT30初始化
  • {
  • start();
  • write_byte(0x80);
  • if(read_byte() != 0x5A)
  • {
  • stop();
  • return;
  • }
  • write_byte(0xBE);
  • if(read_byte() != 0x08 || read_byte() != 0x00)
  • {
  • stop();
  • return;
  • }
  • stop();
  • }
  • void measure() //测量温湿度值
  • {
  • float humi, temp;
  • uint i;
  • start();
  • write_byte(0x80);
  • read_byte();
  • read_byte();
  • read_byte();
  • write_byte(0x2C);
  • write_byte(0x06);
  • for(i=0; i<40000; i++); //等待测量结果
  • start();
  • write_byte(0x80);
  • read_byte();
  • read_byte();
  • read_byte();
  • humi = read_byte() * 256;
  • humi += read_byte();
  • temp = read_byte() * 256;
  • temp += read_byte();
  • stop();
  • temp = -45 + (175*temp)/65535; //转化温度
  • humi = 100 * humi / 65535; //转化湿度
  • //将温湿度值通过串口发送
  • printf("Temperature: %.1fC\n", temp);
  • printf("Humidity: %.1f%%RH\n", humi);
  • }
  • void init_lcd() //液晶屏初始化
  • {
  • RW = 0;
  • RS = 0;
  • E = 0;
  • delay(15);
  • write_byte(0x30);
  • delay(15);
  • write_byte(0x30);
  • delay(5);
  • write_byte(0x30);
  • delay(5);
  • write_byte(0x38);
  • write_byte(0x08);
  • write_byte(0x01);
  • write_byte(0x06);
  • write_byte(0x0c);
  • }
  • void display(float temp, float humi) //显示温湿度值
  • {
  • uchar i;
  • uchar temp_str[5];
  • uchar humi_str[5];
  • //转化为字符串
  • sprintf(temp_str, "%.1f", temp);
  • sprintf(humi_str, "%.1f", humi);
  • //显示温度
  • RS = 0;
  • E = 1;
  • P1 = 0x80; //第一行第一个字符
  • E = 0;
  • RS = 1;
  • for(i=0; i<5; i++)
  • {
  • E = 1;
  • P1 = temp_str[i];
  • E = 0;
  • }
  • //显示湿度
  • RS = 0;
  • E = 1;
  • P1 = 0xc0; //第二行第一个字符
  • E = 0;
  • RS = 1;
  • for(i=0; i<5; i++)
  • {
  • E = 1;
  • P1 = humi_str[i];
  • E = 0;
  • }
  • }
  • void main()
  • {
  • init_sht30(); //SHT30初始化
  • init_lcd(); //液晶屏初始化
  • while(1)
  • {
  • measure(); //测量温湿度值并通过串口发送
  • delay(1000);
  • display(temp, humi); //显示温湿度值
  • }
  • }
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐