(十二)零基础开发小安派-Eyes-S1【外设篇】——ADC

[复制链接]
查看4291 | 回复36 | 2023-10-24 19:48:35 | 显示全部楼层 |阅读模式

本帖最后由 Ai-Thinker小泽 于 2023-10-24 19:48 编辑

零基础开发小安派-Eyes-S1【外设篇】——ADC

ADC 指的是模数转换器(Analog-to-Digital Converter),它是一种用于将模拟信号转换为数字信号的电子设备或电路。 模拟信号是连续变化的信号,可以取无限个可能的值,而数字信号则是离散的,只能表示有限个数值。ADC 的作用就是将模拟信号转换为离散的数字信号,以便数字电子系统进行处理、存储和传输。

ADC 的基本工作原理是通过一系列的采样和量化过程来实现模拟到数字的转换:

1.采样(Sampling):ADC 根据一定的时间间隔,从模拟信号中获取一系列离散的采样点。采样率决定了采样点的密度,较高的采样率可以更精确地表示原始模拟信号。

2.量化(Quantization):采样得到的模拟信号样本通常是连续的,量化则将每个采样点映射为一个特定的数字值。量化过程将连续的模拟信号离散化,并分配给每个样本一个数字值。

3.编码(Encoding):编码将量化后的数字值表示为二进制形式,以便于数字系统处理。常见的编码方式包括无符号二进制、补码和格雷码等。

总的来说,生活中会有许多“模拟量”,如一段从低音到高音的音频,在数字信号中,我们不能简单的把低音表示0,高音表示1,这样歌曲中间的音频变化是空的,没有小数点这些概念来显示他们从0到0.5到1的过程。所以需要有个模数转换的过程,称为ADC。比如用12位精度的ADC来表示这段音频,低音就0,高音就是2^12次也就是4096,那么在这段音频中我们就可以通过0-4096的过程来判断音频的高和低,具体到高到有多高,低到有多低,而ADC的精度越高,如16位,就可达到0-65535的范围。

一、了解小安派-Eyes-S1的ADC

芯片内置一个 12bits 的逐次逼近式模拟数字转换器 (ADC),支持 12 路外部模拟输入和若干内部模拟信号选择。ADC可以工作在 4 种模式下,转换结果为 12/14/16bits左对齐模式。ADC 拥有深度为 32 字节的 FIFO,支持多种中断,支持 DMA 操作。ADC 除了用于普通模拟信号测量外,还可以用于测量供电电压,此外 ADC 还可以通过测量内/外部二极管电压用于温度检测。

具有12路外部模拟通道,对应的GPIO如下:

通道 GPIO
Channel_0 GPIO_20
Channel_1 GPIO_19
Channel_2 GPIO_2
Channel_3 GPIO_3
Channel_4 GPIO_14
Channel_5 GPIO_13
Channel_6 GPIO_12
Channel_7 GPIO_10
Channel_8 GPIO_1
Channel_9 GPIO_0
Channel_10 GPIO_27
Channel_11 GPIO_28

此外,还具有2路DAC内部通道,1路VBAT/2通道,1路TSEN通道

adc clock div

对 adc 时钟再一次进行分频。分频后的时钟必须小于等于 500K。ADC CLK = CLK_SOURCE/CLK_DIV/adc_clk_div

#define ADC_CLK_DIV_4  1
#define ADC_CLK_DIV_8  2
#define ADC_CLK_DIV_12 3
#define ADC_CLK_DIV_16 4
#define ADC_CLK_DIV_20 5
#define ADC_CLK_DIV_24 6
#define ADC_CLK_DIV_32 7

adc resolution

adc 位数,可以选择 12B、14B、16B。其中 14B 和 16B 自带过采样处理

#define ADC_RESOLUTION_12B 0
#define ADC_RESOLUTION_14B 2
#define ADC_RESOLUTION_16B 4

adc vref

adc 内置参考电压选择,可以选择 2.0 V 或者 3.2V

#define ADC_VREF_3P2V 0
#define ADC_VREF_2P0V 1

二、结构体与API

struct bflb_adc_config_s

说明:adc 初始化配置结构体。

struct bflb_adc_config_s {
uint8_t clk_div;
uint8_t scan_conv_mode;
uint8_t continuous_conv_mode;
uint8_t differential_mode;
uint8_t resolution;
uint8_t vref;
};
parameter description
clk_div 分频值
scan_conv_mode 是否开启扫描模式
continuous_conv_mode 是否开启连续转换模式
differential_mode 是否开启差分模式
resolution 采样位数
vref 参考电压选择

扫描模式:可按照用户指定通道个数和顺序逐个转换,结果推入ADC的FIFO。

连续转换模式:允许ADC连续不断地执行模数转换,只需要调用一次ADC启动

差分模式:ADC支持单端输入模式和差分模式,选择单端时负极输入通道选择GND

struct bflb_adc_channel_s

说明:配置 adc 通道时使用。

struct bflb_adc_channel_s {
uint8_t pos_chan;
uint8_t neg_chan;
};
parameter description
pos_chan 正向通道
neg_chan 反向通道(单端模式下无用)

struct bflb_adc_result_s

说明:adc 标准转换结果

struct bflb_adc_result_s {
int8_t pos_chan;
int8_t neg_chan;
int32_t value;
int32_t millivolt;
};
parameter description
pos_chan 正向通道
neg_chan 反向通道(单端模式下无用)
value adc 转换结果
millivolt 转换结果转 mv

bflb_adc_init

说明: 初始化 adc。adc 使用之前需要开启 adc ip 时钟、设置 adc 时钟源和分频值、选择使用的 gpio 为 analog 模式。

void bflb_adc_init(struct bflb_device_s *dev, const struct bflb_adc_config_s *config);
parameter description
dev 设备句柄
config 配置项

bflb_adc_deinit

说明: 反初始化 adc。

void bflb_adc_deinit(struct bflb_device_s *dev);
parameter description
dev 设备句柄

bflb_adc_link_rxdma

说明: adc dma 功能开关。

void bflb_adc_link_rxdma(struct bflb_device_s *dev, bool enable);
parameter description
dev 设备句柄
enable 是否开启 dma 功能

bflb_adc_channel_config

说明: 配置 adc 通道。

int bflb_adc_channel_config(struct bflb_device_s *dev, struct bflb_adc_channel_s *chan, uint8_t channels);
parameter description
dev 设备句柄
chan 通道(一对)
channels 通道对数(单次扫描模式下只能为 1)

bflb_adc_start_conversion

说明: 启动 adc 转换。连续转换模式下只需要调用一次。

void bflb_adc_start_conversion(struct bflb_device_s *dev);
parameter description
dev 设备句柄

bflb_adc_stop_conversion

说明: 停止 adc 转换。

void bflb_adc_stop_conversion(struct bflb_device_s *dev);
parameter description
dev 设备句柄

bflb_adc_get_count

说明: 获取 adc 转换个数。

uint8_t bflb_adc_get_count(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 转换个数(最大为32)

bflb_adc_read_raw

说明: 读取一次 adc 转换值。

uint32_t bflb_adc_read_raw(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 转换值(注意不是最终采样值)

bflb_adc_rxint_mask

说明: adc 转换完成中断开关。

void bflb_adc_rxint_mask(struct bflb_device_s *dev, bool mask);
parameter description
dev 设备句柄
mask 是否屏蔽中断

bflb_adc_errint_mask

说明: adc 错误中断开关。

void bflb_adc_errint_mask(struct bflb_device_s *dev, bool mask);
parameter description
dev 设备句柄
mask 是否屏蔽中断

bflb_adc_get_intstatus

说明: adc 中断标志。

uint32_t bflb_adc_get_intstatus(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 中断标志

返回值如下:

ADC_INTSTS_NEG_SATURATION
ADC_INTSTS_NEG_SATURATION
ADC_INTSTS_FIFO_UNDERRUN
ADC_INTSTS_FIFO_OVERRUN
ADC_INTSTS_ADC_READY

bflb_adc_int_clear

说明: 清除 adc 中断标志。

void bflb_adc_int_clear(struct bflb_device_s *dev, uint32_t int_clear);
parameter description
dev 设备句柄
int_clear 清除值

int_clear 可以填入以下参数:

ADC_INTCLR_NEG_SATURATION
ADC_INTCLR_POS_SATURATION
ADC_INTCLR_FIFO_UNDERRUN
ADC_INTCLR_FIFO_OVERRUN
ADC_INTCLR_ADC_READY

bflb_adc_parse_result

说明: 对 adc 转换结果进行解析。

void bflb_adc_parse_result(struct bflb_device_s *dev, uint32_t *buffer, struct bflb_adc_result_s *result, uint16_t count);
parameter description
dev 设备句柄
buffer 转换值
result 输出结果
count 转换个数

bflb_adc_tsen_init

说明: 初始化 adc tsen 模块。

void bflb_adc_tsen_init(struct bflb_device_s *dev, uint8_t tsen_mod);
parameter description
dev 设备句柄
tsen_mod 模式选择

bflb_adc_tsen_get_temp

说明: 获取 adc tsen 模块采集的温度。

float bflb_adc_tsen_get_temp(struct bflb_device_s *dev);
parameter description
dev 设备句柄
return 温度

bflb_adc_vbat_enable

说明: 开启 vbat 。

void bflb_adc_vbat_enable(struct bflb_device_s *dev);
parameter description
dev 设备句柄

bflb_adc_vbat_disable

说明: 关闭 vbat。

void bflb_adc_vbat_disable(struct bflb_device_s *dev);
parameter description
dev 设备句柄

三、示例——连续读取IO的ADC值,ADC转换完成中断

Main

#include "bflb_adc.h"
#include "bflb_mtimer.h"
#include "board.h"
#include "bflb_gpio.h"
//头文件


struct bflb_device_s *adc;
//外设结构体设置


void My_adc_gpio_init()
{
    struct bflb_device_s *gpio;

    gpio = bflb_device_get_by_name("gpio");
    bflb_gpio_init(gpio, GPIO_PIN_0, GPIO_ANALOG | GPIO_SMT_EN | GPIO_DRV_0);
}
//设置需要AD采集的IO脚,对应的通道和IO要匹配

volatile uint32_t raw_data;
//接收AD值变量

void adc_isr(int irq, void *arg)
{
    uint32_t intstatus = bflb_adc_get_intstatus(adc);
    if (intstatus & ADC_INTSTS_ADC_READY) {
        bflb_adc_int_clear(adc, ADC_INTCLR_ADC_READY);
            raw_data= bflb_adc_read_raw(adc);
        }
 }
 //中断函数,清除中断标志位,将读取的AD变量赋给raw_data


int main(void)
{
    board_init();
    My_adc_gpio_init();

    adc = bflb_device_get_by_name("adc");

    /* adc clock = XCLK / 2 / 32 */
    struct bflb_adc_config_s cfg;
    cfg.clk_div = ADC_CLK_DIV_32;
    cfg.scan_conv_mode = false;
    cfg.continuous_conv_mode = false;
    cfg.differential_mode = false;
    cfg.resolution = ADC_RESOLUTION_16B;
    cfg.vref = ADC_VREF_3P2V;

    //adc结构体配置

    struct bflb_adc_channel_s chan;

    chan.pos_chan = ADC_CHANNEL_9;
    chan.neg_chan = ADC_CHANNEL_GND;
    //通道配置,单端模式下neg选择GND,pos注意对应IO口的通道

    bflb_adc_init(adc, &cfg);
    bflb_adc_channel_config(adc, &chan, 1);
    bflb_adc_rxint_mask(adc, false);
    bflb_irq_attach(adc->irq_num, adc_isr, NULL);
    bflb_irq_enable(adc->irq_num);
    //中断使能配置


    while (1) {
        struct bflb_adc_result_s result;
        bflb_adc_start_conversion(adc);
        bflb_adc_parse_result(adc, (uint32_t *)&raw_data, &result, 1);
        printf("\r\npos chan %d\r\nADC Value = %d\r\nCurrent Voltage = %d mv\r\n", result.pos_chan, result.value, result.millivolt);
        bflb_adc_stop_conversion(adc);
        bflb_mtimer_delay_ms(1000);
        //主函数读取AD值并转化为电压
    }
}

效果

image.png

本帖被以下淘专辑推荐:

回复

使用道具 举报

妖猊 | 2023-10-24 20:02:30 | 显示全部楼层
向大佬学习了
回复 支持 反对

使用道具 举报

iiv | 2023-10-24 21:43:58 | 显示全部楼层
泽哥出马了,泽哥666
回复 支持 反对

使用道具 举报

WangChong | 2023-10-24 21:51:17 | 显示全部楼层
xuexi l
回复

使用道具 举报

jkernet | 2023-10-24 22:10:19 | 显示全部楼层
学习打卡
回复

使用道具 举报

bzhou830 | 2023-10-25 08:27:20 | 显示全部楼层
学习打卡
选择去发光,而不是被照亮
回复

使用道具 举报

WangChong | 2023-10-25 08:54:47 | 显示全部楼层
正好学到这里啊. 太棒
回复 支持 反对

使用道具 举报

18350766600@139 | 2023-10-25 09:02:21 | 显示全部楼层
学习打卡
回复

使用道具 举报

90956 | 2023-10-25 09:08:29 | 显示全部楼层
😀
回复

使用道具 举报

爱笑 | 2023-10-25 09:53:37 | 显示全部楼层
泽哥加油!
用心做好保姆工作
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则