//=====================================================================================
// Module Name : I2C.c
// CreateDate : 2008-3-1
// ModifData : 2008-3-1
// Description : 软件模拟I2C驱动程序.参考了周立功模拟I2C(晶振频率要小于12MHZ)
// Author : LuoWei
// Version : V1.0
//=====================================================================================
#include "reg52.h"
sbit SDA="P1"^7; //模拟I2C数据传送位
sbit SCL="P1"^6; //模拟I2C时钟控制位
bit ack; //应答标志位
//--------------------------------------------------------------------------
//函数名称: I2C_Delay(uint us)
//函数功能: 用于I2C的us级延时
//其他说明: 无
//--------------------------------------------------------------------------
void I2C_Delay(uint us)
{
while(--us);
}
//--------------------------------------------------------------------------
//函数名称: void I2C_Start()
//函数功能: 起动总线函数
//其他说明: 启动I2C总线,即发送I2C起始条件.
//--------------------------------------------------------------------------
void I2C_Start(void)
{
SDA=1; //发送起始条件的数据信号
I2C_Delay(1);
SCL=1;
I2C_Delay(2); //起始条件建立时间大于4.7us延时
SDA=0; //发送起始信号
I2C_Delay(2);
SCL=0; //钳住I2C总线,准备发送或接收数据
I2C_Delay(2);
}
//--------------------------------------------------------------------------
//函数名称: void I2C_Stop()
//函数功能: 结束总线函数
//其他说明: 结束I2C总线,即发送I2C结束条件.
//--------------------------------------------------------------------------
void I2C_Stop(void)
{
SDA=0; //发送结束条件的数据信号
I2C_Delay(1); //发送结束条件的时钟信号
SCL=1; //结束条件建立时间大于4μ
I2C_Delay(2);
SDA=1; //发送I2C总线结束信号
I2C_Delay(2);
}
//--------------------------------------------------------------------------
//函数名称: void SendByte(uchar c)
//函数功能: 字节数据传送函数
//其他说明: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
// 此状态位进行操作.(不应答或非应答都使ack=0 假)
// 发送数据正常,ack=1; ack="0表示被控器无应答或损坏"。
//--------------------------------------------------------------------------
void SendByte(uchar c)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
{
if((c< else SDA="0";
I2C_Delay(1);
SCL=1; //置时钟线为高,通知被控器开始接收数据位
I2C_Delay(2); //保证时钟高电平周期大于4u
SCL=0;
}
I2C_Delay(1);
SDA=1; //8位发送完后释放数据线,准备接收应答位
I2C_Delay(1);
SCL=1;
I2C_Delay(1);
if(SDA==1)ack=0;
else ack="1"; //判断是否接收到应答信号
SCL=0;
I2C_Delay(1);
}
//--------------------------------------------------------------------------
//函数名称: uchar RcvByte();
//函数功能: 字节数据传送函数
//其他说明: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。
//--------------------------------------------------------------------------
uchar RcvByte(void)
{
uchar retc;
uchar BitCnt;
retc=0;
SDA=1; //置数据线为输入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
I2C_Delay(1);
SCL=0; //置时钟线为低,准备接收数据位
I2C_Delay(2); //时钟低电平周期大于4.7u
SCL=1; //置时钟线为高使数据线上数据有效
I2C_Delay(1);
retc=retc<<1;
if(SDA==1)retc=retc+1; //读数据位,接收的数据位放入retc中
I2C_Delay(1);
}
SCL=0;
I2C_Delay(1);
return(retc);
}
//--------------------------------------------------------------------------
//函数名称: void I2C_Ack(bit a);
//函数功能: 应答子函数
//其他说明: 主控器进行应答信号,(可以是应答或非应答信号)
//--------------------------------------------------------------------------
void I2C_Ack(bit a)
{
if(a==0)SDA=0; //在此发出应答或非应答信号
else SDA="1";
I2C_Delay(1);
SCL=1;
I2C_Delay(2); //时钟低电平周期大于4μ
SCL=0; //清时钟线,钳住I2C总线以便继续接收
I2C_Delay(1);
}
//--------------------------------------------------------------------------
//函数名称: bit I2C_SendByte(uchar sla,uchar c)
//函数功能: 向无子地址器件发送字节数据函数
//其他说明: 使用前必须已结束总线。
//--------------------------------------------------------------------------
bit I2C_SendByte(uchar sla,uchar c)
{
I2C_Start(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(c); //发送数据
if(ack==0)return(0);
I2C_Stop(); //结束总线
return(1);
}
//--------------------------------------------------------------------------
//函数名称: bit I2C_SendStr(uchar sla,uchar suba,ucahr *s,uchar no);
//函数功能: 向有子地址器件发送多字节数据函数
//入口参数: sla:从器件地址,suba:子地址,*s:指向发送内容,no:发送字节数。
//其他说明: 使用前必须已结束总线,对于at24cXX元件必须加延时,否则出错
// 一次至多只能写入16字节,否则需要翻页
//--------------------------------------------------------------------------
bit I2C_SendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
I2C_Start(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);
for(i=0;i {
SendByte(*s); //发送数据
if(ack==0)return(0);
s++;
}
I2C_Stop(); //结束总线
I2C_Delay(1000); //对于at24cXX元件需要加延时
return(1);
}
//--------------------------------------------------------------------------
//函数名称: bit I2C_RcvByte(uchar sla,ucahr *c);
//函数功能: 向无子地址器件读字节数据函数
//入口参数: sla:从器件地址,c:返回值
//其他说明: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地址sla,返回值在c.
//--------------------------------------------------------------------------
bit I2C_RcvByte(uchar sla,uchar *c)
{
I2C_Start(); //启动总线
SendByte(sla+1); //发送器件地址
if(ack==0)return(0);
*c=RcvByte(); //读取数据
I2C_Ack(1); //发送非就答位
I2C_Stop(); //结束总线
return(1);
}
//--------------------------------------------------------------------------
//函数名称: I2C_RcvStr(uchar sla,uchar suba,uchar *s,uchar no)
//函数功能: 向有子地址器件读取多字节数据函数,读出的内容放入s指向的存储区
//入口参数: sla:从器件地址,suba:子地址,no:要读的字节数
//其他说明: 无
//--------------------------------------------------------------------------
bit I2C_RcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
uchar i;
I2C_Start(); //启动总线
SendByte(sla); //发送器件地址
if(ack==0)return(0);
SendByte(suba); //发送器件子地址
if(ack==0)return(0);
I2C_Start(); //重新启动总线
SendByte(sla+1);
if(ack==0)return(0);
for(i=0;i {
*s=RcvByte(); //发送数据
I2C_Ack(0); //发送就答位
s++;
}
*s=RcvByte();
I2C_Ack(1); //发送非应位
// I2C_Delay(10);
I2C_Stop(); //结束总线
return(1);
}
用户485340 2008-9-1 16:04
用户461316 2008-8-27 13:16