【STM32CubeMX+HAL库】I2C详解+读写EEPROM

在之前的标准库中,STM32的硬件IIC非常复杂,更重要的是它并不稳定,所以都不推荐使用。但是在我们的HAL库中,对硬件IIC做了全新的优化,使得之前软件IIC几百行代码,在HAL库中,只需要寥寥几行就可以完成 那么这篇文章将带你去感受下它的优异之处。

本文将详细地讲解I2C协议,并基于I2C
来读写EEPROM模块以达到练习的目的

通过本篇博客您将学到:

  • I2C的基本原理
  • STM32CubeMX创建I2C例程
  • I2C函数库(HAL)
  • AT24C256芯片原理及读写方法

I2C简介 

IIC(Inter-Integrated Circuit)总线是一种由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接微控制器及其外围设备。多用于主控制器和从器件间的主从通信。

I2C特性

  • 半双工
  • 没有严格的波特率要求
  • 小数据量场合使用
  • 传输距离短、传输速率不如SPI
  • 任何时刻只能有一个主机,但任何设备都可成为主机
  •  只需要两条总线——SDA与SCL 

 IIC一共有只有两个总线: 一条是双向的数据线SDA,一条是串行时钟线SCL

所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每一个设备都对应一个唯一的地址。

 I2C起始信号与终止信号(代码段为软件I2C)

1、起始信号:SCL为高电平时,SDA由高->低

void I2C_Start()
{
SDA=1;               //确保SDA为高电平
HAL_Delay(1);
SCL=1;               //确保SCL为高电平
HAL_Delay(1);
SDA=0;              //SCL为高时拉低SDA线
HAL_Delay(1);
SCL=0;              //钳住I2C总线,准备数据的发送与接收
}

2、终止信号:SCL为高电平时,SDA由低->高

void I2C_Stop()
{
SCL=0;            
SDA=0;
HAL_Delay(1);
SCL=1;             //确保SCL为高电平
HAL_Delay(1);
SDA=1;            //SCL为高时拉高SDA
} 

I2C应答信号与非应答信号 (代码段为软件I2C)

每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据。

  • 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
  • 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
     

1、应答信号‘0’:SCL高时SDA低

void I2C_Ack()        //产生应答信号
{
SCL=0;
SDA=0;
HAL_Delay(1);
SCL=1;             //确保SCL为高时SDA为低
HAL_Delay(1);
SCL=0;
}

2、非应答信号‘1’:SCL高时SDA高

void I2C_NAck()     //不产生应答信号
{
SCL=0;
SDA=1;
HAL_Delay(1);
SCL=1;             //SCL高时SDA高
HAL_Delay(1);
SCL=0;
}

I2C数据有效性

I2C信号在进行数据传输时, 当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

SCL=1时 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号。也就是在IIC传输数据的过程中,SCL时钟线会频繁的转换电平,以保证数据的传输

 接着我们介绍一下基于AT24C256的I2C通信

AT24C256芯片手册如下:

 描述:

AT24C256是提供131072/262144位串行电可擦除可编程只读存储器(EEPROM),该设备最多允许4个设备共享一条公共的双线总线。

特征:

  • 低电压和标准电压操作-2.7V(Vcc=2.7V至5.5V)(一般选择3.3V)
  • 双线串行接口
  • 施密特触发器,用于噪声抑制的滤波输入
  • 双向数据传输协议
  • 400kHz兼容性
  • 硬件和软件的写保护引脚
  • 64字节页写入模式(允许部分页写入)
  • 自定时写入周期
  • 高可靠性(数据保留:40年)

  •  A0,A1,A2:硬件地址引脚
  • WP:写保护引脚,接高电平只读,接地允许读和写

 芯片的寻址:

AT24C设备地址为如下,前四位固定为1010,A2~A0为由管脚电平。AT24CXX EEPROM Board模块中默认为接地。所以A2~A0默认为000,最后一位表示读写操作。所以AT24Cxx的读地址为0xA1,写地址为0xA0。

也就是说如果是\写24C02的时候,从器件地址为10100000(0xA0);读24C02的时候,从器件地址为10100001(0xA1)。

注意:

  1. 在写数据的过程中,每成功写入一个字节,E2PROM存储空间的地址就会自动加1当加到0xFF后,再写一个字节,地址就会溢出又变成0x00。
  2. 当我们在写多个字节时,写入一个字节之后,再写入下一个字节之前,必须延时5ms才可以

 STM32CubeMX创建I2C例程(作者使用的是STM32f4ccu6)

1、设置RCC时钟

2、配置I2C

  •  Master  features  主模式特性
  • I2C Speed Mode: IIC模式设置 快速模式和标准模式。实际上也就是速率的选择。I2C Clock Speed:I2C传输速率,默认为100KHz
  • Slave  features  从模式特性
  • Clock No Stretch Mode: 时钟没有扩展模式
  • IIC时钟拉伸(Clock stretching) - -clock stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.
  • Primary Address Length selection: 从设备地址长度 设置从设备的地址是7bit还是10bit 大部分为7bit
  • Dual Address Acknowledged: 双地址确认
  • Primary slave address:  从设备初始地址

3、配置串口

这里配置串口是为了读EEPROM并打印出来。 

4、时钟树配置

5、项目文件配置

  • 设置项目名称
  • 设置项目路径(不能包含中文
  • 选择IDE(作者用的是keil5)  

  • 复制所用的.c和.h文件 
  • 不同功能生成独立的.c和.h文件

6、 生成代码

7、配置下载工具

8、重写printf函数

重写printf函数能更方便与上位机通信 ,方法参考printf重写

I2C函数库(HAL)

在I2C.c文件中可以看到I2C初始化函数。在stm32f1xx_hal_i2c.h头文件中可以看到I2C的操作函数。分别对应轮询中断DMA三种控制方式


 

 这里我们简单介绍一下等下用到的函数

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写多个数据 该函数适用于IIC外设里面还有子地址寄存器的设备,比方说E2PROM,除了设备地址,每个存储字节都有其对应的地址 

  • I2C_HandleTypeDef *hi2c  i2c句柄,例如上文配置的&hi2c1,实际上是一个结构体
  • uint16_t DevAddress    从机设备地址,对AT24Cxx来说,0xA0代表写数据,0xA1代表读数据
  • uint16_t MemAddress    从机寄存器地址,每写入一个字节的数据,地址自动+1
  • uint16_t MemAddSize    从机寄存器地址长度,8bit和16bit可选
  • uint8_t *pData    发送数据的起始地址
  •  uint16_t Size     传输数据的大小
  • uint32_t Timeout     传输超时时间 

 读写AT24C256

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define AT24C256_Write 0xA0
#define AT24C256_Read 0xA1
#define BufferSize 64
/* USER CODE END PD */

宏定义,增加了程序的可读性

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
uint8_t w[BufferSize],r[BufferSize];
uint16_t i,j;
/* USER CODE END PV */

定义接收与发送数组

 /* USER CODE BEGIN 2 */
for(i=0;i<64;i++)
{
	w[i]=i;
}
printf("I2C Example Test\n");
//for( j=0;j<16;j++)
//{
	if(HAL_I2C_Mem_Write(&hi2c1,AT24C256_Write,0,I2C_MEMADD_SIZE_16BIT,w,64,10000)==HAL_OK)
	{
		printf("EEPROM AT24C256 Write Test OK\n");
		HAL_Delay(100);
	}
	else
	{
		printf("EEPROM AT24C256 Write Test False");
		HAL_Delay(50);
	}
//}
HAL_Delay(100);
HAL_I2C_Mem_Read(&hi2c1,AT24C256_Read,0,I2C_MEMADD_SIZE_16BIT,r,BufferSize,10000);
for(i=0;i<64;i++)
{
	HAL_Delay(10);
	printf("0x%02X  ",r[i]);
}
  /* USER CODE END 2 */

64字节一次性写入

 /* USER CODE BEGIN 2 */
for(i=0;i<64;i++)
{
	w[i]=i;
}
printf("I2C Example Test\n");
for( j=0;j<16;j++)
{
	if(HAL_I2C_Mem_Write(&hi2c1,AT24C256_Write,0+16*j,I2C_MEMADD_SIZE_16BIT,w+16*j,16,10000)==HAL_OK)
	{
		printf("EEPROM AT24C256 Write Test OK\n");
		HAL_Delay(100);
	}
	else
	{
		printf("EEPROM AT24C256 Write Test False");
		HAL_Delay(50);
	}
}
HAL_Delay(100);
HAL_I2C_Mem_Read(&hi2c1,AT24C256_Read,0,I2C_MEMADD_SIZE_16BIT,r,BufferSize,10000);
for(i=0;i<64;i++)
{
	HAL_Delay(10);
	printf("0x%02X  ",r[i]);
}
  /* USER CODE END 2 */

分批次写入

单片机烧录,运行

 注意:确保写入时地址不会溢出,否则可能像当时的菜鸡博主一样搞半天(如下)

 

<think>好的,我现在需要帮用户解决如何使用STM32CubeMX配置I2C外设的问题。首先,我得回忆一下STM32CubeMX的基本操作流程。用户提到了引脚和时钟的设置,可能还需要考虑I2C协议的相关参数,比如时钟速度、地址模式等。 首先,我应该从创建工程开始。用户可能使用的是特定的STM32型号,比如F4系列,但步骤应该是通用的。创建工程时选择正确的微控制器型号是关键,比如在示例中的STM32F407VETx。这部分需要详细说明,确保用户不会选错型号。 接下来是配置时钟树。用户之前的引用中提到了时钟树的配置,所以需要提到在Clock Configuration中设置HCLK为最大频率,比如168MHz,并确保I2C的时钟源正确,比如APB1总线时钟。这部分可能涉及到系统时钟的配置,用户可能需要先完成基本的时钟设置,如引用[1]所述。 然后是I2C参数的设置。这里需要分步骤说明如何选择I2C模式(标准模式或快速模式),设置时钟速度,7位或10位地址模式,以及是否启用时钟延长。这些参数会影响I2C的通信速率和兼容性,比如标准模式是100kHz,快速模式是400kHz。用户可能需要根据连接的设备(如MPU6050或EEPROM)来选择合适的模式,如引用[2]和[4]提到的设备。 引脚配置部分,需要指出SDA和SCL对应的GPIO引脚,并设置正确的模式为I2C。例如,PB6和PB7作为I2C1的引脚,可能需要配置为复用开漏输出,并启用上拉电阻。这部分需要参考用户提供的引用[4],其中提到PB6和PB7连接到SCL和SDA。 生成代码后的初始化部分,用户需要知道如何调用HAL函数,比如HAL_I2C_Init(),并可能需要添加自己的读写函数。这里可以提到用户可能需要参考引用[3]中关于I2C层次结构和协议的内容,确保通信的正确性。 最后,用户可能会遇到问题,比如通信失败,需要检查硬件连接、地址是否正确、时钟配置等。这部分需要给出常见的排查步骤,帮助用户自行解决问题。 现在需要确保回答结构清晰,分步骤说明,同时引用用户提供的参考文献,比如在配置时钟树时提到引用[1],在引脚配置时提到引用[4]等。同时,根据用户的要求,生成相关问题,可能涉及I2C协议、调试方法、应用实例等。 另外,需要注意用户提到的系统级指令,比如数学公式的格式,但在这个问题中可能用不到数学公式。回答需要使用中文,并且符合Markdown格式,但用户要求最终的思考过程用口语化的中文描述,不需要格式。现在需要将整个思考过程整理成自然的口语化表达,分步骤详细说明,确保覆盖所有关键点,并正确引用提供的资料。</think>### 使用STM32CubeMX配置I2C外设的步骤详解 #### 1. **创建新工程** - 打开STM32CubeMX,选择`File > New Project`。 - 在芯片选择界面输入目标型号(如STM32F407VETx),双击确认[^1]。 #### 2. **配置系统时钟** - 进入`Clock Configuration`选项卡,确保HCLK(系统主频)设置为芯片支持的最大值(如168MHz)。 - 检查APB1总线时钟(I2C时钟源),需满足I2C协议要求(标准模式≤100kHz,快速模式≤400kHz)[^3]。 #### 3. **启用I2C外设** - 在`Pinout & Configuration`界面,左侧导航栏选择`Connectivity > I2C1`。 - 将`Mode`设置为`I2C`模式,此时软件会自动分配SDA(如PB7)和SCL(如PB6)引脚[^4]。 - **注意**:若引脚被其他功能占用,需手动调整或重映射。 #### 4. **配置I2C参数** - 在右侧参数设置栏中: - **Timing Settings**: 选择预定义模式(如`Standard Mode`对应100kHz)或手动输入`Timing`值。 - **Own Address**: 设置STM32作为从机时的地址(主模式可忽略)。 - **Clock Stretching**: 根据外设需求启用/禁用。 #### 5. **GPIO引脚设置** - 确认SDA/SCL引脚模式自动设置为`I2C_SDA`和`I2C_SCL`,模式为`Alternate Function Open Drain`。 - 建议在硬件设计中为这两个引脚添加外部上拉电阻(通常4.7kΩ)以确保信号稳定性[^4]。 #### 6. **生成代码** - 点击`Project > Generate Code`,选择IDE类型(如Keil或STM32CubeIDE)。 - 勾选`Generate peripheral initialization as a pair of .c/.h files`以分离配置代码。 #### 7. **编写应用代码** - 在生成的工程中,I2C初始化代码位于`i2c.c`(函数`MX_I2C1_Init()`)。 - 调用HAL函数进行通信: ```c HAL_I2C_Master_Transmit(&hi2c1, DEVICE_ADDR, data, size, timeout); // 发送数据 HAL_I2C_Master_Receive(&hi2c1, DEVICE_ADDR, data, size, timeout); // 接收数据 ``` - **注意**:`DEVICE_ADDR`需左移1位(HAL要求7位地址格式)[^2][^3]。 #### 8. **调试与验证** - 使用逻辑分析仪抓取SDA/SCL波形,确认时序符合预期。 - 若通信失败,检查: - 硬件连接(短路/虚焊) - 设备地址是否正确 - 是否启用I2C时钟(`__HAL_RCC_I2C1_CLK_ENABLE()`)
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值