• ESP8266或ESP32使用ESP-IDF开发读取DHT12温度湿度


    DHT12支持温度湿度读取,精度高于DHT11
    DHT12支持单总线和I2C两种方式读取,在使用过程中, I2C通信时需要加上拉电阻, 这一点尤为重要

    • 以下代码在ESP8266_RTOS_SDK及ESP-IDF 3.x测试通过
    • 单总线通信方式也支持DHT11,只是精度下降
    • 设置管脚电平的函数可自行实现, 我这里是封装过的, 非常简单
    • 代码有点冗余, 还可以优化一下
    /* dht12.h */
    #ifndef DHT12_H
    #define DHT12_H
    #include "common.h"
    #include "core.h"
    
    int Dht12Init(sNormalMod* pMod);
    
    void Dht12Thread(sNormalMod* pMod);
    
    float TempGet(void);
    
    float HumGet(void);
    
    typedef struct {
    	u8 State;
    	float Hum;
    	float Temp;
    } sDht12Data;
    
    sDht12Data Dht12DataGet(void);
    
    #endif
    
    /* dht12.c */
    #include "freertos/FreeRTOS.h"
    #include "freertos/task.h"
    #include "freertos/semphr.h"
    #include "common.h"
    #include "dht12.h"
    #include "driver/i2c.h"
    #include "driver/gpio.h"
    #include "config.h"
    #include "gpio.h"
    
    #if CONFIG_BOARD_MODAL == BOARD_NODEMCU ||  CONFIG_BOARD_MODAL == BOARD_GOKIT3
    #define DHT12_DATA_IO_NUM		5
    #define READ_SDA() IoGet(DHT12_DATA_IO_NUM)
    #define SEND_SDA(value) IoSet(DHT12_DATA_IO_NUM, value)
    #elif CONFIG_BOARD_MODAL == BOARD_ESP32
    #define DHT12_SDA_IO_NUM		18
    #define DHT12_SCL_IO_NUM		19
    #define CONFIG_DHT12_I2C_FREQ	100000
    #endif
    
    #define DHT12_OK				0
    #define DHT12_ERROR_CHECKSUM	-10
    #define DHT12_ERROR_CONNECT		-11
    #define DHT12_MISSING_BYTES		-12
    #define DHT12_ADDRESS			((u8)0xB8)
    
    #define MOD_TAG					"DHT1X"
    
    #if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
    #define ENTER_CRITICAL() portENTER_CRITICAL()
    #define EXIT_CRITICAL() portEXIT_CRITICAL()
    #define delay_us ets_delay_us
    #endif
    
    
    
    static struct {
    	float Temp;
    	float Hum;
    	u8 SensorAnswerFlag;
    	u8 SensorErrorFlag;
    } Dht12State;
    
    static sDht12Data Dht12Data;
    
    SemaphoreHandle_t	Lock;
    
    sDht12Data Dht12DataGet(void)
    {
    	sDht12Data Temp;
    	xSemaphoreTake(Lock, portMAX_DELAY);
    	memcpy(&Temp, &Dht12Data, sizeof(Dht12Data));
    	xSemaphoreGive(Lock);
    	return Temp;
    }
    
    
    int Dht12Init(sNormalMod* pMod)
    {
    
    	int Ret = -1;
    
    #if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
    	Ret = CfgIo(DHT12_DATA_IO_NUM, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_ONLY, GPIO_INTR_DISABLE);
    	if(Ret) {
    		ESP_LOGE(MOD_TAG, "Set GPIO mode failed");
    		return -1;
    	}
    	IoSet(DHT12_DATA_IO_NUM, 0);
    	#ifdef DHT12_SCL_IO_NUM
    	Ret = CfgIo(DHT12_SCL_IO_NUM, GPIO_MODE_OUTPUT_OD, GPIO_PULLUP_ONLY, GPIO_INTR_DISABLE);
    	if(Ret) {
    		ESP_LOGE(MOD_TAG, "Set GPIO mode failed");
    		return -1;
    	}
    	IoSet(DHT12_SCL_IO_NUM, 0);
    	#endif
    #elif CONFIG_BOARD_MODAL == BOARD_ESP32
    
    	i2c_config_t I2cConfig = {
    		.mode = I2C_MODE_MASTER,
    		.sda_io_num = DHT12_SDA_IO_NUM,
    		.sda_pullup_en = GPIO_PULLUP_ENABLE,
    		.scl_io_num = DHT12_SCL_IO_NUM,
    		.scl_pullup_en = GPIO_PULLUP_ENABLE,
    		.master.clk_speed = CONFIG_DHT12_I2C_FREQ
    	};
    
    	Ret = i2c_param_config(I2C_NUM_1, &I2cConfig);
    
    	if(Ret != ESP_OK) {
    		ESP_LOGE(MOD_TAG, "I2C config failed");
    		return -1;
    	}
    
    	Ret = i2c_driver_install(I2C_NUM_1, I2cConfig.mode, 0, 0, 0);
    
    	if(Ret != ESP_OK) {
    		ESP_LOGE(MOD_TAG, "I2C driver install failed");
    		return -1;
    	}
    
    #endif
    
    	Lock = xSemaphoreCreateMutex();
    	if (!Lock) {
    		return -1;
    	}
    
    	ESP_LOGW(MOD_TAG, "Inited.");
    	
    	return 0;
    }
    
    
    #if CONFIG_BOARD_MODAL == BOARD_NODEMCU || CONFIG_BOARD_MODAL == BOARD_GOKIT3
    /* 单总线 */
    u8 Dht12ReadByte(void)
    {
    	u16 j = 0;
    	u8 data = 0, bit = 0;
    	
    	for(u8 i = 0; i < 8; i++) {
    		// 检测上次低电平是否结束
    		while(!READ_SDA()) {
    			// 防止进入死循环
    			if(++j>=50000) {
    				break;
    			}
    		}
    		// 延时Min=26us Max70us 跳过数据"0" 的高电平		 
    		delay_us(30);
    
    		// 判断传感器发送数据位
    		bit = READ_SDA();
    		j = 0;
    		// 等待高电平结束
    		while(READ_SDA()) {
    			// 防止进入死循环
    			if(++j >= 50000) {
    				break;
    			}		
    		}
    		data <<= 1;
    		data |= bit;
    	}
    	return data;
    }
    static esp_err_t Dht11Read()
    {
    	u32 j;
    	u8 HumHigh, HumLow, TempHigh, TempLow, TempChecksum, Temp;
    
    	// 进入临界区, 防止调度干扰数据读取
    	ENTER_CRITICAL();
    
    	SEND_SDA(0);	// 主机把数据总线(SDA)拉低
    	delay_us(20000);	// 拉低一段时间(至少18ms), 通知传感器准备数据
    	SEND_SDA(1);	// 释放总线
    	delay_us(30);	// 延时30us
    
    	Dht12State.SensorAnswerFlag = 0;
    	// 判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
    	if(READ_SDA() == 0) {
    		Dht12State.SensorAnswerFlag = 1;	//收到起始信号
    		j = 0;
    		// 判断从机发出 80us 的低电平响应信号是否结束	
    		while((!READ_SDA())) {
    			// 防止进入死循环
    			if(++j >= 500) {
    				Dht12State.SensorErrorFlag = 1;
    				break;
    			}
    		}
    
    		j = 0;
    		// 判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
    		while(READ_SDA()) {
    			// 防止进入死循环
    			if(++j >= 800) {
    				Dht12State.SensorErrorFlag = 1;
    				break;
    			}
    		}
    		// 接收数据
    		HumHigh = Dht12ReadByte();
    		HumLow = Dht12ReadByte();
    		TempHigh = Dht12ReadByte();	
    		TempLow = Dht12ReadByte();
    		TempChecksum = Dht12ReadByte();
    		EXIT_CRITICAL();
    
    		// ets_printf("%02x", HumHigh);
    		// ets_printf("%02x", HumLow);
    		// ets_printf("%02x", TempHigh);
    		// ets_printf("%02x", TempLow);
    		// ets_printf("%02x", TempChecksum);
    
    		Temp = (u8)(HumHigh + HumLow + TempHigh + TempLow);
    
    		//如果校验成功,往下运行
    		if(TempChecksum == Temp) {
    			Dht12State.Hum = HumHigh * 10 + HumLow; //湿度
    	
    			// 为负温度
    			if(TempLow & 0x80) {
    				Dht12State.Temp = 0 - (TempHigh * 10 + ((TempLow & 0x7F)));
    			}
    			else {
    				Dht12State.Temp = TempHigh * 10 + TempLow; //为正温度
    			}
    			// 判断数据是否超过量程(温度:-20℃~60℃,湿度20%RH~95%RH)
    			if(Dht12State.Hum > 950) {
    				Dht12State.Hum = 950;
    			}
    			if(Dht12State.Hum < 200) {
    				Dht12State.Hum = 200;
    			}
    			if(Dht12State.Temp > 600) {
    				Dht12State.Temp = 600;
    			}
    			if(Dht12State.Temp < -200) {
    				Dht12State.Temp = -200;
    			}
    			Dht12State.Temp /= 10; // 计算为温度值
    			Dht12State.Hum /= 10; // 计算为湿度值
    			// ESP_LOGW(MOD_TAG, "TEMP:  %.2f", Dht12State.Temp);
    			// ESP_LOGW(MOD_TAG, "HUM:   %.2f", Dht12State.Hum);
    			Dht12Data.Temp = Dht12State.Temp;
    			Dht12Data.Hum = Dht12State.Hum;
    			Dht12Data.State = 0;
    		}
    		else {
    			Dht12Data.State = 1;
    			ESP_LOGE(MOD_TAG, "Checksum Error!");
    		}
    	}
    	else {
    		Dht12State.SensorErrorFlag = 0;  //未收到传感器响应
    		Dht12Data.State = 2;
    		ESP_LOGE(MOD_TAG, "Sensor Error!");
    		return ESP_FAIL;
    	}
    
    	return ESP_OK;
    
    }
    
    #elif CONFIG_BOARD_MODAL == BOARD_ESP32
    /* I2C */
    static esp_err_t Dht11Read()
    {
    	int Ret = -1;
    	u8 Buffer[10];
    	memset(Buffer, 0, 10);
    	i2c_cmd_handle_t I2cHandle = i2c_cmd_link_create();
    	i2c_master_start(I2cHandle);
    	i2c_master_write_byte(I2cHandle, (u8)0xB8, I2C_MASTER_ACK);
    	i2c_master_write_byte(I2cHandle, (u8)0x0, I2C_MASTER_ACK);
    
    	i2c_master_start(I2cHandle);
    	i2c_master_write_byte(I2cHandle, (u8)0xB9, I2C_MASTER_ACK);
    	i2c_master_read_byte(I2cHandle, &Buffer[0], I2C_MASTER_ACK);
    	i2c_master_read_byte(I2cHandle, &Buffer[1], I2C_MASTER_ACK);
    	i2c_master_read_byte(I2cHandle, &Buffer[2], I2C_MASTER_ACK);
    	i2c_master_read_byte(I2cHandle, &Buffer[3], I2C_MASTER_ACK);
    	i2c_master_read_byte(I2cHandle, &Buffer[4], I2C_MASTER_NACK);
    	i2c_master_stop(I2cHandle);
    	Ret = i2c_master_cmd_begin(I2C_NUM_1, I2cHandle, 100 / portTICK_RATE_MS);
    	i2c_cmd_link_delete(I2cHandle);
    
    	if(Ret != ESP_OK) {
    		Dht12Data.State = 1;
    		ESP_LOGE(MOD_TAG, "Data was not vaild");
    		return -1;
    	}
    
    	u8 Checksum = Buffer[0] + Buffer[1] + Buffer[2] + Buffer[3];
    	if (Buffer[4] != Checksum) {
    		Dht12Data.State = 1;
    		ESP_LOGE(MOD_TAG, "Data was not vaild");
    		return -1;
    	} else {
    		Dht12State.Hum = Buffer[0] + Buffer[1] * 0.1;
    		Dht12State.Temp = Buffer[2] + (Buffer[3] & 0x7F) * 0.1;
    		if (Buffer[4] & 0x80) {
    			Dht12State.Temp = -Dht12State.Temp;
    		}
    		Dht12Data.State = 0;
    		Dht12Data.Temp = Dht12State.Temp;
    		Dht12Data.Hum = Dht12State.Hum;
    		return 0;
    	}
    }
    #endif
    
    void Dht12Thread(sNormalMod* pMod)
    {	
    	int Ret = 0;
    	while(1) {
    		vTaskDelay(5000 / portTICK_RATE_MS);
    		xSemaphoreTake(Lock, portMAX_DELAY);
    		Ret = Dht11Read();
    		xSemaphoreGive(Lock);
    		if (Ret != ESP_OK) {
    			ESP_LOGE(MOD_TAG, "Dht11 data was not vaild");
    		} else {
    			ESP_LOGI(MOD_TAG, "Hum: %.2f, Temp: %.2f", Dht12State.Hum, Dht12State.Temp);
    		}
    		
    	}
    }
    
  • 相关阅读:
    离线获取docker镜像(docker save vs load)&docker export vs import& docker commit
    深入分析JavaWeb的中文编码问题
    python中Django的基本使用
    element+springboot实现简单的商品管理
    springboot+thymeleaf自定义标签
    springboot整合shiro
    linux的namespace、docker网络模式
    Docker Compose、Swarm 集群管理
    iOS Share Extension 自定义分享界面
    Mixin Messenger 源码解读 1 — — WCDB Swift
  • 原文地址:https://www.cnblogs.com/rootming/p/10854243.html
Copyright © 2020-2023  润新知