《ESP32S3 Arduino开发指南 V1.0 》第十九章 ADC实验

第十九章 ADC实验


       本章,我们将学习ESP32-S3的ADC外设,教会大家如何利用ADC去测量可调变阻器的电压值。

       本章分为如下几个小节:

       19.1 ADC介绍

       19.2 硬件设计

       19.3 软件设计

       19.4 下载验证


        19.1 ADC介绍


       19.1.1 ADC简介

       生活中接触到的大多数信息是醉着时间连续变化的物理量,如声音、温度、压力等。表达这些信息的电信号,称为模拟信号(Analog Signal)。为了方便存储、处理,在计算机系统中,都是数字0和1信号,将模拟信号(连续信号)转换为数字信号(离散信号)的器件就叫模数转换器(Analog-to-Digital Convert,ADC)。

       ADC转换器可分为:并行比较型A/D转换器(FLASH ADC)、逐次比较型A/D转换器(SAR ADC)和双积分式A/D转换器(Double Integral ADC)。

       A/D转换过程通常为4步:采样、保持、量化和编码,如下图所示。


图19.1.1.1 A/D转换过程图


       采样:把时间连续变化的信号变换为时间离散的信号。

       保持:保持采样信号,使有充分时间转换为数字信号。

       量化:把采样保持电路的输出信号用单位量化电压的整数倍表示。

       编码:把量化的结果用二进制代码表示。

       采样和保持通常是在采样-保持电路中完成,量化和编码通常在ADC数字编码电路中完成。


       19.1.2 ESP32-S3 ADC介绍

       ESP32-S3集成了两个12位SAR ADC,ADC1和ADC2,支持20个模拟通道输入。这20个模拟通道输入对应着具体的IO,并不是随意的IO都有模拟输入功能,具备模拟输入功能的引脚如下表所示。


表19.1.2.1 具备模拟输入功能的引脚


       ESP32-S3的ADC模块的分辨率为12位,所以AD转换后的值范围为0~4095。由于ESP32-S3的工作电压为3.3V,所以当AD值为4095时,对应的电压为3.3V;当AD值为0时,对应的电压为0V。对于AD值和电压值,这里就会有一个简单的关系,如下所示。



       19.1.3 ADC函数介绍

       本小节介绍到的函数可在以下文件中找到:

       Arduino15\packages\esp32\hardware\esp32\2.0.11\cores\esp32\esp32-hal-adc.c

       接下来,我们介绍一下本章节唯一用到的analogRead函数。

       analogRead函数,该函数功能是从指定引脚读取模拟信号,获取返回值。

uint16_t analogRead(uin8_t pin);

       参数pin为模拟输入引脚,可以查看一下表19.1.2.1确认该引脚是否有模拟输入功能;

       返回值:ADC精度是12bit,默认范围为0~4095之间。 


        19.2 硬件设计


       1. 例程功能

       使用ADC采集通道7(IO8)上面的电压,在LCD上面显示ADC转换值以及换算成电压后的电压值。使用短路帽将P3端子中的AIN和RV1排针连接,使得IO8连接到电位器上,然后将ADC采集到的数据和转换后的电压值在LCD屏中显示。用户可以通过调节电位器的旋钮改变电压值。


       2. 硬件资源


       1)USART0

              U0TXD-IO43

              U0RXD-IO44


       2)XL9555

              IIC_SDA-IO41

              IIC_SCL-IO42


       3)SPILCD

              CS-IO21

              SCK-IO12

              SDA-IO11

              DC-IO40(在P5端口,使用跳线帽将IO_SET和LCD_DC相连)

              PWR-IO1_3(XL9555)

              RST-IO1_2(XL9555)


       4)ADC

              RV-AIN(IO8)(在P3端口,使用跳线帽将RV和AIN相连)


       3. 原理图

       ADC相关原理图,如下图所示。


图19.2.1 ADC原理图


       本实验,我们通过ADC1的通道7(IO8)来采集外部电压值,开发板有一个电位器,可调节的电压范围是:0~3.3V。我们可以通过跳线帽将IO8与电位器连接,如下图所示:


图19.2.2 IO8(对应AIN排针)与电位器示意图


       使用跳线帽将AIN和RV排针连接好后,并下载程序后,就可以用螺丝刀调节电位器变换多种电压值进行测量。

       有的朋友可能还想测量其它地方的电压值,我们只需要1根杜邦线,一端接到AIN排针上,另外一端就接你要测试的电压点。一定要保证测试点的电压在0~3.3V的电压范围,否则可能烧坏我们的ADC,甚至是整个主控芯片。


        19.3 软件设计


       19.3.1 程序流程图

       下面看看本实验的程序流程图:


图19.3.1 程序流程图


       19.3.2 程序解析


       1. ADC驱动代码

       这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。ADC驱动源码包括两个文件:adc.cpp和adc.h。

       下面我们先解析adc.h的程序。对模拟输入引脚做了相关定义。

/* 引脚定义 */
#define ADC_IN_PIN      8

       我们选择使用IO8作为读取模拟信号引脚,使用到的是ADC1通道7。

       下面,我们继续获取ADC值的函数adc_get,代码如下:

/**
* @brief   获取ADC值函数
* @param    adc_pin:adc引脚
* @retval   获取到的ADC值
*/
uint16_t adc_get(uint8_t adc_pin) 
{
    return analogRead(adc_pin);   /* 返回ADC值 */
}

       在程序中,我们并不需要对ADC进行配置,就可以直接调用analogRead函数进行读取了。由于ADC的分辨率是12位,所以最终读取的值的范围在0 ~ 4095之间。


       2. 13_adc.ino代码

       在13_adc.ino里面编写如下代码:

#include "uart.h"
#include "xl9555.h"
#include "spilcd.h"
#include "adc.h"
 
uint16_t adc_value = 0;
float adc_vol = 0;
 
/**
 * @brief   当程序开始执行时,将调用setup()函数,通常用来初始化变量、函数等
 * @param   无
 * @retval  无
 */
void setup() 
{
    uart_init(0, 115200); /* 串口0初始化 */
    xl9555_init();           /* IO扩展芯片初始化 */
    lcd_init();              /* LCD初始化 */
 
    lcd_show_string(30, 50, 200, 16, LCD_FONT_16, "ESP32-S3", RED);
    lcd_show_string(30, 70, 200, 16, LCD_FONT_16, "ADC TEST", RED);
    lcd_show_string(30, 90, 200, 16, LCD_FONT_16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, LCD_FONT_16, "ADC_VAL:", BLUE);
lcd_show_string(30, 130, 200, 16, LCD_FONT_16, "ADC_VOL:0.000V", BLUE);   
}
 
/**
 * @brief   循环函数,通常放程序的主体或者需要不断刷新的语句
 * @param  无
 * @retval  无
 */
void loop() 
{
    adc_value = adc_get(ADC_IN_PIN);          /* 读取GPIO8引脚的ADC值 */
lcd_show_xnum(94, 110, adc_value, 5, LCD_FONT_16, NUM_SHOW_NOZERO, BLUE); 
/* 显示ADC采样后的原始值 */
 
    adc_vol = (float)adc_value * 3.3 / 4095;  /* 换算得到电压值 */
adc_value = adc_vol;  /* 赋值整数部分给adc_value变量,因为adc_value为u16整形 */
   lcd_show_xnum(94,130,(uint16_t)adc_value,1,LCD_FONT_16,NUM_SHOW_NOZERO,BLUE);
    /* 显示电压值的整数部分,3.1111的话,这里就是显示3 */
 
    adc_vol -= adc_value; /* 把已显示整数部分去掉,留下小数部分,如3.1111-3=0.1111 */
    adc_vol *= 1000;   /* 小数部分乘1000,0.1111转换为111.1,相当于保留三位小数 */
    lcd_fill(110, 130, 110 + 24, 130 + 16, WHITE);
lcd_show_xnum(110, 130, adc_vol, 3, LCD_FONT_16, NUM_SHOW_ZERO, BLUE);
/* 显示小数部分(前面转换为了整形显示),这里显示的就是111 */
    delay(500);
}

       在setup函数中,调用uart_init函数完成串口初始化,调用xl9555_init函数完成XL9555初始化,然后调用lcd_init函数完成LCD屏初始化,后面就是LCD显示实验信息。

       在loop函数中,调用adc_get函数获取IO8的AD值,然后换算出电压值,通过LCD进行显示。


        19.4 下载验证

       下载代码后,可以看到LCD显示如下图所示。


请使用浏览器的分享功能分享到微信等