【外设篇】STMG4芯片-Hal库-I2C通信AS5600编码器+死锁BUG(基础工程)
AS5600为绝对值编码器,其接口有I2C和ADC两种,为配合FOC的10KHZ运行速率,博主使用I2C的DMA模式+高速波特率1MHZ或ADC模拟的方式读取电机电角度,并讲明绝对值编码器在PMSM电机里如何让电角度对齐正确角度,最后用STM32Cubemx和keil5实习代码。
引言:AS5600为绝对值编码器,其接口有I2C和ADC两种,为配合FOC的10KHZ运行速率,博主使用I2C的DMA模式+高速波特率1MHZ或ADC模拟的方式读取电机电角度,并讲明绝对值编码器在PMSM电机里如何让电角度对齐正确角度,最后用STM32Cubemx和keil5实习代码。
1.I2C的HAL库函数及ADC的HAL库函数
| 序号 | HAL库函数 | 作用 |
|---|---|---|
| 1 | HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); | I2C的DMA模式发送 |
| 2 | HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size); | I2C的DMA模式接收 |
| 3 | HAL_I2C_Master_Stop(I2C_HandleTypeDef *hi2c); | 停止I2C |
解释:
|
||
2.I2C工作原理
I2C(Inter-Integrated Circuit)是一种广泛使用的串行通信协议,主要用于在短距离内连接集成电路(IC)之间的通信。I2C协议由飞利浦(Philips)公司在1982年提出,它是一种半双工通信协议,允许多个设备共享同一对信号线进行数据交换。I2C的工作原理基于主从式通信模型。
2.1 硬件线说明
I2C协议的通信由两条主要的信号线构成:
- SCL(Serial Clock Line,串行时钟线):用于传输时钟信号,由主设备产生。
- SDA(Serial Data Line,串行数据线):用于传输数据,双向通信。
2.2 工作过程
-
设备地址:每个连接到I2C总线上的设备都有一个唯一的地址。主设备在发送数据之前会向总线发送目标设备的地址,确保数据发送给正确的设备。
-
通信模式:I2C支持两种通信模式:
- 主设备模式:主设备生成时钟信号并控制数据流。
- 从设备模式:从设备响应主设备的请求,根据其地址和指令进行通信。
-
开始条件(Start Condition):通信开始时,主设备将SDA线从高电平拉低到低电平,同时SCL保持为高电平。这个信号告诉总线上的所有设备,接下来是一个新的通信会话。
-
地址传输:主设备发送一个包含目标从设备地址的数据包。地址通常是7位或10位,表示目标设备的唯一身份。传输过程中,第8位表示读写标志(0表示写操作,1表示读操作)。
-
数据传输:主设备和从设备通过SDA线传输数据。数据按字节传输,数据的高位在前,低位在后。数据传输时,SCL线会产生时钟脉冲,确保数据同步。
-
确认信号(ACK/NACK):每个字节传输后,接收方(主设备或从设备)会发送一个确认信号。如果接收方成功接收数据,它会将SDA拉低表示ACK(Acknowledgment);如果数据有误或没有接收,接收方会发送NACK(No Acknowledgment),表示数据接收失败。
-
停止条件(Stop Condition):通信完成后,主设备会发送停止条件,表示此次数据传输结束。停止条件是在SCL线为高电平时,SDA从低电平拉高到高电平。
3.STM32CubeMx配置
按如下图开启I2C即可




4.代码讲解
I2C的DMA模式读取AS5600编码值
#define PI 3.1415926f
#define Slave_Addr 0x36<<1//设备从地址
#define Angle_Hight_Register_Addr 0x0C //寄存器高位地址
uint8_t readBuffer[2];
float I2C_AS5600(){
/*
angle_d为机械角度,单位:弧度,范围(0 -- 6.28)
当前I2C模式为DMA模式,波特率1MHZ
*/
float angle_d;
int16_t in_angle;
HAL_I2C_Mem_Read_DMA(&hi2c1,Slave_Addr,Angle_Hight_Register_Addr,I2C_MEMADD_SIZE_8BIT,readBuffer,2);
in_angle = ((int16_t)readBuffer[0] <<8) | (readBuffer[1]);
angle_d = (float)in_angle * 2 *PI / 4096;
return angle_d;
}
Justfloat格式串口发送
load_data[0] = IaU24;
load_data[1] = IaU24;
load_data[2] = IaU24;
load_data[3] = m_theta;
load_data[4] = 0;
memcpy(tempData, (uint8_t *)&load_data, sizeof(load_data));
HAL_UART_Transmit_DMA(&huart3,(uint8_t *)tempData,6*4);
结果:vofa上正常读取机械角度,先正转然后反转,范围是0~6.28


5.Stm32的I2C的死锁BUG
如果在读着I2C时,AS5600突然不工作了(AS5600和Stm32的BUG,或者突然一个电平波动导致),SDA口和SCL口同时拉高I2C进入空闲状态,Stm32会在读取I2C的标志位时,因I2C已经没信号了,造成进入I2C的死循环
__HAL_I2C_GET_FLAG(hi2c, Flag)总是等于Status,导致无限循环。如下代码循环里,或者其他读取I2C标志位的循环里
static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status,
uint32_t Timeout, uint32_t Tickstart)
{
while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
{
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
hi2c->State = HAL_I2C_STATE_READY;
hi2c->Mode = HAL_I2C_MODE_NONE;
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_ERROR;
}
}
}
return HAL_OK;
}
__weak uint32_t HAL_GetTick(void)
{
return uwTick;
}
解决方式:1.用GPIO的开启关闭模拟I2C通信协议原理,缺点是此方式是阻塞方法,占用计算空间大,没I2C的DMA模式快,不能满足10KHZ的FOC运行条件 2.换个编码器吧,STM32的HAL库I2C通信太烂了
创作不易,感性您的指正与关注
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)