AS5600磁编码器接ESP32,四根线读出0到360度

2026-11-02 20:08:45 9阅读

AS5600磁编码器芯片

给舵机或者云台加角度反馈,很多人第一反应是电位器,但电位器有机械磨损,转久了还会漂。ams OSRAM的AS5600是一颗非接触磁编码器,靠霍尔阵列感应磁铁方向读出绝对角度,掉电再上电也知道自己在几度。它I2C接口直出,模块十几块钱,接ESP32只用四根线,这篇把接线、代码和踩坑一次讲完。

先认识这颗芯片:12位、0x36、无接触

AS5600是12位磁角度编码器,一圈4096个位置,换算下来每步约0.088度,量程覆盖完整0到360度。它出厂I2C地址固定为0x36,datasheet里RAW ANGLE寄存器在0x0C,读两个字节再乘个比例就是度数。芯片是霍尔原理,转轴上贴一颗径向充磁的小圆磁铁就行,没有机械接触,理论上不存在磨损问题。

除了I2C,它还有OUT脚输出模拟或PWM角度信号,接没有I2C的主控也能用。不过做机器人反馈一般走I2C,精度和读取稳定性都更好。选模块时注意认准带VCC、GND、OUT、DIR、SCL、SDA、GPO七个引脚的常见版本。

AS5600引脚定义图

接线:四根信号线加一根DIR拉地

ESP32 DevKit上最省事的接法是走默认I2C引脚:VCC接3V3,GND接GND,SDA接GPIO21,SCL接GPIO22。DIR这个脚很多人直接悬空,这是错的——悬空时角度增减方向不确定,读数会莫名其妙反向。把DIR接GND,角度就固定为顺时针增加,行为可预期。

VCC一定要接3.3V而不是5V。模块标称3.0到5.5V都能吃,但它的I2C上拉电阻是拉到供电电压的,接5V就意味着SDA和SCL会被拉到5V,而ESP32的GPIO不耐5V,时间长了伤芯片。OUT和GPO走I2C时用不上,悬空即可。

AS5600模块ESP32 DevKit说明
VCC3V3上拉随供电,必须3.3V
GNDGND共地
SDAGPIO21默认I2C数据脚
SCLGPIO22默认I2C时钟脚
DIRGND顺时针为正方向,别悬空
OUT、GPO不接模拟/PWM输出,走I2C时不用

如果你玩的是Arduino Uno,接法同样简单:SDA接A4,SCL接A5,Uno是5V逻辑,VCC接5V没问题,这点和ESP32正好相反。

磁铁安装:读数跳变八成是它

AS5600对磁铁有两个硬要求:一是径向(直径方向)充磁的两极圆磁铁,轴向充磁的喇叭磁铁不行,磁场方向必须是横着穿过芯片的;二是磁铁圆心要对准芯片中心,悬在芯片正上方。常见套件配的是直径4到6毫米、厚2.5毫米左右的钕磁铁,距离芯片2到3毫米效果比较稳。

贴偏了、离太远或者离太近,读数会在某个区间跳变。好在芯片自带状态自检:STATUS寄存器(0x0B)里有三个标志位,分别表示磁铁已检测到、磁场太弱、磁场太强。上电后先读这个寄存器调磁铁位置,调到只报检测到、不带弱强告警,机械安装就算过关了。

AS5600模块与圆磁铁

代码:不装库,直接读寄存器

官方寄存器表很清楚:I2C地址0x36,STATUS在0x0B,RAW ANGLE从0x0C开始占两个字节。下面这段代码按寄存器直接读,不用装任何第三方库,原始值乘360除以4096就是度数,编译环境为ESP32 Arduino core(写稿时对esp32:esp32:esp32板型验证过编译通过):

// AS5600 magnetic angle sensor + ESP32 DevKit (ESP32-WROOM-32)
// Wiring: VCC -> 3V3, GND -> GND, SDA -> GPIO21, SCL -> GPIO22, DIR -> GND; OUT and GPO unconnected
#include "Wire.h"

const int SDA_PIN = 21;
const int SCL_PIN = 22;
const uint8_t AS5600_ADDR = 0x36;

uint8_t readReg8(uint8_t reg) {
  Wire.beginTransmission(AS5600_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false);
  Wire.requestFrom(AS5600_ADDR, (uint8_t)1);
  return Wire.available() ? Wire.read() : 0;
}

uint16_t readReg12(uint8_t reg) {
  Wire.beginTransmission(AS5600_ADDR);
  Wire.write(reg);
  Wire.endTransmission(false);
  Wire.requestFrom(AS5600_ADDR, (uint8_t)2);
  if (Wire.available() < 2) return 0;
  uint16_t hi = Wire.read();
  uint16_t lo = Wire.read();
  return ((hi << 8) | lo) & 0x0FFF;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(SDA_PIN, SCL_PIN);
  Wire.beginTransmission(AS5600_ADDR);
  if (Wire.endTransmission() != 0) {
    Serial.println("AS5600 not found at 0x36. Check VCC, GND, SDA and SCL.");
    while (true) delay(1000);
  }
}

void loop() {
  uint8_t status = readReg8(0x0B);
  bool md = status & 0x20;   // magnet detected
  bool ml = status & 0x10;   // magnet too weak
  bool mh = status & 0x08;   // magnet too strong
  uint16_t raw = readReg12(0x0C);
  float deg = raw * 360.0f / 4096.0f;
  Serial.printf("Angle: %6.2f deg  raw=%4u  magnet:%s%s%s\n", deg, raw,
                md ? " detected" : " NOT detected", ml ? " too weak" : "", mh ? " too strong" : "");
  delay(200);
}

烧录后打开串口监视器,波特率115200。转磁铁,度数应当跟着走一整圈;如果报AS5600 not found,先查接线,再用万用表确认模块供电是3.3V;如果报NOT detected,就是磁铁的事,回上一节调位置。

代码里有一处写法要说明:头文件用了双引号包含Wire.h,这是站点编辑器不支持尖括号头文件的兼容写法,在Arduino IDE里直接粘贴时改回 #include 完全等价,不影响编译。

AS5600内部功能框图

四个高频坑,提前避开

第一是DIR悬空,症状是角度方向时对时反,拉地即可解决。第二是VCC误接5V,模块自己没事,但ESP32的I2C脚长期吃5V有风险,换3.3V没有副作用。第三是轴向磁铁,怎么调STATUS都不报检测到,换径向充磁的圆磁铁。

第四是OTP误烧。AS5600有一段一次性可编程存储器,BURN寄存器地址0xFF,写进去就永久固化,实验阶段别碰这个寄存器。另外它的地址固定0x36,一根总线上挂不了第二颗,真要装两颗得用ESP32的第二个I2C控制器,或者一颗走I2C一颗走OUT的模拟输出。

这个方案适合做什么

十几块钱加上四根线,换回来一个0.088度分辨率的绝对角度计,性价比确实是电位器给不了的。云台指哪打哪的角度回读、舵机拆限位改连续转之后的闭环反馈、机械臂关节的位置校验,都是它的典型用法。先把串口里的度数调稳,后面的PID闭环才有地基。


作者:舵机老炮
链接:https://www.aiddithome.com/p/804925960b9fa.html
本作版权归作者所有,未经允许请勿转载。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
老张装机
1楼 · 7小时前

DIR脚这个点说得太对了,之前接了个AS5600在云台上,方向一会儿正一会儿反,查了两天才发现是悬空的问题,拉地立刻正常。STATUS寄存器自检这个也实用,比瞎调磁铁位置省事多了。

锡点
2楼 · 7小时前

四根线加一根DIR,比电位器方案香,就是磁铁要对准这个确实麻烦,我第一次贴偏了1毫米读数就跳。

拆开看看再说
3楼 · 7小时前

OTP那段提醒得好,0xFF寄存器写一次就固化,新手真容易手滑。

修啥都行二哥
4楼 · 7小时前

想问下这个和SimpleFOC里常用的磁编码器是一颗吗?看着引脚挺像