# ADC_Sampling_HighVolt **Repository Path**: yuanxi_tech/adc_sampling_high_volt ## Basic Information - **Project Name**: ADC_Sampling_HighVolt - **Description**: STM32F103 十路 ADC 采样固件 | 双串口 DMA 收发 | AT 在线配置 | 配套免费 PC 波形软件 | 0~26V宽电压采集范围 - **Primary Language**: C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-08 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ADC_Sampling_HighVolt **简体中文** | [English](README.en.md) > 基于 STM32F103 的**十路 ADC 高速采样**固件(高压版 0~26V)。 > 10 路 12 位 ADC 由 DMA 循环搬运,双路 UART 全 DMA 收发,输出格式与发送节奏均可通过 **AT 指令在线配置**,参数掉电保存。 `STM32F103C8` · `Cortex-M3` · `ST HAL` · `Keil MDK 5` · `DMA 零阻塞收发` · `配套免费PC上位机(无需安装)` --- ![输入图片说明](pic/pic1.png) --- ![输入图片说明](pic/pic2.png) --- ![输入图片说明](pic/pic5.png) --- ![输入图片说明](pic/pic3.png) --- ![输入图片说明](pic/pic4.png) --- ![输入图片说明](pic/pic6.png) --- ## 目录 - [1. 功能特性](#1-功能特性) - [2. 硬件平台](#2-硬件平台) - [3. 系统架构](#3-系统架构) - [4. 数据输出协议](#4-数据输出协议) - [5. AT 指令集](#5-at-指令集) - [6. 默认配置](#6-默认配置) - [7. 编译与烧录](#7-编译与烧录) - [8. 配套上位机软件](#8-配套上位机软件) - [9. 快速上手](#9-快速上手) - [10. 设计说明](#10-设计说明) - [11. 常见问题](#11-常见问题) - [12. 更新记录](#12-更新记录) - [13. 版权与许可](#13-版权与许可) --- ## 1. 功能特性 | 特性 | 说明 | | --- | --- | | **十路高速采样** | ADC1 连续扫描 10 个通道(**一轮约 85 µs**),配合 DMA 循环搬运,CPU 不参与采集过程 | | **双路串口对等** | USART1 / USART3 **同时接收指令、同时输出相同数据**,接哪一路都能用 | | **全 DMA 收发** | 发送走「环形缓冲 + DMA」,接收走「DMA + IDLE 中断」,发送路径完全非阻塞 | | **五种输出格式** | 位置式 ASCII、文本式 ASCII、JustFloat 二进制、单通道两种 | | **AT 指令配置** | 模式 / 通道 / 波特率 / 帧率均可在线修改,参数写入 Flash 掉电不丢 | | **高帧率能力** | 帧率由 TIM2 时基决定,最高可跑到每节拍一帧;2M baud 下发送吞吐可达线路极限 | | **状态指示** | PB12 指示灯随发送节拍翻转,一眼可见固件是否在出数据 | --- ## 2. 硬件平台 ### 2.1 主控与时钟 | 项目 | 规格 | | --- | --- | | 主控 | STM32F103C8(Cortex-M3,64 KB Flash / 20 KB SRAM) | | 系统时钟 | **64 MHz**(HSI 8 MHz → PLL ×16) | | AHB / APB2 | 64 MHz | | APB1 | 32 MHz | | ADC 时钟 | **8 MHz**(PCLK2 64 MHz ÷ 8,低于 F103 上限 14 MHz) | | ADC 采样速率 | 10 通道连续扫描一轮 **约 85 µs** ≈ **11.8 kHz**(即单通道 11.8 kSPS) | | 发送节拍 | TIM2:64 分频 / 1000 计数(计数时钟 64 MHz)→ **约 1 kHz** 中断,1 节拍 = 1 ms | | 调试接口 | SWD(已禁用 JTAG,释放 PA15 / PB3 / PB4) | > **采样与发送是两条独立的链路。** ADC 每约 **85 µs** 就把 10 个通道全部刷新一遍,而串口最快也要每 **1 ms**(TIM2 一个节拍)才发出一帧 —— 采样比发送快 12 倍以上(默认 `AT+RATE=50` 时快约 580 倍)。因此每次发送取到的都是当时**最新一轮**的采样值,不存在「发送比采样快、重复读到同一批数据」的问题。 > > 另外需要说明:10 个通道是**依次转换**的,并非同时保持采样。相邻通道之间相差约 **8.5 µs**,一轮 10 个通道跨越约 85 µs。对直流、温度、工频等缓变信号没有影响;若被测信号本身在数十 kHz 以上、且需要比较通道间相位,则需把这 8.5 µs 的通道间时差纳入考虑。 ### 2.2 引脚分配 **模拟输入**(12 位,参考电压 3.3 V- AT指令可调参考电压值) | 逻辑通道 | 引脚 | ADC 通道 | 逻辑通道 | 引脚 | ADC 通道 | | --- | --- | --- | --- | --- | --- | | CH0 | PA0 | ADC1_IN0 | CH5 | PA5 | ADC1_IN5 | | CH1 | PA1 | ADC1_IN1 | CH6 | PA6 | ADC1_IN6 | | CH2 | PA2 | ADC1_IN2 | CH7 | PA7 | ADC1_IN7 | | CH3 | PA3 | ADC1_IN3 | CH8 | PB0 | ADC1_IN8 | | CH4 | PA4 | ADC1_IN4 | CH9 | PB1 | ADC1_IN9 | **串口与指示** | 功能 | 引脚 | 说明 | | --- | --- | --- | | USART1_TX | PA9 | 数据与 AT 回包输出 | | USART1_RX | PA10 | AT 指令输入 | | USART3_TX | PB10 | 数据与 AT 回包输出 | | USART3_RX | PB11 | AT 指令输入 | | 状态指示 | PB12 | 每完成一个发送周期翻转一次 | > 两路串口功能完全对等:写入任一路的 AT 指令都会生效,两路同时输出同一份数据。 ### 2.3 外设与 DMA 通道 | DMA 通道 | 用途 | 方向 | 模式 | | --- | --- | --- | --- | | DMA1_Channel1 | ADC1 | 外设 → 内存 | **循环**(半字 → 字) | | DMA1_Channel2 | USART3_TX | 内存 → 外设 | 单次 | | DMA1_Channel3 | USART3_RX | 外设 → 内存 | 单次 | | DMA1_Channel4 | USART1_TX | 内存 → 外设 | 单次 | | DMA1_Channel5 | USART1_RX | 外设 → 内存 | 单次 | > 通道分配与 STM32F103 参考手册的请求映射一致,请勿随意改动,避免与其他外设冲突。 --- ## 3. 系统架构 ### 3.1 数据流 ``` ┌──────────────────┐ PA0..PA7 ──────┤ │ PB0, PB1 ──────┤ ADC1 12-bit ├──┐ │ 10-ch scan / │ │ DMA1_Channel1 (circular) │ continuous │ │ └──────────────────┘ ▼ ADC_BUF[10] (uint32) │ TIM2 (1 kHz) ──► logic_heartbeat() ──┼──► SEND_RATE_FLAG ▼ send_mode1 / 2 / 3 │ ┌─────────────────────┴─────────────────────┐ ▼ ▼ uart1_tx_write() uart3_tx_write() │ │ TX ring 512 B TX ring 512 B │ │ DMA1_CH4 ──► USART1 ──► PA9 DMA1_CH2 ──► USART3 ──► PB10 指令接收(两路完全相同) PA10 ──► USART1 RX (DMA1_CH5) ──► IDLE 中断 ──┐ ├──► at_queue(3 深) ──► 主循环 protocol_analysis() PB11 ──► USART3 RX (DMA1_CH3) ──► IDLE 中断 ──┘ └──► at_command() ``` ### 3.2 目录结构 ``` ADC_Sampling_HighVolt/ ├── app/ # 应用层:业务代码全部在这里 │ ├── common.h # 公共类型定义、全局对象外部声明 │ ├── logic.c / logic.h # 发送节拍、状态指示灯、五种输出模式 │ ├── uart_task.c / uart_task.h # 串口初始化、AT 指令解析、DMA 收发与环形缓冲 │ └── save_info.c / save_info.h # 配置参数的 Flash 读写 ├── Core/ # STM32CubeMX 生成的外设初始化与中断 │ ├── Inc/ # main.h、HAL 配置、中断声明 │ └── Src/ # main.c、MSP、中断服务程序、系统时钟 ├── Drivers/ # ST 官方 HAL 驱动库 + CMSIS └── MDK-ARM/ # Keil MDK 工程(ADC_Sampling.uvprojx) ``` --- ## 4. 数据输出协议 ### 4.1 模式总览 | MODE | 名称 | 通道数 | 格式 | 典型用途 | | --- | --- | --- | --- | --- | | 0 | 静默 | — | 不输出任何数据 | 临时暂停数据流(指令仍可响应) | | 1 | 位置式 ASCII | 10 | `:v0,v1,…,v9\n` | **默认**,配套上位机软件 | | 2 | 文本式 ASCII | 10 | `CH0:0123 0.992V\n` × 10 行 | 串口助手人工读数 | | 3 | JustFloat | 10 | 10 × float32(LE) + `00 00 80 7F` | 配套上位机软件 | | 4 | 单通道文本式 | 1 | `CH:0111 0.894V\n` | 只看一路(通道由 `AT+M2CH` 选) | | 5 | 单通道位置式 | 1 | `:0.894\n` | 只看一路(通道由 `AT+M1CH` 选) | ### 4.2 各模式帧格式 **MODE = 1**(位置式 ASCII,每帧一行) ``` :0.992,1.234,0.001,0.000,3.300,1.650,0.825,2.475,0.000,0.000\n ``` - 标签 `:` 与 10 个数值;数值为**电压**,保留 3 位小数,逗号分隔,`\n` 结尾 - 单帧约 64 字节 **MODE = 2**(文本式 ASCII,每帧 10 行) ``` CH0:0123 0.099V\n CH1:0456 0.367V\n … CH9:0000 0.000V\n ``` - 每行格式:`CH<通道号>:<原始 ADC 码值> <电压>V` - 原始码值固定 4 位宽(`%04d`,范围 0–4095) **MODE = 3**(JustFloat 二进制,定长 44 字节) | 偏移 | 长度 | 内容 | | --- | --- | --- | | 0 | 40 B | 10 个电压值,小端 float32(4 B × 10) | | 40 | 4 B | 帧尾 `00 00 80 7F`(小端的 +Inf,正常采样不可能出现) | - 数值语义与 MODE=1 完全一致,只是二进制浮点,带宽占用更小、解析更快 - 上位机以帧尾切分数据帧,**帧内不得插入任何 ASCII 字符** **MxCH = x**(单通道) ``` AT+M2CH=2 : CH3:0111 0.089V\n # 原始码值 + 电压 AT+M1CH=5 : <3>:0.089\n # 仅电压,位置式标签 ``` ### 4.3 电压换算 ``` 电压(V) = ADC码值 × 3.3 / 4096 * 分压系数 ``` ADC 为 12 位右对齐、参考电压 3.3 V。 --- ## 5. AT 指令集 指令通过**任一路串口**发送,**必须以换行符 `\n` 结尾**。参数一旦变化立即写入 Flash 保存。 | 指令 | 说明 | 取值范围 | 备注 | | --- | --- | --- | --- | | `AT` | 连通性测试 | — | 回 `OK` | | `AT+MODE=` | 设置输出模式 | `0` – `5` | 见 [模式总览](#41-模式总览) | | `AT+M1CH=` | 单通道(位置式)通道号 | `0` – `9` | | `AT+M2CH=` | 单通道(文本式)通道号 | `0` – `9` | | `AT+BAUD=` | 设置波特率 | `110` – `2000000` | **复位后生效** | | `AT+RATE=` | 每帧间隔的 TIM2 节拍数 | `0` – `10000` | **数值越小发送越快**,`0` = 最高速 | **回包规则** | 情况 | 回包 | | --- | --- | | 指令合法 | `OK\n` | | 数值越界 | `ERROR\n` | | 未知指令 / 拼写错误 | `ERROR\n` | **示例** ``` 上位机 → AT\n MCU → OK\n 上位机 → AT+MODE=3\n # 切换为十路 JustFloat MCU → OK\n 上位机 → AT+RATE=100\n # 每 100 个节拍发一帧(约 10 帧/s) MCU → OK\n 上位机 → AT+BAUD=2000000\n # 2 Mbaud,需复位生效 MCU → OK\n ``` > **关于 `AT+RATE` 的语义**:它表示「两帧之间等待多少个 TIM2 节拍」,因此 **1 比 1000 快**,`0` 最快(每个节拍都发一帧)。 > 注意 `0` 是特殊值而非「最慢」——若上位机把它当作普通数值理解,容易产生误解。 --- ## 6. 默认配置 首次烧录或 Flash 中数据校验失败时,固件会退回以下默认值(同时,Flash 里若残留超出范围的值也会被纠正): | 项目 | 默认值 | 说明 | | --- | --- | --- | | 输出模式 | **1** | 十路位置式 ASCII | | 波特率 | **460800** | 打开串口时请使用该波特率 | | 帧间隔 | **50 节拍** | 约 20 帧/s | | 单通道选择 | 0 / 0 | M1、M2 通道号 | 配置存放于 Flash 最后一页 `0x0800FC00`。 --- ## 7. 编译与烧录 **环境要求** - Keil MDK-ARM(μVision)**5.3x** - 器件支持包:`Keil.STM32F1xx_DFP` **2.3.0** - 目标器件:`STM32F103C8` **编译步骤** 1. 打开工程 `MDK-ARM/ADC_Sampling.uvprojx` 2. 确认目标器件为 `STM32F103C8`(Options → Device) 3. 确认 C/C++ 选项中启用 **C99**(源码使用了 `snprintf` 等 C99 特性) 4. `Build` 编译,通过 ST-Link / DAP-Link 下载到目标板 **工程要点** - 发送路径默认启用 DMA(`UART_TX_USE_DMA = 1`);如需退回旧的阻塞式发送,可在 `app/uart_task.h` 中置 `0` 对比排查 - 每个串口的发送环形缓冲为 **512 字节**(`UART_TX_RING_SIZE`),必须为 2 的幂 - 接收缓冲为每路 **200 字节**(`UART1_MAX_LEN` / `UART3_MAX_LEN`) --- ## 8. 配套上位机软件 本固件配套一款 Windows 平台的 PC 上位机软件(**多路模拟量波形显示软件**),用于实时观察、记录与分析本板输出的采样数据,无需另购第三方工具,接线即可使用。 ### 8.1 主要功能 | 分类 | 功能 | | --- | --- | | **数据接入** | 串口号与波特率 / 数据位 / 停止位 / 校验位设置;自动判别设备发送的数据格式,无需手工指定解析方式 | | **波形显示** | 多通道同屏实时绘制;支持**叠加显示**与**通道独立显示**两种视图;每通道可单独设置名称、颜色、增益、偏置与显示开关 | | **视图操作** | 滚轮缩放、拖动平移、跟随最新 / 回看历史、一键自适应、暂停刷新(暂停期间数据仍在后台记录) | | **读数与定位** | 实时十字辅助线,直接读出光标处各通道数值与横坐标 | | **X 轴口径** | 采样点序号 / 真实时间(时:分:秒.毫秒)两种显示方式,可随时切换 | | **数据留存** | 采样数据保存为 CSV;支持回放历史 CSV 文件,离线复现现场数据 | | **串口调试** | 内置串口调试控制台:收发日志、HEX 模式、自动发送,便于发送 AT 指令与排查通信 | | **界面** | 中文 / 英文双语切换;适配高分辨率屏幕 | | **维护** | 关于页显示版本号与更新内容,支持检查更新;串口设备被拔除时自动关闭串口并明确提示 | ### 8.2 软件优势 1. **免配置接入,插上即用** —— 自动判别设备输出的是文本格式还是二进制格式,无需手工填写协议或通道数,选好串口号点开即可看到波形。 2. **多通道同屏,对比直观** —— 最多 30 路模拟量同时呈现,叠加对照或独立分道任选;每路可单独调整增益、偏置与颜色,不同量纲的信号也能放在同一张图上比较。 3. **长历史与流畅交互兼得** —— 单通道可保留十万点量级的历史数据,缩放、拖动、暂停回看全程流畅;既能盯住瞬时细节,也能追溯数分钟前的走势。 4. **X 轴口径可切换** —— 既能按「采样点序号」对照固件的发送节奏,也能切到「真实时间」查看事件发生的时刻,刻度与光标读数同步跟随,排查偶发问题不必再靠推算。 5. **现场使用省心** —— 绿色单文件免安装、中英双语;串口被拔掉自动断开并明确提示;内置串口调试控制台与 CSV 回放,采数据、发指令、复现问题无需切换软件。 --- ## 9. 快速上手 1. **上电**:目标板默认以 `MODE=1`、`460800` 波特率、约 20 帧/s 输出数据,指示灯闪烁 2. **连接**:USB 转串口接入 USART1(PA9/PA10)或 USART3(PB10/PB11),注意 **TX/RX 交叉** 3. **确认**:打开串口(**460800, 8, N, 1**),发送 `AT\n`,收到 `OK` 说明通信正常 4. **切换格式**:按需发送 `AT+MODE=1/2/3` 5. **调节速率**:`AT+RATE=10` 更快 / `AT+RATE=500` 更慢 6. **接入上位机**: - MODE=1 → 配套上位机软件(见 [第 8 节](#8-配套上位机软件)) - MODE=3 → 配套上位机软件,数据解析方式自动识别 `JustFloat`,通道数 `10` --- ## 10. 设计说明 以下设计约束是本固件稳定性与吞吐能力的基础,二次开发时请留意。 **采样:CPU 零参与** ADC1 配置为扫描 + 连续转换,10 个通道的结果由 DMA1_Channel1 循环写入 `ADC_BUF[10]`。CPU 只需在需要发帧时读取该数组,采样过程不受主循环负载影响。 **发送:DMA + 环形缓冲,永不阻塞** `printf` / `send_modeX` 只把数据拷入环形缓冲并启动 DMA,随即返回;一段发完由 USART 传输完成中断接着发下一段。因此单帧耗时从「计算 + 发送」变为 `max(计算, 发送)`。 ⚠️ 缓冲满时策略是**整段丢弃并计数**(`uart1_tx_drop` / `uart3_tx_drop`),绝不等待——因为发送缓冲依赖 USART 中断推进,在中断上下文里等待会造成死锁。 **接收:中断只做搬运,解析放在主循环** RX DMA 运行在单次模式,配合 USART IDLE 中断判定「一帧指令结束」。中断里**只做两件事**:取出本轮字节数、放入 3 深度的命令队列,然后重新布防 DMA。 真正的解析在主循环里执行 —— 因为一条成功指令要擦写一页 Flash,耗时约 **100 ms**,若在中断中执行,这段时间内接收将完全停摆。 **命令队列** 深度 3 的环形队列用于吸收突发指令,以及「上一条指令写 Flash 期间到达的指令」。队列满时丢弃新指令(不覆盖正在解析的槽位),并累加 `drop` 计数便于观察。 **配置持久化** 参数写入 Flash 最后一页,采用「先擦除整页、再按半字编程」的方式。仅在**参数值真正发生变化**时才写入,避免重复指令反复擦写、缩短 Flash 寿命。 **双串口对等** USART1 与 USART3 各自拥有独立的 RX DMA、IDLE 处理、命令队列与发送环形缓冲,但共享同一份采样数据与配置。两路输出内容完全一致,接任一路即可。 --- ## 11. 常见问题 | 现象 | 排查方向 | | --- | --- | | 发送 `AT` 无任何回包 | 波特率是否为 **460800**;指令是否以 `\n` 结尾;TX/RX 是否交叉;PB12 指示灯是否在闪 | | 改了波特率但没变 | `AT+BAUD` **复位后生效**,请重新上电 | | 收到的是一堆乱码 | 输出格式与上位机解析方式不匹配,用 `AT+MODE` 切换到对应格式 | | JustFloat 波形错乱 | 上位机需按 `JustFloat` 解析(配套上位机软件会自动识别);确认通道数为 10,且未被文本模式混入 | | 数据速率达不到预期 | 检查 `AT+RATE`(数值越小越快)与串口波特率;确认上位机读取端没有成为瓶颈 | | 数据断流、无响应 | 主机若持续高速发送指令且从不留间隔,请适当降低发送频率;必要时重启串口 | --- ## 12. 版权与许可 - **作者**:lainien - **版权**:Copyright (c) 2026 上海远夕智能科技有限公司 - **硬件**:[淘宝商品页](https://item.taobao.com/item.htm?id=717251001647) **参与贡献** -我们欢迎任何形式的贡献!请遵循以下流程: -Fork & 分支 — 从 main 创建分支 -开发 & 提交 — 在新分支上完成修改并提交,遵循 Conventional Commits 规范 -发起 PR — 提交 Pull Request 到 develop 分支,维护者会审核并合并 -欢迎通过 Issue 反馈问题或提出改进建议。