一、先了解一下硬件的连接,I2C_SDA和I2C_SCL分别接STM32的PB9、PB6
二、粗阅一下M24C64的数据手册,得知器件地址和存储器地址,器件地址是8bit,而存储器地址是16bit
三、下面是M24C64的写时序
四、下面是M24C64的读时序
五、下面是程序编写流程
六、看看时序参数
七、好啦!需要的知识点差不多都提到了开始搬砖
1、用STM32CubeMX配置生成工程,并打开工程。(具体怎么用这个软件这里不讲)
2、在我的工程里是这样配置的
《1》配置USART3,用打印读出来的数据与写入的是否一致
《2》配置PB6、PB9为开漏输出模式,配置如下:
void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_RESET); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6|GPIO_PIN_9, GPIO_PIN_RESET); /*Configure GPIO pin : PG7 */ GPIO_InitStruct.Pin = GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); /*Configure GPIO pins : PB6 PB9 */ GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_9; //PB6 PB9 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; //开漏输出 GPIO_InitStruct.Pull = GPIO_NOPULL; //上下拉模式配置为既不上拉也不下拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;//IO口速度配置 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //初始化 } 在这里插入代码片1234567891011121314151617181920212223242526272829303132
八、编写读程序,下面的代码是(安富莱电子 www.armfly.com)串行EEPROM 24xx驱动模块的代码,
代码如下:
/*********************************************************************************************** * * * * * * * * ***************************************************************************************************/ #include "stm32f4xx_hal.h" #define EE_MODEL_NAME "AT24C64" #define EE_DEV_ADDR 0xA0 /* 设备地址 */ #define EE_PAGE_SIZE 32 /* 页面大小(字节) */ #define EE_SIZE (8*1024) /* 总容量(字节) */ #define EE_ADDR_BYTES 2 /* 地址字节个数 */ // 定义I2C总线连接的GPIO端口, 用户只需要修改下面3行代码即可任意改变SCL和SDA的引脚 #define GPIO_PORT_I2C GPIOB // GPIO端口 #define I2C_SCL_PIN GPIO_PIN_6 // 连接到SCL时钟线的GPIO #define I2C_SDA_PIN GPIO_PIN_9 // 连接到SDA数据线的GPIO /* 定义读写SCL和SDA的宏 */ #define I2C_SCL_1() GPIO_PORT_I2C->BSRR = I2C_SCL_PIN // SCL = 1 #define I2C_SCL_0() GPIO_PORT_I2C->BSRR = (uint32_t)I2C_SCL_PINBSRR = (uint32_t)GPIO_PIN_9 IDR & I2C_SCL_PIN) // 读SCL口线状态 static void i2c_Delay(void) { uint8_t i; for (i = 0; i > 7) & 0x0E)); /* 此处是写指令 */ // #else i2c_SendByte(EE_DEV_ADDR | I2C_WR); // #endif /* 第3步:发送一个时钟,判断器件是否正确应答 */ if (i2c_WaitAck() == 0) { break; } } if (m == 1000) { goto cmd_fail; /* EEPROM器件写超时 */ } /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */ if (EE_ADDR_BYTES == 1) { i2c_SendByte((uint8_t)usAddr); if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } } else { i2c_SendByte(usAddr >> 8); if (i2c_WaitAck()!= 0) { goto cmd_fail; /* EEPROM器件无应答 */ } i2c_SendByte(usAddr); if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } } } /* 第6步:开始写入数据 */ i2c_SendByte(_pWriteBuf[i]); /* 第7步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } usAddr++; /* 地址增1 */ } /* 命令执行成功,发送I2C总线停止信号 */ i2c_Stop(); /* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms CLK频率为200KHz时,查询次数为30次左右 */ for (m = 0; m > 7) & 0x0E)); /* 此处是写指令 */ #else i2c_SendByte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */ #endif /* 第3步:发送一个时钟,判断器件是否正确应答 */ if (i2c_WaitAck() == 0) { break; } } if (m == 1000) { goto cmd_fail; /* EEPROM器件写超时 */ } /* 命令执行成功,发送I2C总线停止信号 */ i2c_Stop(); return 1; cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */ /* 发送I2C总线停止信号 */ i2c_Stop(); return 0; } uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize) { uint16_t i; /* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */ /* 第1步:发起I2C总线启动信号 */ i2c_Start(); /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */ /* 第3步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } /* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */ if (EE_ADDR_BYTES == 1) { i2c_SendByte((uint8_t)_usAddress); if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } } else { i2c_SendByte(_usAddress >> 8); if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } i2c_SendByte(_usAddress); if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } } /* 第6步:重新启动I2C总线。下面开始读取数据 */ i2c_Start(); /* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte(EE_DEV_ADDR | I2C_RD); /* 此处是写指令 */ /* 第8步:发送ACK */ if (i2c_WaitAck() != 0) { goto cmd_fail; /* EEPROM器件无应答 */ } /* 第9步:循环读取数据 */ for (i = 0; i
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』