Nrf52832 SAADC

一. 测试平台

       环境:win10,64位,MDK集成开发环境.
       SDK:nRF5_SDK_15.2
       协议栈:s132_nrf52_6.1_softdevice.hex.
       硬件平台:pca10040开发板

       参考例程:nRF5_SDK_15.2.0_9412b96\examples\peripheral\saadc

       ADC的最快采样时间为5us采样一个点,如果为两通道扫描采样的话,最快为10us采样一次

二. Application移植

       1. 添加相关头文件

#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"

       2. SAADC的工作模式

      (1). 单次采样模式

                SAADC初始化

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
//   
}

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);
    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);

}

         启动一次ADC采样,获取ADC值

nrf_drv_saadc_sample_convert(0,&saadc_val);

      (2).单缓冲中断模式

                SAADC初始化,相关中断函数

#define SAMPLES_IN_BUFFER 6
static nrf_saadc_value_t       m_buffer_pool[SAMPLES_IN_BUFFER];

void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{   float  val; 
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;
	//设置好缓存,为下次转换预备缓冲
        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        int i;
        for (i = 0; i < p_event->data.done.size; i++)
        {
	    val = p_event->data.done.p_buffer[i] * 3.6 /1024;	
	    printf("Voltage = %.3fV\r\n", val);
        }
    }
}

void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_0_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
	
    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
    APP_ERROR_CHECK(err_code);
	
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool,SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);
}

         启动一次ADC采样,要采样次数等于SAMPLES_IN_BUFFER时,才会进入中断

nrf_drv_saadc_sample();

     (3).双缓冲PPI采样

              用PPI的方式去触发SAADC,工作方式如下所示:

             Nrf52832 SAADC_第1张图片

        所以相对之前的初始化会复杂一点,需要初始化定时器,设置采样时间(这个采样时间是采样一个点的时间,如果采样时间设置为400ms,采集5个点,则全部的采样时间为400*5=2s。如果为两个通道,则400ms取两个点,取五次),设置PPI通道,初始化SAADC

#define SAMPLES_IN_BUFFER 5

static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t     m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t     m_ppi_channel;

void timer_handler(nrf_timer_event_t event_type, void * p_context)
{

}


void saadc_sampling_event_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_ppi_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
    APP_ERROR_CHECK(err_code);

    /* setup m_timer for compare event every 400ms */
    uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
    nrf_drv_timer_extended_compare(&m_timer,
                                   NRF_TIMER_CC_CHANNEL0,
                                   ticks,
                                   NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                   false);
    nrf_drv_timer_enable(&m_timer);

    uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
                                                                                NRF_TIMER_CC_CHANNEL0);
    uint32_t saadc_sample_task_addr   = nrf_drv_saadc_sample_task_get();

    /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
    err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
                                          timer_compare_event_addr,
                                          saadc_sample_task_addr);
    APP_ERROR_CHECK(err_code);
}


void saadc_sampling_event_enable(void)
{
    ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);

    APP_ERROR_CHECK(err_code);
}


void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
    {
        ret_code_t err_code;

        err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);

        int i;

        for (i = 0; i < SAMPLES_IN_BUFFER; i++)
        {
            NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
        }
    }
}


void saadc_init(void)
{
    ret_code_t err_code;
    nrf_saadc_channel_config_t channel_config =
        NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);

    err_code = nrf_drv_saadc_init(NULL, saadc_callback);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_channel_init(0, &channel_config);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);

}

     启动ADC,值需要初始化ADC即可,数据会不停的缓冲在easydma中,每次数据需要及时读取,不然会被覆盖掉。

saadc_init();
saadc_sampling_event_init();
saadc_sampling_event_enable();

       防止数据覆盖的方式:

      ①采样完之后,在ADC中断函数中关掉定时器,等数据处理完再开启定时器,可以用下面两条语句

nrf_drv_timer_disable(&m_timer);
nrf_drv_timer_enable(&m_timer);

      ② 同时将ADC,PPI,TIMER都关掉,可以有效降低功耗

           启动ADC

void ADC_PWM_START(void)
{
	nrf_saadc_enable();
	nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
	nrf_drv_timer_enable(&m_timer);
}

            关闭ADC,需要将相关标志位清楚,不然会导致错误

void ADC_PWM_STOP(void)
{
	nrf_drv_timer_disable(&m_timer);
	nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
	nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
	nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
	nrf_saadc_disable();
}

(4)采样数据的存放方式

         在模式2和3中,如果是多通道的话,数据将会交替存放,如下所示:

                假设采集数据为3,通道为2

                    Nrf52832 SAADC_第2张图片

你可能感兴趣的:(Nordic)