This system is designed based on the 51 microcontroller and features a comprehensive indoor air quality monitoring system that can monitor various air quality parameters in real-time, including temperature and humidity, CO2 concentration, formaldehyde concentration, methane concentration, and PM2.5 concentration, displaying the data through an LCD1602 screen. The system supports threshold settings and automatic control functions, automatically activating corresponding adjustment devices and issuing alarms when detected values exceed the set range.
System Composition
Hardware Components
-
Main Control Chip: STC89C51/52 Microcontroller
-
Temperature and Humidity Sensor: DHT11
-
Gas Sensors: MQ-4 (Methane Detection), SGP30 (CO2 and Formaldehyde Detection)
-
Particulate Matter Sensor: PM2.5 Detection Module
-
Display Module: LCD1602 Liquid Crystal Display
-
Actuators: Relay-controlled humidifier, dehumidifier, cooling equipment, heater, purifier, and ventilation equipment
-
Alarm Device: Buzzer
-
Input Device: Key Matrix
System Block Diagram:
Edit
Simulation Circuit:
Edit Introduction: This design uses the STC89C52 microcontroller as the core controller, along with other modules to form the entire indoor air detection system, which includes the central control part, input part, and output part. The central control part uses the STC89C52 microcontroller, whose main function is to acquire data from the input part, process it internally, and control the output part. The input consists of six parts: the first part is the SGP30 detection module, which can detect the current CO2 and formaldehyde concentrations; the second part is the PM2.5 detection module combined with the ADC0832 chip, which can detect the current PM2.5 concentration; the third part is the MQ-4 methane detection module combined with the ADC0832 chip, which can detect the current methane concentration; the fourth part is the DHT11 temperature and humidity detection module, which can detect the current temperature and humidity; the fifth part is independent keys, which can switch interfaces and adjust set values through three independent keys; the sixth part is the power supply circuit, which powers the entire system. The output consists of four parts: the first part is the LCD1602 display module, which can display the current CO2 concentration, formaldehyde concentration, methane concentration, PM2.5 concentration, temperature and humidity values, and modified set values; the second part is the relay, which closes when the measured gas concentration or temperature and humidity values are outside the set range for abnormal processing; the third part is the LED indicator, which lights up once each time a key is pressed; the fourth part is the buzzer, which issues intermittent alarms when the measured gas concentration or temperature and humidity values are outside the set range.
Software Functions
-
Multi-parameter real-time monitoring and display
-
Adjustable threshold setting system
-
Automatic environmental adjustment control
-
Over-limit alarm function
-
Multi-interface display switching
System Design and Implementation
Core Code Analysis
Main Loop Control
void main()
{
// Initialize each module
Lcd1602_Init();
Delay_function(50);
lcd1602_clean();
Delay_function(50);
DHT11_Init();
Delay_function(50);
while(1)
{
Key_function(); // Key processing
Monitor_function(); // Data monitoring
Display_function(); // Data display
Manage_function(); // Device control
Delay_function(10); // 10ms delay
time_jishi++; // Timer increment
if(time_jishi == 5000)
{
time_jishi = 0;
}
}
}
Key Function Implementation
The system uses 3 keys to implement all interactive functions:
-
Key 1: Mode switching (9 setting modes in total)
-
Key 2: Parameter increase
-
Key 3: Parameter decrease/display interface switching
void Key_function(void)
{
key_num = Chiclet_Keyboard_Scan(); // Key scanning
if(key_num != 0)
{
switch(key_num)
{
case 1: // Mode switching
flag_mode_display++;
if(flag_mode_display == 9)
flag_mode_display = 0;
lcd1602_clean();
break;
case 2: // Parameter increase
// Increase corresponding parameter based on current mode
break;
case 3: // Parameter decrease/display switching
// Decrease corresponding parameter based on current mode or switch display interface
break;
}
}
}
Data Monitoring Function
The system periodically collects data from various sensors:
void Monitor_function(void)
{
if(time_jishi % 50 == 0) // Collect once every 500ms
{
// Read data from each sensor
co2_value = 400*((Adc0832_Get_Value(0)/256.0)*5)-1000;
ch2o_value = 400*((Adc0832_Get_Value(1)/256.0)*5)-1000;
ch4_value = 400*((Adc0832_Get_Value_1(0)/256.0)*5)-1000;
pm25_value = 400*((Adc0832_Get_Value_1(1)/256.0)*5)-1000;
Dht11_Get_Temp_Humi_Value(&temp_value,&humi_value);
}
}
Device Control Function
The system automatically controls various environmental adjustment devices based on monitoring data:
void Manage_function(void)
{
if(flag_mode_display == 0) // Only execute control in monitoring mode
{
// Gas over-limit control
if(co2_value > co2_value_max || ch2o_value > ch2o_value_max ||
ch4_value > ch4_value_max || pm25_value > pm25_value_max)
{
RELAY_MOTOR = 0; // Start ventilation
RELAY_JINGHUA = 0; // Start purification
flag_beep_gas = 1; // Trigger gas alarm
}
else
{
RELAY_MOTOR = 1; // Stop ventilation
RELAY_JINGHUA = 1; // Stop purification
flag_beep_gas = 0; // Turn off gas alarm
}
// Temperature and humidity control logic...
// Alarm control
if(flag_beep_gas == 1 || flag_beep_temp == 1 || flag_beep_humi == 1)
{
if(time_jishi % 20 == 0) BEEP = 0; // Intermittent alarm
if(time_jishi % 40 == 0) BEEP = 1;
}
else
{
BEEP = 1; // Turn off alarm
}
}
else
{
BEEP = 1; // Turn off alarm in setting mode
}
}
Complete Main Function:
#include "main.h"
#include "lcd1602.h"
#include "key.h"
#include "adc.h"
#include "dht11_proteus.h"
/**********************************
Variable Definitions
**********************************/
uchar key_num = 0; // Key scanning flag variable
uchar flag_mode_display = 0; // Display mode flag variable
uchar flag_display = 0; // Display interface flag variable
uchar flag_beep_gas = 0; // Buzzer gas flag variable
uchar flag_beep_temp = 0; // Buzzer temperature flag variable
uchar flag_beep_humi = 0; // Buzzer humidity flag variable
uint co2_value = 0; // CO2 concentration value variable
uint ch2o_value = 0; // Formaldehyde concentration value variable
uint ch4_value = 0; // Methane concentration value variable
uint pm25_value = 0; // PM2.5 concentration value variable
uint temp_value = 0; // Temperature value variable
uint humi_value = 0; // Humidity value variable
uint co2_value_max = 700; // Maximum CO2 concentration value variable
uint ch2o_value_max = 80; // Maximum formaldehyde concentration value variable
uint ch4_value_max = 150; // Maximum methane concentration value variable
uint pm25_value_max = 200; // Maximum PM2.5 concentration value variable
uint temp_value_max = 35; // Maximum temperature value variable
uint temp_value_min = 20; // Minimum temperature value variable
uint humi_value_max = 60; // Maximum humidity value variable
uint humi_value_min = 30; // Minimum humidity value variable
uint time_jishi = 0; // 10ms timer variable
/**********************************
Function Declarations
**********************************/
void Delay_function(uint x); // Delay function (ms)
void Key_function(void); // Key function
void Monitor_function(void); // Monitoring function
void Display_function(void); // Display function
void Manage_function(void); // Processing function
/****
******* Main Function
*****/
void main()
{
Lcd1602_Init(); // LCD1602 initialization
Delay_function(50); // Delay 50ms
lcd1602_clean(); // Clear screen
Delay_function(50); // Delay 50ms
DHT11_Init(); // DHT11 initialization
Delay_function(50); // Delay 50ms
while(1)
{
Key_function(); // Key function
Monitor_function(); // Monitoring function
Display_function(); // Display function
Manage_function(); // Processing function
Delay_function(10); // Delay 10ms
time_jishi++; // Timer variable +1
if(time_jishi == 5000)
{
time_jishi = 0;
}
}
}
/****
******* Delay x ms Function
*****/
void Delay_function(uint x)
{
uint m,n;
for(m=x;m>0;m--)
for(n=110;n>0;n--);
}
/****
******* Key Function
*****/
void Key_function(void)
{
key_num = Chiclet_Keyboard_Scan(); // Key scanning
if(key_num != 0) // If a key is pressed
{
switch(key_num)
{
case 1: // Key 1
flag_mode_display++;
if(flag_mode_display == 9) // A total of 9 modes
flag_mode_display = 0;
lcd1602_clean(); // Clear screen
break;
case 2: // Key 2
if(flag_mode_display == 1) // Mode 1: CO2 maximum value +1
{
co2_value_max++;
if(co2_value_max > 999)
co2_value_max = 999;
}
if(flag_mode_display == 2) // Mode 2: Formaldehyde maximum value +1
{
ch2o_value_max++;
if(ch2o_value_max > 999)
ch2o_value_max = 999;
}
if(flag_mode_display == 3) // Mode 3: Methane maximum value +1
{
ch4_value_max++;
if(ch4_value_max > 999)
ch4_value_max = 999;
}
if(flag_mode_display == 4) // Mode 4: PM2.5 maximum value +1
{
pm25_value_max++;
if(pm25_value_max > 999)
pm25_value_max = 999;
}
if(flag_mode_display == 5) // Mode 5: Temperature maximum value +1
{
temp_value_max++;
if(temp_value_max > 99)
temp_value_max = 99;
}
if(flag_mode_display == 6) // Mode 6: Temperature minimum value +1
{
if(temp_value_max > (temp_value_min+1))
temp_value_min++;
}
if(flag_mode_display == 7) // Mode 7: Humidity maximum value +1
{
humi_value_max++;
if(humi_value_max > 99)
humi_value_max = 99;
}
if(flag_mode_display == 8) // Mode 8: Humidity minimum value +1
{
if(humi_value_max > (humi_value_min+1))
humi_value_min++;
}
break;
case 3: // Key 3
if(flag_mode_display == 0) // Mode 0: Display measurement value flag +1
{
flag_display++;
if(flag_display == 3) // A total of 3 modes
flag_display = 0;
lcd1602_clean(); // Clear screen
}
if(flag_mode_display == 1) // Mode 1: CO2 maximum value -1
{
if(co2_value_max > 0)
co2_value_max--;
}
if(flag_mode_display == 2) // Mode 2: Formaldehyde maximum value -1
{
if(ch2o_value_max > 0)
ch2o_value_max--;
}
if(flag_mode_display == 3) // Mode 3: Methane maximum value -1
{
if(ch4_value_max > 0)
ch4_value_max--;
}
if(flag_mode_display == 4) // Mode 4: PM2.5 maximum value -1
{
if(pm25_value_max > 0)
pm25_value_max--;
}
if(flag_mode_display == 5) // Mode 5: Temperature maximum value -1
{
if(temp_value_max > (temp_value_min+1))
temp_value_max--;
}
if(flag_mode_display == 6) // Mode 6: Temperature minimum value -1
{
if(temp_value_min > 0)
temp_value_min--;
}
if(flag_mode_display == 7) // Mode 7: Humidity maximum value -1
{
if(humi_value_max > (humi_value_min+1))
humi_value_max--;
}
if(flag_mode_display == 8) // Mode 8: Humidity minimum value -1
{
if(humi_value_min > 0)
humi_value_min--;
}
break;
default:
break;
}
}
}
/****
******* Monitoring Function
*****/
void Monitor_function(void)
{
if(time_jishi % 50 == 0) // Check once every 500ms
{
co2_value = 400*((Adc0832_Get_Value(0)/256.0)*5)-1000; // Get CO2 value
ch2o_value = 400*((Adc0832_Get_Value(1)/256.0)*5)-1000; // Get formaldehyde value
ch4_value = 400*((Adc0832_Get_Value_1(0)/256.0)*5)-1000; // Get methane value
pm25_value = 400*((Adc0832_Get_Value_1(1)/256.0)*5)-1000; // Get PM2.5 value
Dht11_Get_Temp_Humi_Value(&temp_value,&humi_value); // Get temperature and humidity values
}
}
/****
******* Display Function
*****/
void Display_function(void)
{
switch(flag_mode_display) // Display different interfaces based on different display mode flags
{
case 0: // Mode 0: Display CO2, formaldehyde, methane, PM2.5, temperature, humidity
switch(flag_display)
{
case 0:
lcd1602_display_str(1,0,"CO2="); // Display CO2
lcd1602_display_gas(1,4,co2_value);
lcd1602_display_str(2,0,"CH2O="); // Display formaldehyde
lcd1602_display_gas(2,5,ch2o_value);
break;
case 1:
lcd1602_display_str(1,0,"CH4="); // Display methane
lcd1602_display_gas(1,4,ch4_value);
lcd1602_display_str(2,0,"PM2.5="); // Display PM2.5
lcd1602_display_pm25(2,6,pm25_value);
break;
case 2:
lcd1602_display_str(1,0,"Temp="); // Display temperature
lcd1602_display_temp(1,5,temp_value);
lcd1602_display_str(2,0,"Humi="); // Display humidity
lcd1602_display_humi(2,5,humi_value);
break;
}
break;
case 1: // Mode 1: Display set CO2 maximum value
lcd1602_display_str(1,0,"CO2_Max=");
lcd1602_display_str(2,0,"CH2O_Max=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 8, co2_value_max);
lcd1602_display_num(2, 9, ch2o_value_max);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(1, 8, " ");
}
break;
case 2: // Mode 2: Display set formaldehyde maximum value
lcd1602_display_str(1,0,"CO2_Max=");
lcd1602_display_str(2,0,"CH2O_Max=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 8, co2_value_max);
lcd1602_display_num(2, 9, ch2o_value_max);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(2, 9, " ");
}
break;
case 3: // Mode 3: Display set methane maximum value
lcd1602_display_str(1,0,"CH4_Max=");
lcd1602_display_str(2,0,"PM2.5_Max=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 8, ch4_value_max);
lcd1602_display_num(2, 10, pm25_value_max);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(1, 8, " ");
}
break;
case 4: // Mode 4: Display set PM2.5 maximum value
lcd1602_display_str(1,0,"CH4_Max=");
lcd1602_display_str(2,0,"PM2.5_Max=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 8, ch4_value_max);
lcd1602_display_num(2, 10, pm25_value_max);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(2, 10, " ");
}
break;
case 5: // Mode 5: Display set temperature maximum value
lcd1602_display_str(1,0,"Temp_Max=");
lcd1602_display_str(2,0,"Temp_min=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 9, temp_value_max);
lcd1602_display_num(2, 9, temp_value_min);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(1, 9, " ");
}
break;
case 6: // Mode 6: Display set temperature minimum value
lcd1602_display_str(1,0,"Temp_Max=");
lcd1602_display_str(2,0,"Temp_min=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 9, temp_value_max);
lcd1602_display_num(2, 9, temp_value_min);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(2, 9, " ");
}
break;
case 7: // Mode 7: Display set humidity maximum value
lcd1602_display_str(1,0,"Humi_Max=");
lcd1602_display_str(2,0,"Humi_min=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 9, humi_value_max);
lcd1602_display_num(2, 9, humi_value_min);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(1, 9, " ");
}
break;
case 8: // Mode 8: Display set humidity minimum value
lcd1602_display_str(1,0,"Humi_Max=");
lcd1602_display_str(2,0,"Humi_min=");
if(time_jishi % 20 == 0)
{
lcd1602_display_num(1, 9, humi_value_max);
lcd1602_display_num(2, 9, humi_value_min);
}
if(time_jishi % 40 == 0)
{
lcd1602_display_str(2, 9, " ");
}
break;
default:
break;
}
}
/****
******* Processing Function
*****/
void Manage_function(void)
{
if(flag_mode_display == 0) // When the display mode is 0
{
if(co2_value > co2_value_max || ch2o_value > ch2o_value_max || ch4_value > ch4_value_max || pm25_value > pm25_value_max) // Gas concentration greater than set concentration
{
RELAY_MOTOR = 0; // Fan relay pulled low to enable
RELAY_JINGHUA = 0; // Air purification relay pulled low to enable
flag_beep_gas = 1; // Buzzer gas flag set to 1
}
else // Gas concentration less than set concentration
{
RELAY_MOTOR = 1; // Fan relay pulled high to disable
RELAY_JINGHUA = 1; // Air purification relay pulled high to disable
flag_beep_gas = 0; // Buzzer gas flag set to 0
}
if(temp_value > temp_value_max*10) // Temperature greater than set maximum temperature
{
RELAY_TEMP_UP = 1; // Heating relay pulled high to disable
RELAY_TEMP_DOWN = 0; // Cooling relay pulled low to enable
flag_beep_temp = 1; // Buzzer temperature flag set to 1
}
else if(temp_value < temp_value_min*10) // Temperature less than set minimum temperature
{
RELAY_TEMP_UP = 0; // Heating relay pulled low to enable
RELAY_TEMP_DOWN = 1; // Cooling relay pulled high to disable
flag_beep_temp = 1; // Buzzer temperature flag set to 1
}
else // Temperature within threshold
{
RELAY_TEMP_UP = 1; // Heating relay pulled high to disable
RELAY_TEMP_DOWN = 1; // Cooling relay pulled high to disable
flag_beep_temp = 0; // Buzzer temperature flag set to 0
}
if(humi_value > humi_value_max*10) // Humidity greater than set maximum humidity
{
RELAY_HUMI_UP = 1; // Humidifier relay pulled high to disable
RELAY_HUMI_DOWN = 0; // Dehumidifier relay pulled low to enable
flag_beep_humi = 1; // Buzzer humidity flag set to 1
}
else if(humi_value < humi_value_min*10)
{
RELAY_HUMI_UP = 0; // Humidifier relay pulled low to enable
RELAY_HUMI_DOWN = 1; // Dehumidifier relay pulled high to disable
flag_beep_humi = 1; // Buzzer humidity flag set to 1
}
else
{
RELAY_HUMI_UP = 1; // Humidifier relay pulled high to disable
RELAY_HUMI_DOWN = 1; // Dehumidifier relay pulled high to disable
flag_beep_humi = 0; // Buzzer humidity flag set to 0
}
if(flag_beep_gas == 1 || flag_beep_temp == 1 || flag_beep_humi == 1) // If buzzer gas flag is 1 or buzzer temperature flag is 1 or buzzer humidity flag is 1
{
if(time_jishi % 20 == 0) // Intermittent alarm
BEEP = 0;
if(time_jishi % 40 == 0)
BEEP = 1;
}
else
{
BEEP = 1; // No alarm
}
}
else
{
BEEP = 1; // No alarm
}
}
ADC Collection:
#include "adc.h"
/**********************************
Function Definitions
**********************************/
/****
******* Get ADC Value Function
******* Parameter Definition: CH: Channel Number 0: Channel 0 1: Channel 1
******* Return Value: ADC Value
*****/
uint Adc0832_Get_Value(uchar CH)
{
uint dat = 0x00;
uchar i,test,adval;
adval = 0x00;
test = 0x00;
// Initialization
ADC_CLK = 0;
ADC_DATI = 1;
_nop_(); _nop_();
ADC_CS = 0;
_nop_();
ADC_CLK = 1;
_nop_(); _nop_();
// Channel Selection
if(CH == 0x00)
{
ADC_CLK = 0;
ADC_DATI = 1; // First bit of channel 0
_nop_();
ADC_CLK = 1;
_nop_(); _nop_();
ADC_CLK = 0;
ADC_DATI = 0; // Second bit of channel 0
_nop_(); _nop_();
ADC_CLK = 1;
_nop_();
}
else
{
ADC_CLK = 0;
ADC_DATI = 1; // First bit of channel 1
_nop_(); _nop_();
ADC_CLK = 1;
_nop_(); _nop_();
ADC_CLK = 0;
ADC_DATI = 1; // Second bit of channel 1
_nop_();
ADC_CLK = 1;
_nop_();
}
ADC_CLK = 0; _nop_();
ADC_DATI = 1;
for( i = 0;i < 8;i++ ) // Read the first 8 bits
{
_nop_();
adval <<= 1;
ADC_CLK = 1;
_nop_(); _nop_();
ADC_CLK = 0;
_nop_();
if (ADC_DATO)
adval |= 0x01;
else
adval |= 0x00;
}
for (i = 0; i < 8; i++) // Read the last 8 bits
{
test >>= 1;
if (ADC_DATO)
test |= 0x80;
else
test |= 0x00;
_nop_();
ADC_CLK = 1;
_nop_(); _nop_();
ADC_CLK = 0;
_nop_();
}
// Compare the first 8 bits with the last 8 bits, if they are not the same, discard. If it always shows zero, please remove this line
if (adval == test)
dat = test;
_nop_(); _nop_();
ADC_CS = 1; // Release ADC0832
ADC_DATO = 1;
ADC_CLK = 1;
return dat;
}
uint Adc0832_Get_Value_1(uchar CH)
{
uint dat = 0x00;
uchar i,test,adval;
adval = 0x00;
test = 0x00;
// Initialization
ADC_CLK_1 = 0;
ADC_DATI_1 = 1;
_nop_(); _nop_();
ADC_CS_1 = 0;
_nop_();
ADC_CLK_1 = 1;
_nop_(); _nop_();
// Channel Selection
if(CH == 0x00)
{
ADC_CLK_1 = 0;
ADC_DATI_1 = 1; // First bit of channel 0
_nop_();
ADC_CLK_1 = 1;
_nop_(); _nop_();
ADC_CLK_1 = 0;
ADC_DATI_1 = 0; // Second bit of channel 0
_nop_(); _nop_();
ADC_CLK_1 = 1;
_nop_();
}
else
{
ADC_CLK_1 = 0;
ADC_DATI_1 = 1; // First bit of channel 1
_nop_(); _nop_();
ADC_CLK_1 = 1;
_nop_(); _nop_();
ADC_CLK_1 = 0;
ADC_DATI_1 = 1; // Second bit of channel 1
_nop_();
ADC_CLK_1 = 1;
_nop_();
}
ADC_CLK_1 = 0; _nop_();
ADC_DATI_1 = 1;
for( i = 0;i < 8;i++ ) // Read the first 8 bits
{
_nop_();
adval <<= 1;
ADC_CLK_1 = 1;
_nop_(); _nop_();
ADC_CLK_1 = 0;
_nop_();
if (ADC_DATO_1)
adval |= 0x01;
else
adval |= 0x00;
}
for (i = 0; i < 8; i++) // Read the last 8 bits
{
test >>= 1;
if (ADC_DATO_1)
test |= 0x80;
else
test |= 0x00;
_nop_();
ADC_CLK_1 = 1;
_nop_(); _nop_();
ADC_CLK_1 = 0;
_nop_();
}
// Compare the first 8 bits with the last 8 bits, if they are not the same, discard. If it always shows zero, please remove this line
if (adval == test)
dat = test;
_nop_(); _nop_();
ADC_CS_1 = 1; // Release ADC0832
ADC_DATO_1 = 1;
ADC_CLK_1 = 1;
return dat;
}
DHT11 Temperature and Humidity Detection
/**********************************
Author: Turnas Electronics
Website: https://www.mcude.com
Contact: 46580829 (QQ)
Taobao Store: Turnas Electronics
**********************************/
/**********************************
Include Header Files
**********************************/
#include "dht11_proteus.h"
/**********************************
Function Definitions
**********************************/
/****
******* DHT11 Write Byte Function
*****/
char s_write_byte(unsigned char value)
{
unsigned char i, error = 0;
for (i = 0x80; i>0; i >>= 1) // High bit is 1, loop right shift
{
if (i&value) DHT11_DATA = 1; // AND with the number to be sent, result is the sent bit
else DHT11_DATA = 0;
DHT11_SCK = 1;
_nop_(); _nop_(); _nop_(); // Delay 3us
DHT11_SCK = 0;
}
DHT11_DATA = 1; // Release data line
DHT11_SCK = 1;
error = DHT11_DATA; // Check response signal to confirm communication is normal
_nop_(); _nop_(); _nop_();
DHT11_SCK = 0;
DHT11_DATA = 1;
return error; // error=1 Communication error
}
/****
******* DHT11 Read Byte Function
*****/
char s_read_byte(unsigned char ack)
{
unsigned char i, val = 0;
DHT11_DATA = 1; // Release data line
for (i = 0x80; i>0; i >>= 1) // High bit is 1, loop right shift
{
DHT11_SCK = 1;
if (DHT11_DATA) val = (val | i); // Read a bit data line value
DHT11_SCK = 0;
}
DHT11_DATA = !ack; // If it is a check, end communication after reading;
DHT11_SCK = 1;
_nop_(); _nop_(); _nop_(); // Delay 3us
DHT11_SCK = 0;
_nop_(); _nop_(); _nop_();
DHT11_DATA = 1; // Release data line
return val;
}
/****
******* DHT11 Start Transmission Function
*****/
void s_transstart(void)
{
DHT11_DATA = 1; DHT11_SCK = 0; // Prepare
_nop_();
DHT11_SCK = 1;
_nop_();
DHT11_DATA = 0;
_nop_();
DHT11_SCK = 0;
_nop_(); _nop_(); _nop_();
DHT11_SCK = 1;
_nop_();
DHT11_DATA = 1;
_nop_();
DHT11_SCK = 0;
}
/****
******* DHT11 Initialization Function
*****/
void DHT11_Init(void)
{
unsigned char i;
DHT11_DATA = 1; DHT11_SCK = 0; // Prepare
for (i = 0; i<9; i++) // DATA remains high, SCK clock triggers 9 times, sends start transmission, communication resets
{
DHT11_SCK = 1;
DHT11_SCK = 0;
}
s_transstart(); // Start transmission
}
/****
******* DHT11 Temperature and Humidity Detection Function
*****/
char s_measure(unsigned char *p_value, unsigned char *p_checksum, unsigned char mode)
{
unsigned error = 0;
unsigned int i;
s_transstart(); // Start transmission
switch (mode) // Select send command
{
case TEMP: error += s_write_byte(DHT11_MEASURE_TEMP); break; // Measure temperature
case HUMI: error += s_write_byte(DHT11_MEASURE_HUMI); break; // Measure humidity
default: break;
}
for (i = 0; i<65535; i++) if (DHT11_DATA == 0) break; // Wait for measurement to end
if (DHT11_DATA) error += 1; // If the data line has not been pulled low for a long time, it indicates measurement error
*(p_value) = s_read_byte(DHT11_ACK); // Read the first byte, high byte (MSB)
*(p_value + 1) = s_read_byte(DHT11_ACK); // Read the second byte, low byte (LSB)
*p_checksum = s_read_byte(DHT11_NOACK); // Read CRC checksum
return error; // error=1 Communication error
}
/****
******* DHT11 Temperature and Humidity Value Scale Transformation and Temperature Compensation Function
*****/
void calc_sth10(float *p_humidity, float *p_temperature)
{
const float C1 = -4.0; // 12-bit humidity precision correction formula
const float C2 = +0.0405; // 12-bit humidity precision correction formula
const float C3 = -0.0000028; // 12-bit humidity precision correction formula
const float T1 = +0.01; // 14-bit temperature precision 5V condition correction formula
const float T2 = +0.00008; // 14-bit temperature precision 5V condition correction formula
float rh = *p_humidity; // rh: 12-bit humidity
float t = *p_temperature; // t: 14-bit temperature
float rh_lin; // rh_lin: Humidity linear value
float rh_true; // rh_true: Humidity true value
float t_C; // t_C : Temperature ℃
t_C = t*0.01 - 40; // Compensate temperature
rh_lin = C3*rh*rh + C2*rh + C1; // Relative humidity non-linear compensation
// rh_true = (t_C - 25)*(T1 + T2*rh) + rh_lin; // Relative humidity temperature dependency compensation
rh_true = rh_lin;
if (rh_true>100) rh_true = 100; // Maximum humidity correction
if (rh_true<0.1) rh_true = 0.1; // Minimum humidity correction
*p_temperature = t_C; // Return temperature result
*p_humidity = rh_true; // Return humidity result
}
/****
******* DHT11 Get Temperature and Humidity Value Function
*****/
void Dht11_Get_Temp_Humi_Value(uint *temp,uint *humi)
{
// unsigned int temp, humi;
unsigned char error; // Used to check for errors
unsigned char checksum; // CRC
value humi_val, temp_val; // Define a union for humidity and temperature
error = 0; // Initialize error=0, that is, no error
error += s_measure((unsigned char*)&temp_val.i, &checksum, TEMP); // Temperature measurement
error += s_measure((unsigned char*)&humi_val.i, &checksum, HUMI); // Humidity measurement
if (error != 0) DHT11_Init(); // If an error occurs, reset the system
else
{
humi_val.f = (float)humi_val.i; // Convert to float
temp_val.f = (float)temp_val.i; // Convert to float
calc_sth10(&humi_val.f, &temp_val.f); // Correct relative humidity and temperature
*temp = temp_val.f * 10;
*humi = (humi_val.f - 3.3 )* 10;
}
}
Project Resources:Design and Implementation of Indoor Air Quality Monitoring System Based on 51 Microcontroller