nRF52840驅動DHT11溫度傳感器

nRF52840開發板現在可供參考的例子只有SDK中的實例,而且實例也很少,在SDK中有一個溫度數據採集的實例,但是採集的是芯片溫度;twi也提供了一個通過I2C獲取溫度傳感器數據的例子,但是溫度傳感器是LM75B,我手頭上沒有這個傳感器,而且這兩個例子都是通過while(true)實現一個死循環來不斷地採集溫度,這樣如果需要集成其他功能的話會導致程序無法正常運行下去,所以決定使用app_timer來定時獲取DHT11溫溼度傳感器的數據。

1.定義DHT11.h

#ifndef __DHT11_H__
#define __DHT11_H__
#include <stdint.h>

#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 <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#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:

// <e> APP_TIMER_ENABLED - app_timer - Application timer functionality
//==========================================================
#ifndef APP_TIMER_ENABLED
#define APP_TIMER_ENABLED 1
#endif
// <o> 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

// <o> APP_TIMER_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> 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

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

#ifndef APP_TIMER_CONFIG_OP_QUEUE_SIZE
#define APP_TIMER_CONFIG_OP_QUEUE_SIZE 10
#endif

// <q> 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

// <q> APP_TIMER_KEEPS_RTC_ACTIVE  - Enable RTC always on
 

// <i> If option is enabled RTC is kept running even if there is no active timers.
// <i> 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

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

#ifndef APP_TIMER_SAFE_WINDOW_MS
#define APP_TIMER_SAFE_WINDOW_MS 300000
#endif

// <h> App Timer Legacy configuration - Legacy configuration.

//==========================================================
// <q> APP_TIMER_WITH_PROFILER  - Enable app_timer profiling
 

#ifndef APP_TIMER_WITH_PROFILER
#define APP_TIMER_WITH_PROFILER 0
#endif

// <q> APP_TIMER_CONFIG_SWI_NUMBER  - Configure SWI instance used.
 

#ifndef APP_TIMER_CONFIG_SWI_NUMBER
#define APP_TIMER_CONFIG_SWI_NUMBER 0
#endif

// </h> 
//==========================================================

// </e>

還有clock配置:

// <e> NRF_CLOCK_ENABLED - nrf_drv_clock - CLOCK peripheral driver - legacy layer
//==========================================================
#ifndef NRF_CLOCK_ENABLED
#define NRF_CLOCK_ENABLED 1
#endif
// <o> 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

// <o> CLOCK_CONFIG_IRQ_PRIORITY  - Interrupt priority
 

// <i> 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

// </e>

其實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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章