原理了解
IIC:Inter Integrated Circuit,集成电路总线,是一种同步 串行 半双工通信总线。
在这里贴一下硬件IIC和软件IIC的区别:
从图中可以看出两者的区别,硬件IIC比软件IIC的用法会比较复杂,但是这里如果不关注底层的实现去使用STM32CubeMx进行IIC的配置,再使用特定函数就能够实现IIC通讯,实际这个过程是非常简单,若想了解软件IIC的实现也可以参考我的另一篇文章:
软件模拟实现IIC
那么接下来看看如何使用STM32CubeMx配置IIC并使用
STM32CubeMx配置
首先根据硬件原理图:
EEPROM是连接在了PB6和PB7两个端口上,而PB6和PB7正好为硬件的IIC接口,所以就直接选用这两个口作为我们的IIC接口,STM32CubeMx配置如下:
打开I2C功能,发现下面的PB6和PB7就会自动配置为我们的SCL和SDA引脚,其余设置我们就不用进行修改了,保持默认即可:
接着就是打开串口通讯功能,通过串口进行函数的功能验证,剩下的配置就是配置时钟源,选择debug调试的接线方式以及配置外部晶振即可,接着就可以生成工程了。
工程生成及代码编写
工程生成
工程生成之后,可以看到左边已经有了相关的代码:
打开i2c.c可以看到
里面已经配置好了IIC的模式以及对应IO口的配置、使能相关时钟。在使用硬件IIC的过程中比较重要的函数如下:
可以看到里面包含了普通模式、中断模式、DMA模式下的函数,功能都是基本一样的,只是用在不同模式而已,而在这里介绍本实验用到的两个函数:
HAL_StatusTypeDef 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);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
这两个函数就是需要用到的写入和读取函数,先来分别看看对应的参数都是什么意思:
- I2C_HandleTypeDef *hi2c:句柄,即iic.c文件中开头定义的结构体 “I2C_HandleTypeDef hi2c1;”
- uint16_t DevAddress:从设备的通讯地址,比方要写入数据时,则为0xA0
- uint16_t MemAddress:内部寄存器地址(要写入或读取的地址) uint16_t
- MemAddSize:内部寄存器地址的大小,8/16位,即规定写入或读取的字节类型为8或16位
4.1可在stm32f1xx_hal_i2c.h中找到相关定义:
/** @defgroup I2C_Memory_Address_Size I2C Memory Address Size
* @{
*/
#define I2C_MEMADD_SIZE_8BIT 0x00000001U
#define I2C_MEMADD_SIZE_16BIT 0x00000010U
/**
* @}
*/
- uint8_t *pData: 要写入或读取的数据的起始地址
- uint16_t Size:写入或读取的数据类型大小,单位:字节
- uint32_t Timeout:超时时间
代码编写
了解完以上内容后就可以开始编写实验的代码了,这里在iic.c文件的USER CODE BEGIN 1中开始添加实现IIC通讯的代码:
/* USER CODE BEGIN 1 */
#define AT24C02_Write_ADD 0xA0
#define AT24C02_Read_ADD 0xA1
uint8_t I2C_Write_Buffer[256];
uint8_t I2C_Read_Buffer[256];
void AT24C02Test(void)
{
int i;
printf("\r\n **********STM32CubeMx IIC Test********** \r\n");
printf("\r\n I2C_Write_Buffer: \r\n");
/* 生成256byte数据 */
for(i = 0; i < 256; i++)
{
I2C_Write_Buffer[i] = i;
printf("%02X ", I2C_Write_Buffer[i]);
}
/* Write Data To AT24C02 */
for(i = 0; i < 256; i= i+8)
{
if(HAL_I2C_Mem_Write(&hi2c1, AT24C02_Write_ADD, i, I2C_MEMADD_SIZE_8BIT, &(I2C_Write_Buffer[i]), 8, 1000) == HAL_OK)
{
printf("\r\n Byte %02d to Byte %02d Write OK \r\n", i, i+8);
HAL_Delay(5);
}
else
{
printf("\r\n Byte %02d to Byte %02d Write Failed \r\n", i, i+8);
}
}
/* Read Data To AT24C02 */
printf("\r\n Read from AT24C02 \r\n");
HAL_I2C_Mem_Read(&hi2c1, AT24C02_Read_ADD, 0, I2C_MEMADD_SIZE_8BIT, I2C_Read_Buffer, 256, 1000);
for(i = 0; i < 256; i++)
{
printf("0x%02X ", I2C_Read_Buffer[i]);
}
}
/* USER CODE END 1 */
在这里调用HAL_I2C_Mem_Write()函数的过程中需要注意,由于硬件使用的是AT24C02,在其手册中说明了EEPROM完整写入的时间需要等待5ms,所以这里需要添加一个延时函数以保证数据成功写入EEPROM,若实验未成功也可适当将延时函数延长为10ms。
接着在main.c中调用我们的功能函数即可:
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf("sys run\r\n");
AT24C02Test();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
实现效果
可以看到已经实现了实验所需的功能,那么在该实验中可以看出,使用STM32CubeMx配置好硬件IIC只需调用库中提供的函数就能轻松实现IIC通讯功能,而用户则可以更加专注于自己想要实现的功能,实际上也是方便很多。至此,硬件IIC实验就完成了,也欢迎大家有问题可以指出,一起讨论一下,谢谢!