.
下载地址: http://wqygogo.download.csdn.net/
//==============头文件=================//
#include "24C16.h"
//===========================================================================================//
//函 数 名:init_24C16
//函数功能:I2C引脚初始化。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void init_24C16(void)
{
//设置SCL为输出,输出'0'
//设置SDA(输入/输出先不管,默认),使能上拉电阻
SCL_OUT_L(); //SCL=0
SET_SCL_OUT(); //set SCL put out
SDA_OUT_H(); //pull up resistance for SDA
#ifdef _AVR_GCC_
SFIOR &= ~(1<<PUD); //enable PUD
#endif //_AVR_GCC_
}
//===========================================================================================//
//函 数 名:I2CStart
//函数功能:模拟I2C起始信号。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void I2CStart(void)
{
//为确保在"SCL = 1"期间,SDA只有一次下降沿,故有以下步骤:
//1、确定SDA的初始状态为高电平;
//2、下降沿
//3、结束,数据线的任何变化不会被作为总线的起始或停止信号
SCL_OUT_L(); //SCL=0,step1: init
SET_SDA_OUT(); //set put out for SDA
SDA_OUT_H(); //SDA=1,SDA put out 1
SOME_NOP(); //等待EEPROM采样到SCL
SCL_OUT_H(); //SCL=1,step2: start
SOME_NOP(); //等待EEPROM采样到SCL
SDA_OUT_L(); //SDA=0,SDA put out 0,pull down edge
SOME_NOP(); //延时,确保SDA的下降沿在SCL的高电平期间产生
SCL_OUT_L(); //SCL=0,step3: end
}
//===========================================================================================//
//函 数 名:I2CStop
//函数功能:模拟I2C停止信号。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void I2CStop(void)
{
//为确保在"SCL = 1"期间,SDA只有一次上升沿,故有以下步骤:
//1、确定SDA的初始状态为低电平;
//2、上升沿
//3、结束,数据线的任何变化不会被作为总线的起始或停止信号
SCL_OUT_L(); //SCL=0,step1: init
SET_SDA_OUT(); //set put out for SDA
SDA_OUT_L(); //SDA=0,put out
SOME_NOP(); //等待EEPROM采样到SCL
SCL_OUT_H(); //SCL=1,step2: start
SOME_NOP(); //等待EEPROM采样到SCL
SDA_OUT_H(); //SDA=1,put out,pull up edge
SOME_NOP(); //延时,确保SDA的上升沿在SCL的高电平期间产生
SCL_OUT_L(); //SCL=0,step3: end
}
//===========================================================================================//
//函 数 名:WaitAck
//函数功能:模拟I2C等待应答。
//输入参数:无。
//输出参数:无。
//返 回 值:应答状态,成功->TRUE or 失败->FALSE。
//修改者 :---
//修改时间:---
//==========================================================================================//
uint8 WaitAck(void)
{
uint8 ErrTime = 255; //set receive time out(超时值) for ACK : 255
SCL_OUT_L(); //SCL=0,step1: init
SET_SDA_OUT(); //set put out for SDA
SDA_OUT_H(); //SDA=1,put out,step2: start
SOME_NOP(); //等待EEPROM采样到SCL
SCL_OUT_H(); //SCL=1
while( READ_SDA() ) //Read SDA,cycle if true
{
ErrTime--; //计超时
if(!ErrTime) //if time out
{
I2CStop(); //Stop
return FALSE; //faile
}
}
SCL_OUT_L(); //SCL=0,step3: end
return TRUE; //succeed
}
//===========================================================================================//
//函 数 名:SendAck
//函数功能:模拟I2C发送应答。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void SendAck(void)
{
//"ACK"即为在第9个时钟周期内,保持SDA为低电平
//确保不产生起始、停止信号。
//总之,SDA跳变或者给SDA赋值(假设赋值前,SDA的状态未知)时,须确保SCL为低电平
SCL_OUT_L(); //SCL=0,step1: init
SOME_NOP(); //等待EEPROM采样到SCL
SET_SDA_OUT(); //set put out for SDA
SDA_OUT_L(); //SDA=0,put out,step2: start
//------SCL周期的上半部分-------//
SCL_OUT_H(); //SCL=1,pull up edge
SOME_NOP(); //SCL、SDA保持时间
SCL_OUT_L(); //SCL=0,pull down edge
SCL_OUT_L(); //延时,确保SCL为低电平
SDA_OUT_H(); //SDA=1,end
}
//===========================================================================================//
//函 数 名:SendNotAck
//函数功能:模拟I2C发送非应答。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void SendNotAck(void)
{
//"NO ACK" 即为在第9个时钟周期内,保持SDA为高电平
//确保不产生起始、停止信号。
//总之,SDA跳变或者给SDA赋值(假设赋值前,SDA的状态未知)时,须确保SCL为低电平
SCL_OUT_L(); //SCL=0,step1: init
SOME_NOP(); //等待EEPROM采样到SCL
SET_SDA_OUT(); //set put out for SDA
SDA_OUT_H(); //SDA=1,put out,step2: start
//-------SCL周期的上半部分------//
SCL_OUT_H(); //SCL=1,pull up edge
SOME_NOP(); //SCL、SDA保持时间
SCL_OUT_L(); //SCL=0,pull down edge
SCL_OUT_L(); //延时,确保SCL为低电平
SDA_OUT_L(); //SDA=0,step3: end
}
//===========================================================================================//
//函 数 名:I2CSendByte
//函数功能:模拟I2C发送字节。
//输入参数:所要写的字节。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void I2CSendByte(uint8 ch)
{
//SDA上的数据状态仅在SCL为低电平期间才能改变
register uint8 i=8; //8 bit Data
SET_SDA_OUT(); //set put out for SDA
while(i--)
{
//SDA上的数据状态仅在SCL为低电平期间才能改变
SCL_OUT_L(); //SCL=0
SOME_NOP(); //等待EEPROM采样到SCL
//----Send Data,先发送高位-----//
if( ch&0x80 ) //1
{ SDA_OUT_H(); } //SDA=1,put out
else //0
{ SDA_OUT_L(); } //SDA=0,put out
ch <<= 1; //shift
SOME_NOP(); //等待EEPROM采样到SDA
SCL_OUT_H(); //SCL=1,pull up edge
SOME_NOP(); //等待EEPROM采样到SCL
}
//保持低电平,从而SDA上的数据状态变化,不会产生起始、停止信号
SCL_OUT_L(); //SCL=0,end
}
//===========================================================================================//
//函 数 名:I2CReceiveByte
//函数功能:模拟I2C接收字节。
//输入参数:无。
//输出参数:无。
//返 回 值:接收的数据。
//修改者 :---
//修改时间:---
//==========================================================================================//
uint8 I2CReceiveByte(void)
{
register uint8 i=8; //8bit Data
uint8 dat=0; //存放接收的数据
SET_SDA_IN(); //set put in for SDA,and pull up resistance
while(i--)
{
//SDA上的数据状态仅在SCL为低电平期间才能改变
SCL_OUT_L(); //SCl=0
//时间主要耗在EEPROM芯片控制器更新SDA上的数值,
//因EEPROM芯片控制器要从EEPROM中读取数值.( 读操作耗时)
//而写操作耗时主要在:EEPROM芯片控制器往EEPROM中写数值.(写周期)
DELAY(); //等待EEPROM采样到SCL,并更新SDA上的数值(耗时)
//----Receive Data,先接收高位------//
dat <<= 1; //shift,第一次为空移,即8bit Data只要移7bit
if( READ_SDA() ) //1 //read SDA,put in
{
dat |= 0x01;
#ifdef _DEBUG_
USART_Transmit('1');//Send '1'
#endif
}
else //0
{
dat &= 0xfe;
#ifdef _DEBUG_
USART_Transmit('0');//Send '0'
#endif
}
SCL_OUT_H(); //SCL=1,pull up edge
SOME_NOP(); //等待EEPROM采样到SCL
}
//保持低电平,从而SDA上的数据状态变化,不会产生起始、停止信号
SCL_OUT_L(); //SCL=0,end
return(dat);
}
//===========================================================================================//
//函 数 名:_24C16WriteChar
//函数功能:I2C的字节写。
//输入参数:所要写数据的地址、所要写数据。
//输出参数:无。
//返 回 值:应答状态,成功->TRUE or 失败->FALSE。
//修改者 :---
//修改时间:---
//==========================================================================================//
uint8 _24C16WriteChar(uint16 addr, uint8 ch)//addr(0~2047)(0x7ff)
{
uint8 StateAck; //应答状态
I2CStart(); //发送I2C起始命令
I2CSendByte( 0xA0 | ((addr>>7)&0x0e) ); //发送EEPROM型号信息及高三位的字节地址(针对24C16)
StateAck = WaitAck(); //wait for ACK
if( StateAck )//succeed
{
I2CSendByte((char)(addr)); //发送低8位的字节地址
StateAck = WaitAck(); //wait for ACK
if( StateAck )//succeed
{
I2CSendByte(ch); //发送数据
StateAck = WaitAck(); //wait for ACK
if( StateAck )//succeed
I2CStop(); //发送停止命令
}//end if2
}//end if1
return StateAck; //应答状态
}//end
//===========================================================================================//
//函 数 名:_24c16WritePage
//函数功能:I2C的页写。
//输入参数:所要写数据的地址、字符串首地址、字符串长度。
//输出参数:无。
//返 回 值:应答状态,成功->TRUE or 失败->FALSE。
//修改者 :---
//修改时间:---
//==========================================================================================//
uint8 _24c16WritePage(uint16 addr, uint8 *str, uint8 len)//addr(0~2047)(0x7ff),len(0~16)
{
//16-byte page write buffer,超过,地址计数器自动翻转,先前写入数据将被覆盖。
uint8 StateAck; //应答状态
I2CStart(); //发送I2C起始命令
I2CSendByte( 0xA0 | ((addr>>7)&0x0e) ); //发送EEPROM型号信息及高三位的字节地址(针对24C16)
StateAck = WaitAck(); //wait for ACK
if( !StateAck )
return FALSE; //faile,无应答跳出
I2CSendByte( (char)addr ); //发送低8位的字节地址
StateAck = WaitAck(); //wait for ACK
if( !StateAck )
return FALSE; //faile,无应答跳出
if(16 != len)
len &= 0x0f; //赋值保护(取值范围),max=16
while(len--)
{
I2CSendByte(*str++); //发送数据
StateAck = WaitAck(); //wait for ACK
if( !StateAck )
return FALSE; //faile,无应答跳出
}
I2CStop(); //发送停止命令
return TRUE; //succeed
}
//===========================================================================================//
//函 数 名:_24c16AtOnceRead
//函数功能:I2C的立即性读。
//输入参数:无。
//输出参数:无。
//返 回 值:应答状态(高8字节)及读到数据(低8字节)。(应答状态,成功->TRUE or 失败->FALSE。)
//修改者 :---
//修改时间:---
//==========================================================================================//
uint16 _24c16AtOnceRead(void)//addr(0~2047)(0x7ff)
{
//无选择性读的伪写操作部分
uint16 Data; //return
uint8 StateAck; //应答状态
//---------读数据操作---------//
I2CStart(); //发送I2C起始命令
I2CSendByte(0xA1); //发送EEPROM型号信息
StateAck = WaitAck();
if( !StateAck )
return FALSE; //无应答跳出,( Data&0xff )=FALSE,其中Data=0,FALSE=0
Data = I2CReceiveByte(); //接收数据
SendNotAck(); //发送非应答
I2CStop(); //发送停止命令
return( Data | 0x0100 ); //( Data|0x0100 )=( Data|(TRUE<<8) )
}
//===========================================================================================//
//函 数 名:_24c16SelRead
//函数功能:I2C的选择性读。
//输入参数:所要读的地址。
//输出参数:无。
//返 回 值:应答状态(高8字节)及读到数据(低8字节)。(应答状态,成功->TRUE or 失败->FALSE。)
//修改者 :---
//修改时间:---
//==========================================================================================//
//========================================//
uint16 _24c16SelRead(uint16 addr) //addr(0~2047)(0x7ff)
{ //也可“I2C的字节写”的写法
uint16 Data; //return
uint8 StateAck; //应答状态
//----------伪写操作----------//
I2CStart(); //发送I2C起始命令
I2CSendByte( 0xA0 | ((addr>>7)&0x0e) ); //发送EEPROM型号信息及高三位的字节地址(针对24C16)
StateAck = WaitAck();
if( !StateAck )
return FALSE; //无应答跳出,( Data&0xff )=FALSE,其中Data=0,FALSE=0
I2CSendByte( (char)(addr) ); //发送低8位的字节地址
StateAck = WaitAck();
if( !StateAck )
return FALSE; //无应答跳出,( Data&(FALSE<<8) )=FALSE
//---------读数据操作---------//
I2CStart(); //发送I2C起始命令
I2CSendByte(0xA1); //发送EEPROM型号信息
StateAck = WaitAck();
if( !StateAck )
return FALSE; //无应答跳出,( Data&(FALSE<<8) )=FALSE
Data = I2CReceiveByte(); //接收数据
SendNotAck(); //发送非应答
I2CStop(); //发送停止命令
return( Data | 0x0100 ); //( Data|0x0100 )=( Data|(TRUE<<8) )
}
//===========================================================================================//
//函 数 名:_24c16SeriesRead
//函数功能:I2C的连续读。
//输入参数:所要读数据的地址、所要读数据的长度。
//输出参数:无。
//返 回 值:动态空间的起始地址,内容包括应答状态(第一字节)、读到数据(len Byte长度)。
// (应答状态,成功->TRUE or 失败->FALSE。)
//修改者 :---
//修改时间:---
//==========================================================================================//
uint8 * _24c16SeriesRead(uint16 addr, uint16 len)//addr(0~2047)(0x7ff),len(0~2047)
{
//len为接收字节数
//两种启动方式:立即性读启动、选择性读启动;
//默认为选择性读启动,定义AT_ONCE_READ_MODE后为立即性启动
uint8 *p,*pp; //p,pp指向同一地址,第一字节用来存放应答信息
//动态存储空间
//len+1,最后一个空间用来存放最后一个数据,因第一个字节空间作为它用
// p = (uint8 *)malloc(len+1); //建立动态存储空间,返回空间起始地址
// pp = p; //保留空间起始地址,待用
//静态存储空间
static uint8 buf[20];
p = buf;
pp = buf;
#ifndef AT_ONCE_READ_MODE //默认为选择性读操作启动
//----------伪写操作----------//
I2CStart(); //发送I2C起始命令
I2CSendByte( 0xA0 | ((addr>>7)&0x0e) ); //发送EEPROM型号信息及高三位的字节地址(针对24C16)
*p = WaitAck(); //存放应答状态,TRUE->succeed,FALSE->failed
if( !*p ) //
return pp; //无应答跳出,
I2CSendByte( (char)(addr) ); //发送低8位的字节地址
*p = WaitAck(); //存放应答状态
if( !*p )
return pp; //无应答跳出,
#endif
I2CStart(); //发送I2C起始命令
I2CSendByte(0xA1); //发送EEPROM型号信息
*p = WaitAck(); //存放应答状态
if( !*p )
return pp; //无应答跳出,
len--; //少次for循环,空间第一字节作为它用
p++; //空间的第一字节已用,存放应答状态
while(len--)
{
*p++ = I2CReceiveByte(); //接收数据
SendAck(); //发送应答
}
*p++ = I2CReceiveByte(); //接收最后一个数据//第len+1个空间
SendNotAck(); //发送非应答
I2CStop(); //发送停止命令
return pp;
}
/*
//===========================================================================================//
//函 数 名:QueryACk
//函数功能:应答查询。
//输入参数:无。
//输出参数:无。
//返 回 值:无。
//修改者 :---
//修改时间:---
//==========================================================================================//
void QueryACk(void)
{
//在EEPROM写周期期间,启动应答查询,来查询下次操作时间
do
{
I2CStart(); //发送I2C起始命令
I2CSendByte( 0xA0); //发送从地址
DataDebug=WaitAck();
}
while( !DataDebug ); //等待应答,应答状态,成功->TRUE or 失败->FALSE。
}
*/
...等,这只是其中一个C文件,要的话赶快下载吧。
下载地址: http://wqygogo.download.csdn.net/
【作者产品开发资料】完全分析EEPROM的驱动时序,编程规范、代码优化等难得的参考资料,本程序兼容Keil和GCCAVR。你是不是想在C51开发的基础上,再学习AVR呢,那赶快下载吧。