zoukankan      html  css  js  c++  java
  • nRF52832的SAADC

    SAADC部分思维导图

    1ADC原理

    1.1主要特点

    1)8/10/12分辨率,使用过采样可达到14位分辨率
    2)多达8个通道
    单端输入时使用1个通道,2个通道可组成差分输入
    单端和差分输入时均可配置为扫描模式
    3)满量程输入范围(0 to VDD)
    参考芯片数据手册

    1.2功能概述

    参考芯片数据手册

    1.3工作模式

    1)单次模式
    2)连续模式
    使用ADC内部定时器实现定时采样
    使用nRF52832的通用定时器定时同PPI触发采样,实现连续采样
    3)扫描模式
    当使能一个ADC通道,ADC工作于单次模式,当使能的通道数量大于1个,ADC进入扫描模式

    2SAADC的应用步骤

    2.1SAADC库文件

    2.2SAADC驱动的应用

    1)阻塞模式
    2)非阻塞模式
    3)门限监测

    3相关寄存器

    4重要的库函数

    5DEMO

    5.1阻塞模式-单端输入采样

    SAADC初始化

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdio.h>
    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "nrf.h"
    #include "bsp.h"
    #include "app_uart.h"
    
    #include "nrf_drv_saadc.h"
    
    #define UART_TX_BUF_SIZE 256      //uart 发送软件缓存大小(字节数)
    #define UART_RX_BUF_SIZE 256      //uart 接收软件缓存大小(字节数) 
    
    //saadc回调函数
    void saadc_callback(nrf_drv_saadc_evt_t const *p_event){}
    //saadc初始化函数
    void saadc_init(void)
    {
    	ret_code_t err_code;
    	//定义SAADC初始化结构体
    	//使用默认的宏初始化时需要指定该通道的模拟输入引脚
    	//具体的引脚分布参考数据手册
    	nrf_saadc_channel_config_t mmysaadc=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    	//初始化SAADC,注册事件回调函数,注意因为使用了阻塞模式
    	//所以可以不用回调函数,但是nrf_drv_saadc_init()要求必须提供回调函数
    	//所以这里要注册回调函数,无论有没有用到
    	err_code=nrf_drv_saadc_init(NULL,saadc_callback);
    	APP_ERROR_CHECK(err_code);
    	//初始化SAADC通道0
    	err_code = nrf_drv_saadc_channel_init(0, &mmysaadc);
        APP_ERROR_CHECK(err_code);
    	
    }
    //uart事件回调函数
    void uart_error_handle(app_uart_evt_t * p_event)
    {
        if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_communication);
        }
        else if (p_event->evt_type == APP_UART_FIFO_ERROR)
        {
            APP_ERROR_HANDLER(p_event->data.error_code);
        }
    }
    //初始化串口
    void usart_init()
    {
    	uint32_t err_code;
        
    	  //定义一个uart配置结构体
        const app_uart_comm_params_t comm_params =
        {
            RX_PIN_NUMBER,  //定义uart接收引脚
            TX_PIN_NUMBER,  //定义uart发送引脚
            RTS_PIN_NUMBER, //定义uart RTS引脚,注意流控关闭后虽然定义了RTS和CTS引脚,但是不起作用
            CTS_PIN_NUMBER, //定义uart CTS引脚 
            APP_UART_FLOW_CONTROL_DISABLED,   //关闭uart流控
            false,
            UART_BAUDRATE_BAUDRATE_Baud115200 //uart波特率
        };
        //初始化app uart,注册uart事件回调函数
        APP_UART_FIFO_INIT(&comm_params,
                             UART_RX_BUF_SIZE,
                             UART_TX_BUF_SIZE,
                             uart_error_handle,
                             APP_IRQ_PRIORITY_LOWEST,
                             err_code);
    
        APP_ERROR_CHECK(err_code);	
    	
    }
    /**********************************************************************************************
     * 描  述 : main函数
     * 入  参 : 无
     * 返回值 : 无
     ***********************************************************************************************/ 
    int main(void)
    {
    	nrf_saadc_value_t saadc_val;
    	float voltage=9.99;;  //转化后的电压值
    	usart_init();  //初始化串口
        saadc_init();  //初始化SAADC
        while(true)	
    	{
    		//启动一次ADC采样
    		nrf_drv_saadc_sample_convert(0,&saadc_val);
    		voltage=(float)saadc_val*3.6/1024;
                    printf("voltage=%f
    ",voltage);
    		nrf_delay_ms(300);  //延时300ms
    		printf("saadc_val=V%d
    ", saadc_val);
    
    	}
    }
    

    SAADC初始化包括两部分:SAADC驱动程序初始化,SAADC通道配置。nrf_drv_saadc.h中定义了两个带输入参数的初始化宏

    #define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) 
    {                                                      
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,         
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,         
        .gain       = NRF_SAADC_GAIN1_6,                   
        .reference  = NRF_SAADC_REFERENCE_INTERNAL,        
        .acq_time   = NRF_SAADC_ACQTIME_10US,              
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,         
        .pin_p      = (nrf_saadc_input_t)(PIN_P),          
        .pin_n      = NRF_SAADC_INPUT_DISABLED             
    }
    

    注意1
    初始化宏配置SAADC通道的参数如下
    ADC输入正极电阻配置:旁路电阻梯
    ADC输入负极电阻配置:旁路电阻梯
    增益:1/6
    参考电压:内部0.6V
    采样时间:10US
    模式:单端输入
    突发模式:禁止
    ADC输入正极连接的模拟输入引脚
    ADC输入负极连接的模拟输入引脚:不连接

    注意2

    err_code=nrf_drv_saadc_init(NULL,saadc_callback);
    

    SAADC初始化函数nrf_drv_saadc_init(),如果没有提供SAADC配置结构体即第一个参数为NULL,这时驱动会使用“sdk_config.h”文件默认参数配置SAADC

    5.2阻塞模式-差分输入采样

    SAADC初始化
    //saadc初始化函数
    void saadc_init(void)
    {
    	ret_code_t err_code;
    	//定义SAADC初始化结构体
    	//使用默认的宏初始化时需要指定该通道的模拟输入引脚
    	//具体的引脚分布参考数据手册
    	nrf_saadc_channel_config_t mmysaadc=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(NRF_SAADC_INPUT_AIN2,NRF_SAADC_INPUT_AIN0);
    	//初始化SAADC,注册事件回调函数,注意因为使用了阻塞模式
    	//所以可以不用回调函数,但是nrf_drv_saadc_init()要求必须提供回调函数
    	//所以这里要注册回调函数,无论有没有用到
    	err_code=nrf_drv_saadc_init(NULL,saadc_callback);
    	APP_ERROR_CHECK(err_code);
    	//初始化SAADC通道0
    	err_code = nrf_drv_saadc_channel_init(0, &mmysaadc);
        APP_ERROR_CHECK(err_code);
    	
    }
    

    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL宏有两个输入参数,对应通道的正极模拟输入引脚和负极模拟输入引脚

    #define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(PIN_P, PIN_N) 
    {                                                                       
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,                          
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,                          
        .gain       = NRF_SAADC_GAIN1_6,                                    
        .reference  = NRF_SAADC_REFERENCE_INTERNAL,                         
        .acq_time   = NRF_SAADC_ACQTIME_10US,                               
        .mode       = NRF_SAADC_MODE_DIFFERENTIAL,                          
        .pin_p      = (nrf_saadc_input_t)(PIN_P),                           
        .pin_n      = (nrf_saadc_input_t)(PIN_N)                            
    }
    

    主函数:

    int main(void)
    {
    	nrf_saadc_value_t saadc_val;
    	float voltage=9.99;;  //转化后的电压值
    	usart_init();  //初始化串口
        saadc_init();  //初始化SAADC
        while(true)	
    	{
    		//启动一次ADC采样
    		nrf_drv_saadc_sample_convert(0,&saadc_val);
    		//这里saadc_val变成了差分值
    		voltage=(float)saadc_val*3.6/1024;
                    printf("voltage=%f
    ",voltage);
    		nrf_delay_ms(300);  //延时300ms
    		printf("saadc_val=V%d
    ", saadc_val);
    
    	}
    }
    

    5.3非阻塞模式-单缓存采样

    //定义SAADC采样数据缓存
    //定义SAADC采样缓存数组大小
    //只有采样结果存满该缓存之后,才会产生SAADC采样完成事件
    #define SAMPLES_IN_BUFFER 1
    
    //定义SAADC采样缓存数组大小
    nrf_saadc_value_t m_buffer_pool[SAMPLES_IN_BUFFER];
    //定义该变量用来保存SAADC采样的次数
    static uint32_t m_adc_evt_counter;
    
    //SAADC初始化函数
    void saadc_init(void)
    {
    	ret_code_t err_code;
    	//定义SAADC初始化结构体
    	//使用默认的宏初始化时需要指定该通道的模拟输入引脚
    	//具体的引脚分布参考数据手册
    	nrf_saadc_channel_config_t mmysaadc=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    	//初始化SAADC,注册事件回调函数,
        //注意,本例使用的是非阻塞模式,非阻塞模式下,采样完成后以事件
    	//的方式通知应用程序,应用程序在事件回调函数中读取采样数据
    	err_code=nrf_drv_saadc_init(NULL,saadc_callback);
    	APP_ERROR_CHECK(err_code);
    	//初始化SAADC通道0
    	err_code = nrf_drv_saadc_channel_init(NULL, &mmysaadc);
        APP_ERROR_CHECK(err_code);
    	
    	//设置好缓存,等待应用程序启动采样
        err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool, SAMPLES_IN_BUFFER);
        APP_ERROR_CHECK(err_code);
    	
    }
    
    

    nrf_drv_saadc_buffer_convert函数将SAADC工作于非阻塞模式,可将SAADC配置为就绪状态,但是不会触发采样

    ret_code_t nrf_drv_saadc_buffer_convert	(	
        nrf_saadc_value_t * 	buffer,
        uint16_t 	size 
    )
    
    Function for issuing conversion of data to the buffer.
    
    Parameters:
    [in]	buffer	Result buffer.
    [in]	size	Buffer size in words.
    
    //saadc回调函数
    void saadc_callback(nrf_drv_saadc_evt_t const *p_event)
    {
    	float val;  //保存SAADC采样数据计算的实际电压值
    	
    	if(p_event->type == NRF_DRV_SAADC_EVT_DONE)  //Event generated when the buffer is filled with samples
    	{
    		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;
    		//串口打印采样次数
    		printf("ADC event number:%d
    ",(int)m_adc_evt_counter);
    		
    		for(i=0;i<SAMPLES_IN_BUFFER;i++)
    		{
    			val=p_event->data.done.p_buffer[i]*3.6/1024;	
          printf("Voltage = %.3fV
    ", val);			
    		}
    		
    		//采样次数加1
    		m_adc_evt_counter++;
    		
    	}
    	
    }
    

    5.4非阻塞模式-双缓存采样

    5.5电池电压采样

    5.6三个通道同时采样-定时器触发

    //定义SAADC采样缓存数组大小
    #define SAMPLES_IN_BUFFER 3
    
    //定义SAADC采样缓存数组
    static nrf_saadc_value_t m_buffer_pool[SAMPLES_IN_BUFFER];
    
    /***********************************************************
    *函数介绍:初始化SAADC
    	        通道0 采集电位器电压   P004
    	        通道1 采集光敏电阻电压 P002
    	        通道2 采样芯片供电电压 不需要外接引脚
    *输入参数:
    *输出参数:
    *返回值:无
    ************************************************************/
    void saadc_init(void)
    {
    	ret_code_t err_code;
    	//定义SAADC采样通道0初始化配置结构体变量,并用默认参数初始化
    	nrf_saadc_channel_config_t channel_0_config=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
    	channel_0_config.gain=NRF_SAADC_GAIN1_6;
    	channel_0_config.reference=NRF_SAADC_REFERENCE_INTERNAL;  //使用内部的0.6V作为参考电压
    	
    	
    	//定义SAADC采样通道1初始化配置结构体,并用默认参数初始化
    		nrf_saadc_channel_config_t channel_1_config=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
    	channel_1_config.gain=NRF_SAADC_GAIN1_6;
    	channel_1_config.reference=NRF_SAADC_REFERENCE_INTERNAL;  //使用内部的0.6V作为参考电压
    
    	//定义SAADC采样通道2初始化配置结构体
    	nrf_saadc_channel_config_t channel_2_config=
    	    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(SAADC_CH_PSELP_PSELP_VDD);
    
    	channel_2_config.gain=NRF_SAADC_GAIN1_6;
    	channel_2_config.reference=NRF_SAADC_REFERENCE_INTERNAL;  //使用内部的0.6V作为参考电压
    
    	//初始化SAADC
    	err_code=nrf_drv_saadc_init(NULL,saadc_callback);
      APP_ERROR_CHECK(err_code);
    	
    	//初始化SAADC的通道0
    	err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
      APP_ERROR_CHECK(err_code);
    
      err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
      APP_ERROR_CHECK(err_code);
    	
    	//使用双缓存
    	//设置好第一个缓存
    	err_code=nrf_drv_saadc_buffer_convert(m_buffer_pool,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);
    }
    

    注意
    三个通道采样,分别配置为通道0,1,2

    //saadc回调函数
    void saadc_callback(nrf_drv_saadc_evt_t const *p_event)
    {
    	  ret_code_t err_code;
        float val;  //保存SAADC采样数据计算的实际电压值
    	  if(p_event->type == NRF_DRV_SAADC_EVT_DONE)
    		{
    		    //设置好缓存,为下一次采样做准备
    			  err_code=nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer,
    			                                        SAMPLES_IN_BUFFER);
    			   APP_ERROR_CHECK(err_code);
    			   //读取采样结果,使用串口发送
    			   for(uint32_t i=0;i<SAMPLES_IN_BUFFER;i++)
    			   {
    			    val=p_event->data.done.p_buffer[i]*3.6/1024;	
    //                printf("Voltage = %.3fV
    ", val);
    					 switch(i)
    					 {
    					    case 0:printf("AIN2=%f
    ",val); break;
    						case 1:printf("AIN0=%f
    ",val); break;
    						case 2:printf("VDD=%f
    ",val); break;
    						default:break;
    					 }
    			   }
    		}
    }
    
    /**********************************************************************************************
     * 描  述 : main函数
     * 入  参 : 无
     * 返回值 : 无
     ***********************************************************************************************/ 
    int main(void)
    {
    	nrf_saadc_value_t saadc_val;
    	usart_init();  //初始化串口
      saadc_init();  //初始化SAADC
      timers_init(); //定时器初始化函数
    	while(true)	
    	{
    
    	}
    }
    
  • 相关阅读:
    JSK42586.Tree(动态开点线段树+树上启发式合并)
    CF1188B.Count Pairsl(数学)
    2021ICPC亚洲区域赛(昆明)复盘
    1009F.Dominant Indices (树上启发式合并)
    246E.Bloods Counsin Return(离线+树上启发式合并)
    208E.Blood Cousins(离线+倍增LCA+树上启发式合并)
    208E.Blood Cousins (离线+树上启发式合并)
    570D.Tree Requests (离线+树上启发式合并)
    Java从入门到实战之(6)SSM框架使用
    Java从入门到实战之(5)Java集合对比汇总
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/9380267.html
Copyright © 2011-2022 走看看