ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AS5600磁编码器IIC读取详解:从选型到滤波标定的完整实践

AS5600磁编码器IIC读取详解:从选型到滤波标定的完整实践 简介AS5600磁编码器获取角度IIC方式的简单应用是一份面向嵌入式初学者的STM32实战资料。它演示了如何通过IIC通信读取磁编码器的绝对角度并区分正转与反转适用于电机转速测量、云台角度反馈、机器人关节位置检测等场景。资源总共包含5个文件压缩包大小约780KB里面既有AS5600的数据手册PDF也有C语言源文件和头文件还有正转和反转两张运行效果图方便边看代码边对照波形或现象。目前已有1699人学习浏览适合正在学习IIC协议、STM32外设驱动或需要快速集成非接触式磁旋转传感器到项目的开发者。通过学习这份代码可以掌握AS5600高低字节读取、零点与量程写入、DIR引脚控制旋转方向等具体方法同时理解非易失性参数配置和智能低功耗模式的应用并可将例程直接迁移到自己的固件中为角度闭环控制或位置反馈打下基础。 如果你做过云台、机械臂关节或者任何需要角度反馈的小项目大概率会碰到同一个问题想测角度但不知道选什么传感器最省事。我去年做一台小型三自由度云台时一开始图便宜用了电位器结果电机负载一上去角度读数就在目标位置附近来回飘噪声大到完全没法做闭环。后来换成了AS5600磁编码器用IIC方式读取角度数据整个控制才算从“能读”变成了“能用”。这篇文章想把我从选型、接线、读寄存器到滤波、标定的完整过程讲清楚重点放在IIC通信相关的细节上。内容不挑开发板Arduino、STM32、ESP32都适用核心思路是一样的。1. 选型电位器、磁编码器和AS5600到底差异在哪1.1 电位器为什么在闭环项目里容易翻车电位器是最便宜的角度传感器本质是一个可变电阻分压器输出模拟电压ADC采样后换算成角度。问题在于它是接触式测量电刷在电阻体上滑动时间一长会磨损磨损会产生接触电阻噪声而且这种噪声是随机、突变的非常难滤波。我在云台项目里实测电位器在静态时读数波动约±5个ADC码换算成角度大约±1度。对于开环手动控制无所谓但一接PID就完蛋微分项会被噪声激励电机在目标位置附近嗡嗡响。后来我明白一个道理噪声不是滤波能完全解决的物理层面的非接触测量才是治本方案。1.2 磁编码器的工作原理AS5600这种磁编码器内部有一组霍尔传感器阵列芯片正上方放一个径向充磁的圆盘磁铁磁铁旋转时芯片内部能检测到磁场方向的变化通过内部计算还原出0°到360°的角度。这个方案是纯非接触的没有机械磨损磁铁和芯片之间允许一定间隙安装容错率比电位器高一个量级。AS5600输出的分辨率是12位也就是一圈能分辨4096份换算成分辨率约0.088度对大多数云台、机械臂关节、舵机反馈来说完全够用。1.3 AS5600与AS5047P的取舍可能有人会问AS5047P是14位分辨率16384份精度更高为什么不用它我也对比过AS5047P贵不少而且它主打的ABI增量输出和UVW换相信号对无刷FOC很有用但我只是要一个绝对角度反馈IIC读寄存器就够了。另外AS5600还支持PWM输出和模拟输出省资源。最后我选它就是因为12位分辨率够用、IIC接口成熟、成本低、单芯片方案不需要编码器码盘。关键是我手里正好有径向充磁的磁铁几块钱包邮一大包。下面这张表基本就是我当时选型时列出来的对比对比项电位器AS5600AS5047P测量方式接触式非接触磁感应非接触磁感应分辨率取决于ADC位数12bit / 409614bit / 16384输出接口模拟电压IIC / SPI / PWM / 模拟SPI / ABI / UVW / PWM是否怕污染怕电刷易磨损不怕只测磁场不怕价格区间几毛钱十几块钱几十块钱适合场景开环手动指示云台/关节/机器人闭环电机FOC控制2. IIC接线中的上拉电阻、电源滤波和地址问题2.1 引脚接线到底怎么接AS5600 IIC方式下总共只需要四根线VCC、GND、SCL、SDA。常见模块会把引脚引出来有的还会带OUT模拟/PWM输出和DIR方向控制。我自己的接法是VCC接3.3VGND共地SCL和SDA分别接MCU的IIC引脚。DIR引脚不用接悬空或者根据模块默认状态处理。这里有一个容易踩的坑AS5600的供电范围是2.7V到5.5V但IIC上拉电平取决于模块上的设计如果你用5V给模块供电模块上的上拉电阻可能已经拉到5V这时MCU如果是3.3V的IO可能会存在电平不匹配风险。稳妥做法是先看模块原理图确定上拉是接到VCC还是3.3V再用逻辑分析仪确认SCL/SDA高电平是3.3V还是5V。2.2 上拉电阻为什么必须有以及怎么取IIC总线的通信原理是开漏输出也就是说芯片只能把SCL/SDA拉低不能主动拉高。高电平全靠上拉电阻把总线拽到VCC。如果没有上拉电阻总线会一直卡在低电平通信直接失败。所以问题不是“要不要上拉”而是“上拉多大”。这个和IIC速率、总线电容、总线上挂几个设备都有关系。IIC标准里对信号上升时间有要求标准模式100kHz要求上升沿不超过1000ns快速模式400kHz要求不超过300ns。上升时间太大信号沿太缓从机可能采样不到正确电平就会出现偶发通信错误。上拉电阻的估算公式是上升时间约等于0.8倍的RC其中C是总线电容包括芯片引脚电容、走线寄生电容。以400kHz为例如果总线电容为200pF取R1kΩ时间常数约200ns还不够想更稳就取R1kΩ再配短走线。如果只需要100kHz总线电容又不高4.7k甚至10k都能用。我实际项目里的经验是3.3V系统、MCU和模块近距离连接用4.7k很稳如果总线速度降到100kHz10k也可以。前提是模块上没有额外的上拉电阻如果模块出厂已经焊了上拉你再加一个并联上拉等效电阻会变小拉低电平时的灌电流变大长期跑可能影响器件寿命。所以在用模块之前先查清楚模块上有没有自带上拉。一个实际案例我一次测试中SCL/SDA没有接上拉电阻代码写了半天逻辑分析仪一看波形SCL高电平只有0.8V一直识别不出来这就是经典的上拉缺失问题。加了2.2k上拉之后波形立刻正常。2.3 地址和总线冲突问题AS5600在IIC总线上默认7位地址是0x36读地址是0x6D写地址是0x6C。IIC标准地址空间有128个地址如果总线上只有这一台设备还好但如果你想把两个AS5600挂到同一条总线上问题就来了——它们默认地址相同会冲突。这里有个细节不同批次的AS5600模块可能已经把地址改过建议每次拿到模块先用IIC扫描程序把地址扫一遍不要想当然。我吃过这个亏焊好板子才发现模块地址不是默认的0x36而是0x39最后查原理图才知道该模块的地址配置引脚被拉高了。如果要多路角度采集最省事的方式是加IIC多路选择器或者直接换其他带地址引脚的磁编码器型号。3. 读角度寄存器写指针、重复起始的完整流程与代码3.1 要读哪个寄存器、为什么读它AS5600内部有十几个寄存器但IIC方式读角度最常用的就两个寄存器地址名称说明0x0CANGLE 高字节12位角度的高8位0x0DANGLE 低字节12位角度的低4位高4位有效0x0BAGC自动增益控制可用来判断磁场强度0x0C和0x0D拼起来是一个16位数据但只用低12位数值范围是0到4095直接对应0°到360°。手册里还有一个0x0E/0x0F的寄存器是配置过零点偏移之后的角度我建议如果你做项目直接用0x0C/0x0D读原始角度零点偏移用软件自己处理。这样后期调试方向、改零点都不用烧录EEPROM代码里改个变量就行。之所以推荐软件处理零点是因为AS5600的EEPROM写操作不是无限次数的反复烧录有写坏风险。把零点偏移放在代码里想改就改编译烧录完事方便太多。3.2 IIC读取的时序细节IIC读一个指定寄存器标准流程是主机发送启动信号发送从机地址加写位0x36 1 | 0也就是0x6C发送寄存器指针比如0x0C发送重复起始信号Repeated Start这一步很关键发送从机地址加读位0x36 1 | 1也就是0x6D读取高字节读取低字节主机发送停止信号我特意说一下第4步为什么用重复起始而不是停止再启动如果在多设备总线上先发停止信号总线就释放了别的设备可能趁这个间隙发起传输你的读操作指针可能被别人打断。重复起始信号在同一个事务里完成“写指针”和“读数据”不会被其他设备插队。这个细节在实时性要求高的控制系统里很重要同时也是排查通信随机错乱时的一个重点检查项。3.3 Arduino示例代码下面这段代码是我在Arduino上用的核心读取函数直接读0x0C和0x0D换算成浮点角度#include Wire.h #define AS5600_ADDR 0x36 // 7位地址 void setup() { Wire.begin(); Wire.setClock(400000); // 400kHz快速模式 Serial.begin(115200); checkMagnet(); } uint16_t readRawAngle() { Wire.beginTransmission(AS5600_ADDR); Wire.write(0x0C); // 写寄存器指针 Wire.endTransmission(false); // 发重复起始不释放总线 Wire.requestFrom(AS5600_ADDR, 2); if (Wire.available() 2) { uint8_t hi Wire.read(); uint8_t lo Wire.read(); return ((uint16_t)hi 8) | lo; // 低12位有效 } return 0; } void loop() { uint16_t raw readRawAngle(); float angle (raw / 4096.0f) * 360.0f; // 换算成角度 Serial.println(angle, 2); delay(10); } void checkMagnet() { Wire.beginTransmission(AS5600_ADDR); Wire.write(0x0B); // AGC寄存器 Wire.endTransmission(false); Wire.requestFrom(AS5600_ADDR, 1); if (Wire.available()) { uint8_t agc Wire.read(); Serial.print(AGC); Serial.println(agc); } }有几个细节我想特别强调Wire.endTransmission(false)这个参数很多人忽略如果不传false库会在发送完寄存器指针后发一个停止信号然后requestFrom再重新启动总线。虽然大多数情况也能工作但和重复起始的时序有微妙差别在400kHz高速模式下建议显式传false。Wire.setClock(400000)把IIC频率切到快速模式。如果你的项目对速率要求不高100kHz也可以但上拉电阻值需要匹配速率高速率配上拉过大就会出问题。读出来的16位数一定要用 0x0FFF取低12位。因为0x0D寄存器的高4位是无效的不带掩码直接当16位处理角度值会多出好几倍这是新手最容易犯错的地方。4. 实测数据的抖动、跳变与滤波方案4.1 症状一数据随机跳变怎么定位AS5600接好之后我第一版代码读出来的角度大部分时间很正常但偶尔会跳一下跳的幅度很大甚至能跳到几百上千的raw值。这种随机跳变通常不是传感器本身精度问题而是IIC通信层面的问题。定位方法就是拿逻辑分析仪抓SCL和SDA波形。我抓到的问题是SCL信号上升沿很慢高电平持续时间不够稳定导致从机偶尔误判数据位。原因正是上拉电阻取太大加上杜邦线比较长总线电容偏大。解决办法是把上拉电阻从10k换到2.2k重新量波形上升沿立刻变陡跳变现象消失。还有一个容易忽视的干扰来源电机。云台电机转动时电流变化大如果电源没有做好滤波电源纹波会耦合到IIC信号上。一定要在AS5600模块的VCC和GND之间加一个100nF陶瓷电容和一个10uF电解电容这属于便宜但效果极好的习惯。4.2 症状二低几位抖动不要算故障还有一种情况是角度在静态时raw值的最低两位不停跳比如1350跳到1351再跳回1350。这是很正常的12位分辨率本来就有量化噪声加上外界磁场微弱波动低两位抖动是常态。这时候不要急着加高大上的滤波算法先分清噪声的量级如果抖动只在几个LSB以内一阶低通滤波就够了如果抖动范围达到几十个LSB那要回到通信和电源上下功夫。4.3 滤波方案对比针对角度数据我试过三种滤波方案原理优点缺点适用场景滑动平均值取最近N次平均值平滑度高简单有滞后N越大滞后越大静态角度测量中值滤波取N次排序中间值能剔除突发毛刺样本越大计算越慢偶尔跳变的场景一阶低通新值α×原始(1-α)×旧值实时性好滞后可调α难调调不好有拖影动态闭环控制我的推荐是做闭环控制首选一阶低通代码简单实时性足够好。下面是实际用的代码片段float alpha 0.3; float filteredAngle 0; bool hasLastAngle false; void loop() { uint16_t raw readRawAngle(); float angle (raw / 4096.0f) * 360.0f; if (!hasLastAngle) { filteredAngle angle; hasLastAngle true; } else { // 处理跨零点的角度回绕 float diff angle - filteredAngle; if (diff 180.0f) diff - 360.0f; if (diff -180.0f) diff 360.0f; filteredAngle alpha * diff; } // 如果不需要跨零点处理直接用下面这行 // filteredAngle alpha * angle (1 - alpha) * filteredAngle; Serial.println(filteredAngle, 2); delay(5); }这里有一个很多教程不会提的坑角度值是0°到360°循环的如果上一个滤波值是359°最新值是1°直接做平均会算出180°完全错误。处理循环量必须先算差值再把差值限制在-180°到180°之间否则滤波越滤越乱。上面的代码就是对这个问题做的针对性处理。5. 安装标定和闭环控制中的实战经验5.1 安装误差从哪来AS5600虽然是非接触测量但它的精度高度依赖磁铁安装质量。最典型的问题有三个磁铁没有贴芯片正中心、磁铁表面和芯片平面不平行、磁铁和芯片之间的距离太远导致磁场强度不足。这些问题最终表现为角度读数不是均匀的比如转动90°读出来的变化可能是85°转到180°时偏差更大。这不是传感器坏了而是磁场本身变形了。判断磁场强度是否合适最直接的方法就是读AGC寄存器也就是0x0B。AGC数值的含义是芯片自动增益控制值正常范围是64到128之间具体和芯片批次有关。我自己的经验如果读出来AGC大于某个明显偏大的阈值说明磁场太弱要把磁铁移近一点如果AGC太小说明磁场太强可能进入饱和区反而也会影响线性度。5.2 软件标定的快速做法如果是要求不高的项目可以不做硬件上的精确对准而是用软件标定。最基础的两步标定法是把轴转到机械0°读角度值记为offset0这个值以后就是软件零点偏移把轴转到机械90°读角度值记为angle90用这个值校准整个量程的比例因子实际计算时校准后的角度可以近似为compensated (raw - offset0) * 90.0f / (angle_raw_at_90 - offset0)。如果要求更高可以做多点标定比如每45°一个采样点形成一张补偿查找表运行时对读数做插值。这个方法能有效修正安装偏心带来的非线性误差。我不太建议上来就烧录ZPOS寄存器做硬件零点因为EEPROM写次数有限而且标定数据想改就得重新烧录。项目开发阶段用软件标定最灵活产品定型后再根据需求决定要不要固化成EEPROM配置。5.3 闭环控制中使用AS5600的建议我最终在云台上用IIC方式以大约1kHz的循环频率运行PID控制角度反馈就是AS5600。实际跑下来几个关键体会和提示磁编码器的最大优点是没有机械回程间隙换向时角度读数不会出现电位器那种滞回。这在对云台方向反转控制时极其舒服。读角度不要用Wire.requestFrom加上大delay的方式尽量在控制循环里每周期都读一次用中断或定时器固定循环频率。如果控制频率要求更高比如电机FOC需要好几kHz的角度反馈IIC可能成为瓶颈这时AS5600的SPI模式更有优势。IIC适合100Hz到1kHz量级的控制场合超过这个范围建议考虑SPI。AS5600输出的是单圈绝对角度不能直接当多圈编码器用。如果你的项目需要记录电机转了几圈要么自己在代码里做多圈计数要么换带ABI增量输出的型号。最后再分享一个排查经验如果AS5600读出来的角度在某几个位置总是不稳定最先怀疑的是磁铁安装偏心而不是芯片坏了。把磁铁的轴心对准芯片中心点用游标卡尺或治具确认再重新读AGC问题往往就消失了。硬件安装偏差是磁编码器项目里最常见的“慢性病”它的表现不像通信故障那么明显但会影响整个系统的角度精度。本文还有配套的精品资源点击获取
返回列表