赞
踩
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
EEPROM一共有256个字节对应的地址为(0~255)
当读取到最后一个字节,也就是255地址,第256个字节,在读取又会从头(第一个字节数据)开始读取。
STM32作为主机向从机EEPROM存储器写入256个字节的数据
STM32作为主机向从机EEPROM存储器读取写入的256个字节的数据
读写成功亮绿灯,读写失败亮红灯
编程要点
(1) 配置通讯使用的目标引脚为开漏模式;
(2) 编写模拟 I2C 时序的控制函数;
(3) 编写基本 I2C 按字节收发的函数;
(4) 编写读写 EEPROM 存储内容的函数;
(5) 编写测试程序,对读写数据进行校验。
两个引脚PB6,PB7都要配置成复用的开漏输出
这里有一个注意的点,你配置成输出模式,并不会影响引脚的输入功能
详情请看——>GPIO端口的八种工作模式
i2c_ee.h
前面理论已经讲得已经很详细了,直接上代码叭!!
#ifndef \_\_IIC\_EE\_H #define \_\_IIC\_EE\_H #include "stm32f10x.h" #include <stdio.h> //IIC1 #define EEPROM\_I2C I2C1 #define EEPROM\_I2C\_CLK RCC\_APB1Periph\_I2C1 #define EEPROM\_I2C\_APBxClkCmd RCC\_APB1PeriphClockCmd #define EEPROM\_I2C\_BAUDRATE 400000 // IIC1 GPIO 引脚宏定义 #define EEPROM\_I2C\_SCL\_GPIO\_CLK (RCC\_APB2Periph\_GPIOB) #define EEPROM\_I2C\_SDA\_GPIO\_CLK (RCC\_APB2Periph\_GPIOB) #define EEPROM\_I2C\_GPIO\_APBxClkCmd RCC\_APB2PeriphClockCmd #define EEPROM\_I2C\_SCL\_GPIO\_PORT GPIOB #define EEPROM\_I2C\_SCL\_GPIO\_PIN GPIO\_Pin\_6 #define EEPROM\_I2C\_SDA\_GPIO\_PORT GPIOB #define EEPROM\_I2C\_SDA\_GPIO\_PIN GPIO\_Pin\_7 //STM32自身地址1 与从机设备地址不相同即可(7位地址) #define STM32\_I2C\_OWN\_ADDR 0x6f //EEPROM设备地址 #define EEPROM\_I2C\_Address 0XA0 #define I2C\_PageSize 8 //等待次数 #define I2CT\_FLAG\_TIMEOUT ((uint32\_t)0x1000) #define I2CT\_LONG\_TIMEOUT ((uint32\_t)(10 \* I2CT\_FLAG\_TIMEOUT)) /\*信息输出\*/ #define EEPROM\_DEBUG\_ON 0 #define EEPROM\_INFO(fmt,arg...) printf("<<-EEPROM-INFO->> "fmt"\n",##arg) #define EEPROM\_ERROR(fmt,arg...) printf("<<-EEPROM-ERROR->> "fmt"\n",##arg) #define EEPROM\_DEBUG(fmt,arg...) do{\ if(EEPROM\_DEBUG\_ON)\ printf("<<-EEPROM-DEBUG->> [%d]"fmt"\n",\_\_LINE\_\_, ##arg);\ }while(0) void I2C\_EE\_Config(void); void EEPROM\_Byte\_Write(uint8\_t addr,uint8\_t data); uint32\_t EEPROM\_WaitForWriteEnd(void); uint32\_t EEPROM\_Page\_Write(uint8\_t addr,uint8\_t \*data,uint16\_t Num_ByteToWrite); uint32\_t EEPROM\_Read(uint8\_t \*data,uint8\_t addr,uint16\_t Num_ByteToRead); void I2C\_EE\_BufferWrite(uint8\_t\* pBuffer,uint8\_t WriteAddr, uint16\_t NumByteToWrite); #endif /\* \_\_IIC\_EE\_H \*/
i2c_ee.c
#include "i2c\_ee.h" //设置等待时间 static __IO uint32\_t I2CTimeout = I2CT_LONG_TIMEOUT; //等待超时,打印错误信息 static uint32\_t I2C\_TIMEOUT\_UserCallback(uint8\_t errorCode); void I2C\_EE\_Config(void) { GPIO_InitTypeDef GPIO_InitStuctrue; I2C_InitTypeDef I2C_InitStuctrue; //开启GPIO外设时钟 EEPROM\_I2C\_GPIO\_APBxClkCmd(EEPROM_I2C_SCL_GPIO_CLK|EEPROM_I2C_SDA_GPIO_CLK,ENABLE); //开启IIC外设时钟 EEPROM\_I2C\_APBxClkCmd(EEPROM_I2C_CLK,ENABLE); //SCL引脚-复用开漏输出 GPIO_InitStuctrue.GPIO_Mode=GPIO_Mode_AF_OD; GPIO_InitStuctrue.GPIO_Pin=EEPROM_I2C_SCL_GPIO_PIN; GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz; GPIO\_Init(EEPROM_I2C_SCL_GPIO_PORT,&GPIO_InitStuctrue); //SDA引脚-复用开漏输出 GPIO_InitStuctrue.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStuctrue.GPIO_Pin = EEPROM_I2C_SDA_GPIO_PIN; GPIO_InitStuctrue.GPIO_Speed=GPIO_Speed_50MHz; GPIO\_Init(EEPROM_I2C_SDA_GPIO_PORT,&GPIO_InitStuctrue); //IIC结构体成员配置 I2C_InitStuctrue.I2C_Ack=I2C_Ack_Enable; I2C_InitStuctrue.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit; I2C_InitStuctrue.I2C_ClockSpeed=EEPROM_I2C_BAUDRATE; I2C_InitStuctrue.I2C_DutyCycle=I2C_DutyCycle_2; I2C_InitStuctrue.I2C_Mode=I2C_Mode_I2C; I2C_InitStuctrue.I2C_OwnAddress1=STM32_I2C_OWN_ADDR; I2C\_Init(EEPROM_I2C,&I2C_InitStuctrue); I2C\_Cmd(EEPROM_I2C,ENABLE); } //向EEPROM写入一个字节 void EEPROM\_Byte\_Write(uint8\_t addr,uint8\_t data) { //发送起始信号 I2C\_GenerateSTART(EEPROM_I2C,ENABLE); //检测EV5事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR); //发送设备写地址 I2C\_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter); //检测EV6事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR); //发送要操作设备内部的地址 I2C\_SendData(EEPROM_I2C,addr); while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR); I2C\_SendData(EEPROM_I2C,data); //检测EV8\_2事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR); //发送停止信号 I2C\_GenerateSTOP(EEPROM_I2C,ENABLE); } //向EEPROM写入多个字节 uint32\_t EEPROM\_Page\_Write(uint8\_t addr,uint8\_t \*data,uint16\_t Num_ByteToWrite) { I2CTimeout = I2CT_LONG_TIMEOUT; //判断IIC总线是否忙碌 while(I2C\_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY)) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(1); } //重新赋值 I2CTimeout = I2CT_FLAG_TIMEOUT; //发送起始信号 I2C\_GenerateSTART(EEPROM_I2C,ENABLE); //检测EV5事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT)==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(2); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送设备写地址 I2C\_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter); //检测EV6事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(3); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送要操作设备内部的地址 I2C\_SendData(EEPROM_I2C,addr); //检测EV8事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(4); } while(Num_ByteToWrite) { I2C\_SendData(EEPROM_I2C,\*data); I2CTimeout = I2CT_FLAG_TIMEOUT; while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(5); } Num_ByteToWrite--; data++; } I2CTimeout = I2CT_FLAG_TIMEOUT; //检测EV8\_2事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(6); } //发送停止信号 I2C\_GenerateSTOP(EEPROM_I2C,ENABLE); return 1; } //向EEPROM读取多个字节 uint32\_t EEPROM\_Read(uint8\_t \*data,uint8\_t addr,uint16\_t Num_ByteToRead) { I2CTimeout = I2CT_LONG_TIMEOUT; //判断IIC总线是否忙碌 while(I2C\_GetFlagStatus(EEPROM_I2C, I2C_FLAG_BUSY)) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(1); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送起始信号 I2C\_GenerateSTART(EEPROM_I2C,ENABLE); //检测EV5事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(7); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送设备写地址 I2C\_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter); //检测EV6事件等待从机应答 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(8); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送要操作设备内部存储器的地址 I2C\_SendData(EEPROM_I2C,addr); //检测EV8事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_TRANSMITTING )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(9); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送起始信号 I2C\_GenerateSTART(EEPROM_I2C,ENABLE); //检测EV5事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(10); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送设备读地址 I2C\_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Receiver); //检测EV6事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(10); } while(Num_ByteToRead--) { //是否是最后一个字节,若是则发送非应答信号 if( Num_ByteToRead==0) { //发送非应答信号 I2C\_AcknowledgeConfig(EEPROM_I2C,DISABLE); //发送停止信号 I2C\_GenerateSTOP(EEPROM_I2C,ENABLE); } I2CTimeout = I2CT_FLAG_TIMEOUT; //检测EV7事件 while( I2C\_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_BYTE_RECEIVED )==ERROR) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(10); } \*data=I2C\_ReceiveData(EEPROM_I2C); data++; } //重新开启应答信号 I2C\_AcknowledgeConfig(EEPROM_I2C,ENABLE); return 1; } void I2C\_EE\_BufferWrite(uint8\_t\* pBuffer,uint8\_t WriteAddr, uint16\_t NumByteToWrite) { u8 NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0; //I2C\_PageSize=8 Addr = WriteAddr % I2C_PageSize; count = I2C_PageSize - Addr; NumOfPage = NumByteToWrite / I2C_PageSize; NumOfSingle = NumByteToWrite % I2C_PageSize; /\* 写入数据的地址对齐,对齐数为8 \*/ if(Addr == 0) { /\* 如果写入的数据个数小于8 \*/ if(NumOfPage == 0) { EEPROM\_Page\_Write(WriteAddr, pBuffer, NumOfSingle); EEPROM\_WaitForWriteEnd(); } /\* 如果写入的数据个数大于8 \*/ else { //按页写入 while(NumOfPage--) { EEPROM\_Page\_Write(WriteAddr, pBuffer, I2C_PageSize); EEPROM\_WaitForWriteEnd(); WriteAddr += I2C_PageSize; pBuffer += I2C_PageSize; } //不足一页(8个)单独写入 if(NumOfSingle!=0) { EEPROM\_Page\_Write(WriteAddr, pBuffer, NumOfSingle); EEPROM\_WaitForWriteEnd(); } } } /\*写的数据的地址不对齐\*/ else { NumByteToWrite -= count; NumOfPage = NumByteToWrite / I2C_PageSize; NumOfSingle = NumByteToWrite % I2C_PageSize; if(count != 0) { EEPROM\_Page\_Write(WriteAddr, pBuffer, count); EEPROM\_WaitForWriteEnd(); WriteAddr += count; pBuffer += count; } while(NumOfPage--) { EEPROM\_Page\_Write(WriteAddr, pBuffer, I2C_PageSize); EEPROM\_WaitForWriteEnd(); WriteAddr += I2C_PageSize; pBuffer += I2C_PageSize; } if(NumOfSingle != 0) { EEPROM\_Page\_Write(WriteAddr, pBuffer, NumOfSingle); EEPROM\_WaitForWriteEnd(); } } } uint32\_t EEPROM\_WaitForWriteEnd(void) { I2CTimeout = I2CT_FLAG_TIMEOUT; do { I2CTimeout = I2CT_FLAG_TIMEOUT; //发送起始信号 I2C\_GenerateSTART(EEPROM_I2C,ENABLE); //检测EV5事件 while( I2C\_GetFlagStatus(EEPROM_I2C,I2C_FLAG_SB )==RESET) { if((I2CTimeout--) == 0) return I2C\_TIMEOUT\_UserCallback(10); } I2CTimeout = I2CT_FLAG_TIMEOUT; //发送设备写地址 I2C\_Send7bitAddress(EEPROM_I2C,EEPROM_I2C_Address,I2C_Direction_Transmitter); }while( (I2C\_GetFlagStatus(EEPROM_I2C,I2C_FLAG_ADDR )==RESET) && (I2CTimeout--) ); //发送停止信号 I2C\_GenerateSTOP(EEPROM_I2C,ENABLE); return 1; } static uint32\_t I2C\_TIMEOUT\_UserCallback(uint8\_t errorCode) { /\* Block communication and all processes \*/ EEPROM\_ERROR("I2C 等待超时!errorCode = %d",errorCode); return 0; }
main.c
#include "stm32f10x.h" #include "led.h" #include "./i2c/i2c\_ee.h" #include <string.h> #include "usart.h" #define SOFT\_DELAY Delay(0x0FFFFF); void Delay(__IO u32 nCount); //声明I2C测试函数 uint8\_t I2C\_EE\_Test(void); int main(void) { //初始化IIC I2C\_EE\_Config(); //初始化USART Usart\_Config(); //初始化LED LED\_GPIO\_Config(); printf("\r\nIIC读写EEPROM测试实验\r\n"); //读写成功亮绿灯,失败亮红灯 if( I2C\_EE\_Test()==1 ) { LED\_G(NO); } else { LED\_R(NO); } while(1) { ; } } uint8\_t I2C\_EE\_Test(void) { uint8\_t ReadData[256]={0}; uint8\_t WriteDdta[256]={0}; uint16\_t i; //初始化写入数组 for(i=0;i<256;i++) { WriteDdta[i]=i; } //向EEPROM从地址为0开始写入256个字节的数据 I2C\_EE\_BufferWrite(WriteDdta,0,256); //等待EEPROM写入数据完成 EEPROM\_WaitForWriteEnd(); //向EEPROM从地址为0开始读出256个字节的数据 EEPROM\_Read(ReadData,0,256); for (i=0; i<256; i++) { if(ReadData[i] != WriteDdta[i]) { EEPROM\_ERROR("0x%02X ", ReadData[i]); EEPROM\_ERROR("错误:I2C EEPROM写入与读出的数据不一致\n\r"); return 0; } printf("0x%02X ", ReadData[i]); if(i%16 == 15) printf("\n\r"); } EEPROM\_INFO("I2C(AT24C02)读写测试成功\n\r"); return 1; } void Delay(__IO uint32\_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); }
重点讲一下,如何解决以下页写入问题,实现连续写入
现在来解释代码中下图函数如何解决问题
如果地址对齐:
如果地址不对齐:
STM32作为主机向从机EEPROM存储器写入256个字节的数据
STM32作为主机向从机EEPROM存储器读取写入的256个字节的数据
读写成功亮绿灯,读写失败亮红灯
软件模式I2C由我们CPU来控制引脚产生I2C时序,所以我们随便选引脚都可以,不过你选择的引脚肯定要连接到通信的EEPROM的SCL,SDA引脚上。这里是用了PC12,PC11充当主机STM32SCL,SDA引脚。
i2c_gpio.h
#ifndef \_I2C\_GPIO\_H #define \_I2C\_GPIO\_H #include "stm32f10x.h" #define EEPROM\_I2C\_WR 0 /\* 写控制bit \*/ #define EEPROM\_I2C\_RD 1 /\* 读控制bit \*/ #define EEPROM\_GPIO\_PORT\_I2C GPIOB #define EEPROM\_RCC\_I2C\_PORT RCC\_APB2Periph\_GPIOB #define EEPROM\_I2C\_SCL\_PIN GPIO\_Pin\_6 #define EEPROM\_I2C\_SDA\_PIN GPIO\_Pin\_7 /\*当 STM32 的 GPIO 配置成开漏输出模式时,它仍然可以通过读取 GPIO 的输入数据寄存器获取外部对引脚的输入电平,也就是说它同时具有浮空输入模式的 功能\*/ #define EEPROM\_I2C\_SCL\_1() EEPROM\_GPIO\_PORT\_I2C->BSRR |= EEPROM\_I2C\_SCL\_PIN /\* SCL = 1 \*/ #define EEPROM\_I2C\_SCL\_0() EEPROM\_GPIO\_PORT\_I2C->BRR |= EEPROM\_I2C\_SCL\_PIN /\* SCL = 0 \*/ #define EEPROM\_I2C\_SDA\_1() EEPROM\_GPIO\_PORT\_I2C->BSRR |= EEPROM\_I2C\_SDA\_PIN /\* SDA = 1 \*/ #define EEPROM\_I2C\_SDA\_0() EEPROM\_GPIO\_PORT\_I2C->BRR |= EEPROM\_I2C\_SDA\_PIN /\* SDA = 0 \*/ #define EEPROM\_I2C\_SDA\_READ() ((EEPROM\_GPIO\_PORT\_I2C->IDR & EEPROM\_I2C\_SDA\_PIN)!=0 ) /\* 读SDA口线状态 \*/ void i2c\_Start(void); void i2c\_Stop(void); void i2c\_Ack(void); void i2c\_NAcK(void); uint8\_t i2c\_WaitAck(void); void i2c\_SendByte(uint8\_t data); uint8\_t i2c\_ReadByte(void); uint8\_t i2c\_CheckDevice(uint8\_t Address); #endif /\* \_I2C\_GPIO\_H \*/
i2c_gpio.c
#include "i2c\_gpio.h" #include "stm32f10x.h" void I2c\_gpio\_config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC\_APB2PeriphClockCmd(EEPROM_RCC_I2C_PORT, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Pin = EEPROM_I2C_SCL_PIN | EEPROM_I2C_SDA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO\_Init(EEPROM_GPIO_PORT_I2C, &GPIO_InitStructure); /\* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 \*/ i2c\_Stop(); } static void i2c\_Delay(void) { uint8\_t i; for(i=0;i<10;i++) { } } void i2c\_Start(void) { EEPROM\_I2C\_SCL\_1(); EEPROM\_I2C\_SDA\_1(); i2c\_Delay(); EEPROM\_I2C\_SDA\_0(); i2c\_Delay(); EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); } void i2c\_Stop(void) { EEPROM\_I2C\_SDA\_0(); EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); EEPROM\_I2C\_SDA\_1(); i2c\_Delay(); } void i2c\_Ack(void) { EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); EEPROM\_I2C\_SDA\_0(); i2c\_Delay(); EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); EEPROM\_I2C\_SDA\_1(); i2c\_Delay(); } void i2c\_NAcK(void) { EEPROM\_I2C\_SDA\_1(); i2c\_Delay(); EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); } uint8\_t i2c\_WaitAck(void) { uint8\_t ret; EEPROM\_I2C\_SDA\_1(); EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); if( EEPROM\_I2C\_SDA\_READ() ) { ret=1; } else { ret=0; } EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); return ret; } void i2c\_SendByte(uint8\_t data) { uint8\_t i; for(i=0;i<8;i++) { if( data&0x80 ) { EEPROM\_I2C\_SDA\_1(); } else { EEPROM\_I2C\_SDA\_0(); } i2c\_Delay(); EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); if( i==7 ) { EEPROM\_I2C\_SDA\_1(); i2c\_Delay(); } data=data<<1; } } uint8\_t i2c\_ReadByte(void) { uint8\_t value=0; uint8\_t i; for(i=0;i<8;i++) { value=value<<1; EEPROM\_I2C\_SCL\_1(); i2c\_Delay(); if( EEPROM\_I2C\_SDA\_READ() ) { value++; } EEPROM\_I2C\_SCL\_0(); i2c\_Delay(); } return value; } uint8\_t i2c\_CheckDevice(uint8\_t Address) { uint8\_t ucACK; I2c\_gpio\_config(); i2c\_Start(); i2c\_SendByte(Address|EEPROM_I2C_WR); ucACK=i2c\_WaitAck(); i2c\_Stop(); return ucACK; }
i2c_ee.h
#ifndef \_I2C\_EE\_H #define \_I2C\_EE\_H #include "stm32f10x.h" #define EEPROM\_DEV\_ADDR 0xA0 /\* 24xx02的设备地址 \*/ #define EEPROM\_PAGE\_SIZE 8 /\* 24xx02的页面大小 \*/ #define EEPROM\_SIZE 256 /\* 24xx02总容量 \*/ uint8\_t ee\_Checkok(void); uint8\_t ee\_ReadByte( uint8\_t \*pReaddata,uint16\_t Address,uint16\_t num ); uint8\_t ee\_WriteByte( uint8\_t \*Writepdata,uint16\_t Address,uint16\_t num ); uint8\_t ee\_WaitStandby(void); uint8\_t ee\_WriteBytes(uint8\_t \*_pWriteBuf, uint16\_t _usAddress, uint16\_t _usSize); uint8\_t ee\_ReadBytes(uint8\_t \*_pReadBuf, uint16\_t _usAddress, uint16\_t _usSize); uint8\_t ee\_Test(void) ; #endif /\* \_I2C\_EE\_H\*/
i2c_ee.c
#include "i2c\_ee.h" #include "i2c\_gpio.h" //检测EEPORM是否忙碌 uint8\_t ee\_Checkok(void) { if(i2c\_CheckDevice(EEPROM_DEV_ADDR)==0) { return 1; } else { i2c\_Stop(); return 0; } } //检测EEPROM写入数完成 uint8\_t ee\_WaitStandby(void) { uint32\_t wait_count = 0; while(i2c\_CheckDevice(EEPROM_DEV_ADDR)) { //若检测超过次数,退出循环 if(wait_count++>0xFFFF) { //等待超时 return 1; } } //等待完成 return 0; } //向EEPROM写入多个字节 uint8\_t ee\_WriteBytes(uint8\_t \*_pWriteBuf, uint16\_t _usAddress, uint16\_t _usSize) { uint16\_t i,m; uint16\_t addr; addr=_usAddress; for(i=0;i<_usSize;i++) { //当第一次或者地址对齐到8就要重新发起起始信号和EEPROM地址 //为了解决8地址对齐问题 if(i==0 || (addr % EEPROM_PAGE_SIZE)==0 ) { //循环发送起始信号和EEPROM地址的原因是为了等待上一次写入的一页数据\ 写入完成 for(m=0;m<1000;m++) { //发送起始地址 i2c\_Start(); //发送设备写地址 i2c\_SendByte(EEPROM_DEV_ADDR|EEPROM_I2C_WR); //等待从机应答 if( i2c\_WaitAck()==0 ) { break; } } //若等待的1000次从机还未应答,等待超时 if( m==1000 ) { goto cmd_fail; } //EEPROM应答后发送EEPROM的内部存储器地址 i2c\_SendByte((uint8\_t)addr); //等待从机应答 if( i2c\_WaitAck()!=0 ) { goto cmd_fail; } } //发送数据 i2c\_SendByte(_pWriteBuf[i]); //等待应答 if( i2c\_WaitAck()!=0 ) { goto cmd_fail; } //写入地址加1 addr++; } i2c\_Stop(); return 1; cmd_fail: i2c\_Stop(); return 0; } uint8\_t ee\_ReadBytes(uint8\_t \*_pReadBuf, uint16\_t _usAddress, uint16\_t _usSize) { uint16\_t i; i2c\_Start(); i2c\_SendByte(EEPROM_DEV_ADDR|EEPROM_I2C_WR); if( i2c\_WaitAck()!=0 ) { goto cmd_fail; } i2c\_SendByte((uint8\_t)_usAddress); if( i2c\_WaitAck()!=0 ) { goto cmd_fail; } i2c\_Start(); i2c\_SendByte(EEPROM_DEV_ADDR|EEPROM_I2C_RD); if( i2c\_WaitAck()!=0 ) { goto cmd_fail; } for(i=0;i<_usSize;i++) { _pReadBuf[i]=i2c\_ReadByte(); /\* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack \*/ if (i != _usSize - 1) { // i2c\_NAcK(); /\* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) \*/ i2c\_Ack(); /\* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) \*/ } else { i2c\_NAcK(); /\* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) \*/ } } i2c\_Stop(); return 1; cmd_fail: i2c\_Stop(); return 0; } uint8\_t ee\_Test(void) { uint16\_t i; uint8\_t write_buf[EEPROM_SIZE]; uint8\_t read_buf[EEPROM_SIZE]; /\*-----------------------------------------------------------------------------------\*/ if (i2c\_CheckDevice(EEPROM_DEV_ADDR) == 1) { /\* 没有检测到EEPROM \*/ printf("没有检测到串行EEPROM!\r\n"); return 0; } /\*------------------------------------------------------------------------------------\*/ /\* 填充测试缓冲区 \*/ for (i = 0; i < EEPROM_SIZE; i++) { write_buf[i] = i; } /\*------------------------------------------------------------------------------------\*/ if (ee\_WriteBytes(write_buf, 0, EEPROM_SIZE) == 0) { printf("写EEPROM出错!\r\n"); return 0; } else { printf("写EEPROM成功!\r\n"); } /\*-----------------------------------------------------------------------------------\*/ if (ee\_ReadBytes(read_buf, 0, EEPROM_SIZE) == 0) { printf("EEPROM出错!\r\n"); return 0; } else { printf("EEPROM成功,数据如下:\r\n"); } /\*-----------------------------------------------------------------------------------\*/ for (i = 0; i < EEPROM_SIZE; i++) { if(read_buf[i] != write_buf[i]) { printf("0x%02X ", read_buf[i]); printf("错误:EEPROM读出与写入的数据不一致"); return 0; } printf(" %02X", read_buf[i]); if ((i & 15) == 15) { printf("\r\n"); } } printf("EEPROM读写测试成功\r\n"); return 1; }
main
#include "stm32f10x.h" ![img](https://img-blog.csdnimg.cn/img_convert/f754a0b6dc156951eda27688b81a0e5d.png) ![img](https://img-blog.csdnimg.cn/img_convert/3955ab88c1c22f530954a7631bc7ffc7.png) **既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!** **由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新** **[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)** printf("写EEPROM成功!\r\n"); } /\*-----------------------------------------------------------------------------------\*/ if (ee\_ReadBytes(read_buf, 0, EEPROM_SIZE) == 0) { printf("EEPROM出错!\r\n"); return 0; } else { printf("EEPROM成功,数据如下:\r\n"); } /\*-----------------------------------------------------------------------------------\*/ for (i = 0; i < EEPROM_SIZE; i++) { if(read_buf[i] != write_buf[i]) { printf("0x%02X ", read_buf[i]); printf("错误:EEPROM读出与写入的数据不一致"); return 0; } printf(" %02X", read_buf[i]); if ((i & 15) == 15) { printf("\r\n"); } } printf("EEPROM读写测试成功\r\n"); return 1; }
main
#include "stm32f10x.h"
[外链图片转存中...(img-iOLQcz0T-1715530888210)]
[外链图片转存中...(img-XPEcuprk-1715530888210)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618668825)**
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。