AS5600旋转磁编码器



1.引脚说明


2.读写地址

3.相关寄存器

1. ZMCO(0x00)------ 烧录次数
Bit1:0,只读。
记录 ZPOS/MPOS 已经被 BURN_ANGLE 永久烧录过几次。
最多 3 次,所以该字段最大值为 3。
2.ZPOS(0x01-0x02)------ 零位/起始角
12 位,分成高 4 位(0x01 的低 4 位)+ 低 8 位(0x02)。
定义角度的起始位置,即输出为 0 时对应的机械角度。
默认值 0(0°)。
3. MPOS(0x03-0x04)------ 最大角/终止角
12 位,格式同 ZPOS。
定义角度的终止位置,与 ZPOS 一起限定有效角度范围。
默认值 4095(360°)。
4. MANG(0x05-0x06)------ 最大角度范围
12 位,格式同 ZPOS。
直接设定角度范围的大小(而不是终点位置)。
只能在没有烧录过 ZPOS/MPOS 时烧录(ZMCO=00)。
范围必须 > 18°。
ZPOS/MPOS 与 MANG 的区别:
ZPOS+MPOS = 指定起点和终点。
ZPOS+MANG = 指定起点和范围大小。
两种方式二选一,不要混用。
5. CONF(0x07-0x08)------ 配置寄存器(重点)
这是最核心的配置寄存器,按位段划分:
位段 名称 功能 取值
1:0 PM 功耗模式 00=NOM, 01=LPM1, 10=LPM2, 11=LPM3
3:2 HYST 迟滞 00=关, 01=1LSB, 10=2LSB, 11=3LSB
5:4 OUTS 输出模式 00=模拟全量程, 01=模拟10%~90%, 10=PWM
7:6 PWMF PWM 频率 00=115Hz, 01=230Hz, 10=460Hz, 11=920Hz
9:8 SF 慢滤波 00=16x, 01=8x, 10=4x, 11=2x
12:10 FTH 快滤波阈值 000=仅慢滤波, 001=6LSB, ... 111=10LSB
13 WD 看门狗 0=关, 1=开
注意:CONF 是 16 位,跨 0x07(高字节)和 0x08(低字节)
6. RAW ANGLE(0x0C-0x0D)------ 原始角度
12 位,未缩放、未修正的原始角度值。
反映芯片直接测量到的机械角度(0~4095 对应 0~360°)。
读这个寄存器时,地址指针不会自动递增,方便连续读取。
7. ANGLE(0x0E-0x0F)------ 缩放后角度
12 位,经过 ZPOS/MPOS/MANG 映射后的角度值。
这是最终用于输出(模拟/PWM)的角度值。
同样具有地址指针不自动递增的特性。
在 360° 边界处有 10 LSB 迟滞,防止输出在 0°/360° 附近抖动。
RAW ANGLE vs ANGLE:
RAW = 机械绝对角度,不受编程影响。
ANGLE = 应用角度,受 ZPOS/MPOS/MANG 影响。
8. STATUS(0x0B)------ 状态
位 名称 含义
5 MH AGC 最小增益溢出(磁铁太强)
4 ML AGC 最大增益溢出(磁铁太弱)
3 MD 检测到磁铁
MD=1 表示磁铁在位;烧录命令必须在 MD=1 时执行。
MH/ML 可用来判断气隙是否合适。
9. AGC(0x1A)------ 自动增益
8 位,反映内部 AGC 环路当前增益。
5V 模式范围 0~255,3.3V 模式范围 0~128。
最佳值在量程中间,可用来调整磁铁与芯片的气隙。
10. MAGNITUDE(0x1B-0x1C)------ 磁场幅值
12 位,CORDIC 计算出的磁场矢量幅值。
可用于诊断磁场强度是否合适。
11. BURN(0xFF)------ 烧录命令
只写寄存器,写入特定值触发 OTP 烧录:
写入值 命令 作用 次数限制
0x80 BURN_ANGLE 烧录 ZPOS + MPOS 最多 3 次
0x40 BURN_SETTING 烧录 MANG + CONF 只能 1 次
重要约束:
BURN_ANGLE 要求 MD=1(磁铁在位)。
BURN_SETTING 要求 ZMCO=00(ZPOS/MPOS 从未烧录过)。
烧录时供电必须稳定,5V 模式 4.5~5.5V,3.3V 模式 3.25~3.35V。
3.3V 烧录时 VDD3V3 需要外接 10µF 电容
4.相关代码
c
void Iic_Gpio_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);
}
void IIC_Start(void)
{
IIC_SDA=1;
IIC_SCL=1;
delay_us(2);
IIC_SDA=0;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
void IIC_Stop(void)
{
IIC_SCL=0;
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SDA=1;
delay_us(2);
}
u8 IIC_Wait_Ack(void)
{
u8 ucErrTime=0;
IIC_SDA=1;
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>250)
{
IIC_Stop();
return 0;
}
}
delay_us(2);
IIC_SCL=0;
delay_us(2);
return 0;
}
void IIC_Ack(void)
{
IIC_SDA=0;
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
delay_us(2);
}
void IIC_NAck(void)
{
IIC_SDA=1;
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
delay_us(2);
}
u8 IIC_Send_Byte(u8 txd)
{
u8 t;
IIC_SCL=0;
for(t=0;t<8;t++)
{
if((txd&0x80)>>7)IIC_SDA=1;
else IIC_SDA=0;
txd<<=1;
delay_us(2);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
delay_us(2);
}
return IIC_Wait_Ack();
}
u8 IIC_Read_Byte(u8 ack)
{
unsigned char i,receive=0;
IIC_SCL=0;
IIC_SDA=1;
for(i=0;i<8;i++ )
{
delay_us(2);
IIC_SCL=1;
delay_us(2);
receive<<=1;
if(READ_SDA)receive++;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
if (!ack)IIC_NAck();
else IIC_Ack();
return receive;
}
u8 I2C_Write(u8 dev_addr, u8 reg_addr,u8 *data, u8 len)
{
u8 i, result = 0;
IIC_Start();
//
result=IIC_Send_Byte(dev_addr << 1);
if(result != 0) return result;
//
result=IIC_Send_Byte(reg_addr);
if(result != 0) return result;
//
for (i=0; i<len; i++)
{
result=IIC_Send_Byte(data[i]);
if (result != 0) return result;
}
IIC_Stop();
return 0x00;
}
u8 I2C_Read(u8 dev_addr, u8 reg_addr,u8 *data, u8 len)
{
uint8_t result;
IIC_Start();
result = IIC_Send_Byte(dev_addr << 1);
if(result != 0) return result;
//
result = IIC_Send_Byte(reg_addr);
if(result != 0) return result;
//
IIC_Start();
result = IIC_Send_Byte(dev_addr << 1 | 0x01);
if(result != 0) return result;
//
while (len)
{
if (len == 1)*data = IIC_Read_Byte(0);
else *data = IIC_Read_Byte(1);
data ++;
len --;
}
IIC_Stop();
return 0x00;
}
c
#ifndef __AS5600_H
#define __AS5600_H
#include "stm32f10x.h"
/* AS5600 7位从机地址 */
#define AS5600_ADDR 0x36
/* 寄存器地址 */
#define AS5600_REG_ZMCO 0x00
#define AS5600_REG_ZPOS 0x01
#define AS5600_REG_MPOS 0x03
#define AS5600_REG_MANG 0x05
#define AS5600_REG_CONF 0x07
#define AS5600_REG_STATUS 0x0B
#define AS5600_REG_RAWANGLE 0x0C
#define AS5600_REG_ANGLE 0x0E
#define AS5600_REG_AGC 0x1A
#define AS5600_REG_MAGNITUDE 0x1B
#define AS5600_REG_BURN 0xFF
/* STATUS 位 */
#define AS5600_STATUS_MH (1 << 5)
#define AS5600_STATUS_ML (1 << 4)
#define AS5600_STATUS_MD (1 << 3)
/* CONF 位段 */
#define AS5600_PM_NOM 0x00
#define AS5600_PM_LPM1 0x01
#define AS5600_PM_LPM2 0x02
#define AS5600_PM_LPM3 0x03
#define AS5600_OUTS_ANALOG_FULL 0x00
#define AS5600_OUTS_ANALOG_REDUCE 0x01
#define AS5600_OUTS_PWM 0x02
/* 返回值 */
#define AS5600_OK 0
#define AS5600_ERR 1
/* 角度换算:12位 -> 0.1度,避免浮点 */
#define AS5600_RAW_TO_DEG(x) ((float)(x) * 360.0f / 4096.0f)
/* API */
u8 AS5600_Init(void);
u8 AS5600_GetRawAngle(u16 *angle);
u8 AS5600_GetAngle(u16 *angle);
u8 AS5600_GetStatus(u8 *status);
u8 AS5600_GetAGC(u8 *agc);
u8 AS5600_GetMagnitude(u16 *mag);
u8 AS5600_GetZMCO(u8 *zmco);
u8 AS5600_GetZPOS(u16 *zpos);
u8 AS5600_SetZPOS(u16 zpos);
u8 AS5600_GetMPOS(u16 *mpos);
u8 AS5600_SetMPOS(u16 mpos);
u8 AS5600_GetMANG(u16 *mang);
u8 AS5600_SetMANG(u16 mang);
u8 AS5600_GetCONF(u16 *conf);
u8 AS5600_SetCONF(u16 conf);
u8 AS5600_BurnAngle(void);
u8 AS5600_BurnSetting(void);
u8 AS5600_ReloadOTP(void);
#endif
c
#include "All_Header.h"
extern u8 I2C_Write(u8 dev_addr, u8 reg_addr, u8 *data, u8 len);
extern u8 I2C_Read(u8 dev_addr, u8 reg_addr, u8 *data, u8 len);
/* ------------------------------------------------------------------ */
/* 基本读写 */
/* ------------------------------------------------------------------ */
/* 写单个字节 */
static u8 AS5600_WriteByte(u8 reg, u8 data)
{
return I2C_Write(AS5600_ADDR, reg, &data, 1);
}
/* 读单个字节 */
static u8 AS5600_ReadByte(u8 reg, u8 *data)
{
return I2C_Read(AS5600_ADDR, reg, data, 1);
}
/* 读16位(大端:高字节在前,低字节在后) */
static u8 AS5600_ReadU16(u8 reg, u16 *val)
{
u8 buf[2];
if (I2C_Read(AS5600_ADDR, reg, buf, 2) != 0) return AS5600_ERR;
*val = ((u16)buf[0] << 8) | buf[1];
return AS5600_OK;
}
/* 写16位(大端) */
static u8 AS5600_WriteU16(u8 reg, u16 val)
{
u8 buf[2];
buf[0] = (u8)(val >> 8);
buf[1] = (u8)(val & 0xFF);
return I2C_Write(AS5600_ADDR, reg, buf, 2);
}
/* ------------------------------------------------------------------ */
/* 初始化:只检查通信 + 读状态 */
/* ------------------------------------------------------------------ */
u8 AS5600_Init(void)
{
u8 status = 0;
if (AS5600_GetStatus(&status) != AS5600_OK) return AS5600_ERR;
return AS5600_OK;
}
/* ------------------------------------------------------------------ */
/* 角度读取 */
/* ------------------------------------------------------------------ */
/* 读原始角度(12位,0~4095) */
u8 AS5600_GetRawAngle(u16 *angle)
{
u16 v;
if (AS5600_ReadU16(AS5600_REG_RAWANGLE, &v) != AS5600_OK) return AS5600_ERR;
*angle = v & 0x0FFF;
return AS5600_OK;
}
/* 读缩放后角度(受 ZPOS/MPOS/MANG 影响) */
u8 AS5600_GetAngle(u16 *angle)
{
u16 v;
if (AS5600_ReadU16(AS5600_REG_ANGLE, &v) != AS5600_OK) return AS5600_ERR;
*angle = v & 0x0FFF;
return AS5600_OK;
}
/* ------------------------------------------------------------------ */
/* 状态 / 诊断 */
/* ------------------------------------------------------------------ */
u8 AS5600_GetStatus(u8 *status)
{
return AS5600_ReadByte(AS5600_REG_STATUS, status);
}
u8 AS5600_GetAGC(u8 *agc)
{
return AS5600_ReadByte(AS5600_REG_AGC, agc);
}
u8 AS5600_GetMagnitude(u16 *mag)
{
return AS5600_ReadU16(AS5600_REG_MAGNITUDE, mag);
}
u8 AS5600_GetZMCO(u8 *zmco)
{
u8 v;
if (AS5600_ReadByte(AS5600_REG_ZMCO, &v) != AS5600_OK) return AS5600_ERR;
*zmco = v & 0x03;
return AS5600_OK;
}
/* ------------------------------------------------------------------ */
/* 配置寄存器 */
/* ------------------------------------------------------------------ */
u8 AS5600_GetZPOS(u16 *zpos) { return AS5600_ReadU16(AS5600_REG_ZPOS, zpos); }
u8 AS5600_SetZPOS(u16 zpos) { return AS5600_WriteU16(AS5600_REG_ZPOS, zpos & 0x0FFF); }
u8 AS5600_GetMPOS(u16 *mpos) { return AS5600_ReadU16(AS5600_REG_MPOS, mpos); }
u8 AS5600_SetMPOS(u16 mpos) { return AS5600_WriteU16(AS5600_REG_MPOS, mpos & 0x0FFF); }
u8 AS5600_GetMANG(u16 *mang) { return AS5600_ReadU16(AS5600_REG_MANG, mang); }
u8 AS5600_SetMANG(u16 mang) { return AS5600_WriteU16(AS5600_REG_MANG, mang & 0x0FFF); }
u8 AS5600_GetCONF(u16 *conf) { return AS5600_ReadU16(AS5600_REG_CONF, conf); }
u8 AS5600_SetCONF(u16 conf) { return AS5600_WriteU16(AS5600_REG_CONF, conf); }
/* ------------------------------------------------------------------ */
/* OTP 烧录命令 */
/* ------------------------------------------------------------------ */
u8 AS5600_BurnAngle(void)
{
u8 cmd = 0x80;
return I2C_Write(AS5600_ADDR, AS5600_REG_BURN, &cmd, 1);
}
u8 AS5600_BurnSetting(void)
{
u8 cmd = 0x40;
return I2C_Write(AS5600_ADDR, AS5600_REG_BURN, &cmd, 1);
}
/* 依次写 0x01, 0x11, 0x10,把 OTP 内容重新加载到寄存器 */
u8 AS5600_ReloadOTP(void)
{
u8 c;
c = 0x01; if (I2C_Write(AS5600_ADDR, AS5600_REG_BURN, &c, 1)) return AS5600_ERR;
c = 0x11; if (I2C_Write(AS5600_ADDR, AS5600_REG_BURN, &c, 1)) return AS5600_ERR;
c = 0x10; if (I2C_Write(AS5600_ADDR, AS5600_REG_BURN, &c, 1)) return AS5600_ERR;
return AS5600_OK;
}
c
/* 读原始角度 */
AS5600_GetRawAngle(&raw);
/* 读缩放后角度 */
AS5600_GetAngle(&angle);
/* 读状态和 AGC */
AS5600_GetStatus(&status);
AS5600_GetAGC(&agc);
printf("RAW=%4d ANGLE=%4d DEG=%.1f AGC=%3d MD=%d ML=%d MH=%d\r\n",
raw, angle,
AS5600_RAW_TO_DEG(raw),
agc,
(status & AS5600_STATUS_MD) ? 1 : 0,
(status & AS5600_STATUS_ML) ? 1 : 0,
(status & AS5600_STATUS_MH) ? 1 : 0);
delay_ms(500);