nRF52840驱动DHT11温度传感器

nRF52840开发板现在可供参考的例子只有SDK中的实例,而且实例也很少,在SDK中有一个温度数据采集的实例,但是采集的是芯片温度;twi也提供了一个通过I2C获取温度传感器数据的例子,但是温度传感器是LM75B,我手头上没有这个传感器,而且这两个例子都是通过while(true)实现一个死循环来不断地采集温度,这样如果需要集成其他功能的话会导致程序无法正常运行下去,所以决定使用app_timer来定时获取DHT11温湿度传感器的数据。

1.定义DHT11.h

#ifndef __DHT11_H__
#define __DHT11_H__
#include 

#define DATA_PIN        NRF_GPIO_PIN_MAP(1,7)  //设定P1.07为温度传感器out接口  
#define PIN_DATA_OUT   (nrf_gpio_cfg_output(DATA_PIN));   
#define PIN_DATA_IN    (nrf_gpio_cfg_input(DATA_PIN,NRF_GPIO_PIN_PULLUP));    


#define PIN_DATA_SET    (nrf_gpio_pin_set(DATA_PIN));  //DATA_PINê?3???μ???
#define PIN_DATA_CLEAR  (nrf_gpio_pin_clear(DATA_PIN));

#define DHT11_SUCCESS   NRF_SUCCESS  
#define DHT11_DATA_ERR  0xFD            
#define DHT11_NACK      0xFE            

typedef struct
{
	uint8_t  h_int;		 
	uint8_t  h_deci;	 	
	uint8_t  t_int;	 	 
	uint8_t  t_deci;	 	
	uint8_t  check_sum;		                 
}DHT11_Data_t;

uint32_t Read_DHT11(DHT11_Data_t *DHT11_Data);         

#endif 

我用的是Segger Embeded Studio,所以需要将新建的dht11.h的文件放入工程的同一文件夹下,或者在#include的时候写明dht11.h文件的路径。

2.main.c中完成DHT11驱动定义、数据采集的功能

#include 
#include 
#include 
#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_temp.h"
#include "app_error.h"
#include "bsp.h"
#include "dht11.h"

#include "app_timer.h"
#include "nrf_drv_clock.h"
///** @brief Function for main application entry.
// */
//
DHT11_Data_t DHT11_Data;
APP_TIMER_DEF(m_repeated_timer_id);
/**@brief Timeout handler for the repeated timer.
 */

static void lfclk_request(void)
{

    ret_code_t err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);
}

static uint32_t waitfor_state(bool pin_state) 
{
	uint8_t delay_us = 100;
	do
	{
	if(nrf_gpio_pin_read(DATA_PIN)==pin_state)
		{
			return DHT11_SUCCESS;
		}
		nrf_delay_us(1);
		delay_us--;
	}while(delay_us);
	return DHT11_NACK;
}

static uint8_t Read_Byte(void)     
{     
	uint8_t i, temp=0; 
 	for(i=0;i<8;i++)    
	{
		
		if(waitfor_state(1)!=DHT11_SUCCESS)return DHT11_NACK;
                nrf_delay_us(40);
		if(nrf_gpio_pin_read(DATA_PIN)==1)  
		{
                  if(waitfor_state(0)!=DHT11_SUCCESS)return DHT11_NACK; 
		  temp|=(uint8_t)(0x01<<(7-i));  
		}
		else
		{			   
			temp&=(uint8_t)~(0x01<<(7-i)); 
		}
	} 
	return temp;
}
uint32_t Read_DHT11(DHT11_Data_t *DHT11_Data)
{
	PIN_DATA_OUT
	PIN_DATA_CLEAR;
	nrf_delay_ms(19);  
	PIN_DATA_SET; 
	PIN_DATA_IN;
	nrf_delay_us(30);
	if(nrf_gpio_pin_read(DATA_PIN) == 0) 
	{
		if(waitfor_state(1)!=DHT11_SUCCESS)return DHT11_NACK;
		if(waitfor_state(0)!=DHT11_SUCCESS)return DHT11_NACK;
		DHT11_Data->h_int= Read_Byte();
		DHT11_Data->h_deci= Read_Byte();
		DHT11_Data->t_int= Read_Byte();
		DHT11_Data->t_deci= Read_Byte();
		DHT11_Data->check_sum= Read_Byte();

		PIN_DATA_OUT;    
		PIN_DATA_SET;  
		if(DHT11_Data->check_sum == DHT11_Data->h_int + DHT11_Data->h_deci + DHT11_Data->t_int+ DHT11_Data->t_deci)
			return DHT11_SUCCESS;
		else 
			return DHT11_DATA_ERR;
	} 
	else 
	{
		return DHT11_NACK;
	} 
}

static void gpio_output_voltage_setup_3v3(void)
{
    if ((NRF_UICR->REGOUT0 & UICR_REGOUT0_VOUT_Msk) !=
        (UICR_REGOUT0_VOUT_3V3 << UICR_REGOUT0_VOUT_Pos))
    {
        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}

        NRF_UICR->REGOUT0 = (NRF_UICR->REGOUT0 & ~((uint32_t)UICR_REGOUT0_VOUT_Msk)) |
                            (UICR_REGOUT0_VOUT_3V3 << UICR_REGOUT0_VOUT_Pos);

        NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren;
        while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
     
        NVIC_SystemReset();
    }
}


static void repeated_timer_handler(void * p_context)
{   
      uint32_t err_code = Read_DHT11(&DHT11_Data);
      if(err_code==DHT11_SUCCESS)
	{
          nrf_gpio_pin_toggle(LED_2);
//NRF_LOG_INFO("Temperature: %d.%d C Humidity: %d.%d H \r\n",DHT11_Data.t_int,DHT11_Data.t_deci,DHT11_Data.h_int,DHT11_Data.h_deci);
//以上为采集到的温度,可以通过访问DHT11_Data数据结构得到温度及湿度数据,但是因为LOG没办法正常工作所以注释了这段

        }
      else if(err_code==DHT11_DATA_ERR)
	{
         //Do nothing 
	}	
      else if(err_code==DHT11_NACK)
	{
         //Do nothing
	}
      else
	{
         //Do nothing
	}
}


/**@brief Create timers.
 */
static void create_timers()
{
    // Create timers
    ret_code_t err_code = app_timer_create(&m_repeated_timer_id,
                                APP_TIMER_MODE_REPEATED,
                                repeated_timer_handler);
    APP_ERROR_CHECK(err_code);
}
int main(void)
{  
    log_init();
    app_timer_init();
    lfclk_request();
    bsp_board_init(BSP_INIT_LEDS);
    create_timers();
    ret_code_t err_code = app_timer_start(m_repeated_timer_id, APP_TIMER_TICKS(1000), NULL);
    APP_ERROR_CHECK(err_code);
}

3.配置sdk_config.h

首先配置app_timer:

//  APP_TIMER_ENABLED - app_timer - Application timer functionality
//==========================================================
#ifndef APP_TIMER_ENABLED
#define APP_TIMER_ENABLED 1
#endif
//  APP_TIMER_CONFIG_RTC_FREQUENCY  - Configure RTC prescaler.
 
// <0=> 32768 Hz 
// <1=> 16384 Hz 
// <3=> 8192 Hz 
// <7=> 4096 Hz 
// <15=> 2048 Hz 
// <31=> 1024 Hz 

#ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
#define APP_TIMER_CONFIG_RTC_FREQUENCY 0
#endif

//  APP_TIMER_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

//  Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef APP_TIMER_CONFIG_IRQ_PRIORITY
#define APP_TIMER_CONFIG_IRQ_PRIORITY 6
#endif

//  APP_TIMER_CONFIG_OP_QUEUE_SIZE - Capacity of timer requests queue. 
//  Size of the queue depends on how many timers are used
//  in the system, how often timers are started and overall
//  system latency. If queue size is too small app_timer calls
//  will fail.

#ifndef APP_TIMER_CONFIG_OP_QUEUE_SIZE
#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10
#endif

//  APP_TIMER_CONFIG_USE_SCHEDULER  - Enable scheduling app_timer events to app_scheduler
 

#ifndef APP_TIMER_CONFIG_USE_SCHEDULER
#define APP_TIMER_CONFIG_USE_SCHEDULER 0
#endif

//  APP_TIMER_KEEPS_RTC_ACTIVE  - Enable RTC always on
 

//  If option is enabled RTC is kept running even if there is no active timers.
//  This option can be used when app_timer is used for timestamping.

#ifndef APP_TIMER_KEEPS_RTC_ACTIVE
#define APP_TIMER_KEEPS_RTC_ACTIVE 0
#endif

//  APP_TIMER_SAFE_WINDOW_MS - Maximum possible latency (in milliseconds) of handling app_timer event. 
//  Maximum possible timeout that can be set is reduced by safe window.
//  Example: RTC frequency 16384 Hz, maximum possible timeout 1024 seconds - APP_TIMER_SAFE_WINDOW_MS.
//  Since RTC is not stopped when processor is halted in debugging session, this value
//  must cover it if debugging is needed. It is possible to halt processor for APP_TIMER_SAFE_WINDOW_MS
//  without corrupting app_timer behavior.

#ifndef APP_TIMER_SAFE_WINDOW_MS
#define APP_TIMER_SAFE_WINDOW_MS 300000
#endif

//  App Timer Legacy configuration - Legacy configuration.

//==========================================================
//  APP_TIMER_WITH_PROFILER  - Enable app_timer profiling
 

#ifndef APP_TIMER_WITH_PROFILER
#define APP_TIMER_WITH_PROFILER 0
#endif

//  APP_TIMER_CONFIG_SWI_NUMBER  - Configure SWI instance used.
 

#ifndef APP_TIMER_CONFIG_SWI_NUMBER
#define APP_TIMER_CONFIG_SWI_NUMBER 0
#endif

//  
//==========================================================

// 

还有clock配置:

//  NRF_CLOCK_ENABLED - nrf_drv_clock - CLOCK peripheral driver - legacy layer
//==========================================================
#ifndef NRF_CLOCK_ENABLED
#define NRF_CLOCK_ENABLED 1
#endif
//  CLOCK_CONFIG_LF_SRC  - LF Clock Source
 
// <0=> RC 
// <1=> XTAL 
// <2=> Synth 
// <131073=> External Low Swing 
// <196609=> External Full Swing 

#ifndef CLOCK_CONFIG_LF_SRC
#define CLOCK_CONFIG_LF_SRC 1
#endif

//  CLOCK_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

//  Priorities 0,2 (nRF51) and 0,1,4,5 (nRF52) are reserved for SoftDevice
// <0=> 0 (highest) 
// <1=> 1 
// <2=> 2 
// <3=> 3 
// <4=> 4 
// <5=> 5 
// <6=> 6 
// <7=> 7 

#ifndef CLOCK_CONFIG_IRQ_PRIORITY
#define CLOCK_CONFIG_IRQ_PRIORITY 6
#endif

// 

其实nordic提供了NRF_LOG调试器供用户使用,可以直接通过putty连接COM端口去看打印出来的DHT11采集到的温度及湿度,但是我在调试过程中发现LOG和我定义的TIMER冲突,为了程序正常运行我取消了所有的LOG,所以采集到的温湿度不能打印出来,但是我标志成功采集到温度的响应为LED2闪烁一次,所以大家可以看到每采集成功一次LED2就会闪烁一次。温湿度输保存在DHT11_Data数据结构中,大家可以访问DHT11_Data数据结构获得温度及湿度数据:

温度DHT11_Data.t_int,DHT11_Data.t_deci

湿度DHT11_Data.h_int,DHT11_Data.h_deci

因为我后续的工作不需要打印出数据,只需要判断数据大小是否超过阈值所以就不准备继续探究为什么TIMER和LOG冲突。如果有人知道为什么可以评论一下,方便大家交流,博文写的不多,如果哪里有问题还请指正。另外附加app_timer官方使用教程,方便大家学习如何写app_timer:https://devzone.nordicsemi.com/tutorials/b/software-development-kit/posts/application-timer-tutorial

你可能感兴趣的:(硬件)