基于C51的 温湿度监测系统(及蓝牙温控风扇)

news/2024/11/25 8:33:18/

项目介绍:

C51、DHT11、LCD1602、蓝牙模块、继电器、直流电机及扇叶。实时监测温湿度并通过LCD显示和串口蓝牙传输,蓝牙控制风扇开、关和自动温控模式,自动温控模式可以设置需要的温度阈值,达到阈值启动风扇,低于阈值自动关闭。附有源码。

c51蓝牙温湿度监测系统

目录

项目介绍:

一 DHT11温湿度传感器

 检测模块是否存在

二 温湿度通过串口传给PC

代码:

三 在LCD1602上显示温湿度

代码:

温控风扇:

分文件实现代码优化:

各部分代码:

四 蓝牙控制风扇电机实现


一 DHT11温湿度传感器

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,应用领域:暖通空调;汽车;消费品;气象站;湿度调节器;除湿器;家电;医疗;自动控制

特点:

相对湿度和温度测量
全部校准,数字输出
长期稳定性
超长的信号传输距离:20米
超低能耗:休眠
4 引脚安装:可以买封装好的
完全互换 : 直接出结果,不用转化

 DHT11的供电电压为3-5.5V。传感器上电后,要等待1s 以越过不稳定状态在此期间无需发送任何指令。电源引脚(VDD,GND)之间可增加一个100nF 的电容,用以去耦滤波。

数据传送逻辑:

从一根数据线DATA,C51发送序列指令给DHT11模块,模块一次完整的数据传输为40bit,高位先

数据格式:

8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和

通讯过程时序图:

 检测模块是否存在

根据如下时序图,做通信初始化,并检测模块是否存在,功能是否正常

时序逻辑分析:从左到右

1 先拉高

2 拉低至少18ms

3 拉高后,持续20~40微秒后模块会自动拉低,输出响应信号

4 模块自动拉低的响应信号有80微秒

检测:结合3和4中时间取交集,判断出第3步拉高后,只要在40~100微秒内为低电平,模块存在。
 

代码:模块通电要先稳定一秒。

	Delay1000ms();DHT = 1;DHT = 0;Delay30ms();DHT = 1;Delay70us();if(!DHT)	LED = 0;

 LED被点亮,检测到模块存在。

二 温湿度通过串口传给PC

关于串口知识参考本人之前的博客

(41条消息) C52串口_我有在好好学习的博客-CSDN博客

检测到存在后,会再主动拉高80us然后主动拉低,开始传送数据

卡开始传输数据的点:

检测到存在后,while低,while高,开始接收数据

用户MCU发送一次开始信号后,DHT11从低功耗模式 转换到高速模式, 等待主机开始信号结束后,DHT11发送响应信号, 送出40bit的数据, 并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集. 采集数据后转换到低速模式 

DHT11传输0的时序分析

DHT11传输1的时序分析

 

代码:

获得数据:因为温度整数、小数,湿度整数、小数,校验和,共5段数据,每段8bit

输出数据:串口发送给电脑,参考本人C51串口文章内代码

参照ANSI码表,低位高位分别+0x30

sfr AUXR = 0x8E;char datas[5];//串口部分代码
void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定时器1工作方式位8位自动重装TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//启动定时器EA = 1;//开启总中断ES = 1;//开启串口中断
}void sendByte(char data_msg)
{SBUF = data_msg;while(!TI);TI = 0;
}void sendString(char* str)
{while( *str != '\0'){sendByte(*str);str++;}
}//模块初始化开始
void start_DHT()
{DHT = 1;DHT = 0;Delay30ms();DHT = 1;while(DHT);while(!DHT);while(DHT);
}//读取模块数据
void GET_DATA_FROM_DHT()
{int i;//读5轮int j;//每轮读8次char tmp;char flag;//重新初始模块start_DHT();for(i=0;i<5;i++){for(j=0;j<8;j++){//等待主动拉高while(!DHT);//检测0/1Delay40us();if(DHT){flag = 1;//等待拉低while(DHT);}else{flag = 0;}//DATA左移一位,用来储存数据tmp <<= 1;//移出来的最后一位储存数据tmp |= flag;}datas[i] = tmp;}
}void main()
{//串口初始化UartInit();while(1){//每秒获取一次数据Delay1000ms();GET_DATA_FROM_DHT();sendString("hum: ");sendByte(datas[0]/10 + 0x30);sendByte(datas[0]%10 + 0x30);sendByte('.');sendByte(datas[1] + 0x30);sendString("	");sendString("tmp: ");sendByte(datas[2]/10 + 0x30);sendByte(datas[2]%10 + 0x30);sendByte('.');sendByte(datas[3] + 0x30);sendString("\r\n");}
}

吐槽自己 for(j=0;j<8;j++) 写成了 for(j=0;j<8;i++) 竟然调试几个小时没发现问题在哪!!

三 在LCD1602上显示温湿度

参考本人上个LCD1602外设的博客

(41条消息) C51外设:LCD1602_我有在好好学习的博客-CSDN博客

 原本传给PC的数据,改为传给LCD屏

代码:

... ...
#define dataBuffer P0 //P0端口组//LCD1602
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;
//DHT11
sbit DHT = P3^3;char temp[12];
char huma[12];
char datas[5];... ...//LCD1602代码
void check_busy()//查忙
{char tmp = 0x80;dataBuffer = 0x80;while(tmp & 0x80){RS = 0;//低电平选指令寄存器RW = 1;//高电平时进行读操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();EN = 1;_nop_();_nop_();tmp = dataBuffer;EN = 0;_nop_();}
}void Write_Cmd_Func(char cmd){//发指令check_busy();RS = 0;//低电平选指令寄存器RW = 0;//低电平时进行写操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();dataBuffer = cmd;EN = 1;_nop_();_nop_();EN = 0;_nop_();
}void Write_Data_Func(char Data){//发数据check_busy();RS = 1;//高电平时选择数据寄存器RW = 0;//低电平时进行写操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();dataBuffer = Data;EN = 1;_nop_();_nop_();EN = 0;_nop_();
}void LCD1602_INIT()//lcd初始化
{//(1)延时 15msDelay15ms();//(2)写指令 38H(不检测忙信号)Write_Cmd_Func(0x38);//(3)延时 5msDelay5ms();//(4)以后每次写指令,读/写数据操作均需要检测忙信号//(5)写指令 38H:显示模式设置Write_Cmd_Func(0x38);//(6)写指令 08H:显示关闭Write_Cmd_Func(0x08);//(7)写指令 01H:显示清屏Write_Cmd_Func(0x01);//(8)写指令 06H:显示光标移动设置Write_Cmd_Func(0x06);//(9)写指令 0CH:显示开及光标设置}Write_Cmd_Func(0x0c);
}void PrintChar(char Data,char Position)//显示字符
{char position = 0x80 + Position;char dataShow = Data;Write_Cmd_Func(position);Write_Data_Func(dataShow);
}void PrintString(char str[],char Position)//显示字符串
{int i = 0;while(str[i] != '\0'){if(Position+i == 0x10)	Position += 0x30;if(Position+i == 0x50)	break;PrintChar(str[i],Position + i);i++;}
}void print_datas(){//LCD显示温湿度huma[0] = 'H';huma[1] = 'U';huma[2] = 'M';huma[3] = ':';huma[4] = ' ';huma[5] = datas[0]/10 + 0x30;huma[6] = datas[0]%10 + 0x30;huma[7] = '.';huma[8] = datas[1] + 0x30;huma[9] = ' ';huma[10] = '%';huma[11] = '\0';temp[0] = 'T';temp[1] = 'E';temp[2] = 'P';temp[3] = ':';temp[4] = ' ';temp[5] = datas[2]/10 + 0x30;temp[6] = datas[2]%10 + 0x30;temp[7] = '.';temp[8] = datas[3] + 0x30;temp[9] = 0xDF;//'°'temp[10] = 'C';temp[11] = '\0';PrintString(temp,0x02);PrintString(huma,0x42);
}... ...void main()
{//LCD1602初始化LCD1602_INIT();while(1){//每秒获取一次数据Delay1000ms();GET_DATA_FROM_DHT();//LCD显示print_datas();}
}

温控风扇:

通过外部连接一个 继电器 ,来控制风扇的开关,继电器为低电平导通,可以设置温度超过多少摄氏度,就打开风扇电机。

分文件实现代码优化:

全在一个文件里显得又臭又长,不便于阅读。

这里做分文件处理,各文件之间以函数互相调用进行联系,因此封装了一些调用函数,如:

//温度值调用
char* get_temp()
{return datas[2];
}//温度字符串调用
char* temp_string()
{return temp;
}//湿度字符串调用
char* humi_string()
{return humi;
}

分出        .c         文件:

 

 分出        .h         文件:(只包含被外部调用的函数的声明)

 最终结构如下

 

各部分代码:

各个        .c        :

main.c

#include "reg52.h"
#include "delay.h"
#include "dht11.h"
#include "lcd1602.h"
#include "uart.h"sbit fan = P3^2;void main()
{fan = 1;//串口初始化UartInit();//LCD1602初始化LCD1602_INIT();while(1){//每秒获取一次数据Delay1000ms();GET_DATA_FROM_DHT();//串口传输uart_send();//LCD显示print_datas();//温度大于29度打开风扇if(get_temp() >= 29)	fan = 0;else fan = 1;}
}

uart.c

#include "reg52.h"
#include "dht11.h"sfr AUXR = 0x8E;char fan_ON = 1;//串口部分代码
void UartInit(void)		//9600bps@11.0592MHz
{AUXR = 0x01;SCON = 0x50; //配置串口工作方式1,REN使能接收TMOD &= 0x0F;TMOD |= 0x20;//定时器1工作方式位8位自动重装TH1 = 0xFD;TL1 = 0xFD;//9600波特率的初值TR1 = 1;//启动定时器EA = 1;//开启总中断ES = 1;//开启串口中断
}//发送字符
void sendByte(char data_msg)
{SBUF = data_msg;while(!TI);TI = 0;
}//发送字符串
void sendString(char* str)
{while( *str != '\0'){sendByte(*str);str++;}
}//发送温湿度信息
void uart_send(){sendString(temp_string());sendString("	");sendString(humi_string());sendString("\r\n");
}

dht11.c

#include "reg52.h"
#include "delay.h"sbit DHT = P3^3;char temp[12];
char humi[12];
char datas[5];//DHT11代码
void start_DHT()//模块初始化开始
{DHT = 1;DHT = 0;Delay30ms();DHT = 1;while(DHT);while(!DHT);while(DHT);
}void build_string(){humi[0] = 'H';humi[1] = 'U';humi[2] = 'M';humi[3] = ':';humi[4] = ' ';humi[5] = datas[0]/10 + 0x30;humi[6] = datas[0]%10 + 0x30;humi[7] = '.';humi[8] = datas[1] + 0x30;humi[9] = ' ';humi[10] = '%';humi[11] = '\0';temp[0] = 'T';temp[1] = 'E';temp[2] = 'P';temp[3] = ':';temp[4] = ' ';temp[5] = datas[2]/10 + 0x30;temp[6] = datas[2]%10 + 0x30;temp[7] = '.';temp[8] = datas[3] + 0x30;temp[9] = 0xDF;//'°'temp[10] = 'C';temp[11] = '\0';
}void GET_DATA_FROM_DHT()//读取模块数据
{int i;//读5轮int j;//每轮读8次char tmp;char flag;//重新初始模块start_DHT();for(i=0;i<5;i++){for(j=0;j<8;j++){//等待主动拉高while(!DHT);//检测0/1Delay40us();if(DHT){flag = 1;//等待拉低while(DHT);}else{flag = 0;}//DATA左移一位,用来储存数据tmp <<= 1;//移出来的最后一位储存数据tmp |= flag;}datas[i] = tmp;}build_string();
}//温度值调用
char* get_temp()
{return datas[2];
}//温度字符串调用
char* temp_string()
{return temp;
}//湿度字符串调用
char* humi_string()
{return humi;
}

lcd1602.c

#include "reg52.h"
#include "intrins.h"
#include "delay.h"
#include "dht11.h"#define dataBuffer P0 //P0端口组//LCD1602
sbit RS = P1^0;
sbit RW = P1^1;
sbit EN = P1^4;//LCD1602代码
void check_busy()//查忙
{char tmp = 0x80;dataBuffer = 0x80;while(tmp & 0x80){RS = 0;//低电平选指令寄存器RW = 1;//高电平时进行读操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();EN = 1;_nop_();_nop_();tmp = dataBuffer;EN = 0;_nop_();}
}void Write_Cmd_Func(char cmd){//发指令check_busy();RS = 0;//低电平选指令寄存器RW = 0;//低电平时进行写操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();dataBuffer = cmd;EN = 1;_nop_();_nop_();EN = 0;_nop_();
}void Write_Data_Func(char Data){//发数据check_busy();RS = 1;//高电平时选择数据寄存器RW = 0;//低电平时进行写操作EN = 0;//变成低电平时,液晶模块执行命令_nop_();dataBuffer = Data;EN = 1;_nop_();_nop_();EN = 0;_nop_();
}void LCD1602_INIT()//lcd初始化
{//(1)延时 15msDelay15ms();//(2)写指令 38H(不检测忙信号)Write_Cmd_Func(0x38);//(3)延时 5msDelay5ms();//(4)以后每次写指令,读/写数据操作均需要检测忙信号//(5)写指令 38H:显示模式设置Write_Cmd_Func(0x38);//(6)写指令 08H:显示关闭Write_Cmd_Func(0x08);//(7)写指令 01H:显示清屏Write_Cmd_Func(0x01);//(8)写指令 06H:显示光标移动设置Write_Cmd_Func(0x06);//(9)写指令 0CH:显示开及光标设置}Write_Cmd_Func(0x0c);
}void PrintChar(char Data,char Position)//显示字符
{char position = 0x80 + Position;char dataShow = Data;Write_Cmd_Func(position);Write_Data_Func(dataShow);
}void PrintString(char str[],char Position)//显示字符串
{int i = 0;while(str[i] != '\0'){if(Position+i == 0x10)	Position += 0x30;if(Position+i == 0x50)	break;PrintChar(str[i],Position + i);i++;}
}void print_datas(){//LCD显示温湿度PrintString(temp_string(),0x02);PrintString(humi_string(),0x42);
}

delay.c        (略,内为各种软件延时函数)

各个        .h        :        (只有被外部调用的函数需要声明)

//软件延时函数集
void Delay1000ms();void Delay30ms();void Delay40us();void Delay15ms();void Delay5ms();
//DHT11
void GET_DATA_FROM_DHT();//读取模块数据char* get_temp();char* temp_string();char* humi_string();
//LCD1602
void LCD1602_INIT();//LCD初始化void print_datas();//LCD显示温湿度
void UartInit(void);void uart_send();

四 蓝牙控制风扇电机实现

蓝牙功能,基于串口,在串口的代码进行修改。

参考本人博客

(41条消息) C52串口_我有在好好学习的博客-CSDN博客

(41条消息) C52项目3:蓝牙/Wifi/4G智能控制开关_我有在好好学习的博客-CSDN博客

串口代码文件中增加:手机蓝牙端输入  o  或  c  ,即代表开关风扇,a  为自动模式,随温度阈值开关。

uart.c:

//调取蓝牙命令内容
char If_fan_ON(){return fan_ON;
}//蓝牙指令接收(中断)
void UART_HANDLER() interrupt 4
{char cmd;if(RI)//中断处理函数中,对于接收中断的响应{RI = 0;//清除接收中断标志位cmd = SBUF;//接收命令if(cmd == 'o'){fan_ON = 1;sendString("已经为您打开风扇!\r\n");}if(cmd == 'c'){fan_ON = 0;sendString("已经为您关闭风扇!\r\n");}if(cmd == 'a'){fan_ON = 2;sendString("风扇进入温控模式!\r\n");}}
}

 main.c:

		//安装蓝牙指令开关风扇或自动根据温度阈值开关风扇if(If_fan_ON() == 1){fan = 0;}if(If_fan_ON() == 0){fan = 1;}if(If_fan_ON() == 2){if(get_temp() >= 29)	fan = 0;else fan = 1;


http://www.ppmy.cn/news/694500.html

相关文章

风扇常见事故处理

风扇 随着微处理器内集成越来越多电路&#xff0c;以及不断增加的能耗&#xff0c;散热问题就不得不再次重提。针对电脑的散热系统多种多样&#xff0c;大致分为水冷、半导体制冷、油冷等。但我们最常使用的还是比较廉价的风冷&#xff0c;也就是散热风扇。在台式机里使用散热风…

计算机硬盘 电机 利用,如何利用坏硬盘来做一个超强风扇,变废为宝 利用坏硬盘来做一个超强风扇,变废为宝的方法...

今天给大家带来如何利用坏硬盘来做一个超强风扇&#xff0c;变废为宝&#xff0c;利用坏硬盘来做一个超强风扇&#xff0c;变废为宝的方法&#xff0c;让您轻松解决问题。 店里好多坏硬盘,回收了又值不了几个钱.今天无事,突发奇想,为什么不做个7200风扇. 首先选风扇很重要,我选…

英国发明家推出无扇叶转轮风扇(图)

没有叶片的风扇 新浪科技讯 北京时间10月14日消息&#xff0c;据英国媒体报道&#xff0c;英国发明家詹姆士戴森最近推出了一款新发明无叶片风扇&#xff0c;这种新型电扇叫戴森空气增加器&#xff0c;它能产生神奇的凉风&#xff0c;由于没有叶片&#xff0c;不会覆盖尘土&…

普中科技51单片机直流电机控制风扇调速

目录 实验介绍硬件设计静态数码管介绍独立按键介绍直流电机介绍ULN2003 芯片介绍 硬件实物连接直流电机连接按键、数码管连接 软件设计main.c 实验现象实验总结 实验介绍 通过独立按键控制带风扇叶的直流电机的转速&#xff0c;并在静态数码管上显示风扇的挡数&#xff0c;其中…

【.NET 与树莓派】小风扇模块

小风扇&#xff0c;其实就是一个电机&#xff08;马达&#xff09;&#xff0c;然后轴子上套一个扇叶。扇叶有两叶的&#xff0c;也有三叶的。这种我们小时候没少玩&#xff0c;太阳能帽子上就有一个小风扇&#xff0c;骑着自行车上学&#xff0c;路上只要有太阳光照射到&#…

AE制作全息风扇视频制作笔记

AE制作全息风扇视频制作笔记 如上图&#xff0c;头脚身体三部分&#xff0c;并添加圆形蒙版 突然想起便做一下记录 AE如何制作 这个是测试文件&#xff0c;可以用来尝试回忆练习步骤 下面便是操作步骤了 AE软件打开后&#xff0c;首先将视频拖拽到以下位置 2. 然后将上面那个…

风扇扇叶产生的基本噪声模型

由于与本人研究相关&#xff0c;参考一些国内外的相关资料 希望有志同道合的朋友一起讨论&#xff0c;可以私信我。 根据电机和扇叶不同进行噪声分析&#xff0c;希望对被控对象进行建模&#xff0c;分析潜在的频率成分以及传播能量。 目前在使用Comsol进行CFD以及声学有限元…

浅谈容器技术之Podman

1.Podman容器简介 Podman&#xff08;Pod Manager&#xff09;是一个由RedHat公司推出的容器管理工具&#xff0c;它的定位就是 Docker 的替代品&#xff0c;在使用上与Docker 的体验类似。Podman源于CRI-O项目&#xff0c;可以直接访问 OCI 的实现&#xff08;如 runC&#x…