#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT) 原创 精华

发布于 2022-6-17 09:26
浏览
1收藏

本文正在参加星光计划3.0–夏日挑战赛

1. 功能介绍

自从地球上出现森林以来,每年平均发生森林火灾超过20万次。森林火灾不仅烧毁树木,直接减少森林面积,而且严重破坏森林结构和森林环境,导致森林生态系统失衡,森林生物量下降,生产力下降,牲畜减少和鸟类减少,甚至牺牲一些重要东西。高强度的火灾会破坏土壤的化学和物理性质,降低水的积累和土壤,使部分林区地下水位升高而溃败,造成沼泽;此外,通过焦化和使土壤表面变暖,也会加速焦土的干燥,导致杂草过度生长。近年来,世界各地每年都会发生许多火灾。大多数国家的火灾直接损失超过国民经济总量的0.2%。事实上,除了直接的经济死亡和财产损失外,火灾后还有重大的间接损失,因此,有必要发展和加强防火和火灾报警。

这篇文章就采用华为云iot物联网平台快速搭建一个森林火灾预警联动控制系统模型,模拟演示检测到森林火灾之后,如何快速上报到云平台,向关联的指定服务器发送数据报告,并自动向抽水泵发送指令,打开开关抽水灭火。

硬件平台介绍:

MCU: STM32F103ZET6

物联网云平台: 华为IOT云平台

气体检测传感器: MQ2-烟雾传感器、MQ135-空气质量检测传感器

火焰检测: 采用火焰检测传感器

抽水机: 采用直流电机模拟水泵,打开开关抽水喷水灭火

上网网卡: 采用GSM模块SIM800C,使用的是物联网专用卡,包年只能上网这种。

与云端服务器的通信协议: 终端设备采用MQTT3.1.1协议与华为云服务器进行登录连接。

温湿度检测传感器: DHT11

供电方式: 电池+太阳能供电

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

为了演示联动控制,火警(烟雾)检测装置和灭火(直流电机)装置分为两个独立的设备,分别连接上云端。

火警检测装置连接上物联网服务器之后,可以在服务器上配置数据处理规则,如果烟雾浓度超标,可以自动向灭火装置发送指令,进行灭火操作。服务器收到火警检测装置上传的烟雾浓度、空气质量等数据后,可以向自己的私有服务器转发数据,方便自己服务器收到数据后做分析存储处理,比如: 向指定邮箱发送邮件、手机APP推送通知栏、向指定用户推送短消息提示等等。

2. 创建产品(火警预警装置)

打开官网链接: https://www.huaweicloud.com/s/JeeJqeiBlOe9kSU

(1)选择设备接入IotTDA选项。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(2)选择免费试用。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(3)在产品页面选择创建新的产品。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(4)填入产品信息,创建产品

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(5)选择自己刚才创建的产品,创建数据模型,点击自定义模型

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(6)选择添加属性

这个添加的属性就是设备端上报的数据类型。 比如: MQ2烟雾传感器检测的烟雾数据值类型。

在这个页面上还有一个添加命令的功能,这是用于云端下发指令给设备端使用的。当前这个设备是火警检测装置,只需要上报数据给服务器,不需要下发指令,这里就只需要添加属性就行了。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

根据自己的设备的具体情况填写即可,如果上报的数据有多种类型就创建多个属性。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

3. 创建产品(灭火装置)

创建的流程和上面一样,这是多增加了一个命令下发的功能,方便云端远程控制电机开启和关闭,实现灭火功能。

(1)创建产品

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(2)产品创建完毕之后,添加服务器ID

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(3)添加属性,电机属性是可以读可以写的,范围设置为0和1,只能开关

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(4)添加命令,这个命令用于云端远程向设备下发指令,设备收到指令后可以做出相应的逻辑处理

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

接着选择新增输入参数:

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

最后点击确定即可。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

现在产品已经创建完毕。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

4. 创建设备(火警预警装置)

(1)在设备页面,选择注册设备,选择自己的对应的产品,设备标识码一般填自己设备的硬件标号。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(2)设备创建成功之后会弹出弹窗,点击保存并关闭,会自动弹出下载窗口,是个文本文件,存放了密匙信息

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

{
    "device_id": "61bacdc02b2aa20288c5a094_QQ1126626497",
    "secret": "1126626497"
}

5. 创建设备(灭火装置)

流程与上面火警预警装置设备一样的。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

{
    "device_id": "61bad0564d9b020287193be2_QQ1126626497",
    "secret": "1126626497"
}

6. 生成MQTT协议登录ID和密匙

设备创建完成接来下生成MQTT登录账号、密匙,方便设备登录云端平台。

官网工具地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

填入刚才创建设备时,保存下载文件里的信息,对着弹窗填入,最后生成了ID、用户名、password参数,用于MQTT协议登录使用。

(1)火警预警装置生成登录参数

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

ClientId  61bacdc02b2aa20288c5a094_QQ1126626497_0_0_2021121605
Username  61bacdc02b2aa20288c5a094_QQ1126626497
Password  43ed43bcbddc48772694fc2b18ec1112170f4d6cc52fbf1e01401c2ea1748475

(2)灭火装置

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

ClientId 61bad0564d9b020287193be2_QQ1126626497_0_0_2021121605
Username 61bad0564d9b020287193be2_QQ1126626497
Password 43ed43bcbddc48772694fc2b18ec1112170f4d6cc52fbf1e01401c2ea1748475

7. 上报属性格式与主题订阅格式

产品设备、MQTT登录参数都到位了,接下来需要了解设备向服务器上报数据时,如何上报,格式是怎么样的。

(1)第一个问题是:华为云IoT物联网服务器的IP和端口号是多少?

在总览选项页面,点击多协议接入选项,就能看到了。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

如果选择MQTT协议接入:

域名是: a161a58a78.iot-mqtts.cn-north-4.myhuaweicloud.com
如果你的设备不能解析域名,也可以直接填IP地址 121.36.42.100
端口号: 1883

(2)第二个问题是:发布数据的主题和订阅数据的主题怎么填?

在产品页面,选择自己的产品,进去之后就能看到主题的格式介绍页面了。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

为了方便后续复制粘贴,这里总结下格式:

火警预警装置:

格式: $oc/devices/{device_id}/sys/messages/down
//订阅主题: 平台下发消息给设备
$oc/devices/61bacdc02b2aa20288c5a094_QQ1126626497/sys/messages/down


格式: $oc/devices/{device_id}/sys/properties/report
//设备上报数据
$oc/devices/61bacdc02b2aa20288c5a094_QQ1126626497/sys/properties/report

灭火装置:

格式: $oc/devices/{device_id}/sys/messages/down
//订阅主题: 平台下发消息给设备
$oc/devices/61bad0564d9b020287193be2_QQ1126626497/sys/messages/down


格式: $oc/devices/{device_id}/sys/properties/report
//设备上报数据
$oc/devices/61bad0564d9b020287193be2_QQ1126626497/sys/properties/report

(3)第三个问题是:上报属性时,数据格式是什么?

官方文档介绍: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

总结下格式: 上报的数据就是JSON格式,一次性可以上传多个属性数据,JSON数组里按照顺序增加即可。

重要的字段含义解释:这两个字段后面的数据需要自己根据自己的设备产品去填充的。

service_id 示设备服务的ID。

properties 是设备服务的属性列表,具体字段在设备关联的产品模型中定义。

火警预警装置上传的数据:

{"services": [{"service_id": "MQ2","properties":{"MQ2":100}}]}

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

灭火装置上传的数据:

{"services": [{"service_id": "motor","properties":{"motor":1}}]}

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

8. 使用MQTT客户端模拟设备测试

(1)登录火警预警装置

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(2)灭火装置登录

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

可以看到,设备已经成功登录服务器,完成了数据上报。这也证明服务器端设备创建已经全部OK,正常。

9. 配置设备联动

(1)创建规则

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(2)填写规则信息

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(3)添加触发条件,选择需要处理数据的设备,设置条件:当烟雾浓度大于等于100就触发

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(4)添加执行动作,当烟雾浓度超过100就下发指令给灭火装置

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(3)最后点击创建规则,生效规则

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

(4)测试效果

使用两个MQTT客户端分别模拟火警预警装置和灭火装置,当烟雾浓度超过100时,查看灭火装置是否收到云端下发的指令。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

10. 数据转发

如果数据需要转发到其他地方,可以自己创建规则配置。

#夏日挑战赛# 基于STM32+SIM800C设计的森林火灾预警系统(IOT)-开源基础软件社区

11. 硬件设备测试

设备端采用GSM模块SIM800C完成上网功能,主控MCU采用STM32F103ZET6。

任意只要能上网的设备都可以使用当前代码连接服务器,因为当前模拟的是户外设备,只能采用GSM模块上网。

如果是智能家居,屋里小区的设备,有WIFI的可以采用ESP8266这些无线网卡。

代码校对较多,这里只贴出核心代码,需要完整工程的在评论区留言,留下邮箱即可。

1. SIM800C.c

这是SIM800C的配置代码

#include "sim800c.h"

也可以去这里下载工程: https://download.csdn.net/download/xiaolong1126626497/81993720

/*
函数功能:向SIM800C模块发送指令
函数参数:
				char *cmd  发送的命令
			  char *check_data 检测返回的数据
返回值: 0表示成功 1表示失败
*/
u8 SIM800C_SendCmd(char *cmd,char *check_data)
{
   u16 i,j;
   for(i=0;i<5;i++) //测试的总次数
   {
      USART2_RX_FLAG=0;
      USART2_RX_CNT=0;
			memset(USART2_RX_BUFF,0,sizeof(USART2_RX_BUFF));
			USART_X_SendString(USART2,cmd); //发送指令
      for(j=0;j<500;j++) //等待的时间(ms单位)
      {
          if(USART2_RX_FLAG)
          {
              USART2_RX_BUFF[USART2_RX_CNT]='\0';
              if(strstr((char*)USART2_RX_BUFF,check_data))
              {
                  return 0;
              }
              else break;
          }
          delay_ms(20); //一次的时间
      }
   }
   return 1;
}


/*
函数  功能:GSM模块初始化检测
函数返回值:1表示模块检测失败,0表示成功
*/
u8 SIM800C_InitCheck(void)
{
	  if(SIM800C_SendCmd("AT\r\n","OK"))return 1;
	  else printf("SIM800模块正常!\r\n");
	  
		if(SIM800C_SendCmd("ATE0\r\n","OK"))return 2;
	  else printf("设置模块不回显成功!\r\n");
	
		if(SIM800C_SendCmd("AT+CGMI\r\n","OK"))return 3;
		else printf("查询制造商名称成功!%s\r\n",USART2_RX_BUFF);
	
		if(SIM800C_SendCmd("AT+CGMM\r\n","OK"))return 4;
		else printf("查询模块型号成功!%s\r\n",USART2_RX_BUFF);
		
	  DelayMs(1000);
		DelayMs(1000);
		if(SIM800C_SendCmd("AT+CNUM\r\n","+CNUM:"))return 5;
		else printf("获取本机号码成功!%s\r\n",USART2_RX_BUFF);
	  /* 返回格式如下:
		+CNUM: "","+8613086989413",145,7,4
		OK
		*/
		return 0;
}

/*
函数  功能:GSM模块短信模式设置
函数返回值:0表示模块设置成功
*/
u8 SIM800C_SetNoteTextMode(void)
{
		if(SIM800C_SendCmd("AT+CSCS=\"GSM\"\r\n","OK"))return 1;// "GSM"字符集
		else printf("短信GSM字符集设置成功!\r\n");
	
	  if(SIM800C_SendCmd("AT+CMGF=1\r\n","OK"))return 2; //文本模式
		else printf("短信文本模式设置成功!\r\n");
		return 0;
}

/*
函数功能:发送短信
函数参数:
					num:电话号码
					text:短信内容
函数返回值:0表示发送成功
*/
u8 SIM800C_SendNote(u8 *num,u8 *text,u16 len)
{
		char data[50];
		char send_buf[2];
		sprintf(data,"AT+CMGS=\"%s\"\r\n",num);
		if(SIM800C_SendCmd(data,">"))return 1; //设置发送的手机号
		USART_X_SendData(USART2,text,len);     //发送短信内容
	
		send_buf[0] = 0x1a;
		send_buf[1] = '\0';
	  if(SIM800C_SendCmd(send_buf,"+CMGS"))return 2; //发送结束符号
		return 0;
}


/*
函数功能:NTP网络同步时间
*/
void SIM800C_NtpUpdate(void)
{  
	 SIM800C_SendCmd("AT+SAPBR=3,1,\"Contype\",\"GPRS\"\r\n","OK");//配置承载场景1
	 SIM800C_SendCmd("AT+SAPBR=3,1,\"APN\",\"CMNET\"\r\n","OK");
	 SIM800C_SendCmd("AT+SAPBR=1,1\r\n","OK");                     //激活一个GPRS上下文
   DelayMs(5);
   SIM800C_SendCmd("AT+CNTPCID=1\r\n","OK");                     //设置CNTP使用的CID
	 SIM800C_SendCmd("AT+CNTP=\"202.120.2.101\",32\r\n","OK");     //设置NTP服务器和本地时区(32时区 时间最准确)
   SIM800C_SendCmd("AT+CNTP\r\n","+CNTP: 1");                    //同步网络时间
	 printf("同步网络时间:%s\r\n",USART2_RX_BUFF);
}


/*
函数功能:GPRS数据通信初始化
返 回 值: 0表示成功
*/
u8 SIM800C_GPRS_Init(void)
{
	 SIM800C_SendCmd("AT+CIPCLOSE=1\r\n","CLOSE OK");	//关闭连接
	 SIM800C_SendCmd("AT+CIPSHUT\r\n","SHUT OK");		//关闭移动场景 
	 if(SIM800C_SendCmd("AT+CGCLASS=\"B\"\r\n","OK"))return 1;				//设置GPRS移动台类别为B,支持包交换和数据交换 
	 if(SIM800C_SendCmd("AT+CGDCONT=1,\"IP\",\"CMNET\"\r\n","OK"))return 2;//设置PDP上下文,互联网接协议,接入点等信息
	 if(SIM800C_SendCmd("AT+CGATT=1\r\n","OK"))return 3;					//附着GPRS业务
	 if(SIM800C_SendCmd("AT+CIPCSGP=1,\"CMNET\"\r\n","OK"))return 4;	 	//设置为GPRS连接模式
	 if(SIM800C_SendCmd("AT+CIPHEAD=1\r\n","OK"))return 5;	 				//设置接收数据显示IP头(方便判断数据来源)
	 return 0;
}

/*
函数功能: 连接TCP服务器
函数参数: 
				ipaddr:ip地址
				port:端口 
返 回 值: 0表示成功,其他值表示失败
*/
u8 SIM800C_Connect_TCP_Server(char *ipaddr,char *port)
{
	 char cmd_buff[100];
	 SIM800C_SendCmd("AT+CIPCLOSE=1\r\n","CLOSE OK");	//关闭连接
	 SIM800C_SendCmd("AT+CIPSHUT\r\n","SHUT OK");		//关闭移动场景 
	 sprintf(cmd_buff,"AT+CIPSTART=\"TCP\",\"%s\",\"%s\"\r\n",ipaddr,port);
	 if(SIM800C_SendCmd(cmd_buff,"OK"))return 1;		//发起连接
	 return 0;
}


/*
函数功能: TCP客户端模式下发送数据
返 回 值: 0表示成功,其他值表示失败
*/
u8 SIIM800C_TCP_SendData(u8 *data,u32 len)
{
	 char send_buf[2];
	//准备发送数据
	 if(SIM800C_SendCmd("AT+CIPSEND\r\n",">")==0)
	 {
		  //发送数据
			USART_X_SendData(USART2,data,len);
		  //发送结束符号
		  DelayMs(50);
		  send_buf[0] = 0x1a;
		  send_buf[1] = '\0';
		  if(SIM800C_SendCmd(send_buf,"SEND OK"))return 2;
		  else 	return 0;
	 }
	 return 1;
}

2. adc.c

这是烟雾传感器的ADC通道配置代码。

//////////////////////////////////////////////////////////////////////////////////	 
//  功能描述   : 智能环境检测系统
//   时间      : 20190605
//   版本      : v3.3
//             版权所有,盗版必究。
//Copyright(C) DS小龙哥 2016 - 2020
///////////////////////////////////////////////////////////////////////////////////
#include "adc.h"

/*
函数功能: ADC1的初始化
规则通道方式
*/
void ADC1_Init(void)
{
	  /*1. 配置ADC采集输入的IO口*/
	RCC->APB2ENR |= 1 << 3;//PB
	GPIOB->CRL &= 0xFFFFFFF0;
	GPIOB->CRL |= 0x00000000;//配置PB0为模拟输入模式
	
	/*2.配置ADC1时钟*/
	RCC->APB2ENR|=1<<9; 		//开启ADC1时钟
	RCC->APB2RSTR|=1<<9;		//开启复位时钟
	RCC->APB2RSTR&=~(1<<9); //关闭复位时钟
		
	/*3. 配置ADC的预分频器*/
	RCC->CFGR&=~(0x3<<14); //清空预分频
	RCC->CFGR|=0x2<<14;    //12MHZ
	
	/*4. 配置ADC CR1基本寄存器*/
	ADC1->CR1&=~(0xF<<16); //0000:独立模式
	ADC1->CR2|=1<<23;      //1:启用温度传感器和VREFINT。
	//ADC1->CR2|=1<<22;    //1:开始转换规则通道。
	ADC1->CR2|=1<<20;      //1:使用外部事件启动转换
	ADC1->CR2|=0x7<<17;    //111: SWSTART
	ADC1->CR2&=~(1<<11);   //0:右对齐;
	ADC1->CR2&=~(1<<1);    //0:单次转换模式;
	
	/*5. 配置ADC规则序列寄存器*/
	ADC1->SQR1&=~(0xF<<20); //0000: 1个转换
	ADC1->SMPR2|=0x7<<3;    //配置通道1 111: 239.5周期
	ADC1->SMPR1|=0x7<<18;   //配置通道16 111: 239.5周期
		
	ADC1->CR2|=1<<0;        //1:开启ADC并启动转换。
	ADC1->CR2|=1<<3;        //1:初始化校准寄存器。
	ADC1->CR2|=1<<2;        //1:开始校准
	while(ADC1->CR2&1<<2){} //等待校准结束
}


/*
函数功能: 获取指定通道的ADC值
函数参数: u8 ch  通道号
*/
u16 ADC1_GetCHx(u8 ch)
{
		ADC1->SQR3&=0xFFFFFFE0;   //00000
	  ADC1->SQR3|=ch<<0;        //规则序列中的第1个转换
		ADC1->CR2|=1<<22;         //1:开始转换规则通道。
		while(!(ADC1->SR&1<<1)){} //等待转换完成
		return ADC1->DR;          //返回接收到的数据值
}

3. DHT11.c

这是温湿度检测代码。

//////////////////////////////////////////////////////////////////////////////////	 
//  功能描述   : 智能环境检测系统
//   时间      : 20190605
//   版本      : v3.3
//             版权所有,盗版必究。
//Copyright(C) DS小龙哥 2016 - 2020
///////////////////////////////////////////////////////////////////////////////////
#include "dht11.h"
#include "delay.h"

/*
复位DHT1
*/
void DHT11_Rst(void)	   
{                 
	  DHT11_IO_OUT(); 	//SET OUTPUT
    DHT11_DQ_OUT=0; 	//拉低DQ
    delay_ms(20);    	//拉低至少18ms
    DHT11_DQ_OUT=1; 	//DQ=1 
	  delay_us(30);     //主机拉高20~40us
}

/*
等待DHT11的回应
返回1:未检测到DHT11的存在
返回0:存在
*/
u8 DHT11_Check(void) 	   
{   
	u8 retry=0;
	DHT11_IO_IN();//SET INPUT	 
    while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		delay_us(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
	if(retry>=100)return 1;	    
	return 0;
}

/*
从DHT11读取一个位
返回值:1/0
*/
u8 DHT11_Read_Bit(void) 			 
{
 	u8 retry=0;
	while(DHT11_DQ_IN&&retry<100)//等待变为低电平
	{
		retry++;
		delay_us(1);
	}
	retry=0;
	while(!DHT11_DQ_IN&&retry<100)//等待变高电平
	{
		retry++;
		delay_us(1);
	}
	delay_us(40);//等待40us
	if(DHT11_DQ_IN)return 1;
	else return 0;		   
}


/*
从DHT11读取一个字节
返回值:读到的数据
*/
u8 DHT11_Read_Byte(void)    
{        
  u8 i,dat;
  dat=0;
	for(i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
  }						    
  return dat;
}

/*
从DHT11读取一次数据
temp:温度值(范围:0~50°)
humi:湿度值(范围:20%~90%)
返回值:0,正常;1,读取失败
*/
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 	u8 buf[5];
	u8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
	}else return 1;
	return 0;	    
}


/*
初始化DHT11的IO口 DQ 同时检测DHT11的存在
返回1:不存在
返回0:存在  
*/  	 
u8 DHT11_Init(void)
{
	RCC->APB2ENR|=1<<2;    //使能PORTG口时钟 
	GPIOA->CRL&=0XFF0FFFFF;//PORTG.11 推挽输出
	GPIOA->CRL|=0X00300000;
	GPIOA->ODR|=1<<5;      //输出1				    
	DHT11_Rst();
	return DHT11_Check();
}

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-6-17 09:27:49修改
2
收藏 1
回复
举报
回复
添加资源
添加资源将有机会获得更多曝光,你也可以直接关联已上传资源 去关联
    相关推荐