当前位置: 首页 > news >正文

zephyr实现ADC方式有那些?

在 Zephyr RTOS 中,使用 ADC 主要有三种官方示例所展示的标准方式,它们可以满足从简单到复杂的各类采集需求。

下面的表格可以帮你快速了解它们的区别:

特性方式一: ADC with devicetree方式二: ADC sequence sample方式三: Generic ADC stream
核心思路通过设备树 (devicetree) 静态配置通道,简化代码在代码中动态配置通道,进行单次或多次序列采样使用流式API (Stream API),持续、高效地采集数据
配置方式设备树(.dts/.overlay) 中定义io-channels和通道参数C 代码中填充adc_channel_cfg结构体设备树中为 ADC 设备添加adc0别名
典型场景推荐方式,通道固定、配置不变的工程需要动态调整通道或采样顺序的场景需要高频率、持续采样,如音频、传感器数据流
上手难度

📝 方式一:ADC with devicetree(推荐)

这是 Zephyr最推荐的使用方式,通过设备树将硬件配置与代码逻辑分离,使代码更简洁、可移植性更强。你的vbat.c正是采用了这种方式。

  • 核心步骤

    1. 设备树配置:在板级或应用 Overlay 文件中,于zephyr,user节点下通过io-channels属性指定 ADC 通道。通道的具体参数(如增益、参考电压)也在设备树中配置。

    2. 代码实现

      • 使用ADC_DT_SPEC_GET_BY_IDX等宏,自动从设备树生成通道规格数组adc_dt_spec

      • 调用adc_channel_setup_dt()adc_sequence_init_dt()进行初始化。

      • 调用adc_read_dt()触发读取。

  • 优点:代码与硬件解耦,修改通道或参数时无需改动 C 代码,只需更新设备树文件。

🎯 方式二:ADC sequence sample

此方式更侧重于在C 代码中灵活控制采样序列,适用于需要动态配置通道或采样顺序的场景。

  • 核心步骤

    1. 设备获取:直接通过DEVICE_DT_GET()device_get_binding()获取 ADC 设备实例。

    2. 通道配置:在代码中填充adc_channel_cfg结构体,并调用adc_channel_setup()进行配置。

    3. 定义序列:填充adc_sequence结构体,指定缓冲区、通道等。可通过adc_sequence_options设置采样间隔等高级选项。

    4. 执行读取:调用adc_read()触发采样。

🌊 方式三:Generic ADC stream

这是为需要持续、高速数据流的场景(如音频采集)设计的高效 API。

  • 核心步骤

    1. 设备树别名:需要为 ADC 设备设置adc0别名。

    2. 流式读取:使用专门的 Stream API 来管理和处理持续涌入的 ADC 数据。

除了以上三种主要方式,Zephyr 的 ADC 驱动还提供了一些高级特性:

  • 异步读取:支持不阻塞线程的异步读取,完成后通过回调函数通知。

  • 连续采样模式:通过配置adc_sequence_optionsextra_samplings等字段,可在一次请求中完成多次采样。

  • 内部温度传感器:部分 SoC 支持读取内部温度传感器,可与普通 ADC 采样功能共存。

  • DMA 支持:许多 ADC 驱动底层实现了 DMA 支持,可高效传输大量数据。

💎 总结与建议

对于大多数嵌入式应用,强烈推荐使用“方式一:ADC with devicetree”。这是 Zephyr 的现代开发范式,能最大程度提升代码的可移植性和可维护性。

下面是方式一参考程序:

/*

* Copyright (c) 2020 Libre Solar Technologies GmbH

*

* SPDX-License-Identifier: Apache-2.0

*/

#include <inttypes.h>

#include <stddef.h>

#include <stdint.h>

#include <zephyr/device.h>

#include <zephyr/devicetree.h>

#include <zephyr/drivers/adc.h>

#include <zephyr/kernel.h>

#include <zephyr/sys/printk.h>

#include <zephyr/sys/util.h>

#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \

!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)

#error "No suitable devicetree overlay specified"

#endif

#define DT_SPEC_AND_COMMA_FOR_INPUTS(node_id, prop, idx) \

COND_CODE_1(DT_PHA_HAS_CELL_AT_IDX(node_id, prop, idx, input), \

(ADC_DT_SPEC_GET_BY_IDX(node_id, idx),), ())

/* Data of ADC io-channels specified in devicetree. */

static const struct adc_dt_spec adc_channels[] = {

DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,

DT_SPEC_AND_COMMA_FOR_INPUTS)

};

int main(void)

{

int err;

uint32_t count = 0;

uint32_t buf = 0;

struct adc_sequence sequence = {

.buffer = &buf,

/* buffer size in bytes, not number of samples */

.buffer_size = sizeof(buf),

#if CONFIG_SAMPLE_ADC_CALIBRATE_REQUIRED

.calibrate = true,

#endif

};

/* Configure channels individually prior to sampling. */

for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {

if (!adc_is_ready_dt(&adc_channels[i])) {

printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);

return 0;

}

err = adc_channel_setup_dt(&adc_channels[i]);

if (err < 0) {

printk("Could not setup channel #%d (%d)\n", i, err);

return 0;

}

}

#ifndef CONFIG_COVERAGE

while (1) {

#else

for (int k = 0; k < 10; k++) {

#endif

printk("ADC reading[%u]:\n", count++);

for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {

int32_t val_mv;

/*

* Clear buffer before reading. This ensures the upper 16-bits will be zero

* when the adc uses a 16-bit buffer size.

*/

buf = 0;

printk("- %s, channel %d: ",

adc_channels[i].dev->name,

adc_channels[i].channel_id);

(void)adc_sequence_init_dt(&adc_channels[i], &sequence);

err = adc_read_dt(&adc_channels[i], &sequence);

if (err < 0) {

printk("Could not read (%d)\n", err);

continue;

}

/*

* If using differential mode, the 16 bit value

* in the ADC sample buffer should be a signed 2's

* complement value.

*/

if (adc_channels[i].channel_cfg.differential) {

val_mv = (int32_t)((int16_t)buf);

} else {

val_mv = (int32_t)buf;

}

printk("%"PRId32, val_mv);

err = adc_raw_to_millivolts_dt(&adc_channels[i],

&val_mv);

/* conversion to mV may not be supported, skip if not */

if (err < 0) {

printk(" (value in mV not available)\n");

} else {

printk(" = %"PRId32" mV\n", val_mv);

}

}

k_sleep(K_MSEC(1000));

}

return 0;

}

http://www.gsyq.cn/news/1619045.html

相关文章:

  • 从“ELK 捞针”到结构化归因:基于 Grok 4.3 的分布式并发 Bug 排查实战
  • U535992 J-C 小梦的宝石收集
  • 什么是联盟营销(Affiliate Marketing)?2026海内外创作者商业化指南
  • 从Markdown到PDF:前端Canvas排版优化实践
  • 基于STM32单片机智能窨井盖井报警系统 倾斜角度水位气体WIFI 2(设计源文件+万字报告+讲解)(支持资料、图片参考_降重降ai)
  • 计算机毕业设计之基于大数据加护的国产美妆行业发展状况研究
  • QQ群聊天记录分析终极指南:三分钟解锁你的群聊数据洞察力
  • ISO 13355:2016简单介绍,ISO 13355标准是啥
  • 数据库的种类
  • 2026二三极管交易平台哪家好?5个核心判断标准
  • 【CDA干货】什么人适合学统计学?高考志愿填报哪些院校值得选?就业情况怎么样?
  • AI防爆摄像如何实时检测港口船体倾斜状态?
  • 2026龙虾安装推荐实测榜单8款主流智能AI盘点:按需选型规避部署踩坑
  • 用PIC微控制器驱动RGB灯带实现智能照明
  • 高安全行业音视频会议内网回撤转型
  • 06 — 接口层架构与实现
  • 品牌在 AI 回答里“掉线“了吗?——全天候 GEO 监测与竞品攻防指南
  • AI 自动写作覆盖自媒体,四成团队已落地流程
  • 2026临汾国省考+事业单位一年无限学机构TOP5红黑榜:选错真的耽误一年
  • 懂事的 Agent 已经开始自己看屏幕干活了,效率起飞!
  • 零成本解锁全能AI助手:Codex++接入Agnes免费全模态API完全指南(免费生成图片、视频)
  • 跨平台存储革命:如何在Windows上解锁Linux Btrfs文件系统的全部潜能
  • 制造业集团数字化转型,标签打印软件国产化替代优先落地思路
  • Java虚拟线程实战:Project Loom让并发编程更简单
  • 厨房电热水器出海:初创品牌如何用轻量化海外客服破解复杂售后难题
  • 智谱GLM-5.2开源引发安全警报,无审查限制具备仓库级漏洞挖掘能力
  • 深度拆解维普露禾AI教科研平台:学术知识图谱+大模型如何破解教育场景AI幻觉问题
  • 2026智能门锁硬核横评:安全、AI与售后全维度大解密,谁才是真正的“看门神”?
  • 共同关心的话题进行了建设性交流
  • 每个人的遗忘程度都不一样,建议第二天复习前一天的内容,