【Orange Pi+DHT11】Orange Pi (Allwinner H616) + DHT11 Temperature and Humidity Sensor Driver Tutorial

I. Introduction

I recently wrote DHT11 code to Orange Pi (Allwinner H616), and found that most of the online cases are Raspberry Pi + DHT11, and there are few Orange Pi. The few found codes are unstable or the data is relatively Not very accurate, so I wrote an article here for your reference and criticism

product description


DHT11 digital temperature and humidity sensor is a temperature and humidity composite sensor with calibrated digital signal output. Application fields: HVAC; automobile; consumer goods; weather station; humidity regulator; dehumidifier; home appliance; medical treatment; automatic control
insert image description here

features

  • Relative Humidity and Temperature Measurement
  • Fully calibrated, digital output
  • long-term stability
  • Ultra-long signal transmission distance: 20 meters
  • Ultra-low power consumption: sleep
  • 4-pin installation: can buy packaged
  • Completely interchangeable: get the result directly without conversion

data transfer logic

There is only one data line, DATA, and the main control MCU sends sequence commands to the DHT11 module. The complete data transmission of the module is 40bit, high bit first out

Data Format

8bit humidity integer data+8bit humidity decimal data+8bi temperature integer data+8bit temperature decimal data+8bit checksum

About verification : Assume that the received 40-bit data is:
insert image description here

Calculation:
0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001 (check digit)


DHT11 communication sequence

insert image description here

(1) The host sends the start signal.
First, the microcontroller will output a low level to the GPIO port connected to the DHT11 DATA pin, and the low level should not be kept for less than 18ms (t1) can not exceed 30ms at most, and then pull the data line high for 20~40us (t2), waiting to read the response signal of DHT11.

(2) Detect
the DATA pin of the slave response signal DHT11 detects that the external signal has a low level (t1), and wait for the end of the external low level signal (t2). After the delay, the DATA pin of the DHT11 is in the output state, and then the DHT11 Start to output 80us (t3) low level as a response signal, and then output 80us (t4) high level to inform the host to prepare to receive data.
The I/O of the host is in the input state at this time. After detecting the low level of the I/O (DHT11 response signal), wait for the high level of 80us to receive the data.

(3) Data transmission
DHT11's DATA pin outputs 40-bit data, using MSB first, and the microprocessor receives 40-bit data according to the change of I/0 level.
The format of bit data "0" is: low level of 50 microseconds and high level of 26-28us.
The format of the bit data "1" is: 50 microseconds low level plus 70us high level.


Two, the code


The main code mainly uses multi-threading. Every time the user sends a data reading request, a thread is created for reading data; it is beneficial to improve the robustness and scalability of the code;

At the same time, a blockFlag flag is introduced to avoid the problem that the sub-thread code runs away and cannot exit;

And during the test, it is found that there are occasional data with obvious temperature errors; considering that the data may be inaccurate due to the environment, sensors, delay errors, etc., the program will regard data exceeding 50°C as Invalid data, retest by yourself, up to 5 times by yourself

GPIO initialization

Because the initial signal sent to DHT11 is to pull down the level first, so maintain a stable high level state before pulling down the level

void GPIO_init(int gpio_pin)
{
    
    
    pinMode(gpio_pin, OUTPUT); // set mode to output
    digitalWrite(gpio_pin, 1); // output a high level
    delay(1000);
}

start signal

Because the trigger of DHT11 is single, that is, the temperature and humidity will be checked every time the initial signal is sent, so the code for sending the initial signal must be multiplexed, so it is also encapsulated into a function here

void DHT11_Start_Sig()
{
    
    
	pinMode(pinNumber,OUTPUT);	//让GPIO为输出模式
	digitalWrite(pinNumber,HIGH);
	digitalWrite(pinNumber,LOW);
	delay(25);	//维持25ms的低电平
	digitalWrite(pinNumber,HIGH);	//转化为高电平,等待DHT11的响应信号
	
	pinMode(pinNumber,INPUT);
	//响应信号为80us电平与80us的准备信号
	
	pullUpDnControl(pinNumber,PUD_UP);	//进行上拉,增加稳定性,非必选
	delayMicroseconds(35);	//维持35微秒
}

read data

void* readSensorData(void *arg)
{
    
    
    uint8 crc; 	
    uint8 i;	
	int attempt = 5;	//调用一次最多尝试测5次
	
	while(attempt)
	{
    
    
		databuf = 0;	//清空数据存储buf
		crc = 0;		//清空校验位数据存储buf
		DHT11_Start_Sig();	
        
	    if(digitalRead(pinNumber)==0) //检测DHT11是否应答,应答则继续下一步
	    {
    
    
	      while(!digitalRead(pinNumber)); //wait to high
          
          //读取4个数据,合计32位
	      for(i=0;i<32;i++)
	      {
    
    
		       while(digitalRead(pinNumber)); //data clock start
		       while(!digitalRead(pinNumber)); //data start
	           delayMicroseconds(HIGH_TIME);	//如果32微秒后,仍然检测到是高电平,则该数据位为1
	           databuf*=2;		//移位到buf的更高位
	           if(digitalRead(pinNumber)==1) //1
	            {
    
    
	                databuf++;
	            }
	      }
          //读取校验位
	      for(i=0;i<8;i++)
	      {
    
    
			  	while(digitalRead(pinNumber)); //data clock start
			    while(!digitalRead(pinNumber)); //data start
		        delayMicroseconds(HIGH_TIME);
		        crc*=2;  
		        if(digitalRead(pinNumber)==1) //1
		        {
    
    
		           crc++;
		        }
	      }
          
		  //用于校验数据的准确性,当温度大于50时,视为无效数据
	  	  if(((databuf>>8)&0xff) > 50)
		  {
    
    
			 attempt--;
			 delay(500);	//不加这段延迟,下一次传感器来不及响应
			 continue;
		  }	
		  else
		  {
    
    
            //打印数据
		  	printf("Congratulations ! Sensor data read ok!\n");
	       	printf("RH:%lu.%lu\n",(databuf>>24)&0xff,(databuf>>16)&0xff); 
	       	printf("TMP:%lu.%lu\n",(databuf>>8)&0xff,databuf&0xff);
			blockFlag = 0;	//用来避免程序有时候跑飞,卡在此函数中,无法跳出
			return (void*)1;
		  }
	   }
	   else		//dht not answer
	   {
    
    
	   		blockFlag = 0;
	   		printf("Sorry! Sensor dosent ans!\n");
	        return (void*)0;
	   }
	}
    
    //如果代码执行到这里,则证明尝试读取了5次数据,都是不准确的数据
	blockFlag = 0;
	printf("get data fail\n");
	return (void*)2;
}

overall code

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "contrlDevices.h"

typedef unsigned char uint8;
typedef unsigned int  uint16;
typedef unsigned long uint32;
 
#define HIGH_TIME 32
 
int pinNumber = 6;  //use gpio1 to read data
uint32 databuf;
int blockFlag;


void GPIO_init(int gpio_pin)
{
    
    
    pinMode(gpio_pin, OUTPUT); // set mode to output
    digitalWrite(gpio_pin, 1); // output a high level
    delay(1000);
    //return;
}


void DHT11_Start_Sig()
{
    
    
	pinMode(pinNumber,OUTPUT);
	digitalWrite(pinNumber,HIGH);
	digitalWrite(pinNumber,LOW);
	delay(25);
	digitalWrite(pinNumber,HIGH);
	
	pinMode(pinNumber,INPUT);
	//响应信号为80us电平与80us的准备信号
	
	pullUpDnControl(pinNumber,PUD_UP);
	delayMicroseconds(35);
}
 
 
void* readSensorData(void *arg)
{
    
    
    uint8 crc; 	
    uint8 i;	
	int attempt = 5;	//调用一次最多尝试测5次
	
	while(attempt)
	{
    
    
		databuf = 0;	//清空数据存储buf
		crc = 0;		//清空校验位数据存储buf
		DHT11_Start_Sig();	
        
	    if(digitalRead(pinNumber)==0) //检测DHT11是否应答,应答则继续下一步
	    {
    
    
	      while(!digitalRead(pinNumber)); //wait to high
          
          //读取4个数据,合计32位
	      for(i=0;i<32;i++)
	      {
    
    
		       while(digitalRead(pinNumber)); //data clock start
		       while(!digitalRead(pinNumber)); //data start
	           delayMicroseconds(HIGH_TIME);	//如果32微秒后,仍然检测到是高电平,则该数据位为1
	           databuf*=2;		//移位到buf的更高位
	           if(digitalRead(pinNumber)==1) //1
	            {
    
    
	                databuf++;
	            }
	      }
          //读取校验位
	      for(i=0;i<8;i++)
	      {
    
    
			  	while(digitalRead(pinNumber)); //data clock start
			    while(!digitalRead(pinNumber)); //data start
		        delayMicroseconds(HIGH_TIME);
		        crc*=2;  
		        if(digitalRead(pinNumber)==1) //1
		        {
    
    
		           crc++;
		        }
	      }
          
		  //用于校验数据的准确性,当温度大于50时,视为无效数据
	  	  if(((databuf>>8)&0xff) > 50)
		  {
    
    
			 attempt--;
			 delay(500);	//不加这段延迟,下一次传感器来不及响应
			 continue;
		  }	
		  else
		  {
    
    
            //打印数据
		  	printf("Congratulations ! Sensor data read ok!\n");
	       	printf("RH:%lu.%lu\n",(databuf>>24)&0xff,(databuf>>16)&0xff); 
	       	printf("TMP:%lu.%lu\n",(databuf>>8)&0xff,databuf&0xff);
			blockFlag = 0;	//用来避免程序有时候跑飞,卡在此函数中,无法跳出
			return (void*)1;
		  }
	   }
	   else		//dht not answer
	   {
    
    
	   		blockFlag = 0;
	   		printf("Sorry! Sensor dosent ans!\n");
	        return (void*)0;
	   }
	}
    
    //如果代码执行到这里,则证明尝试读取了5次数据,都是不准确的数据
	blockFlag = 0;
	printf("get data fail\n");
	return (void*)2;
}
 
int main ()
{
    
    

	pthread_t tid;
	int waitTimes = 10;
	char cmd[5] = {
    
    '\0'};
	
    if (wiringPiSetup() == -1) 
    {
    
    
    	printf("Setup wiringPi failed!");
    	return 1;
  	}
  	printf("Enter OS-------\n");
  
    while(1)
    {
    
    
     	waitTimes = 10;		
        blockFlag = 1;
        delay(1000);
        printf("input y\n");
        scanf("%s",cmd);
        getchar();
        if(strcmp(cmd,"y") == 0)
        {
    
    
            //创建一个线程用于读取传感器数据;
            //严谨来说此处的tid并发时有bug;读者可以自行优化,可以用互斥锁或者tid设为数组等都行
            //就当作留给读者的一个小作业吧
            if (pthread_create(&tid, NULL, readSensorData, NULL) != 0)
            {
    
    
                printf("thread create fail!\n");
                return -1;
            }
            
            //等待数据读取线程10s钟,如果10后blockFlag未置0,则说明读数据时跑飞卡住了
            while(waitTimes && blockFlag)
            {
    
    
                delay(1000);
                waitTimes--;
            }
            //强行结束跑飞的线程
            if(blockFlag == 1)
            {
    
    
                pthread_cancel(tid);
                printf("线程超时退出.....\n");
            }
        }
        else
        {
    
    
            printf("go on\n");
            continue;
        }
    }
    return 0;
}


Results of the

insert image description here


Reference article:
STM32 first-line protocol - DHT11 temperature and humidity sensor sampling implementation

Guess you like

Origin blog.csdn.net/weixin_44517500/article/details/130339028