Skip to content

Repository files navigation

AutoTitrator-Free

English | 中文

多模态自动滴定控制器。STM32F103 裸机固件驱动进样与滴定双蠕动泵,采集电位与光谱信号;Rust/Tauri 上位机对两路信号做在线终点判定,并支持泵标定、浓度计算与数据记录。

项目概览

项目
MCU STM32F103C8T6 (ARM Cortex-M3)
Flash 64 KB @ 0x08000000
RAM 20 KB @ 0x20000000
工具链 GCC ARM (arm-none-eabi-g++)
语言标准 C++23,裸机,无 HAL / 无 RTOS / 无堆
构建系统 SCons
调试器 ST-Link V2 (SWD)
上位机 Rust/Tauri 2 + Next.js
授权 PolyForm Shield 1.0.0

文档

文档 读者 内容
上位机使用手册 做实验的人 安装、连接、标定、滴定、导出、常见问题
通信协议 对接协议的人 帧格式、命令表、时序、重试
固件二次开发指南 固件开发者 代码布局、初始化、寄存器层、中断、协议扩展
硬件接线 组装样机的人 引脚分配、接线说明、供电
标定与数据格式 处理数据的人 calibre.npz 结构、sidecar、settings.json
算法技术报告 关注算法的开发者 多模态融合、终点判定、参数与验证

目录结构

AutoTitrator-Free
├── SConstruct              # SCons 构建脚本
├── Startup/                # 启动代码、中断向量表、链接脚本
│   ├── Vectors.cpp
│   ├── linker.ld
│   └── CXXStubs.cpp
├── src/                    # 固件应用源码
│   ├── main.cpp            # 主循环入口
│   └── Interrupts.cpp      # 中断处理函数
├── include/                # 头文件
│   ├── register/           # Cortex-M3 寄存器/MMIO 抽象层
│   ├── stm32f103/          # 从 SVD 自动生成的 61 个外设头文件
│   ├── platform/           # 系统时钟、SysTick、NVIC 辅助
│   ├── hal/                # 外设 HAL 驱动
│   ├── device/             # 设备级驱动
│   └── protocol/           # 通信协议栈
├── TController/            # Rust/Tauri 上位机
│   ├── crates/controller-core/ # 协议、检测、重建与工作流
│   ├── app/src-tauri/      # Tauri 命令与后端状态
│   ├── app/ui-next/        # Next.js 仪器工作台
│   └── data/               # calibre.npz 与运行时状态
├── scripts/                # 代码生成脚本
│   └── generate_stm32f103.py   # 从 CMSIS-SVD 生成外设头文件
├── requirements-dev.txt    # 固件构建与寄存器生成依赖
├── openocd.cfg             # OpenOCD 调试配置
├── .gdbinit                # GDB 初始化脚本
├── README.md
└── LICENSE

固件架构

1. 寄存器抽象层

位于 include/register/,为 header-only、纯 C++23、零运行时开销的 MMIO 抽象:

  • CortexM3::Register<T, Address>:整寄存器读写、位域读写、原子 Set / Clear / Modify
  • CortexM3::Field<T, Position, Width>:位域类型,Mask() 在编译期计算。
  • atomic.hpp:通过 LDREX / STREX 实现 8/16/32 位原子 RMW。

2. 外设头文件生成

include/stm32f103/ 下 61 个外设头文件由 scripts/generate_stm32f103.py 从 CMSIS-SVD 自动生成:

uv run scripts/generate_stm32f103.py

每个寄存器对应一个纯静态单例类,按 SVD <access> 属性生成 Read / Write 与按位域访问方法,命名空间为 STM32F103::{Peripheral}

3. HAL 层

文件 外设 说明
include/hal/GPIO.hpp GPIO 端口模式/上下拉/速度配置、置位/读取
include/hal/UART.hpp USART1 RX 用 DMA1_CH5 循环 + IDLE 中断,TX 用 TXE 中断逐字节
include/hal/I2C.hpp I2C1 100 kHz,PB8/PB9,同步阻塞 + 异步中断双模式
include/hal/TIM.hpp TIM3 / TIM4 TIM3 作为 ADC 触发时基,TIM4 双通道 PWM 驱动蠕动泵
include/hal/ADC.hpp ADC1 单通道 PA0,TIM3_TRGO 触发,EOC 中断

4. 设备驱动与协议栈

文件 功能
include/device/PumpMotor.hpp 两个蠕动泵驱动(TIM4 CH1/CH2),支持 MaxCount / FreeRun
include/device/ADCOversample.hpp 256 次 ADC 累加过采样,右移 4 位输出 16-bit 结果
include/device/AS7341.hpp AS7341 光谱传感器驱动,两 phase SMUX 扫描状态机
include/device/SerialPort.hpp 环形缓冲 RX + 中断逐字节 TX
include/protocol/CommandDispatcher.hpp 解析下行命令、调用设备 API、打包上行数据
include/protocol/FrameCodec.hpp CRC-8(Maxim-Dallas, poly = 0x31)编解码
include/protocol/CommandParser.hpp 下行帧状态机解析器

5. 中断分配

中断 优先级 用途
USART1 0 IDLE 接收 + TXE 发送
DMA1_Channel5 0 USART1 RX DMA half/full
TIM4 1 泵脉冲计数
ADC1_2 2 ADC 转换完成
I2C1_EV / I2C1_ER 2 AS7341 异步 I2C
SysTick 15 1 ms 时基

所有中断处理函数在 Startup/Vectors.cpp 中以 [[gnu::weak]] 声明为弱符号并默认指向 Default_Handler,用户只需在任意 .cpp 中定义同名 extern "C" 函数即可覆盖。

6. 主循环

src/main.cpp 初始化时钟、SysTick、LED、串口、泵、ADC 过采样和 AS7341,随后在主循环中轮询协议服务、光谱服务和 ADC 服务,并在光谱测量完成后自动启动下一轮采集。

构建与烧录

固件构建

需要 arm-none-eabi 工具链在 PATH 中:

scons
# 或指定前缀
scons CROSS=arm-none-eabi-

构建产物位于 build/

  • AutoTitrator-Firmware.elf — 可执行文件(含调试信息)
  • AutoTitrator-Firmware.hex — Intel HEX
  • AutoTitrator-Firmware.map — 内存映射
  • AutoTitrator-Firmware.lst — 反汇编清单

清理:

scons -c

烧录与调试

# Terminal 1 — 启动 OpenOCD
cd D:/Projects/AutoTitrator/Firmware
openocd -f openocd.cfg

# Terminal 2 — 连接 GDB
arm-none-eabi-gdb build/AutoTitrator-Firmware.elf -x .gdbinit

寄存器生成工具

寄存器头文件生成脚本需要 cmsis-svd,开发依赖使用:

uv pip install -r requirements-dev.txt
uv run scripts/generate_stm32f103.py

上位机(TController)

Rust/Tauri 上位机通过串口与 MCU 通信,提供:

  • 实时光谱曲线与电位曲线
  • 在线滴定终点检测
  • 双泵控制与进度显示
  • 泵校准与 pH 电极校准
  • 状态持久化、运行历史和可靠性诊断

主要模块

目录 功能
TController/crates/controller-core/src/protocol/ 串口线程、协议帧解析与重试
TController/crates/controller-core/src/processing/ 终点检测、光谱重建、泵校准
TController/crates/controller-core/src/workflow.rs 滴定工作流与泵控状态机
TController/app/src-tauri/ 后端状态快照、命令和持久化
TController/app/ui-next/ Next.js 仪器工作台

技术栈

组件 技术
UI 框架 Tauri 2 + Next.js
状态管理 Rust backend snapshot + Zustand 视图缓存
数值计算 Rust ndarray / ndarray-npy
串口通信 Rust serialport

运行方式

cd TController/app/src-tauri
cargo tauri dev       # 自动启动 Next.js 开发服务器
cargo tauri build     # 自动执行 Next.js 静态导出并打包 Tauri 应用

单独验证前端时,可在 TController/app/ui-next 下运行 npm run buildnpm run lint。浏览器直接访问 Next 开发服务器时使用显式 mock adapter,真实 Tauri 环境始终以 Rust backend snapshot 为状态源。

应用图标

TController/app/src-tauri/icons/ 下的 PNG 与 ICO 由 scripts/gen_app_icons.mjs 从同目录的 icon.svg 生成,产物已提交进仓库,CI 不会重新生成。换图标时改 icon.svg 后本地重跑:

cd TController/app/ui-next && npm ci   # 脚本复用前端的 sharp
cd ../../.. && node scripts/gen_app_icons.mjs

bundle.icon 必须至少包含一个正方形 PNG:tauri-bundler 的 Linux 分支会跳过非 PNG 图标,而 AppImage 打包器在找不到正方形 PNG 时会直接 panic。macOS 不需要额外准备 .icns;列表里没有 .icns 时,打包器会把这些 PNG 合成为 ICNS。

持续集成与发布

.github/workflows/build.yml 在推送到任意分支、提交 PR、以及打 RELEASE-* 标签时运行,固件与上位机各平台并行构建(fail-fast: false,单一构建目标失败不影响其他目标)。

构建目标 Runner 产物
固件 cortex-m3 ubuntu-24.04 .elf .hex.map .lst 另存为 CI 制品,不进 Release)
上位机 Windows x86_64 windows-latest .msi -setup.exe -portable.zip
上位机 Windows aarch64 windows-11-arm -setup.exe -portable.zip
上位机 Linux x86_64 ubuntu-24.04 .deb .rpm .tar.gz .AppImage
上位机 Linux aarch64 ubuntu-24.04-arm .deb .rpm .tar.gz .AppImage
上位机 macOS aarch64 macos-15 .dmg .app.zip
上位机 macOS x86_64 macos-15-intel .dmg .app.zip

六个上位机构建目标都跑在原生架构的 runner 上,不做交叉编译。Tauri 的 AppImage、MSI、DMG 打包器都无法跨架构工作。

发布时推 RELEASE-* 标签:所有构建成功后,release job 汇总全部产物、生成 SHA256SUMS 并创建 GitHub Release。任一平台失败则不发布,避免出现只覆盖部分平台的 Release。

已知约束:

  • Windows aarch64 只出 NSIS。WiX v3 的 arm64 支持没在 Windows on ARM 上验证过,Tauri 官方也只保证 NSIS 支持 ARM64。
  • .tar.gz 由 CI 自己打。Tauri 没有 tar.gz 目标,CI 把 .deb 的文件树解出来重新打包,内容与 deb 一致,安装方式是 sudo tar -xzf TController_*.tar.gz -C /(依赖需自行安装)。
  • Linux 产物的 glibc 下限是 2.39(Ubuntu 24.04 及更新)。选 24.04:22.04 镜像从 2026-09-17 起进入弃用期;若要支持更老的发行版需换回 22.04 或改用容器构建。
  • macOS 下限压到 10.13 (High Sierra),由 bundle.macOS.minimumSystemVersion 设定,同时写入 LSMinimumSystemVersionMACOSX_DEPLOYMENT_TARGET。这是当前工具链能压到的最低值:Apple 的 SDK 支持表里 Xcode 16.x 支持的 deployment target 是 macOS 10.13–15(Xcode 27 起抬到 12.0),Tauri 打包器的默认下限也是 10.13。所以 macOS 的两个构建目标都固定用 macos-15(Xcode 16.x),不用 macos-latest。 注意 Tauri 官方在 Prerequisites 页只声明支持 macOS 10.15 (Catalina) 及以上,10.13 / 10.14 属于工具链允许但上游未验证的区间。若实测在 10.13/10.14 起不来,把 minimumSystemVersion 改成 "10.15" 即可;Apple Silicon 机型本身最低就是 11.0,不受影响。
  • macOS 产物未签名、未公证。仓库没有配置 Apple 开发者证书,Tauri 只在设置了 APPLE_CERTIFICATE 时才签名。用户首次打开需右键「打开」,或执行 xattr -dr com.apple.quarantine /Applications/TController.app。要启用签名就给 workflow 加上 APPLE_CERTIFICATE / APPLE_CERTIFICATE_PASSWORD / APPLE_SIGNING_IDENTITY 等 secret。

注意事项

  • 无 HAL / 无标准库:所有外设寄存器通过自定义抽象层直接访问。
  • 堆内存new / delete 默认触发死循环;如需动态分配请在 Startup/CXXStubs.cpp 中实现。
  • 静态构造.init_arraymain() 之前由 Reset_Handler 调用,支持全局 C++ 对象的构造函数。

授权

本项目采用 PolyForm Shield 1.0.0 授权。

  • 允许个人学习、研究、内部使用
  • 禁止将本软件或其衍生品作为竞争产品提供
  • 分发时必须附带本许可证全文或其 URL

About

开源的多模态自动滴定装置

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages