跳转至

1 adc-模数转换

作者:王城钧 | 最后修改:2026-10-30

一、概述

ADC,模拟到数字转换器(Analog-to-Digital Converter),它是一种电子设备或模块,用于将连续变化的模拟信号转换为离散的数字信号,以便数字系统能够对其进行处理和分析。

关于 ADC 的常见指标有两个:

一个是电压输入范围,一个是分辨率;

对某一个确定的模组型号来说,其 ADC 分辨率指标是固定的(目前主流模组都是 12bit),但电压输入范围可能在不同条件上会有所调整,比如 Air780Exx 系列、Air8000 系列等;

特别注意!

合宙主流模组软件上对ADC都可以配置ADC_RANGE_MAX和ADC_RANGE_MIN两种量程
Air8000:adc.ADC_RANGE_MIN对应量程为0-1.5V,
adc.ADC_RANGE_MAX量程对应0-3.3V

Air780EPM/Air780EHM/Air780EHV/Air780EGH:adc.ADC_RANGE_MIN对应量程为0-1.5V,
adc.ADC_RANGE_MAX量程对应0-3.3V

Air8101/Air1601/Air1602不需要设置量程

1.当被测电压最大值在1.5V以内,使用adc.ADC_RANGE_MIN;
2.当被测电压大于1.5V小于3.3V,使用adc.ADC_RANGE_MAX,且不添加外部分压电路;
3.当被测量电压最高值在3.3v以上时, 使用ADC_RANGE_MIN,且必须添加外部分压电路;

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、更加完整和详细的 demo,请参考 LuatOS 仓库 中各个产品目录下的 demo/adc

local function adc_all_task()
    while true do
        sys.wait(1000)--延时1S           
        adc.setRange(adc.ADC_RANGE_MIN)--设置ADC引脚的测量范围0-1.5V,这种方式被测电压可以经过外部电阻分压后再挂在ADC上;
        adc.open(0)--打开ADC通道0
        local data0 = adc.get(0)--获取adc计算值,将获取到的值赋给data0
        adc.close(0)--关闭ADC通道0
        log.info("adc通道0", data0)--打印adc计算值

        adc.open(1)--打开ADC通道1
        local data1 = adc.get(1)--获取adc计算值,将获取到的值赋给data1
        adc.close(1)--关闭ADC通道1
        log.info("adc通道1", data1)--打印adc计算值

        adc.open(2)--打开ADC通道2
        local data2 = adc.get(2)--获取adc计算值,将获取到的值赋给data2
        adc.close(2)--关闭ADC通道2
        log.info("adc通道2", data2)--打印adc计算值

        adc.open(3)--打开ADC通道3
        local data3 = adc.get(3)--获取adc计算值,将获取到的值赋给data3
        adc.close(3)--关闭ADC通道3
        log.info("adc通道3", data3)--打印adc计算值

        adc.open(adc.CH_CPU)--打开adc.CH_CPU通道
        local data5 = adc.get(adc.CH_CPU)--获取adc.CH_CPU计算值,将获取到的值赋给data5
        adc.close(adc.CH_CPU)--关闭adc.CH_CPU通道
        log.info("CPU TEMP", data5)--打印adc.CH_CPU计算值

        adc.open(adc.CH_VBAT)--打开adc.CH_VBAT通道
        local data6 = adc.get(adc.CH_VBAT)--获取adc.CH_VBAT计算值,将获取到的值赋给data6
        adc.close(adc.CH_VBAT)--关闭adc.CH_VBAT通道
        log.info("VBAT", data6)--打印adc.CH_VBAT计算值
    end  
end

sys.taskInit(adc_all_task)

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;

如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;

合宙模组的 adc 量程一些说明:

合宙主流模组软件上对ADC都可以配置ADC_RANGE_MAX和ADC_RANGE_MIN两种量程
Air8000:adc.ADC_RANGE_MIN对应量程为0-1.5V,
adc.ADC_RANGE_MAX量程对应0-3.3V

Air780EPM/Air780EHM/Air780EHV/Air780EGH:adc.ADC_RANGE_MIN对应量程为0-1.5V,
adc.ADC_RANGE_MAX量程对应0-3.3V

Air8101硬件不支持内部分压

1.当被测电压最大值在1.5V以内,使用adc.ADC_RANGE_MIN;
2.当被测电压大于1.5V小于3.3V,使用adc.ADC_RANGE_MAX,且不添加外部分压电路;
3.当被测量电压最高值在3.3v以上时, 使用ADC_RANGE_MIN,且必须添加外部分压电路;

合宙模组的 adc id 的一些说明:

Air8000:ADC0对应通道ID:0,ADC1对应通道ID:1,ADC2对应通道ID:2,ADC3对应通道ID:3

Air780EPM/Air780EHM/Air780EHV/Air780EGH:ADC0对应通道ID:0,ADC1对应通道ID:1,
ADC2对应通道ID:2,ADC3对应通道ID:3

Air8101:Air8101 内部具有 10 个 ADC 接口通道,
以ADC1对应通道ID:1为例,以此类推。

Air8101有ADC1,ADC2,ADC3,ADC4,ADC5,ADC6,ADC10,
ADC12,ADC13,ADC14,一共10路外部ADC;
每个通道对应的关系如下:
ADC1对应通道1
ADC2对应通道2
ADC3对应通道3
ADC4对应通道4
ADC5对应通道5
ADC6对应通道6
ADC10对应通道10
ADC12对应通道12
ADC13对应通道13
ADC14对应通道14

adc.ADC_RANGE_MAX

常量含义:合宙主流模组ADC引脚的测量范围0-3.3V
         注意!仅适用于无外部分压电路的情况;
数据类型:number;
示例代码:adc.setRange(adc.ADC_RANGE_MAX);

adc.ADC_RANGE_MIN

常量含义:合宙主流模组ADC引脚的测量范围0-1.5V
         注意!适用于两种情况,一种是本身就小于1.5V无需外部分压电路,一种是本身大于1.5V需要外部分压电路;
数据类型:number;
示例代码:adc.setRange(adc.ADC_RANGE_MIN);

adc.CH_CPU

常量含义:CPU内部温度的通道id;
数据类型:number;
示例代码:adc.open(adc.CH_CPU);

adc.CH_VBAT

常量含义:VBAT供电电压的通道id;
数据类型:number;
示例代码:adc.open(adc.CH_VBAT);

adc.CFG_RANGE

常量含义:全局量程参数,等效于 adc.setRange,配合 adc.config 使用;
          设置的是全局默认量程,之后 adc.open 的通道都会按这个量程工作;
数据类型:number;
示例代码:adc.config(adc.CFG_RANGE, adc.ADC_RANGE_MAX);

adc.CFG_CYCLE

常量含义:ADC 读取时的循环次数参数,配合 adc.config 使用;
          循环次数越多(指循环次数本身,不是总采样次数),转换越慢、结果越准,
          对被测量对象的内阻 R_src 要求也越低;
数据类型:number;
示例代码:adc.config(adc.CFG_CYCLE, 8);

adc.T1

常量含义:第 1 个 ADC 控制器(ADC1)的编号基址,取值为 16;
          仅当平台存在多个 ADC 控制器时才有意义,用法是「adc.T1 + 通道号」;
          例如 adc.open(adc.T1 + 2) 表示打开 ADC1 的第 2 通道;
数据类型:number;
示例代码:
          -- 打开 ADC1 的第 2 通道
          adc.open(adc.T1 + 2)
注意事项:只有一个 ADC 控制器的平台(如 Air780EXXX 系列)直接用通道号即可,
          不需要也不应该加 adc.T1,加了会打开错误的通道或直接打开失败;

adc.T2

常量含义:第 2 个 ADC 控制器(ADC2)的编号基址,取值为 32;
          含义与 adc.T1 相同,只是对应第 2 个 ADC 控制器;
数据类型:number;
示例代码:
          -- 打开 ADC2 的第 3 通道
          adc.open(adc.T2 + 3)
注意事项:同上,平台没有第 2 个 ADC 控制器时该写法无效;

adc.ADC_RANGE_3_6

常量含义:ADC 内部分压电阻开启,固定量程 0~3.76V;
          属于早期的固定量程常量,取值为 1;
数据类型:number;
示例代码:adc.setRange(adc.ADC_RANGE_3_6);
注意事项:源码注释未标注废弃,仍可正常使用;
          但新代码建议统一用 adc.ADC_RANGE_MAX / adc.ADC_RANGE_MIN,
          这两个常量的实际量程由具体芯片决定,跨型号更安全;

adc.ADC_RANGE_1_8

常量含义:ADC 内部分压电阻关闭,固定量程 0~1.88V;
          属于早期的固定量程常量,取值为 0(与 adc.ADC_RANGE_MIN 取值相同);
数据类型:number;
示例代码:adc.setRange(adc.ADC_RANGE_1_8);
注意事项:同上,新代码建议用 adc.ADC_RANGE_MIN;

已废弃的量程常量(不要在新代码里使用)

下面两个常量在源码注释里已经明确写了“将要废弃,不建议使用”,这里列出来只是为了便于排查旧代码:

常量 源码注释原文 说明
adc.ADC_RANGE_3_8 air780E开启ADC0,1分压电阻,范围0~3.8V,将要废弃,不建议使用 仅早期 Air780E 的 ADC0/ADC1 有意义
adc.ADC_RANGE_1_2 air780E关闭ADC0,1分压电阻,范围0~1.2V,将要废弃,不建议使用 取值 0,与 ADC_RANGE_MIN 相同

量程常量的选取原则见本章开头的“合宙模组的 adc 量程一些说明”: 被测电压不超过 1.5V 用 adc.ADC_RANGE_MIN;1.5V~3.3V 用 adc.ADC_RANGE_MAX 且不加外部分压; 超过 3.3V 用 adc.ADC_RANGE_MIN 并外加分压电路。

四、函数详解

adc.open(id)

功能

打开 adc 通道

参数

id

参数含义:通道id,通常从0开始;
数据类型:number;
取值范围:参考第三章合宙模组的adc id的一些说明;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:0,1,2,3,adc.CH_CPU,adc.CH_VBAT;

返回值

local result = adc.open(id)

result

含义说明:表示返回结果,失败返回false,成功返回true;
数据类型:boolean;
取值范围:true或false;
注意事项:暂无;
返回示例:true;

示例

-- 打开adc通道4,并读取
if adc.open(3) then
    log.info("adc", adc.read(3)) -- 返回值有2个, 原始值和计算值,通常只需要后者
    log.info("adc", adc.get(3))  -- 返回值有1个, 仅计算值
end
adc.close(3) -- 若需要持续读取, 则不需要close, 功耗会高一点.

adc.setRange(range)

功能

设置 ADC 的测量范围,设置分压(adc.setRange)要在 adc.open 之前设置,否则无效!!

参数

range

参数含义:表示adc通道的量程的最大值;
数据类型:number;
取值范围:ADC_RANGE_MIN和ADC_RANGE_MAX,参考第三章合宙模组的adc量程一些说明;
是否必选:必须传入此参数;
注意事项:adc.CH_VBAT和adc.CH_CPU不需要设置量程,在模组正常工作时都可以正常测量;
         8101硬件不支持内部分压;
参数示例:adc.ADC_RANGE_MAX,adc.ADC_RANGE_MIN;

返回值

nil

示例

adc.setRange(adc.ADC_RANGE_MIN)

adc.read(id)

功能

读取 adc 通道计算值

参数

id

参数含义:通道id,通常从0开始;
数据类型:number;
取值范围:参考第三章合宙模组的adc id的一些说明;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:0,1,2,3,adc.CH_CPU,adc.CH_VBAT;

返回值

local data0,data1 = adc.read(id)

data0

含义说明:adc的一个返回值,因历史原因第一个返回值没有意义,此返回值一点儿用都没有,用户使用第二个返回值即可;
数据类型:number;
取值范围:暂无;
注意事项:暂无;
返回示例:暂无;

data1

含义说明:adc的计算值,单位是mV;
数据类型:number;
取值范围:当量程设置为adc.ADC_RANGE_MIN,最大可获取到1500mv;
         当量程设置为adc.ADC_RANGE_MAX,最大可测量到3600mv;
注意事项:暂无;
返回示例:暂无;

示例

local function adc_task()
     while true do
         sys.wait(1000)--延时1S
         adc.setRange(adc.ADC_RANGE_MIN)--设置ADC引脚的测量范围0-1.5V,这种方式被测电压可以经过外部电阻分压后再挂在ADC上;
         adc.open(1)--打开ADC通道1
         local data0,data1 = adc.read(1)--获取adc的原始值和计算值,将获取到的值赋给data0,data1
         adc.close(1)--关闭ADC通道1
         log.info("adc通道1", data0,data1)--打印adc计算值
     end
 end

sys.taskInit(adc_task)

adc.get(id)

功能

获取 adc 计算值

参数

id

参数含义:通道id,从0开始;
数据类型:number;
取值范围:参考第三章合宙模组的adc id的一些说明;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:0,1,2,3,adc.CH_CPU,adc.CH_VBAT;

返回值

local data = adc.get(id)

data

含义说明:adc的计算值,单位是mV,  如果是adc.CH_CPU通道会返回温度值,单位千分之一摄氏度,
         若读取失败,会返回-1;
数据类型:number;
取值范围:当量程设置为adc.ADC_RANGE_MIN,最大可获取到1500mv;          
         当量程设置为adc.ADC_RANGE_MAX,最大可测量到3600mv;
         当量程设置为adc.ADC_RANGE_MAX,最大可测量到3600mv;
注意事项:暂无;
返回示例:暂无;

示例

local function adc_task()
     while true do
         sys.wait(1000)--延时1S
         adc.setRange(adc.ADC_RANGE_MIN)--设置ADC引脚的测量范围0-1.5V,这种方式被测电压可以经过外部电阻分压后再挂在ADC上;
         adc.open(0)--打开ADC通道0
         local data = adc.get(0)--获取adc计算值,将获取到的值赋给data
         adc.close(0)--关闭ADC通道0
         log.info("adc读出值", data)--打印adc计算值
     end
 end

sys.taskInit(adc_task)

adc.close(id)

功能

关闭 adc 通道

若需要持续读取, 则不需要 close, ADC 工作时的功耗大概是 400uA 左右;

若不需要持续读取,则需要 close,否则 ADC 通道将浪费至少 400uA 左右;

参数

id

参数含义:通道id,从0开始;
数据类型:number;
取值范围:参考第三章合宙模组的adc id的一些说明;
是否必选:必须传入此参数;
注意事项:暂无;
参数示例:0,1,2,3,adc.CH_CPU,adc.CH_VBAT;

返回值

nil

示例

adc.close(1)

adc.fast_read(id, cnt)

功能

高速读取 ADC 原始值,一次调用连续采样 cnt 次后直接返回原始 ADC 值,不走 adc.read 的计算流程;

参数

id

参数含义:通道id;
数据类型:number;
取值范围:与 adc.read 一致,参考第三章 adc id 的说明;
是否必选:必须传入此参数;
注意事项:调用前仍需 adc.open 打开通道;
参数示例:0,1,adc.CH_VBAT;

cnt

参数含义:采样次数;
数据类型:number;
取值范围:正整数,默认 2;
是否必选:可选;
注意事项:次数越多耗时越长,按被测信号的稳定程度取舍;
参数示例:2,8,16;

返回值

local ok, raw = adc.fast_read(id, cnt)

log.info("adc", ok, raw)

ok

含义说明:本次读取是否成功;
数据类型:boolean;
取值范围:true/false;
注意事项:返回 false 时后面的原始值没有意义,不要使用;
返回示例:true;

raw

含义说明:ADC 原始值;
数据类型:number;
取值范围:由芯片位宽决定,没有单位;
注意事项:是原始码值,没有换算成电压,需要按量程与位宽自行换算;
返回示例:2048;

示例

-- 该函数于 2026.10.26 新增
-- 注意: 底层依赖 BSP 提供的块读实现, 未实现的平台会恒返回 false,
--       此时请继续使用 adc.read / adc.get
adc.open(1)
local ok, raw = adc.fast_read(1, 8)
log.info("adc", "fast_read", ok, raw)
adc.close(1)

adc.config(param, value)

功能

设置 ADC 的全局参数,目前支持全局量程与循环次数两项;

参数

param

参数含义:参数类型;
数据类型:number;
取值范围:adc.CFG_RANGE / adc.CFG_CYCLE;
是否必选:必须传入此参数;
注意事项:全局参数对所有通道生效,不针对单个通道;
参数示例:adc.CFG_RANGE,adc.CFG_CYCLE;

value

参数含义:参数值;
数据类型:number;
取值范围:CFG_RANGE 取 adc.ADC_RANGE_MIN ~ adc.ADC_RANGE_MAX,CFG_CYCLE 取正整数;
是否必选:必须传入此参数;
注意事项:通道特性为 CH_VBAT / CH_CPU 时不需要设置量程;
参数示例:adc.ADC_RANGE_MAX,8;

返回值

local res = adc.config(adc.CFG_RANGE, adc.ADC_RANGE_MAX)

log.info("adc", res)

res

含义说明:设置结果;
数据类型:boolean;
取值范围:true/false;
注意事项:参数或取值不合法时返回 false;
返回示例:true;

示例

-- 该函数于 2026.10.26 新增
-- 等价于 adc.setRange(adc.ADC_RANGE_MAX), 但作用在全局
adc.config(adc.CFG_RANGE, adc.ADC_RANGE_MAX)

-- 单个通道循环采样 8 次, 结果更稳
adc.config(adc.CFG_CYCLE, 8)

adc.open(1)
log.info("adc", adc.read(1))
adc.close(1)

五、产品支持说明

支持 LuatOS 开发的所有产品都支持 adc 核心库。

搜索