[bsp层][nrf52832][nrf52840][nrf52810][nrf52820][bsp_adc] ADC/SSADC配置和使用

发布者:qin199099最新更新时间:2022-08-22 来源: csdn关键字:nrf52832  nrf52840  nrf52810  ADC 手机看文章 扫描二维码
随时随地手机看文章

SAADC -逐次逼近模拟-数字转换器

ADC是一种差分逐次逼近寄存器(SAR)模数转换器。

以下是SAADC的主要特点:


8/10/12位分辨率,带过采样的14位分辨率

多达8个输入通道

单端输入一个通道,差分输入两个通道

扫描模式可以配置单端通道和差分通道。

满量程输入范围(0到VDD)

通过软件或PPI通道的任务触发采样,以充分灵活的采样频率源,从低功耗32.768kHz RTC或更准确的1/16MHz定时器

一次性转换模式,采样单通道

扫描模式,按顺序采样一系列通道。 信道之间的采样延迟是tack + tconv,根据用户的tack配置,信道之间的延迟会有所不同。 •支持使用EasyDMA直接将样品传输到RAM

在单个样本和满缓冲区事件上中断

对于差分和单端采样,样本存储为16位2的补值

不需要外部定时器的连续采样

内部电阻串

限制匆忙检查

共享资源

ADC可以与COMP和其他使用AIN0-AIN7之一的外围设备共存,只要这些是分配到不同的引脚。

不建议两个模块选择相同的模拟输入引脚。


综述

ADC支持多达8个外部模拟输入通道,取决于封装变体。 它可以

在软件控制下的一次采样模式下操作,或具有可编程采样速率的连续转换模式下操作。


模拟输入可以配置为8个单端输入,4个差分输入或这些的组合。 每个通道可配置为选择AIN0 ~ AIN7引脚或VDD引脚。 通道可以在单次或连续采样模式下单独采样,或者,使用扫描模式,多个通道可以顺序采样。 信道也可以进行过采样以提高噪声性能。

在这里插入图片描述

图98:简化的ADC框图

在内部,ADC始终是一个差分模数转换器,但默认情况下,它在CH[n]的MODE字段中配置为单端输入。 配置寄存器。 在单端模式下,负输入将在内部短路到接地。


单端模式下的假设是ADC的内部接地与测量电压所参考的外部接地相同。 因此,ADC在单端模式下对PCB上的地反弹非常敏感。 如果这是一个问题,我们建议使用差分测量。


EasyDMA

配置后的结果。 PTR和结果。 MAXCNT,通过触发START任务来启动ADC资源。 ADC使用EasyDMA将结果存储在RAM的Result buffer中。


Result缓冲区位于Result中指定的地址。 PTR登记。 结果。 PTR寄存器是双缓冲的,它可以在START事件生成后立即更新并准备下一个START任务。 Result缓冲区的大小在Result中指定。 当MAXCNT寄存器和ADC填满Result缓冲区时,将生成一个END事件,参见第362页的图101:ADC。 结果以小端字节顺序存储在数据RAM中。 每个样本将被符号扩展到16位,然后存储在结果缓冲区中。


通过触发STOP任务来停止ADC。 STOP任务将终止正在进行的采样。 当ADC停止时,将生成一个STOPPED事件。 如果在触发STOP任务时ADC已经停止,则仍然会生成stopped事件。

图101:ADC

如果 RESULT.PTR没有指向Data RAM区域,一个EasyDMA传输可能会导致HardFault或RAM损坏。 有关不同内存区域的更多信息,请参阅第23页的内存。 当END或STOPPED事件生成时,EasyDMA将完成对RAM的访问。


RESULT.AMOUNT 可以在END事件或STOPPED事件之后读取AMOUNT寄存器,查看自触发START任务以来有多少结果被转移到RAM中的Result缓冲区。 在Scan模式下,Result缓冲区的大小必须足够大,以便有足够的空间容纳来自每个启用通道的至少一个结果。 为了确保这一点,结果。 MAXCNT必须指定为RESULT。 MAXCNT >= “启用的通道数量”。 更多信息请参见第360页的扫描模式关于扫描模式。


/********************************************************************************

* @file    bsp_adc.c

* @author  jianqiang.xue

* @version V1.0.0

* @date    2021-07-06

* @brief   ADC操作 参考:https://blog.csdn.net/polaris_zgx/article/details/80405334

********************************************************************************/


/* Includes ------------------------------------------------------------------*/

#include "RTE_Components.h"

#include CMSIS_device_header


#include "nrf_drv_saadc.h"

#include "sdk_errors.h"


#include "bsp_gpio.h"

#include "bsp_exti.h"

#include "bsp_adc.h"


/* Private Includes ----------------------------------------------------------*/

#include "business_gpio.h"

#include "business_function.h"


/* Private Define ------------------------------------------------------------*/

#define ADC0_CH_NUM                   8


#define ADC0_CH0                      0

#define ADC0_CH1                      1

#define ADC0_CH2                      2

#define ADC0_CH3                      3

#define ADC0_CH4                      4

#define ADC0_CH5                      5

#define ADC0_CH6                      6

#define ADC0_CH7                      7


#define CH_NUM  (BS_ADC0_CH0 + BS_ADC0_CH1 + BS_ADC0_CH2 + BS_ADC0_CH3 + BS_ADC0_CH4 + BS_ADC0_CH5 + BS_ADC0_CH6 + BS_ADC0_CH7)

/* Private Variables ---------------------------------------------------------*/

// ADC初始化状态(0--deinit 1--init)

static bool g_adc_init = false;

// ADC采集数据存储buff

uint16_t bsp_adc0_val[ADC0_CH_NUM] = {0};

uint16_t bsp_adc0_temp_val[CH_NUM] = {0};

// 定义ADC采集完毕回调函数

typedef void(*bsp_adc0_callback)(void);

static bsp_adc0_callback irq_callback;


/* External Variables --------------------------------------------------------*/

/* Private Function Prototypes -----------------------------------------------*/

#if BS_ADC0_EN

/**

 * @brief  将ADC采集的值重新排序到另一个数组

 * @note   NULL

 * @retval None

 */

static void bsp_adc0_val_copy(void)

{

    uint8_t num = 0;

    bool flag = false;


    for (uint8_t i = 0; i < ADC0_CH_NUM; i++)

    {

        if (i == ADC0_CH0 && BS_ADC0_CH0)

        {

            flag = true;

        }

        else if(i == ADC0_CH1 && BS_ADC0_CH1)

        {

            flag = true;

        }

        else if(i == ADC0_CH2 && BS_ADC0_CH2)

        {

            flag = true;

        }

        else if(i == ADC0_CH3 && BS_ADC0_CH3)

        {

            flag = true;

        }

        else if(i == ADC0_CH4 && BS_ADC0_CH4)

        {

            flag = true;

        }

        else if(i == ADC0_CH5 && BS_ADC0_CH5)

        {

            flag = true;

        }

        else if(i == ADC0_CH6 && BS_ADC0_CH6)

        {

            flag = true;

        }

        else if(i == ADC0_CH7 && BS_ADC0_CH7)

        {

            flag = true;

        }

        if (flag)

        {

            flag = false;

            bsp_adc0_val[i] = bsp_adc0_temp_val[num];

            num++;

            if (num == CH_NUM)

            {

                break;

            }

        }

    }

}


/**

 * @brief ADC interrupt handler.

 */

static void saadc_callback(nrf_drv_saadc_evt_t const * p_event)

{

    if (p_event->type == NRF_DRV_SAADC_EVT_DONE)

    {

        bsp_adc0_val_copy();

        nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, CH_NUM);

        if (irq_callback)

        {

            irq_callback();

        }

    }

}


/* Public Function Prototypes ------------------------------------------------*/

/**

 * @brief  ADC0初始化,并使能通道

 * @note   NULL

 * @retval None

 */

void bsp_adc0_init(void)

{

#if CH_NUM > 0

    if (g_adc_init)

    {

        return;

    }

    nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;

    saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;

    uint32_t err_code;


    err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);

    APP_ERROR_CHECK(err_code);

#if BS_ADC0_CH0

    nrf_saadc_channel_config_t channel_0_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);

    err_code = nrfx_saadc_channel_init(ADC0_CH0, &channel_0_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH1

    nrf_saadc_channel_config_t channel_1_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);

    err_code = nrfx_saadc_channel_init(ADC0_CH1, &channel_1_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH2

    nrf_saadc_channel_config_t channel_2_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);

    err_code = nrfx_saadc_channel_init(ADC0_CH2, &channel_2_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH3

    nrf_saadc_channel_config_t channel_3_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);

    err_code = nrfx_saadc_channel_init(ADC0_CH3, &channel_3_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH4

    nrf_saadc_channel_config_t channel_4_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);

    err_code = nrfx_saadc_channel_init(ADC0_CH4, &channel_4_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH5

    nrf_saadc_channel_config_t channel_5_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);

    err_code = nrfx_saadc_channel_init(ADC0_CH5, &channel_5_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH6

    nrf_saadc_channel_config_t channel_6_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);

    err_code = nrfx_saadc_channel_init(ADC0_CH6, &channel_6_config);

    APP_ERROR_CHECK(err_code);

#endif

#if BS_ADC0_CH7

    nrf_saadc_channel_config_t channel_7_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);

    err_code = nrfx_saadc_channel_init(ADC0_CH7, &channel_7_config);

    APP_ERROR_CHECK(err_code);

#endif

    err_code = nrf_drv_saadc_buffer_convert((nrf_saadc_value_t *)(bsp_adc0_temp_val), CH_NUM);

    APP_ERROR_CHECK(err_code);

    g_adc_init = true;

#endif

}


/**

 * @brief  ADC0功能关闭,并移除

 * @note   NULL

 * @retval None

 */

void bsp_adc0_deinit(void)

{

#if CH_NUM > 0

    if (!g_adc_init)

    {

        return;

    }

    nrf_drv_saadc_uninit();

    g_adc_init = false;

#endif

}


/**

 * @brief  ADC0 启动采样功能

 * @note   NULL

 * @retval None

 */

void bsp_adc0_start(void)

[1] [2]
关键字:nrf52832  nrf52840  nrf52810  ADC 引用地址:[bsp层][nrf52832][nrf52840][nrf52810][nrf52820][bsp_adc] ADC/SSADC配置和使用

上一篇:[bsp层][nrf52832][nrf52840][nrf52810][nrf52820][bsp_key] KEY配置和使用
下一篇:[bsp层][nrf52832][nrf52840][nrf52810][nrf52820][bsp_exti] exti/gpioe配置和使用

推荐阅读最新更新时间:2024-11-05 15:20

嵌入式模数转换器的原理及应用
   前言   在数据采集系统中,模数转换器是其中至关重要的环节,模数转换器的精度以及系统的成本直接影响到系统的实用性,因此,如何提高模数转换器的精度和降低系统的成本是衡量系统是否具有实际应用价值的标准。   一般来说,想提高模数转换器的精度,势必会引起成本的增加,这就要求我们按照具体的精度要求合理的设计模数转换器,来达到具体的要求和降低系统的成本。在精度要求不是很高的场合,我们经常利用嵌入微控制器片内的A/D转换器来实现模数转换,以此来降低系统的成本,但由此又产生了另外的问题,嵌入式模数转换器是否具有所要求的精度,若超出测量范围如何与测量电路进行接口,以及如何减小微控制器的电磁干扰提高嵌入式模数转换器的精度问题。这都要求我
[模拟电子]
利用24位Σ-Δ型ADC实现精密电子秤设计
电路功能与优势   本电路为采用AD7192构建的电子秤系统。AD7192是一款超低噪声、低漂移24位Σ-Δ转换器,内置PGA。该器件将大多数系统构建模块置于芯片内,因此能够简化电子秤设计。该器件可在4.7 Hz至4.8 kHz的完整输出数据速率范围内工作,并保持良好的性能,因此可用于以较低速度工作的电子秤系统,以及料斗秤等较高速电子秤系统。 图1:采用AD7192的电子秤系统(原理示意图,未显示所有连接)    电路描述   AD7192提供一种集成式电子秤解决方案,可以直接与称重传感器接口。只需在模拟输入端用一些滤波器,在基准电压引脚上配置一些电容等外部元件,便可满足电磁屏蔽(EMC)要求。来自称重传感器的
[模拟电子]
使用STM8S003K3 ADC简介以及初始化
简介 最近用stm8s003k3开发项目,用到了ADC模块,记录一下笔记也分享一下心得 软件环境:STVD+COSMIC 硬件环境:STM8S003K3 TSSOP20封装 模块:ADC 1.ADC功能以及框图 由STM8S参考手册可以得到几个信息: 1、有ADC1和ADC2两个(实际上得看封装,我这款只有ADC1) 2、有多达16个输入通道(看封装,我这款只有2~6输入) 3、有好几个扩展功能 具体的功能如下所示 *由框图可以看出ADC1和ADC2差别还是有一点的,一些多引脚的芯片中ADC2的带模拟参考正负极,在模拟放大中,可通过减小参考电压来提供更大的分辨率。由于没有用到所以不考虑 *转换结束时可产生中断 *
[单片机]
使用STM8S003K3 <font color='red'>ADC</font>简介以及初始化
ADC0831模数转换程序
/* 程序效果:数码管显示AD转换到的一字节数据,以十进制显示      调节相应的电位器,显示数据作相应的变化 程序开发:http://www.51hei.com 原理:0831是串行AD芯片,调节点位器就是调节了输入0831的模拟电压的大小,然后通过数码管显示 运行环境:51hei单片机学习板 */ #include reg52.h #include intrins.h #define uchar unsigned char #define uint unsigned int uchar code table ={0x3f,0x06,0x5b,//数码管显示的数值 0x4f,0x66,0x6d,0x7d,0x07,0x7f,0
[单片机]
选择用于电机控制应用的模数转换器
设计师必须解决电流电压监控、光编码器反馈和旋转变压器――数字转换等难题         在电机控制应用中,设计师必须解决电流电压监控、光编码器反馈和旋转变压器-数字转换等难题。这些过程对需要精确控制电机转速和机械运动的应用来说非常重要,比如工业流水线机器人和汽车助力驾驶等应用。          这些应用中所用的转换器必须速度快、同步取样、单调运算、无流水线延迟、体积小、功耗低(见图1)。有些应用需要高压隔离和安全操作,有些应用必须连接旋转变压器型位置检测器。 逐次逼近A-D转换器          光编码器可以为伺服控制应用提供低成本、高精度的位置感应,比如,需要向控制器提供轴反馈以便为机械运动精确定位的工业机
[嵌入式]
STM32 ADC基础与多通道采样
12位ADC是一种逐次逼近型模拟数字数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。ADC的输入时钟不得超过14MHZ,它是由PCLK2经分频产生。如果被ADC转换的模拟电压低于低阀值或高于高阀值,AWD模拟看门狗状态位被设置。 ADC通常要与DMA一起使用 这里只是简单的用库配置ADC 不断扫描来实现ADC的应用。 配置DMA: void DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure;//定义DMA初始化结构体 DMA_DeInit(DMA_Channel1);//复位DMA通道1 DMA_InitStructure.DMA_Peri
[单片机]
STM32 <font color='red'>ADC</font>基础与多通道采样
STM32初学笔记5之ADC(下)
在上一篇文章中,笔者已经实现了通过ADC1的一个通道采样外部电压数据,本文主要是通过ADC1的通道16来采样芯片内部温度的变化。注意:这里说的变化,而不是绝对温度,因为STM32内部的温度传感器的准确度并不高,需要人为调整。 本文是在上一篇ADC采样外部电压的基础上进行修改的,还请参照上一篇文章。 =========================================================== ADC_Config.C =========================================================== /** ** 文件名
[单片机]
STM32初学笔记5之<font color='red'>ADC</font>(下)
avr单片机精练的两路ADC代码+仿真图
电路原理图如下: #include iom16v.h #include macros.h #define uchar unsigned char #define uchar unsigned int const uchar SEG_CODE = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF}; uchar display = {0,0,0,10,0,0,0,10}; void delay(uint mS); void main() { uchar i; DDRA = 0xfc;
[单片机]
avr单片机精练的两路<font color='red'>ADC</font>代码+仿真图
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved