RP2040(树莓派Pico) ADC

/ 1评 / 8

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

在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);

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

  1. yufu说道:

    温度传感器的,有相关代码可以参考一下吗?

发表回复

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