搜索
您的当前位置:首页正文

I2C 24CXX驱动程序(真正实用 全)

来源:独旅网
#ifndef _24cXX_H #define _24cXX_H

/* Includes ----------------------------------------------------------------*/ #include \"stm32f10x.h\" #include \"value.h\" //#include \"stdbool.h\"

/* Define ------------------------------------------------------------------*/ /* EEPROM Addresses defines */

//注:32 64 的字地址是16位 2个字节 如果使用32或64请简单修改驱动即可 #define WC24cXX 0x00 // 器件地址 写 #define RC24cXX 0x01 // 器件地址 读

#define USE_24C08 //使用24C08

#ifdef USE_24C02 #define MAXSIZE24cXX 256 // 总容量 Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量 Bytes #define I2C_PAGESIZE 8 // 8个字节每页 #endif

#ifdef USE_24C04 #define MAXSIZE24cXX 512 // 总容量 Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量 Bytes #define I2C_PAGESIZE 16 // 16个字节每页 #endif

#ifdef USE_24C08 #define MAXSIZE24cXX 1024 // 总容量 Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 256 // 块容量 Bytes #define I2C_PAGESIZE 16 // 16个字节每页 /* user define */ #define YBCV_ADDR_0 0x0000 //定义仪表控制数据结构体的EEPROM存储地址0 #define YBCV_ADDR_1 0x0200 //定义仪表控制数据结构体的EEPROM存储地址1 #define EEPROM_VERIFY YB_CTRL_VALE_SIZE //EEPROM仪表通道修正参数存储地址 #endif

#ifdef USE_24C16 #define MAXSIZE24cXX 2048 // 总容量 Bytes #define I2C_PAGESIZE 16 // 16个字节每页 #endif

#ifdef USE_24C32 #define MAXSIZE24cXX 4096 // 总容量 Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 4096 // 块容量 Bytes #define I2C_PAGESIZE 32 // 16个字节每页 #endif

#ifdef USE_24C64 #define MAXSIZE24cXX 8192 // 总容量 Bytes //级联时请修改本参数和硬件驱动 #define BLOCK_SIZE 8192 // 块容量 Bytes #define I2C_PAGESIZE 32 // 16个字节每页 #endif

#define I2CInit I2C_GPIO_Config #define SCL(a) if (a) \\ GPIO_SetBits(GPIOB, GPIO_Pin_10);\\ else \\ GPIO_ResetBits(GPIOB,GPIO_Pin_10) #define SDA(a) if (a) \\ GPIO_SetBits(GPIOB, GPIO_Pin_11);\\ else \\ GPIO_ResetBits(GPIOB,GPIO_Pin_11) #define SCLO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_10) #define SDAO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) /* Private ------------------------------------------------------------------*/ /* Public -------------------------------------------------------------------*/ /*uint idata ucSendBuffer[8]={0x01,0x02,0x04,0x08, 0x10,0x20,0x40,0x80}; uint idata ucReceData;

uint idata ucReceiveBuffer[8];

//从器件中读出的多字节数据暂存区*/

/* Function Declaration -----------------------------------------------------*/ extern bool I2C2_Init(void); //I2C初始化

//extern bool I2C_ByteWrite(u8* pBuffer, u8 WriteAddr); //向24cXX中写入1个字节

extern bool I2C_PageWrite(u8* pBuffer, u8 BlockCode, u16 WriteAddr, u8 n); //24cXX页写 (不超过一页)

extern bool I2C_BlockWrite(u8* pBlock, u8 BlockCode, u16 WriteAddr, u16 n); //24cXX数据块写(不超过BLOCK_SIZE个字节)

extern bool I2C_BufferWrite(u8* pBuffer, u16 WriteAddr, u16 n); //24cXX数据写(不超过MAXSIZE24cXX个字节)

extern bool I2C_BufferRead(u8* pBuffer, u16 ReadAddr, u16 n); //从24cXX中读出N字节数据(不超过MAXSIZE24cXX个字节)

//extern void I2C_EE_WaitEepromStandbyState(void); //等待24CXX内部写周期结束 #endif /*_24cXX_H*/

/******************** (C) COPYRIGHT 2015 XXXXX ********************************** * 文件名 :24cXX.c

* 描述 :本函数是xx项目的24cXX的读写函数 * 平台 :Keil 4 MDK \\ stm32 3.5.0库

* 库版本 :基于野火相关资料及程序上优化修改 * 作者 :天涯月下红颜醉 * 时间 :2015.4.19

**********************************************************************************/

/* Includes ------------------------------------------------------------------*/ #include \"24cXX.h\" #include \"value.h\" #include \"systick.h\" #include /*

* 函数名:I2C2_Init * 描述 :I2C2初始化 * 输入 :无 * 输出 :无

* 调用 :内部调用 */

bool I2C2_Init(void) { bool s = true;

GPIO_InitTypeDef GPIO_InitStructure; /* 使能与 I2CGPIO 有关的时钟 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

/* PB10-I2C2_SCL、PB11-I2C2_SDA*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; // 普通开漏输出 GPIO_Init(GPIOB, &GPIO_InitStructure);

SDA(1); SCL(1); Delay_nop(); Delay_nop(); if(!SDAO) s = false; if(!SCLO) s = false; SDA(0); Delay_nop(); Delay_nop(); if(SDAO) s = false; SCL(0); Delay_nop(); SDA(0); SCL(0); Delay_nop(); Delay_nop(); if(SDAO) s = false; if(SCLO) s = false; SCL(1); Delay_nop(); Delay_nop(); SDA(1); return s; }

/********开启24cXX的I2C总线********/ static bool I2CStart(void) { SDA(1); SCL(1); Delay_nop(); Delay_nop(); if(!SDAO)return false; //SDA线为低电平则总线忙,退出 SDA(0); Delay_nop(); Delay_nop(); if(SDAO)return false; //SDA线为高电平则总线出错,退出 SCL(0); Delay_nop(); return true; }

/********关闭24cXX的I2C总线*******/ static void I2CStop(void) { SDA(0); SCL(0); Delay_nop(); Delay_nop(); SCL(1); Delay_nop(); Delay_nop(); SDA(1); }

/*********发送 ACK*********/ static void I2CAck(void) { SDA(0); SCL(0); Delay_nop(); // Delay_nop(); SCL(1); Delay_nop(); // Delay_nop(); SCL(0); }

/*********发送NO ACK*********/ static void I2CNoAck(void) { SDA(1); SCL(0); Delay_nop(); // Delay_nop(); SCL(1); Delay_nop(); // Delay_nop(); SCL(0); }

/*********读取ACK信号*********/

static bool I2CWaitAck(void) //返回为:1=有ACK,0=无ACK

{ SCL(0); SDA(1); //设置SDA为输入 Delay_nop(); // Delay_nop(); SCL(1); Delay_nop(); // Delay_nop(); if(SDAO) { SCL(0); return false; } SCL(0); return true; }

/************MCU向24cXX发送一个字节数据 *************/ static void I2CSendByte(u8 demand) //数据从高位到低位// { u8 i=8; while(i--) { SCL(0); Delay_nop(); SDA((bool)(demand&0x80)); demand<<=1; Delay_nop(); // Delay_nop(); SCL(1); Delay_nop(); // Delay_nop(); } SCL(0); }

/*********MCU从24cXX读入一字节数据*********/ static u8 I2CReceiveByte(void) //数据从高位到低位// { u8 i=8;

u8 ddata=0; SDA(1); //设置SDA为输入 while(i--) { ddata<<=1; //数据从高位开始读取 SCL(0); Delay_nop(); // Delay_nop(); SCL(1); Delay_nop(); //从高位开始 ddata|=SDA;ddata<<=1 // Delay_nop(); if(SDAO) { ddata|=0x01; } } SCL(0); return ddata; } /*

* 函数名:I2C_EE_WaitEepromStandbyState * 描述 :Wait for EEPROM Standby state * 输入 :无 * 输出 :无 * 返回 :无 * 调用 : */

static void I2C_EE_WaitEepromStandbyState(u8 BlockCode) { int i = 50; do { Delay_us(100); I2CStart(); I2CSendByte(BlockCode | WC24cXX);//发送器件地址 写 }while(I2CWaitAck() == 0 && i-- > 0); I2CStop(); }

/****************向24cXX中写入1个字节****************/ /*static bool I2C_ByteWrite(u8* pBuffer, u8 WriteAddr) { I2CStart();//启动I2C I2CSendByte(WC24cXX);//发送器件地址 写

if(I2CWaitAck() == 0) return false; I2CSendByte(WriteAddr); if(I2CWaitAck() == 0) return false; I2CSendByte(*pBuffer); if(I2CWaitAck() == 0) return false; I2CStop(); return true; }*/ /*

* 函数名:I2C_PageWrite

* 描述 :在EEPROM的一个写循环中可以写多个字节,但一次写入的字节数 * 不能超过EEPROM页的大小。AT24C08每页有16个字节。 * 输入 :-pBuffer 缓冲区指针

* -BlockCode 起始器件地址

* -WriteAddr 接收数据的EEPROM的地址 * -n 要写入EEPROM的字节数 * 返回 :0:失败 1:成功 * 调用 :外部调用 */

bool I2C_PageWrite(u8* pBuffer, u8 BlockCode, u16 WriteAddr, u8 n) { u16 i; if(n > I2C_PAGESIZE - WriteAddr%I2C_PAGESIZE) //para check return false; if(n == 0) return true; if(I2CStart() == false) { Delay_us(100); if(I2CStart() == false) return false; };//启动I2C I2CSendByte(BlockCode | WC24cXX);//发送器件地址 写 if(I2CWaitAck() == 0) return false; #if defined(USE_24C32) I2CSendByte((u8)(WriteAddr >> 8)); #elif defined(USE_24C64) I2CSendByte((u8)(WriteAddr >> 8)); #endif I2CSendByte((u8)WriteAddr);

if(I2CWaitAck() == 0) return false; for(i = 0; i < n; i++)//写入I2C_PAGESIZE字节数据 { I2CSendByte(pBuffer[i]); if(I2CWaitAck() == 0) return false; } I2CStop(); I2C_EE_WaitEepromStandbyState(BlockCode); return true; } /*

* 函数名:I2C_BlockWrite

* 描述 :将块缓冲区中的数据写到I2C EEPROM中 * 输入 :-pBuffer 块缓冲区指针 * -BlockCode 起始器件地址

* -WriteAddr 接收数据的EEPROM的地址 * -n 要写入EEPROM的字节数 * 返回 :0:失败 1:成功 * 调用 :外部调用 */

bool I2C_BlockWrite(u8* pBlock, u8 BlockCode, u16 WriteAddr, u16 n) {

u16 ByteOf1st = 0, ByteOfOther = 0; //第一页的字节数 最后一页的字节数 u8 NumOfMPage = 0; //需要写满数据的页数 if(n > BLOCK_SIZE - WriteAddr%BLOCK_SIZE) //para check return false; if(n == 0) return true;

ByteOf1st = I2C_PAGESIZE - WriteAddr % I2C_PAGESIZE; if(n > ByteOf1st) { NumOfMPage = (n - ByteOf1st) / I2C_PAGESIZE; ByteOfOther = (n - ByteOf1st) % I2C_PAGESIZE; } else { ByteOf1st = n; NumOfMPage = 0; ByteOfOther = 0; } if(I2C_PageWrite(pBlock, BlockCode, WriteAddr, ByteOf1st) == false)

{ return false; } WriteAddr += ByteOf1st; pBlock += ByteOf1st; while(NumOfMPage--) { if(I2C_PageWrite(pBlock, BlockCode, WriteAddr, I2C_PAGESIZE) == false) { return false; } WriteAddr += I2C_PAGESIZE; pBlock += I2C_PAGESIZE; } if(I2C_PageWrite(pBlock, BlockCode, WriteAddr, ByteOfOther) == false) { return false; } return true; } /*

* 函数名:I2C_BufferWrite

* 描述 :将缓冲区中的数据写到I2C EEPROM中 * 输入 :-pBuffer 缓冲区指针

* -WriteAddr 接收数据的EEPROM的地址 * -n 要写入EEPROM的字节数 * 返回 :0:失败 1:成功 * 调用 :外部调用 */

bool I2C_BufferWrite(u8* pBuffer, u16 WriteAddr, u16 n) {

u16 ByteOf1st = 0, ByteOfOther = 0; //第一块的字节数 最后一块的字节数 u8 NumOfMBlock = 0; //需要写满数据的块 const u16 ReadAddr = WriteAddr; //读地址 u8* pstr = pBuffer; u8 BlockCode = 0; //起始器件地址 u8* pReadBuff = NULL; u16 i = 0; if(n + WriteAddr > MAXSIZE24cXX || n + WriteAddr == 0) //para check return false;

ByteOf1st = BLOCK_SIZE - WriteAddr % BLOCK_SIZE; if(n > ByteOf1st) { NumOfMBlock = (n - ByteOf1st) / BLOCK_SIZE;

ByteOfOther = (n - ByteOf1st) % BLOCK_SIZE; } else { ByteOf1st = n; NumOfMBlock = 0; ByteOfOther = 0; }

__close_interrupt(); //关总中断

BlockCode = (u8)((WriteAddr/BLOCK_SIZE << 1) | 0xA0);

if(I2C_BlockWrite(pstr, BlockCode, WriteAddr, ByteOf1st) == false) { __open_interrupt(); //开总中断 return false; }

WriteAddr += ByteOf1st; pstr += ByteOf1st;

while(NumOfMBlock--) { BlockCode += 0x02; if(I2C_BlockWrite(pstr, BlockCode, WriteAddr, BLOCK_SIZE) == false) { __open_interrupt(); //开总中断 return false; } WriteAddr += BLOCK_SIZE; pstr += BLOCK_SIZE; }

BlockCode += 0x02;

if(I2C_BlockWrite(pstr, BlockCode, WriteAddr, ByteOfOther) == false) { __open_interrupt(); //开总中断 return false; }

pReadBuff = (u8*)malloc(n); if(pReadBuff == NULL) { __open_interrupt(); //开总中断 return false; }

if(I2C_BufferRead(pReadBuff,ReadAddr,n) == false) { __open_interrupt(); //开总中断 return false;

} for(i = 0; i < n; i++) { if(pReadBuff[i] != pBuffer[i]) { free(pReadBuff); __open_interrupt(); //开总中断 return false; } } free(pReadBuff); __open_interrupt(); //开总中断 return true; }

/************************************************************* **名称:bool I2C_BufferRead

**功能:从24cXX中读出读取一块数据(不超过MAXSIZE24cXX个字节) * 输入 :-pBuffer 缓冲区指针

* -ReadAddr EEPROM的数据地址 * -n 要从EEPROM读出的字节数 * 返回 :0:失败 1:成功 * 调用 :外部调用

**************************************************************/ bool I2C_BufferRead(u8* pBuffer, u16 ReadAddr, u16 n) { u16 i = 50; u8 BlockCode = 0; BlockCode = (u8)((ReadAddr/BLOCK_SIZE << 1) | 0xA0); __close_interrupt(); //关总中断 if(n > MAXSIZE24cXX) { __open_interrupt(); //开总中断 return false; }

I2CSTART: if(I2CStart() == false) { Delay_us(100); if(I2CStart() == false) { __open_interrupt(); //开总中断 return false; } };//启动I2C

I2CSendByte(BlockCode | WC24cXX);//发送器件地址 写 if(I2CWaitAck() == 0) { if(i-- > 0) goto I2CSTART; else { __open_interrupt(); //开总中断 return false; } }

#if defined(USE_24C32) I2CSendByte((u8)(ReadAddr >> 8)); #elif defined(USE_24C64) I2CSendByte((u8)(ReadAddr >> 8)); #endif I2CSendByte((u8)ReadAddr);//发送器件字地址 if(I2CWaitAck() == 0) { __open_interrupt(); //开总中断 return false; } if(I2CStart() == false) { Delay_us(100); if(I2CStart() == false) { __open_interrupt(); //开总中断 return false; } };//启动I2C I2CSendByte(BlockCode | RC24cXX); //发送器件地址 读 if(I2CWaitAck() == 0) { __open_interrupt(); //开总中断 return false; } for(i = 0; i < n - 1; i++)//读取字节数据 { pBuffer[i]=I2CReceiveByte();//读取数据 I2CAck(); } pBuffer[n - 1] = I2CReceiveByte(); I2CNoAck();

I2CStop(); __open_interrupt(); //开总中断 return true; }

/**************************************************************/

//本程序采用软件延时的方法产生SCL脉冲,为保证有足够的延时,特延时100us,在使 //用时可根据要求适当调整。(如12M晶振时,只要4.7us即可)

因篇幅问题不能全部显示,请点此查看更多更全内容

Top