【雅特力AT-START-F435】I2C读取AS5600角度数据
[复制链接]
本帖最后由 hitwpc 于 2023-7-11 02:14 编辑
本次测评中参考例程中I2C,获取无刷电机实时角度位置,并使用串口将数据信息通过VOFA进行实时波形显示。
参考文件目录如下:
AT32F435_437_Firmware_Library_V2.1.2\project\at_start_f435\examples\i2c\communication_int
参考AS5600驱动开源链接:
IIC的基础原理
参考大佬Z小旋的教程,对I2C的物理层、协议层、时序图都做了很好的解释,如果单片机作为主机去读取从机的信息,完全足够,可以参考下面的文章。
(71条消息) IIC原理超详细讲解---值得一看_Z小旋的博客-CSDN博客
程序介绍
官方例程I2C参考
首先查看库函数(文件at32f435437i2c.c),可以看到里面的的库函数还是比较底层的,如获取地址,操作数据寄存器直接发送数据。如果认真观看了IIC的基础原理,就会发现,IIC的时许和逻辑较为复杂,此类底层函数库是不能完成IIC的发送和读取数据的。
碰巧官方例程(AT32F435_437_Firmware_Library_V2.1.2\project\at_start_f435\examples\i2c\communication_int)中完善了IIC相关的驱动函数,文件为i2c_application.c。
因此我们首先把该文件的函数都拷走,下面我们将主要用到这个函数
i2c_status_type i2c_memory_read(i2c_handle_type* hi2c, i2c_mem_address_width_type mem_address_width, uint16_t address, uint16_t mem_address, uint8_t* pdata, uint16_t size, uint32_t timeout)
可以实现使用指定I2C,向指定从机地址的内存地址读取指定长度的数据(STM32的HAL库中有类似的函数)。
下面看下函数内部的实现逻辑
①等待检测I2C是否忙碌
②发送启动信号,同时发送从机地址
③等待检测发送从机地址的ACK信号是否收到
④发送需要读取的内存地址
⑤等待检测是否发送完成
⑥发送启动信号,同时发送从机地址
⑦等待检测发送从机地址的ACK信号是否收到
⑧循环读取指定长度的数据
从这个过程中,我们可以看到读取的过程是②发送从机地址、④发送内存地址、⑥发送从机地址、⑧读取指定内存的数据,其余过程都在校验上一步是否完成。校验函数的形式如下:
i2c_wait_flag(hi2c, I2C_TCRLD_FLAG, I2C_EVENT_CHECK_NONE, timeout)
里面有timeout超时机制,因此I2C的发送失败(或者示波器根本抓不到发出的波形),可以尝试调大timeout值(本人在实验过程中,timeout为0XFF时会发送失败,0XFFF则发送成功)。
源码如下:
i2c_status_type i2c_memory_read(i2c_handle_type* hi2c, i2c_mem_address_width_type mem_address_width, uint16_t address, uint16_t mem_address, uint8_t* pdata, uint16_t size, uint32_t timeout)
{
/* initialization parameters */
hi2c->pbuff = pdata;
hi2c->pcount = size;
hi2c->error_code = I2C_OK;
/* wait for the busy flag to be reset */
if (i2c_wait_flag(hi2c, I2C_BUSYF_FLAG, I2C_EVENT_CHECK_NONE, timeout) != I2C_OK)
{
return I2C_ERR_STEP_1;
}
/* start transfer */
i2c_transmit_set(hi2c->i2cx, address << 1, mem_address_width, I2C_SOFT_STOP_MODE, I2C_GEN_START_WRITE);
//i2c_start_transfer(hi2c, address<<1, I2C_GEN_START_WRITE);
/* wait for the tdis flag to be set */
if (i2c_wait_flag(hi2c, I2C_TDIS_FLAG, I2C_EVENT_CHECK_ACKFAIL, timeout) != I2C_OK)
{
return I2C_ERR_STEP_2;
}
/* send memory address */
if (i2c_memory_address_send(hi2c, mem_address_width, mem_address, timeout) != I2C_OK)
{
return I2C_ERR_STEP_3;
}
/* wait for the tdc flag to be set */
if (i2c_wait_flag(hi2c, I2C_TDC_FLAG, I2C_EVENT_CHECK_NONE, timeout) != I2C_OK)
{
return I2C_ERR_STEP_4;
}
/* start transfer */
i2c_start_transfer(hi2c, address<<1, I2C_GEN_START_READ);
while (hi2c->pcount > 0)
{
/* wait for the rdbf flag to be set */
if (i2c_wait_flag(hi2c, I2C_RDBF_FLAG, I2C_EVENT_CHECK_ACKFAIL, timeout) != I2C_OK)
{
return I2C_ERR_STEP_5;
}
/* read data */
(*hi2c->pbuff++) = i2c_data_receive(hi2c->i2cx);
hi2c->pcount--;
hi2c->psize--;
if ((hi2c->psize == 0) && (hi2c->pcount != 0))
{
/* wait for the tcrld flag to be set */
if (i2c_wait_flag(hi2c, I2C_TCRLD_FLAG, I2C_EVENT_CHECK_NONE, timeout) != I2C_OK)
{
return I2C_ERR_STEP_6;
}
/* continue transfer */
i2c_start_transfer(hi2c, address, I2C_WITHOUT_START);
}
}
/* wait for the stop flag to be set */
if (i2c_wait_flag(hi2c, I2C_STOPF_FLAG, I2C_EVENT_CHECK_ACKFAIL, timeout) != I2C_OK)
{
return I2C_ERR_STEP_7;
}
/* clear stop flag */
i2c_flag_clear(hi2c->i2cx, I2C_STOPF_FLAG);
/* reset ctrl2 register */
i2c_reset_ctrl2_register(hi2c);
return I2C_OK;
}
AS5600驱动
参考下面的代码
AS5600是一种易于编程的磁性旋转位置传感器,具有高分辨率12位模拟或PWM输出。该非接触系统测量轴上径向磁化磁体的绝对角度。AS5600专为无触点电位器应用而设计,其坚固的设计消除了任何均匀外部杂散磁场的影响。行业标准I²C接口支持非易失性参数的简单用户编程,无需专门的程序员。默认情况下,输出表示0到360度的范围。也可以通过编程零角度(开始位置)和最大角度(停止位置)来定义输出的较小范围。AS5600还配备了智能低功耗模式功能,可自动降低功耗。输入引脚(DIR)选择输出相对于旋转方向的极性。如果DIR接地,输出值随顺时针旋转而增加。如果DIR连接到VDD,则输出值随逆时针旋转而增加。LibDriver AS5600是LibDriver推出的AS5600全功能驱动,该驱动提供磁角度读取等功能并且它符合MISRA标准。
在以下函数接口中,添加自己的驱动函数
①初始化函数
uint8_t as5600_interface_iic_init(void)
{
hi2cx.i2cx = I2Cx_PORT;
/* i2c config */
i2c_config(&hi2cx);
return 0;
}
②I2C读取函数
uint8_t as5600_interface_iic_read(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len)
{
i2c_memory_read(&hi2cx, I2C_MEM_ADDR_WIDIH_8,addr,reg,buf,len,0xFFF);
return 0;
}
③I2C写函数
uint8_t as5600_interface_iic_write(uint8_t addr, uint8_t reg, uint8_t *buf, uint16_t len)
{
i2c_memory_write(&hi2cx, I2C_MEM_ADDR_WIDIH_8,addr,reg,buf,len,0xFFF);
return 0;
}
④延时函数
void as5600_interface_delay_ms(uint32_t ms)
{
delay_ms(ms);
}
接下来主函数中,初始化阶段添加as5600_basic_init();
在主循环中添加 as5600_basic_read(float *angle),即可读取出AS5600的机械角度值(当然还需要电角度换算)。
在测试过程中,发现AT32F435的I2C的发送从机地址时,需要将从机地址左移一位,然后在最低位(LSB)来判断时读还是写。需要手动改一下库函数
i2c_transmit_set(hi2c->i2cx, address << 1, mem_address_width, I2C_SOFT_STOP_MODE, I2C_GEN_START_WRITE);
实物测试效果
红色线为机械角度,绿色线为电角度(使用的无刷电机24N22P,是11对级,因此电角度是11倍的机械角度)。
20230711-010829
|