8

RP2040(树莓派Pico) ADC

 3 years ago
source link: https://www.taterli.com/7512/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

RP2040(树莓派Pico) ADC

  • TaterLi
  • 2021年1月29日2021年1月29日

Pico模块有3个ADC通道,固定在4个引脚上,总共5个通道,其中一个内部通道即温度传感器,还有专用的ADC_VREF引脚,主要特性如下:

  • SAR ADC (现在的单片机上除了仪表系的,基本都是SAR ADC了!)
  • 500 kSPS (独立48MHz时钟,因此是固定的,对比来看,STM32G0入门级芯片是2.5 MSPS,差距5倍.)
  • 12Bit (9.5 ENOB) (对比STM32G0入门级芯片是10.2 ENOB)
  • 5个输入源 (GPIO26,GPIO27,GPIO28,GPIO29,内部温度传感器) (和传统单片机数量差远了.)
  • 4个坑位采样FIFO (应该是标配的吧,容量不大不小.)
  • 中断/DMA支持 (标配,不用说.)
  • 采样一次停止/连续采样不停止 (标配,不用说.)
  • 自由模式下定时器控制采样速率 (不是采样率,是采样速率,即延迟多久之后还是按照500 kSPS采样,不能从降低采样率来获得更高的精度,不过可以避免多通道扫描的干扰,控制寄存器DIV如果设置到47999,则看起来才1 kSPS,但是要知道大多数芯片One-Shot模式也支持采样率可控.)
  • 自由模式下多通道循环采样 (标配,不用说,实际上大多数芯片还会配备可编程顺序.)
  • 自动缩减至8位 (竟然是用12位右移来做的,浪费采样时间啊,正常芯片都是采样8B自己停下来.)
  • 内置温度传感器固定公式 (居然没有出厂校正,什么玩意.)
  • 没有内置VREF,因此不能反推AVCC电压. (如果可以反推可以减少误差.)

在Pico板子上,GPIO29即ADC/4通道是用来测量VSYS/3电压的.

现在修改hello_adc来测量VSYS电压.

/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"

int main() {
    stdio_init_all();
    printf("ADC Example, measuring GPIO29\n");

    adc_init();

    // Make sure GPIO is high-impedance, no pullups etc
    adc_gpio_init(29);
    // Select ADC input 3 (GPIO29)
    adc_select_input(3);

    while (1) {
        // 12-bit conversion, assume max value == ADC_VREF == 3.3 V
        const float conversion_factor = 3.3f / (1 << 12);
        uint16_t result = adc_read();
        printf("Raw value: 0x%03x, voltage: %f V\n", result, 3 * result * conversion_factor);
        sleep_ms(500);
    }
}

得到测量结果.

如果需要采样多个通道,需要不断调用adc_select_input切换通道,说明,他们是共享一个ADC外设的.具体可以看joystick_display例子.

如果我们要测量温度传感器,需要先使能温度传感器.

/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/gpio.h"
#include "hardware/adc.h"

int main() {
    stdio_init_all();
    printf("ADC Example, measuring GPIO29\n");

    adc_init();

    adc_set_temp_sensor_enabled(true);
    adc_select_input(4);

    while (1) {
        // 12-bit conversion, assume max value == ADC_VREF == 3.3 V
        const float conversion_factor = 3.3f / (1 << 12);
        uint16_t result = adc_read();
        printf("Raw value: 0x%03x, voltage: %f V,temp: %f degC\n", result, result * conversion_factor,27 - (result * conversion_factor - 0.706)/0.001721);
        sleep_ms(500);
    }
}

但是现在温度计实测23度,芯片内部传感器比环境还冷?

最后看看连续采样,即Free Run,这里的Free Run只能按特定顺序(一个或多个通道)扫描,并不能编程顺序.通过adc_set_round_robin的5个bit(BIT0 – BIT5)来配置扫描,数据存入FIFO后然后人为取出,为什么要存入FIFO是因为数据进来后立马有新的采样,如果用传统read,可能会导致数据消失.

adc_fifo_setup(true, false, 0, false, false);
adc_set_round_robin(0x0F);
adc_run(true);
for (int i = 0; i < count; i = i + 1)
    buf[i] = adc_fifo_get_blocking();
adc_run(false);
adc_fifo_drain();

首先用adc_fifo_setup初始化,然后有函数adc_fifo_get_blocking,当然也有adc_fifo_get,前者会查询标志位,等数据,堵塞CPU,后者直接读取,需要用户自己判断数据是不是来了,可以通过adc_fifo_get_level查询现在数据有多满,也可以用adc_fifo_is_empty查询数据是不是完全没有,最后用adc_fifo_drain清理FIFO队列,可能会丢掉最后几个数据,不过那都是不要紧的数据.

adc_fifo_setup基本是配置整个寄存器功能的,具体描述如下:


/*! \brief Setup the ADC FIFO
 *  \ingroup hardware_adc
 *
 * FIFO 最多可以存4个样本,存满的话新数据就没法进来.
 *
 * \param en FIFO使能,启用后结果可以存入FIFO.
 * \param dreq_en 当FIFO包含数据且到达dreq_thresh阈值,请求DMA.
 * \param dreq_thresh 参考dreq_en.
 * \param err_in_fifo FIFO的BIT15(最高位)包含样本错误标志.
 * \param byte_shift 把12位样本缩减成8位,但是实际采样速度没变.
 */
static inline void adc_fifo_setup(bool en, bool dreq_en, uint16_t dreq_thresh, bool err_in_fifo, bool byte_shift);

这种采样方式我想到的就是采样很多遍,然后进行平均或者其他什么信号处理…

发表评论 取消回复

邮箱地址不会被公开。 必填项已用*标注

评论

姓名 *

电子邮件 *

站点


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK