• 方案介紹
    • 一、項目介紹
    • 二、硬件設(shè)計
    • 三、軟件設(shè)計
  • 附件下載
  • 相關(guān)推薦
申請入駐 產(chǎn)業(yè)圖譜

基于51單片機+SHT30設(shè)計的環(huán)境溫度與濕度檢測設(shè)備(IIC模擬時序)

04/10 09:05
906
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

更多詳細資料請聯(lián)系.docx

共1個文件

一、項目介紹

當前文章介紹基于51單片機和SHT30傳感器設(shè)計的環(huán)境溫度與濕度檢測設(shè)備。設(shè)備采用IIC模擬時序通信協(xié)議,能夠?qū)崟r監(jiān)測環(huán)境的溫度和濕度,并將數(shù)據(jù)通過LCD顯示屏顯示出來;可以廣泛應(yīng)用于室內(nèi)環(huán)境監(jiān)測、氣象觀測、農(nóng)業(yè)溫室監(jiān)測等領(lǐng)域。

在本項目中,使用了51單片機作為主控芯片,SHT30傳感器作為溫濕度傳感器,LCD顯示屏作為數(shù)據(jù)顯示模塊。通過51單片機的GPIO口模擬IIC通信協(xié)議,實現(xiàn)了與SHT30傳感器的數(shù)據(jù)通信。

image-20230618123229983

二、硬件設(shè)計

2.1 硬件構(gòu)成

本次設(shè)計所需的硬件主要包括以下部分:

2.2 硬件接口及信號

本次設(shè)計使用51單片機通過IIC總線與SHT30傳感器進行通信,同時使用串口與上位機進行數(shù)據(jù)傳輸,并使用液晶顯示屏顯示當前溫濕度值。

具體接口和信號定義如下:

(1) 51單片機與SHT30傳感器之間的IIC接口:

端口 功能 說明
P2.0 SDA 數(shù)據(jù)線
P2.1 SCL 時鐘線
P2.2 RESET 復位線

(2) 51單片機與串口通信模塊之間的接口:

端口 功能 說明
P3.0 TXD 發(fā)送線
P3.1 RXD 接收線
P3.2 GND 地線

(3) 51單片機與液晶屏之間的接口:

端口 功能 說明
P1.0-P1.7 DB0-DB7 數(shù)據(jù)線
P0.0 RS 指令/數(shù)據(jù)選擇線
P0.1 RW 讀/寫選擇線
P0.2 E 使能線
P0.3 CS 片選線
VCC 電源正極 5V
GND 電源地

三、軟件設(shè)計

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);  // 主機發(fā)送寫地址
    write_byte(0x2C);  // 選擇開始溫度測量命令
    write_byte(0x06);
    stop();

    delay(15);    // 延時等待溫度測量完成

    start();
    write_byte(0x81);  // 主機發(fā)送讀地址
    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; // 溫度值轉(zhuǎn)換公式

    return temp;
}

float measure_humi(void)
{
    uchar humi_h, humi_l, crc;
    float humi;

    start();
    write_byte(0x80);  // 主機發(fā)送寫地址
    write_byte(0x2C);  // 選擇開始濕度測量命令
    write_byte(0x06);
    stop();

    delay(15);    // 延時等待濕度測量完成

    start();
    write_byte(0x81);  // 主機發(fā)送讀地址
    humi_h=read_byte();  
    ack();
    humi_l=read_byte(); 
    ack();
    crc=read_byte();
    stop();

    humi = ((humi_h<<8)+humi_l)*100.0/0xffff; // 濕度值轉(zhuǎn)換公式

    return humi;
}

void main()
{   
    float temp, humi;

    init_sht30();   // SHT30 初始化

    TMOD=0x20;      // 定時器0工作方式2,8位定時器,用于波特率設(shè)置
    TH1=0xfd;       // 波特率9600
    TL1=0xfd;
    TR1=1;          // 啟動定時器0

    SCON=0x50;      // 設(shè)置串口工作方式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)          // 接收到數(shù)據(jù)
    {
        RI=0;       // 清除標志位
    }
    if(TI)          // 發(fā)送完畢
    {
        TI=0;       // 清除標志位
    }
}

在上面的代碼中,定義了兩個函數(shù) measure_tempmeasure_humi,分別用于測量溫度和濕度值,并返回結(jié)果。在主函數(shù)中,利用這兩個函數(shù)得到當前的溫濕度值,然后通過串口打印出來。

3.2 LCD1602顯示屏代碼

下面代碼是LCD1602驅(qū)動代碼,完成數(shù)字字符顯示。

#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中寫入數(shù)字12345
        RS = 0;  //選擇指令寄存器

        LCD1602_DB = 0x80;  //設(shè)置地址為第一行的第一個字符位置(0x80 + 0x00)

        E = 1;
        delay(5);
        E = 0;

        RS = 1;  //選擇數(shù)據(jù)寄存器

        LCD1602_DB = 0x31;  //寫入數(shù)字1
        E = 1;
        delay(5);
        E = 0;

        LCD1602_DB = 0x32;  //寫入數(shù)字2
        E = 1;
        delay(5);
        E = 0;

        LCD1602_DB = 0x33;  //寫入數(shù)字3
        E = 1;
        delay(5);
        E = 0;

        LCD1602_DB = 0x34;  //寫入數(shù)字4
        E = 1;
        delay(5);
        E = 0;

        LCD1602_DB = 0x35;  //寫入數(shù)字5
        E = 1;
        delay(5);
        E = 0;

        delay(500); //間隔時間為500ms
    }
}

在上面的代碼中,定義了函數(shù) delay 用于延時等待,并且實現(xiàn)了LCD1602的初始化和寫入操作。在主函數(shù)中,執(zhí)行LCD1602的初始化操作,然后循環(huán)不斷向LCD中寫入數(shù)字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;		//定義液晶屏指令/數(shù)據(jù)引腳
sbit E = P0^2;		//定義液晶屏使能引腳

void delay(int n)	//延時函數(shù),n為延時時間
{
    int i;
    while(n--)
    {
        for(i=0; i<120; i++);
    }
}

void start()		//開始信號
{
    SDA = 1;		//數(shù)據(jù)線高電平
    _nop_();
    SCL = 1;		//時鐘線高電平
    _nop_();
    SDA = 0;		//數(shù)據(jù)線低電平
    _nop_();
    SCL = 0;		//時鐘線低電平
    _nop_();
}

void stop()			//結(jié)束信號
{
    SDA = 0;		//數(shù)據(jù)線低電平
    _nop_();
    SCL = 1;		//時鐘線高電平
    _nop_();
    SDA = 1;		//數(shù)據(jù)線高電平
    _nop_();
}

void ack()			//應(yīng)答信號
{
    SDA = 0;		//數(shù)據(jù)線低電平
    _nop_();
    SCL = 1;		//時鐘線高電平
    _nop_();
    SCL = 0;		//時鐘線低電平
    _nop_();
    SDA = 1;		//數(shù)據(jù)線高電平
    _nop_();
}

void nack()			//非應(yīng)答信號
{
    SDA = 1;		//數(shù)據(jù)線高電平
    _nop_();
    SCL = 1;		//時鐘線高電平
    _nop_();
    SCL = 0;		//時鐘線低電平
    _nop_();
}

void write_byte(uchar dat)	//寫一個字節(jié)
{
    uchar i;
    for(i=0; i<8; i++)
    {
        SDA = dat & 0x80;
        _nop_();
        SCL = 1;
        _nop_();
        SCL = 0;
        _nop_();
        dat <<= 1;
    }
    ack();
}

uchar read_byte()	//讀一個字節(jié)
{
    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++);	//等待測量結(jié)果
    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;	//轉(zhuǎn)化溫度
    humi = 100 * humi / 65535;		//轉(zhuǎn)化濕度
    //將溫濕度值通過串口發(fā)送
    printf("Temperature: %.1fCn", temp);
    printf("Humidity: %.1f%%RHn", 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];
    //轉(zhuǎn)化為字符串
    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();	//測量溫濕度值并通過串口發(fā)送
        delay(1000);
        display(temp, humi);	//顯示溫濕度值
    }
}

  • 更多詳細資料請聯(lián)系.docx
    下載

相關(guān)推薦