使用STM32F103C8T6驱动磁编码器AS5600

材料





从网上下单的2套模块,手里又STM32C8T6单片机,还需要USB串口线,拿一个圆柱体的小棍,在顶部用胶水贴上模块的配套磁铁,一会测试用(这样旋转磁铁方便一些),OK,家伙什齐全,开整。
硬件连接







商家没有给数据手册,只有一个原理图的截图,又搜了下网络。它是用IIC驱动的,用IIC写和读
硬件连接:
VDD GND 不用说之间对联即可,SCK SDA 和单片机的 SCK SDA 引脚直连,我用的是硬件IIC口,PB6 PB7,然后就是用串口线连接电脑和单片机。在电脑上打开STC-ISP的烧录软件,它上面自带一个串口助手。
软件




用KEIL5新建工程,然后新建 as5600.c 和 as5600.h 文件,串口的代码就不再多讲了,我用的是正点原子的串口代码。开始写代码。先写IIC的部分,再写AS5600编码器部分。
IIC代码:
/**
* @brief I2C 外设配置
*/
void I2C_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 1. 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
// 2. 配置I2C引脚为开漏输出
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PORT, &GPIO_InitStructure);
// 3. I2C参数配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // I2C模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 占空比50%
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 主机地址(任意)
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // 使能ACK
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 7位地址
I2C_InitStructure.I2C_ClockSpeed = I2C_CLK_SPEED; // 时钟速度
I2C_Init(I2Cx, &I2C_InitStructure);
I2C_Cmd(I2Cx, ENABLE); // 使能I2C
}
编码器代码:
/**
* @brief 从AS5600读取角度值
* @retval 12位角度数据(0-4095)
*/
uint16_t AS5600_ReadAngle(void)
{
uint8_t reg_addr = AS5600_ANGLE_REG_H; // 起始寄存器地址
uint8_t buffer[2] = {0}; // 存储读取数据
uint16_t angle = 0;
// 1. 发送起始条件
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
// 2. 发送设备地址(写操作)
I2C_Send7bitAddress(I2Cx, AS5600_ADDRESS << 1, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 3. 发送要读取的寄存器地址
I2C_SendData(I2Cx, reg_addr);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 4. 发送重复起始条件(重启)
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
// 5. 发送设备地址(读操作)
I2C_Send7bitAddress(I2Cx, AS5600_ADDRESS << 1, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// 6. 读取高字节(带ACK)
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));
buffer[0] = I2C_ReceiveData(I2Cx);
// 7. 读取低字节(带NACK)
I2C_AcknowledgeConfig(I2Cx, DISABLE); // 发送NACK
I2C_GenerateSTOP(I2Cx, ENABLE); // 准备停止条件
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED));
buffer[1] = I2C_ReceiveData(I2Cx);
// 8. 重新使能ACK
I2C_AcknowledgeConfig(I2Cx, ENABLE);
// 9. 组合12位角度数据
angle = ((uint16_t)buffer[0] << 8) | buffer[1]; // 合并高低字节
angle = angle & 0x0FFF; // 屏蔽高4位
return angle; // 返回0-4095的角度值
}
然后在main.c 中轮询检测IIC读到的角度值,用一个变量存个BUFF,然后检测它和备份的有没有改变,如果有就用串口发送到电脑端。用串口助手观看结果。
main.c代码:
#include "sys.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "delay.h"
#include "as5600.h"
int main(void)
{
u16 angle = 0;
u16 angleBuff = 0;
LED_Init();
delay_init();
KEY_Init();
I2C_Configuration();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置中断分组
uart_init(9600);
while(1)
{
angle = AS5600_ReadAngle(); // 读取角度值
if(angleBuff != angle)
{
// 例如: 通过串口输出角度值或控制电机
printf("角度值是:%d", angle);
// USART1->DR = angle>>4;
// USART1->DR = angle&0x0F;
while((USART1->SR&0X40)==0); //等待发送结束
angleBuff = angle;
}
LED_Flashing(300); //闪烁 LED,提示系统正在运行.
// delay_ms(100);
}
}
烧录上机测试





编译代码没有错误的话,就可以上机了。
打开电脑端的STC-ISP软件,打开串口调试助手,然后拿刚才自制的测试手棒开始测试。可以看到它返回的数据在0---4096之间,对应360度封闭圆环的角度。实验顺利通过。
因为这个模块芯片里有一个磁场产生器和一个霍尔磁场检测器,所以对机械贴合度,要求精确。咱们是手拿着精度差的太远,所以看到的值飘忽不定。属于正常现象。只要范围在0---4096之间,表示驱动时没有问题的。











