首先感谢灵动微电子和极术社区提供免费的开发板。
刚好这段时间我们的电机驱动产品准备更换成国产方案,基于各种原因综合考虑,选择了灵动微电子的MM32F5370系列单片机,项目刚启动,就遇到了此次活动。那必须得冲一波!
运气挺好,通过了活动的审核,拿到了心心念念的开发板。
既然是为了开发电机驱动,那磁编码器自然不可少。基于我手上的物料储备,选择了AS5600作为电机驱动的位置传感器。
AS5600是一个12位的非接触式磁角度位置传感器,提供I2C数字通信接口,设备地址为0x36。
首先需要准备以下物料:
- 灵动Mini-F5375-OB开发板
- AS5600磁编码器
- 5*2 磁铁
使用到的单片机外设如下:
- IIC2(PA4,PA5 复用功能AF20);
- USART3(PC10,PC11 复用功能AF7);
开始编程
首先需要初始化i2c,代码如下:
void I2C_Configure(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
I2C_InitTypeDef I2C_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
I2C_DeInit(I2C2);
I2C_StructInit(&I2C_InitStruct);
I2C_InitStruct.I2C_Mode = I2C_MODE_MASTER;
I2C_InitStruct.I2C_OwnAddress = I2C_OWN_ADDRESS;
I2C_InitStruct.I2C_ClockSpeed = 100000;
I2C_Init(I2C2, &I2C_InitStruct);
I2C_TargetAddressConfig(I2C2, 0x36 << 1); // AS5600的地址,注意要移位
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource4, GPIO_AF_20);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_20);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_High;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOA, &GPIO_InitStruct);
I2C_Cmd(I2C2, ENABLE);
}
然后根据AS5600的读写时序编写AS5600驱动
AS5600头文件,申明寄存器地址和接口函数
#ifndef __AS5600_H #define __AS5600_H #include "i2c/i2c.h" typedef union { uint8_t data8[2]; uint16_t data16; }byte8_to_byte16; typedef enum { _zmco = 0x00, _zpos_h = 0x01, _zpos_l = 0x02, _mpos_h = 0x03, _mpos_l = 0x04, _mang_h = 0x05, _mang_l = 0x06, _conf_h = 0x07, _conf_l = 0x08, _raw_ang_h = 0x0c, _raw_ang_l = 0x0d, _ang_h = 0x0e, _ang_l = 0x0f, _stat = 0x0b, _agc = 0x1a, _mag_h = 0x1b, _mag_l = 0x1c, _burn = 0xff }as5600_registers_t; uint16_t read_raw_angle(void); uint8_t detect_magnet(void);
AS5600源文件,实现读写逻辑
#include "as5600.h" uint8_t read_one_byte(uint8_t reg_addr) { uint8_t data = 0; I2C_SendData(I2C2, reg_addr); while(RESET == I2C_GetFlagStatus(I2C2, I2C_STATUS_FLAG_TFE)) { } I2C_ReadCmd(I2C2); while (RESET == I2C_GetFlagStatus(I2C2, I2C_STATUS_FLAG_RFNE)) { } data = I2C_ReceiveData(I2C2); return data; } byte8_to_byte16 buff; uint16_t read_raw_angle(void) { buff.data8[1] = read_one_byte(0x0C); buff.data8[0] = read_one_byte(0x0D); return buff.data16; } uint8_t detect_magnet(void) { uint8_t ret_val; ret_val = read_one_byte(_stat); if(ret_val & 0x20) { ret_val = 1; }else { ret_val = 0; } return ret_val; }
接下来就是主函数部分:
读取磁铁检测寄存器,读取角度信息,通过串口打印到串口助手。
int main(void) { uint16_t raw_angle = 0; float angle = 0.0f; PLATFORM_Init(); printf("\r\nTest %s", __FUNCTION__); I2C_Configure(); while (1) { raw_angle = read_raw_angle(); angle = raw_angle * _PI / 2048; printf("as5600:%d, %d, %f\n", detect_magnet(), raw_angle, angle); PLATFORM_LED_Toggle(LED1); PLATFORM_DelayMS(10); } }
结果如下:
由于手动转动的磁铁,所以位置曲线看起来并不是很均匀。
总结
以上内容都是基于MM32的例程修改,库函数使用起来还是十分方便的,但是由于粗心还是小小折磨了一下。
例程中串口打印功能配的是串口1,对应的时钟配置代码如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
开发板的串口调试对应的串口为串口3,我修改后的代码如下:
RCC_APB2PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
细心的小伙伴一定知道是什么原因。
!!!简直造孽啊!!!
代码自取:MM32F5375-AS5600
————————————————————————————————
以上就是此次使用IIC读取AS5600磁编码器的全部内容。