前言:
在课程设计中选择了DHT11和LCD1602作为微机原理的课程设计任务。其中,单片机是AT89C52(51/52单片机)设计程序。
首先,展示代码。
Main函数
#include <reg52.h>
#include "LCD1602.h"
#include "dht11.h"
sbit Key_Add = P3^0;
sbit Key_Sub = P3^1;
sbit Buzzer = P2^5;
void Delay_Main_Ms(unsigned int ms)
{
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 110; j++);
}
unsigned char Key_Scan(void)
{
static unsigned char key_up = 1;
if(Key_Add==1 && Key_Sub==1) key_up = 1;
if(key_up == 1)
{
if(Key_Add == 0)
{
Delay_Main_Ms(10);
if(Key_Add == 0) { key_up = 0; return 1; }
}
else if(Key_Sub == 0)
{
Delay_Main_Ms(10);
if(Key_Sub == 0) { key_up = 0; return 2; }
}
}
return 0;
}
void main(void)
{
unsigned char set_temp = 30;
unsigned char key_val = 0;
unsigned int time_count = 0;
Buzzer = 1;
LCD_Init();
LCD_ShowString(1, 1, "DHT11 Sensor SYS");
LCD_ShowString(2, 1, "Wait Connect...");
Delay_Main_Ms(1000);
LCD_ShowString(1, 1, "Temp: C ");
LCD_ShowString(2, 1, "Humi: % SET: ");
LCD_ShowNum(2, 15, set_temp, 2);
while(1)
{
key_val = Key_Scan();
if(key_val != 0)
{
if(key_val == 1)
{
if(set_temp < 99) set_temp++;
}
else if(key_val == 2)
{
if(set_temp > 0) set_temp--;
}
LCD_ShowNum(2, 15, set_temp, 2);
}
time_count++;
if(time_count >= 100)
{
time_count = 0;
Read_Data_From_DHT();
LCD_ShowNum(1, 6, DHT_Datas[0], 2);
LCD_ShowNum(2, 6, DHT_Datas[2], 2);
if(DHT_Datas[0] >= set_temp)
{
Buzzer = 0;
}
else
{
Buzzer = 1;
}
}
Delay_Main_Ms(10);
}
}
接下来,DHT11驱动程序。
#include <reg52.h>
#include <intrins.h>
#include "dht11.h"
sbit dht = P3^7;
unsigned char U8FLAG;
unsigned char U8temp;
unsigned char U8comdata;
unsigned char DHT_Datas[5] = {0};
unsigned char U8T_data_H_temp, U8T_data_L_temp, U8RH_data_H_temp, U8RH_data_L_temp, U8checkdata_temp;
void Delay_10us2(void)
{
unsigned char i;
i = 2;
while (--i);
}
void Delay2(unsigned int j)
{
unsigned char i;
for (; j > 0; j--)
{
for (i = 0; i < 100; i++);
}
}
void COM(void)
{
unsigned char i;
for (i = 0; i < 8; i++)
{
U8FLAG = 2;
while ((!dht) && U8FLAG++);
Delay_10us2();
Delay_10us2();
Delay_10us2();
U8temp = 0;
if (dht) U8temp = 1;
U8FLAG = 2;
while ((dht) && U8FLAG++);
if (U8FLAG == 1) break;
U8comdata <<= 1;
U8comdata |= U8temp;
}
}
void Read_Data_From_DHT(void)
{
EA = 0;
dht = 0;
Delay2(180);
dht = 1;
Delay_10us2();
Delay_10us2();
Delay_10us2();
Delay_10us2();
dht = 1;
if (!dht)
{
U8FLAG = 2;
while ((!dht) && U8FLAG++);
U8FLAG = 2;
while ((dht) && U8FLAG++);
COM();
U8RH_data_H_temp = U8comdata;
COM();
U8RH_data_L_temp = U8comdata;
COM();
U8T_data_H_temp = U8comdata;
COM();
U8T_data_L_temp = U8comdata;
COM();
U8checkdata_temp = U8comdata;
dht = 1;
U8temp = (U8T_data_H_temp + U8T_data_L_temp + U8RH_data_H_temp + U8RH_data_L_temp);
if (U8temp == U8checkdata_temp)
{
DHT_Datas[0] = U8T_data_H_temp;
DHT_Datas[1] = U8T_data_L_temp;
DHT_Datas[2] = U8RH_data_H_temp;
DHT_Datas[3] = U8RH_data_L_temp;
DHT_Datas[4] = U8checkdata_temp;
}
}
EA = 1;
}
接下来,LCD1602驱动程序:
#include "LCD1602.h"
static void delay_ms_proteus(unsigned int ms);
static void LCD_WriteCommand(unsigned char Command);
static void LCD_WriteData(unsigned char Data);
static void delay_ms_proteus(unsigned int ms)
{
unsigned int i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 500; j++);
static void LCD_WriteCommand(unsigned char Command)
{
LCD_RS = 0;
LCD_RW = 0;
LCD_DATA_PORT = Command;
LCD_EN = 1;
delay_ms_proteus(1);
LCD_EN = 0;
delay_ms_proteus(1);
}
static void LCD_WriteData(unsigned char Data)
{
LCD_RS = 1;
LCD_RW = 0;
LCD_DATA_PORT = Data;
LCD_EN = 1;
delay_ms_proteus(1);
LCD_EN = 0;
delay_ms_proteus(1);
}
void LCD_Init()
{
delay_ms_proteus(20);
LCD_WriteCommand(0x38);
delay_ms_proteus(5);
LCD_WriteCommand(0x0C);
delay_ms_proteus(5);
LCD_WriteCommand(0x06);
delay_ms_proteus(5);
LCD_WriteCommand(0x01);
delay_ms_proteus(5);
}
void LCD_Clear(void)
{
LCD_WriteCommand(0x01);
delay_ms_proteus(5);
}
void LCD_ShowString(unsigned char Line, unsigned char Column, char *String)
{
unsigned char addr;
if (Line == 1)
addr = 0x80 + (Column - 1);
else
addr = 0xC0 + (Column - 1);
LCD_WriteCommand(addr);
while (*String != '\0')
{
LCD_WriteData(*String);
String++;
}
}
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i;
unsigned char buf[6];
for(i=0; i<Length; i++)
{
buf[i] = Number % 10 + '0';
Number /= 10;
}
for(i=Length; i>0; i--)
{
LCD_ShowChar(Line, Column + Length - i, buf[i-1]);
}
}
void LCD_ShowChar(unsigned char Line, unsigned char Column, char Char)
{
unsigned char addr;
if (Line == 1)
addr = 0x80 + (Column - 1);
else
addr = 0xC0 + (Column - 1);
LCD_WriteCommand(addr);
LCD_WriteData(Char);
}
最后是头文件区块:
===================================LCD1602.H===================================
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include <reg52.h>
sbit LCD_RS = P1^2;
sbit LCD_RW = P1^1;
sbit LCD_EN = P1^0;
#define LCD_DATA_PORT P0
void LCD_Init(void);
void LCD_ShowChar(unsigned char Line, unsigned char Column, char Char);
void LCD_ShowString(unsigned char Line, unsigned char Column, char *String);
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length);
void LCD_Clear(void);
#endif
===================================DHT11.H===================================
#ifndef __DHT11_H__
#define __DHT11_H__
#include <reg52.h>
extern unsigned char DHT_Datas[5];
void Read_Data_From_DHT(void);
#endif
现在我们查看DHT11时序信号,也就是与主机对话的过程。



代码片段解释:
void COM(void)
{
unsigned char i;
for (i = 0; i < 8; i++)//读取8位数据循环
{
U8FLAG = 2;
while ((!dht) && U8FLAG++);//看门狗程序
Delay_10us2();//延迟30us
Delay_10us2();
Delay_10us2();
//54+27us等待判定电平
U8temp = 0;//初始化数据
if (dht) U8temp = 1;//写数据,如果0则为0,如果1则为1
U8FLAG = 2;//重置看门狗
while ((dht) && U8FLAG++);//看门狗数据递增
if (U8FLAG == 1) break;//看门狗检查是否死循环
U8comdata <<= 1;
U8comdata |= U8temp;
}
}
void Read_Data_From_DHT(void)
{
EA = 0;//关闭中断
dht = 0;
Delay2(180);//延迟18ms
dht = 1;//拉高电平
//等待40us
Delay_10us2();
Delay_10us2();
Delay_10us2();
Delay_10us2();
dht = 1;//由时序图,拉高后监测低电平输入
if (!dht)如果是低电平进入循环
{
U8FLAG = 2;
while ((!dht) && U8FLAG++);//看门狗
U8FLAG = 2;
while ((dht) && U8FLAG++);//看门狗
COM();//读数据
U8RH_data_H_temp = U8comdata;//写高位
COM();
U8RH_data_L_temp = U8comdata;//写低位
COM();
U8T_data_H_temp = U8comdata;//写高位
COM();
U8T_data_L_temp = U8comdata;//写低位
COM();
U8checkdata_temp = U8comdata; //写校验值
dht = 1; //拉高总线等待下一次数据传送
U8temp = (U8T_data_H_temp + U8T_data_L_temp + U8RH_data_H_temp + U8RH_data_L_temp);
if (U8temp == U8checkdata_temp)//判断数据是否有误,如果无误,存入数组(内存)
{
DHT_Datas[0] = U8T_data_H_temp;
DHT_Datas[1] = U8T_data_L_temp;
DHT_Datas[2] = U8RH_data_H_temp;
DHT_Datas[3] = U8RH_data_L_temp;
DHT_Datas[4] = U8checkdata_temp;
}
}
EA = 1;//恢复中断
}
接下来是LCD1602的困难函数解析:
void LCD_Init()//初始化函数
{
delay_ms_proteus(20);
LCD_WriteCommand(0x38);//设置8位2行
delay_ms_proteus(5);
LCD_WriteCommand(0x0C);//开显示,关光标
delay_ms_proteus(5);
LCD_WriteCommand(0x06);//设置输入模式
delay_ms_proteus(5);
LCD_WriteCommand(0x01);//清屏
delay_ms_proteus(5);
}
void LCD_ShowNum(unsigned char Line, unsigned char Column, unsigned int Number, unsigned char Length)
{
unsigned char i;
unsigned char buf[6];
for(i=0; i<Length; i++)循环位数
{
buf[i] = Number % 10 + '0';//ASCII码获取
Number /= 10;//取得下一组数
}
for(i=Length; i>0; i--)
{
LCD_ShowChar(Line, Column + Length - i, buf[i-1]);//正序显示
}
}
最后是Proteus模拟电路图展示:

- THE END -
最后修改:2025年12月22日
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://boxcat.cc/?p=343
共有 0 条评论