48-AS5600旋转磁编码器

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);
相关推荐
iCxhust2 小时前
8088的nmi中断能关闭吗?
嵌入式硬件·8088单板机
黑妹天下第一乖6 小时前
第 08 讲:阿加犀 AidGenSE 端侧大模型服务化与 OpenAI 兼容接口
人工智能·嵌入式硬件·深度学习·机器人·iot
辰哥单片机设计6 小时前
漏水传感器(STM32)
stm32·单片机·嵌入式硬件
恶魔泡泡糖7 小时前
stm32F103C8T6标准库串口接收之多串口基础应用5
stm32·单片机·嵌入式硬件
木子单片机7 小时前
基于51单片机计步器—无线蓝牙APP上传
单片机·嵌入式硬件·51单片机·keil
恒锐丰科技林技术员7 小时前
EG2123A 三相独立半桥驱动芯片解析与工程应用
经验分享·嵌入式硬件·硬件工程
硅基手札8 小时前
【Linux 内核专栏 13】快IO层
linux·服务器·嵌入式硬件
xiangw@GZ9 小时前
纽扣电池型号
嵌入式硬件
优信电子9 小时前
Raspberry Pi Pico 硬件开发 —— 第二课:MicroPython 从入门到项目实践(LED篇)
单片机·嵌入式硬件·树莓派·micropython·pico·入门教学