嵌入式|STM32硬件IIC读写EEPROM
前面一篇写了软件模拟IIC读写EEPROM。
本篇介绍硬件IIC读写EEPROM。平台是STM32F103+AT24C04N。SDA和SCL接5K上拉电阻到3.3v。
首先介绍AT24C04N的基本特性。512byte。支持1.8v~5.5v供电。支持5种读写模式。BYTE WRITE(字节写),PAGE WRITE(按页写)。RANDOM READ(随机读),SEQUENTIAL READ(顺序读)和CURRENT ADDRESS READ .具体时序参考数据手册。
文章图片
【嵌入式|STM32硬件IIC读写EEPROM】
文章图片
我用的是I2C1接口。
宏定义如下:
#define EEPROM_Block_ADDRESS 0xA0/* Device Address */#define I2C1_SLAVE_ADDRESS70xA0
#define I2C_PageSize16
#define I2C_BUF_LEN256#define EEPROM_I2CI2C1
#define EEPROM_I2C_CLKRCC_APB1Periph_I2C1
#define EEPROM_I2C_SCL_PINGPIO_Pin_6/* PB.6 */
#define EEPROM_I2C_SCL_GPIO_PORTGPIOB/* GPIOB */
#define EEPROM_I2C_SCL_GPIO_CLKRCC_APB2Periph_GPIOB
#define EEPROM_I2C_SDA_PINGPIO_Pin_7/* PB.7 */
#define EEPROM_I2C_SDA_GPIO_PORTGPIOB/* GPIOB */
#define EEPROM_I2C_SDA_GPIO_CLKRCC_APB2Periph_GPIOB#define I2C_SPEED 200000extern uint8_t I2C_Buf[I2C_BUF_LEN];
配置和功能函数如下:
/* Includes ------------------------------------------------------------------*/
#include /* Private macro -------------------------------------------------------------*/
#define TIMEOUT 1000/* Private variables ---------------------------------------------------------*/
uint8_t EEPROM_ADDRESS = EEPROM_Block_ADDRESS;
u32 I2C_Timeout =1000;
static void delay_ms(u32 t)
{
u16 i = 8000;
while(t--)
{
i = 8000;
while(i--);
}
}static void delay_us(u32 d)
{
while(d--) ;
}/**
* @briefConfigure the used I/O ports pin
* @paramNone
* @retval : None
*/
void GPIO_Configuration(void)
{
#if 1
GPIO_InitTypeDefGPIO_InitStructure;
RCC_APB2PeriphClockCmd( EEPROM_I2C_SCL_GPIO_CLK | EEPROM_I2C_SDA_GPIO_CLK, ENABLE );
/* Configure I2C1 pins: SCL and SDA */
GPIO_InitStructure.GPIO_Pin=EEPROM_I2C_SCL_PIN | EEPROM_I2C_SDA_PIN;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;
//GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT | EEPROM_I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
GPIO_Init(EEPROM_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
#endif
}/**
* @briefI2C Configuration
* @paramNone
* @retval : None
*/
void I2C_Configuration(void)
{
#if 1
I2C_InitTypeDefI2C_InitStructure;
RCC_APB1PeriphClockCmd( EEPROM_I2C_CLK, ENABLE );
/* I2C configuration */
I2C_InitStructure.I2C_Mode= I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle= I2C_DutyCycle_2;
//I2C_InitStructure.I2C_OwnAddress1 = I2C1_SLAVE_ADDRESS7;
I2C_InitStructure.I2C_Ack= I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed= I2C_SPEED;
/* Apply I2C configuration after enabling it */
I2C_Init(EEPROM_I2C, &I2C_InitStructure);
/* I2C Peripheral Enable */
I2C_Cmd(EEPROM_I2C, ENABLE);
#endif
}/**
* @briefInitializes peripherals used by the I2C EEPROM driver.
* @paramNone
* @retval : None
*/
void I2C_EE_Init()
{
/* GPIO configuration */
GPIO_Configuration();
/* I2C configuration */
I2C_Configuration();
/* depending on the EEPROM Address selected in the i2c_ee.h file */
/* Select the EEPROM Block0 to write on */
EEPROM_ADDRESS = EEPROM_Block_ADDRESS;
}
/**
* @briefWrites one byte to the I2C EEPROM.
* @param pBuffer : pointer to the buffercontaining the data to be
*written to the EEPROM.
* @param WriteAddr : EEPROM's internal address to write to.
* @retval : None
*/
void I2C_EE_ByteWrite(uint8_t* pBuffer, uint8_t WriteAddr)
{
/* While the bus is busy */
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY));
/* Send STRAT condition */
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
{
if(I2C_Timeout-- == 0) break;
}/* Send EEPROM address for write */
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2C_Timeout = TIMEOUT;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if(I2C_Timeout-- == 0) break;
}/* Send the EEPROM's internal address to write to */
I2C_SendData(EEPROM_I2C, WriteAddr);
I2C_Timeout = TIMEOUT;
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if(I2C_Timeout-- == 0) break;
}/* Send the byte to be written */
I2C_SendData(EEPROM_I2C, *pBuffer);
I2C_Timeout = TIMEOUT;
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if(I2C_Timeout-- == 0) break;
}/* Send STOP condition */
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
/* 延时不得小于5ms write cycle time*/
delay_ms(15);
}/**
* @briefWrites more than one byte to the EEPROM with a single WRITE
*cycle. The number of byte can't exceed the EEPROM page size.
* @param pBuffer : pointer to the buffer containing the data to be
*written to the EEPROM.
* @param WriteAddr : EEPROM's internal address to write to.
* @param NumByteToWrite : number of bytes to write to the EEPROM.
* @retval : None
*/
void I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr)
{
#if 1
uint8_t NumByteToWrite;
NumByteToWrite = I2C_PageSize;
/* While the bus is busy */
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY));
/* Send START condition */
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT));
/* Send EEPROM address for write */
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
/* Send the EEPROM's internal address to write to */
I2C_SendData(EEPROM_I2C, WriteAddr);
/* Test on EV8 and clear it */
while(! I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
/* While there is data to be written */
while(NumByteToWrite--)
{
/* Send the current byte */
I2C_SendData(EEPROM_I2C, *pBuffer);
/* Point to the next byte to be written */
pBuffer++;
/* Test on EV8 and clear it */
while (!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}/* Send STOP condition */
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
/* 延时不得小于5ms write cycle time*/
delay_ms(20);
#endif
}void I2C_EE_RandomrRead(uint8_t* pBuffer, uint8_t ReadAddr)
{/* While the bus is busy */
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY));
/* step 1 Send START condition */
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
{
if(I2C_Timeout-- == 0) break;
}/* step 2 Send EEPROM address for write */
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Transmitter);
I2C_Timeout = TIMEOUT;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
{
if(I2C_Timeout-- == 0) break;
}/* Clear EV6 by setting again the PE bit */
I2C_Cmd(EEPROM_I2C, ENABLE);
//printf("\r\nstep 3:IIC reg addr \r\n");
/* step 3 Send the EEPROM's internal address to write to */
I2C_SendData(EEPROM_I2C, ReadAddr);
I2C_Timeout = TIMEOUT;
/* Test on EV8 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
{
if(I2C_Timeout-- == 0) break;
}/* step 4 Send STRAT condition a second time */
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
{
if(I2C_Timeout-- == 0) break;
}/*step 5Send EEPROM address for read */
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Receiver);
I2C_Timeout = TIMEOUT;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if(I2C_Timeout-- == 0) break;
}/*step 6Disable Acknowledgement */
I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
/*step 7 Send STOP Condition ,如果不在此处发stop信号, 而在接收数据后,会多收一个字节*/
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_RXNE) == RESET)
{
if(I2C_Timeout-- == 0) break;
}
*pBuffer = I2C_ReceiveData(EEPROM_I2C);
/*step 7 Send STOP Condition */
//I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
//printf("\r\nIIC rec data0x%x\r\n",*pBuffer);
}uint8_t I2C_EE_CurrentRead(void)
{
uint8_t recdata = https://www.it610.com/article/0x0;
#if 1
/* While the bus is busy */
while(I2C_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY));
/* step 4 Send STRAT condition a second time */
I2C_GenerateSTART(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
/* Test on EV5 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_MODE_SELECT))
{
if(I2C_Timeout-- == 0) break;
}/*step 5Send EEPROM address for read */
I2C_Send7bitAddress(EEPROM_I2C, EEPROM_ADDRESS, I2C_Direction_Receiver);
I2C_Timeout = TIMEOUT;
/* Test on EV6 and clear it */
while(!I2C_CheckEvent(EEPROM_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
{
if(I2C_Timeout-- == 0) break;
}/*step 6Disable Acknowledgement */
I2C_AcknowledgeConfig(EEPROM_I2C, DISABLE);
/*step 7 Send STOP Condition ,如果不在此处发stop信号, 而在接收数据后,会多收一个字节*/
I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
I2C_Timeout = TIMEOUT;
while(I2C_GetFlagStatus(EEPROM_I2C,I2C_FLAG_RXNE) == RESET)
{
if(I2C_Timeout-- == 0) break;
}recdata = I2C_ReceiveData(EEPROM_I2C);
/*step 7 Send STOP Condition */
//I2C_GenerateSTOP(EEPROM_I2C, ENABLE);
#endif
return recdata;
}
代码参考了普中科技的ARM板子例程。板子例程里有很多bug不太好用。如果有源码大家可以对比研究。我实现了随机读,顺序读,按字节写,按页写等4种标准操作。请注意注释部分,这些代码都经过平台验证,可以直接使用,因为我的板子A0~A2都接到GND上了,所以,我的代码支持前256字节操作。
实际波形如下:
文章图片
推荐阅读
- 嵌入式(编译内核、根文件系统等)
- 基于stm32智能风扇|基于stm32智能风扇_一款基于STM32的智能灭火机器人设计
- stm32|基于STM32和freeRTOS智能门锁设计方案
- STM32F4|STM32F4 TIM6 TIM7 基本定时器
- Android|Android 清单文件的硬件加速android:hardwareAccelerated 慎重
- 嵌入式-外设|DDR3基础详解
- SpringBoot中的嵌入式ActiveMQ
- 杭州视频会议硬件终端和四海云视频会议软件系统解决方案
- Ubuntu查看硬件配置
- 嵌入式电脑|Paddle Inference——基于python API在Jetson上部署PaddleSeg模型