首先说明下开发条件:
1、开发板:秉火霸道,STM32F103ZET
2、软件:Cubemx V4.23(F1 V1.60库)
3、硬件:AT24C02 256KByte
问题描述:Cubemx生成IIC代码会出现死机问题,或者压根运行不了!
问题原因:
1、ST为了规避飞利浦IIC专利问题,将STM32的硬件IIC设计的比较复杂,而且稳定性不怎么好,所以一般教程都不推荐使用。
2、Cubemx生成的代码有Bug!
解决办法:
1、设置
2、IIC的回调函数里面需要将时钟初始化放在引脚初始化之前!
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(hi2c->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
__HAL_RCC_I2C1_CLK_ENABLE(); //默认生成的放在了引脚初始化后面!
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Peripheral clock enable */
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
3、函数的具体应用需要结合AT24C02的数据手册,符合AT24C02的要求!
我们在读写IIC时,即使不知道IIC的协议是什么,直接调用 HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout) 这个函数就可以对IIC的设备进行读写,这就是Cubemx的优势!
我先解释下这个函数里面的几个变量:
I2C_HandleTypeDef *hi2c IIC的句柄
uint16_t DevAddress IIC设备的外部地址
uint16_t MemAddress IIC设备的内部地址
uint16_t MemAddSize 读写内部地址的方式,一般使用I2C_MEMADD_SIZE_8BIT方式
注意只有两种选择:I2C_MEMADD_SIZE_8BIT 或者 I2C_MEMADD_SIZE_16BIT
uint8_t *pData 写入的数组或者指针
uint16_t Size 写入的字节数!
注意:如果是AT24C02,这个字节数不能超过8!!!!!这也叫AT24C02的页写入!当然这是为了提高速度,如果你想不出错也不在乎速度,你可以将字节数设置为1,这样肯定不会出错!
uint32_t Timeout 时间超时
4、程序实现
注意:需要在写函数后面加入短延时!
uint8_t I2c_Buf_Write[256];
uint8_t I2c_Buf_Read[256];
uint8_t I2C_Test(void)
{
uint16_t i;
i2cStatus=HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000); //0表示ready
printf("i2cStatus = %d\r\n ", i2cStatus);
i2cStatus1=HAL_I2C_GetState(&hi2c1);//32表示ready HAL_I2C_STATE_READY = 0x20U, /*!< Peripheral Initialized and ready for use */
printf("i2cStatus1 = %d\r\n ", i2cStatus1);
printf("写入的数据\n\r");
for ( i=0; i<256; i++ ) //填充缓冲
{
I2c_Buf_Write[i] = i;
HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, i, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(&(I2c_Buf_Write[i])), 1, 10000);//一个字节一个字节写,如果需要页写入(不超过8),使用40行的函数
// HAL_I2C_Mem_Write(&hi2c1, (uint16_t)EEPROM_Block0_ADDRESS, 0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t*)I2c_Buf_Write, 8, 10000);//不能超过8个字节,如果超过需要分开写,for循环里面改为i=i+8
printf("0xX ", I2c_Buf_Write[i]);
HAL_Delay(5);//不能少
}
EEPROM_INFO("\n\r写成功\n\r");
HAL_Delay(500);
EEPROM_INFO("\n\r读出的数据\n\r");
//将EEPROM读出数据顺序保持到I2c_Buf_Read中
//if(HAL_I2C_GetState(&hi2c1) == 0x20 ) //加入检测
if( HAL_I2C_IsDeviceReady(&hi2c1, 0xA0, 256, 1000) == HAL_OK)//另外一种检测方法
{
HAL_I2C_Mem_Read(&hi2c1, (uint16_t)(EEPROM_Block0_ADDRESS+1 ),0x00, I2C_MEMADD_SIZE_8BIT,(uint8_t *)I2c_Buf_Read, 256, 10000); //读对字节数没有限制
}
//将I2c_Buf_Read中的数据通过串口打印
for (i=0; i<256; i++)
{
printf("0xX ", I2c_Buf_Read[i]);
if(I2c_Buf_Read[i] != I2c_Buf_Write[i])
{
EEPROM_ERROR("0xX ", I2c_Buf_Read[i]);
EEPROM_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r");
return 0;
}
}
EEPROM_INFO("I2C(AT24C02)读写测试成功\n\r");
return 1;
}
5、联系方式:微信Startingray,本人准备将cubemx的小bug解决的过程记录下来,也是给爱好者一点启示,欢迎微信和我沟通,共同进步!个人觉得Cubemx是未来的发展方向,可以使我们避免很多小错误,但是由于现在软件版本之间的兼容性,加上不同版本库之间存在的bug,还是需要我们在使用时时刻保持警惕!
2020.08.22重新学习记录:
1、开发板:秉火霸道,STM32F103ZET
2、软件:Cubemx V6.01(F1 V1.80库)
还有IIC的7bit地址是0x50,但是调用的函数需要的是8bit表示的这个地址应该是0xA0
很遗憾IIC的BUG还存在,而且如果使用FSMC的时候,IIC的配置会影响FSMC,两者一起用的时候要注意。