1 项目任务介绍
1.1 任务背景
本项目围绕ADMT4000多圈绝对角度传感器展开,通过SPI通信接口实时读取传感器的单圈角度、多圈角度及累计圈数,并通过串口输出验证其在断电条件下的数据保持能力。
1.2 任务目标
序号 | 任务目标 | 说明 |
1 | SPI 通信实现 | 通过 bitbangio 软件模拟 SPI 读取 ADMT4000 寄存器数据 |
2 | 实时数据读取 | 读取单圈角度(ANGLE 寄存器)和多圈角度+圈数(ABSANGLE 寄存器) |
3 | 串口数据打印 | 实时输出当前圈数、绝对角度、单圈角度 |
4 | 断电数据保持测试 | 手动旋转至任意位置后断电,重新上电验证数据一致性 |
5 | 断电转动记忆测试 | 断电期间手动转动传感器,上电后验证角度记录功能 |
2 项目描述
2.1 项目概述
本项目设计了一套基于ADMT4000多圈绝对角度传感器的实时角度监测系统。系统以ESP32开发板为主控,通过SPI协议与传感器通信,实时采集并显示传感器的单圈角度值和多圈累计圈数。同时,系统验证了 ADMT4000传感器的非易失性数据存储特性,测试了断电前后数据一致性以及断电期间转动角度的记忆能力。
3 硬件介绍
3.1 主控板 — Adafruit ESP32-S3
这个开发板带有原生USB和4mb闪存+ 2mb PSRAM,非常适合与CircuitPython开发。原生USB意味着它可以像键盘或磁盘驱动器一样工作。WiFi意味着它对物联网项目来说非常棒。ESP32-S3是一款高度集成、低功耗、2.4 GHz Wi-Fi/BLE片上系统(SoC)解决方案,内置本地USB以及其他一些有趣的新技术。凭借其最先进的功率和射频性能,该SoC是与物联网(IoT),可穿戴电子产品和智能家居相关的各种应用场景的理想选择。
3.2 角度传感器 — ADMT4000
ADMT4000 是一款 多圈绝对角度传感器,能够在断电后保持位置数据,上电后立即读取当前绝对位置。
参数 | 说明 |
工作电压 | 3.3V |
通信协议 | SPI |
分辨率 | 12位(单圈4096等分) |
测量范围 | 0 ~ 46圈(0 ~ 16560°) |
数据保持 | 非易失性存储 |
时钟频率 | 最大 4 MHz |
工作温度 | -40°C ~ +85°C |
寄存器映射
寄存器 | 地址 | 功能 | 数据长度 |
CNVPAGE | 0x01 | 转换页面选择 | - |
ABSANGLE | 0x03 | 绝对角度+多圈圈数 | 16位 |
ANGLE | 0x05 | 单圈角度 | 12位 |
FAULT | 0x06 | 故障状态 | 8位 |
GENERAL | 0x10 | 通用配置 | 8位 |
3.3 硬件连接图

3.4 引脚定义
SPI 通信引脚
ESP32-S3 引脚 | ADMT4000 | 功能说明 |
D10 | CLK | SPI 时钟信号 |
D11 | MOSI | 主输出从输入数据 |
D12 | MISO | 主输入从输出数据(可选) |
A5 | CS | 片选信号,低电平有效 |
复位控制引脚(ADMT4000_RST)
XIAO 引脚 | 功能 | 说明 |
A2 | RST | 复位信号引脚 |
A3 | SHDN | 供电关断控制引脚 |
A4 | COIL_PS | 线圈电源使能引脚 |
人机交互
XIAO 引脚 | 功能 | 说明 |
BOOT | 启动按钮 | 低电平触发复位操作 |
4 方案设计
4.1 系统框图

5 软件设计
5.1 软件流程图

5.2 主程序代码结构
代码文件列表
文件名 | 功能说明 |
code.py | 主程序入口,初始化和主循环 |
ADMT4000.py | 传感器驱动类(ADMT4000、ADMT4000_RST) |
关键代码说明
SPI 初始化(code.py)
spi_admt = bitbangio.SPI(
clock=board.D10, # 模拟SPI时钟
MOSI=board.D11, # 主输出从输入
MISO=board.D12 # 主输入从输出(可选)
)
cs = board.A5 # 片选引脚
# 初始化ADMT4000
admt4000 = ADMT4000(spi_admt, cs)
使用bitbangio库模拟SPI通信,D10 作为时钟、D11 作为 MOSI、D12 作为 MISO。A5 作为片选信号。
复位控制类(ADMT4000.py)
class ADMT4000_RST:
def __init__(self, coil_ps_pin=board.A4, shdn_pin=board.A3, rst_pin=board.A2):
"""初始化复位控制引脚"""
self.coil_ps = digitalio.DigitalInOut(coil_ps_pin)
self.coil_ps.direction = digitalio.Direction.OUTPUT
self.shdn = digitalio.DigitalInOut(shdn_pin)
self.shdn.direction = digitalio.Direction.OUTPUT
self.rst = digitalio.DigitalInOut(rst_pin)
self.rst.direction = digitalio.Direction.OUTPUT
# 初始状态
self.coil_ps.value = False
self.shdn.value = True # SHDN默认高(正常工作)
self.rst.value = True # RST默认高(正常工作)
初始化三个控制引脚,设置为输出模式,初始值为正常工作状态。
复位流程
def coil_rst(self):
"""执行线圈复位流程"""
print("开始复位流程...")
# 1. RST拉低
self.rst.value = False
time.sleep(0.01)
# 2. SHDN拉高 (为线圈供电)
self.shdn.value = True
print("线圈充电中...")
time.sleep(5) # 等待5秒充电
self.shdn.value = False
# 3. COIL_PS拉高 (启动复位)
self.coil_ps.value = True
print("触发复位")
time.sleep(0.02)
# 4. COIL_PS拉低
self.coil_ps.value = False
# 5. RST拉高
self.rst.value = True
time.sleep(0.02)
print("复位完成")
寄存器读取
def read_register(self, reg_addr):
"""从指定寄存器读取数据"""
self.cs.value = False # 片选拉低
while not self.spi.try_lock():
pass # 等待SPI锁
try:
# 发送读命令:寄存器地址 | 0x01
tx = bytearray([reg_addr | 0x01, 0x00, 0x00, 0x00])
rx = bytearray(len(tx))
self.spi.write_readinto(tx, rx) # SPI传输
finally:
self.spi.unlock()
self.cs.value = True # 片选拉高
# 解析返回数据
Data1 = rx[1] << 8
Data1 |= rx[2]
return int(Data1)
读取寄存器时,发送字节的第一个 bit 必须为 1(表示读操作),后 7 bit 为寄存器地址。
绝对角度解析
def read_absolute_angle(self):
"""读取绝对角度和旋转计数"""
abs_angle_data = self.read_register(self.ABSANGLE)
# 解析数据
turn_count = (abs_angle_data >> 8) / 4 # 高8位/4 = 圈数
angle = (abs_angle_data & 0x3ff) * 0.351 # 低10位 × 0.351°
return angle, turn_count
ABSANGLE 寄存器返回 16 位数据,高 8 位表示累计圈数(需除以 4),低 10 位表示当前圈的细分数(乘以 0.351° 得到角度值)。
按键检测与主循环
# 初始化启动按钮
boot_btn = digitalio.DigitalInOut(board.BOOT)
boot_btn.switch_to_input(pull=digitalio.Pull.UP)
reset_in_progress = False
while True:
# 检测启动按钮按下 (低电平触发)
if not boot_btn.value and not reset_in_progress:
reset_in_progress = True
admt_rst.coil_rst()
reset_in_progress = False
# 读取并打印角度数据
ABSangle, turn_count = admt4000.read_absolute_angle()
angle = admt4000.read_angle()
print(f"Abs Angle: {ABSangle:.0f}°, Turn Count: {turn_count}")
print(f"Angle: {angle:.0f}°")
time.sleep(1)
6 实物演示及测试结果
数据读取测试
上电后手动旋转传感器,观察串口输出的角度变化。
单圈角度和多圈圈数读取正常,数据随旋转实时更新。
断电数据保持测试
测试方法: 旋转至特定位置后断电,重新上电观察数据。
ADMT4000 传感器具有非易失性数据存储功能,断电后数据完整保留,重新上电即可读取。
断电转动记忆测试
测试方法: 断电期间手动转动传感器,重新上电观察数据变化。
断电期间传感器的转动角度大概是180°,上电后读取的数据包含了断电期间的转动量,实现转动记忆功能。
7 遇到的难点及解决方法
复位操作失败
问题描述: 按下复位按钮后,传感器角度未能归零,复位流程执行但效果不佳。
尝试的解决方案:
方案 | 调整内容 | 测试结果 |
方案1 | 增加充电时间(2秒→5秒) | 仍未成功 |
方案2 | 调整复位引脚时序 | 效果不明显 |
方案3 | 修改 COIL_PS 脉冲宽度 | 角度有微小变化但未归零 |
经过多次软件调试和时序优化,复位功能仍未能完全实现目标。
8 心得体会
在本次项目实践中,积累了极为宝贵的经验。在软件模拟SPI通信方面,我们不仅深入探究了SPI协议的运作机制,还熟练掌握了bitbangio库的应用技巧,成功实现了通过软件手段模拟硬件通信接口的功能。对于多圈传感器数据处理,我们透彻理解了ADMT4000传感器的数据协议规范,能够精准解析16位寄存器数据,并掌握了单圈角度与多圈累计圈数的精确计算方法。