Funpack4-3: 基于admt4000的绝对定位功能
该项目使用了admt4000磁编码器,m1w dock 开发板,实现了绝对定位功能的设计,它的主要功能为:通过SPI获取角度数据,并通过LCD展示角度数据。
标签
Funpack活动
磁编码器
ADMT4000
clr
更新2026-02-09
17

一、 项目介绍

ADMT4000 是 Analog Devices(ADI)公司推出的一款高性能磁性多圈位置传感器,具备"true power-on multiturn"功能,能够在断电状态下记录旋转圈数信息,重新上电后继续读取绝对角度位置(最多46圈)。该传感器精度高达±0.25°,可以应用于工业执行器、定位系统和机械臂关节位置检测等高精度应用场景。


项目目标:

  1. 完成ADMT4000传感器电路板和测试结构的设计与实现
  2. 基于Sipeed M1w Dock开发板实现旋转圈数和角度数据的读取
  3. 在LCD屏幕上实时显示传感器数据结果



二. 设计思路

根据 admt4000 的官方数据手册设计原理图,引出所有接口便于测试,在42步进电机底部居中放置径向磁铁,确保磁场强度在ADMT4000推荐范围内。

image.png


admt4000 的连续采样速率固定为 1ksps,可以通过监听 ACALC 引脚,在上升沿触发数据获取。

image.png


M1w Dock 开发板初始化SPI接口和LCD屏幕,在LCD上显示识别结果


软件流程图:

admt4000.png


三、实现过程

1 CRC5校验算法

基于ADMT4000数据手册标准实现,确保26位数据传输的完整性:

def calc_admt_crc5(bits_val, length=26):
"""
ADMT4000专用CRC5校验算法
参数:
bits_val: 包含校验位的整数值
length: 校验位数(默认26位)
返回:
5位CRC校验值
"""
crc = 0x1F # 初始种子值
for i in range(length - 1, -1, -1):
bit_in = (bits_val >> i) & 0x01
shft4 = (crc >> 4) & 0x01
xor_0 = bit_in ^ shft4

# LFSR移位逻辑
b3 = (crc >> 3) & 0x01
b2 = (crc >> 2) & 0x01
b1 = (crc >> 1) & 0x01
b0 = (crc >> 0) & 0x01

new_b4 = b3
new_b3 = b2
new_b2 = b1 ^ xor_0
new_b1 = b0
new_b0 = xor_0

crc = (new_b4 << 4) | (new_b3 << 3) | (new_b2 << 2) | (new_b1 << 1) | new_b0

return crc & 0x1F


2 数据解析算法

多圈绝对角度解析(寄存器0x03):

def parse_0x03_absangle(raw_val):
"""
解析绝对角度和多圈数据
位分配:
Bit 15-10: 圈数数据(6位,补码表示)
Bit 9-0: 角度数据(10位,0.351°/LSB
"""
turns_raw = (raw_val >> 10) & 0x3F

if turns_raw == 0b110110: # 无效数据标志
return "INV", 0, True
elif turns_raw >= 0b110111: # 负数(补码)
turn_count = turns_raw - 64
turn_str = "{:+d}".format(turn_count)
else: # 正数
turn_count = turns_raw
turn_str = "{:+d}".format(turn_count)

angle_bits = raw_val & 0x3FF
angle_val = angle_bits * 0.351 # 转换为角度值

return turn_str, angle_val, False


单圈角度解析(寄存器0x05)


def parse_0x05_angle(raw_val):
"""
解析单圈角度数据
12位分辨率,直接映射到0-360°
"""
return (raw_val >> 4) / 4096 * 360.0


3 寄存器读取

读取 admt4000 寄存器数据,并进行 CRC 校验

def read_admt_register(addr_6bit):
"""
读取 ADMT4000 寄存器
addr_6bit: 6位地址 (例如 0x03 或 0x05)
"""
# 1. 构造发送命令字节
# Bit 7: 0 (Discard)
# Bit 6: 0 (0 = Read, 1 = write)
# Bit 5-0: Address
cmd_byte = (addr_6bit & 0x3F) # 0x00 | addr

# 2. SPI 通信
cs.value(0)
# 发送命令
spi.write(bytes([cmd_byte]))
# 读取数据 (假设读取3个字节: DataH, DataL, Status+CRC)
# 16位数据 + 3位状态 + 5位CRC = 24位 = 3字节
recv_bytes = spi.read(3)
cs.value(1)

if not recv_bytes or len(recv_bytes) < 3:
return None, "Err: No Data"

# 3. 解析接收到的数据
# 假设接收顺序: [Byte0: Data15-8] [Byte1: Data7-0] [Byte2: Status(3) + CRC(5)]

raw_val_16 = (recv_bytes[0] << 8) | recv_bytes[1]
status_crc_byte = recv_bytes[2]

# 提取接收到的 CRC (假设在最后5位)
recv_crc = status_crc_byte & 0x1F

# 提取状态位 (假设在 CRC 之前的 3 位)
status_bits = (status_crc_byte >> 5) & 0x07

# 4. 准备 CRC 校验数据
# 手册说明 CRC 覆盖 26 位:
# SPI Read: Rb/W bit(1) + Address(6) + Data(16) + Fault/Count(3)

# 构造用于校验的大整数 (共 26 bits)
# [Bit 25]: R/W (0)
# [Bit 24-19]: Address (6 bits)
# [Bit 18-3]: Data (16 bits)
# [Bit 2-0]: Status (3 bits)

crc_payload = 0
crc_payload |= (0 & 0x01) << 25 # R/W 位 (读=0)
crc_payload |= (addr_6bit & 0x3F) << 19 # 地址位
crc_payload |= (raw_val_16 & 0xFFFF) << 3 # 16位数据
crc_payload |= (status_bits & 0x07) # 3位状态

# 5. 计算本地 CRC
calc_crc = calc_admt_crc5(crc_payload, length=26)

is_valid = (calc_crc == recv_crc)

return raw_val_16, is_valid, recv_bytes


4 LCD 数据显示

构建数据显示布局,通过 scale 功能突出显示数据

    # 绘制背景 (仅清除数据区域可以更快,这里为了简单全屏清)
img.draw_rectangle(0, 0, 320, 240, fill=True, color=C_BG)

# 标题
img.draw_string(10, 10, "ADMT4000 Monitor", color=C_BLU, scale=2)

# ---------------- 处理 0x03 (Abs Angle) ----------------
raw_03, crc_03, bytes_03 = read_admt_register(0x03)
turns_str, sub_angle, turns_inv = parse_0x03_absangle(raw_03)

# 显示标签
img.draw_string(10, 50, "Reg 0x03 (Multi-Turn):", color=C_TEXT, scale=1.5)

# 显示原始 HEX (固定宽度 {:02X} 避免抖动)
hex_s = "{:02X} {:02X} {:02X}".format(bytes_03[0], bytes_03[1], bytes_03[2])
img.draw_string(10, 75, "Raw: " + hex_s, color=(100,100,100), scale=1.2)

# 显示 CRC 状态
crc_str = "[CRC OK]" if crc_03 else "[CRC ERR]"
img.draw_string(220, 75, crc_str, color=(C_GRN if crc_03 else C_RED), scale=1.2)

# 显示解析数值 (使用定长格式化)
if turns_inv:
t_disp = "Turns: Invalid"
else:
# {:>3} 右对齐占3
t_disp = "Turns: {:>4}".format(turns_str)

# {:6.2f} 总宽6位(含小数点)2位小数,不够补空格 -> 解决抖动
a_disp = "Angle: {:6.2f}".format(sub_angle)

img.draw_string(10, 95, t_disp, color=C_TEXT, scale=1.5)
img.draw_string(160, 95, a_disp, color=C_TEXT, scale=1.5)

# ---------------- 处理 0x05 (Angle) ----------------
raw_05, crc_05, bytes_05 = read_admt_register(0x05)
deg_05 = parse_0x05_angle(raw_05)

img.draw_string(10, 140, "Reg 0x05 (Single-Turn):", color=C_TEXT, scale=1.5)

hex_s5 = "{:02X} {:02X} {:02X}".format(bytes_05[0], bytes_05[1], bytes_05[2])
img.draw_string(10, 165, "Raw: " + hex_s5, color=(100,100,100), scale=1.2)

crc_str5 = "[CRC OK]" if crc_05 else "[CRC ERR]"
img.draw_string(220, 165, crc_str5, color=(C_GRN if crc_05 else C_RED), scale=1.2)

# 显示大字体角度
# {:0>7.3f} -> 补0总宽7位 (012.345) 或者 {:7.3f} 补空格
deg_str = "{:7.3f} deg".format(deg_05)
img.draw_string(10, 190, deg_str, color=C_BLU, scale=2.5) # 大字体
# ---------------- 刷新 LCD ----------------
lcd.display(img)


四、实现效果

能够正确读取角度数据

image.png

image.png



附件下载
admt4000.py
程序
ProDoc_Board2_2026-01-08.epro2
PCB
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号