📄 i2c.c
字号:
#include <reg52.h>
#include<intrins.h>
#define BYTE unsigned char //宏定义
#define WORD int
#define _Nop() _nop_() //定义空指令
/*常量、变量定义区*/
/*端口位定义区*/
sibt SCL=P3^0; //模拟I2C时钟控制位
sibt SDA=P3^1; //模拟I2C数据传送位
/*状态标志*/
bit ack;
/**************************************************
启动总线函数
函数原形:
void start_I2C();
功能:
启动I2C总线,即发送I2C起始条件
参数:无
返回值:无
*****************************************************/
void start_I2C()
{ SDA=1; //发送起始条件的数据信号\
_Nop();
SCL=1;
_Nop(); //起始条件建立时间大于4uS
_Nop();
_Nop();
_Nop();
_Nop();
SDA=0; //发送起始信号
_Nop(); //起始条件锁定时间大于4us
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; //准备发送或接受数据
_Nop();
_Nop();
}
/**************************************************
结束总线函数
函数原形:
void stop_I2C();
功能:
结束I2C总线,即发送I2C结束条件
参数:无
返回值:无
*****************************************************/
void stop_I2C()
{ SDA=0; //发送结束条件的数据信号
_Nop();
SCL=1; //发送结束条件的时钟信号
_Nop(); //结束条件建立时间大于4uS
_Nop();
_Nop();
_Nop();
_Nop();
SDA=1; //发送结束信号
_Nop(); //结束条件锁定时间大于4us
_Nop();
_Nop();
_Nop();
}
/*******************************************************
字节数据传送函数
函数原形:
void sendbyte(BYTE data);
功能:
发送数据,可以是地址,发送后等待回应,并对此状态位进行操作.
应答或非应答都使ack=0,发送正常,ack=1;
ack=0,表示接收器无应答或损坏
参数:
data:需要发送的数据
返回值:无
********************************************************/
void sendbyte(BYTE data)
{
BYTE bitcount;
for(bitcount=0;bitcount<8;bitcount++) //要传送的数据长度为8位
{
if((data<<bitcount)&0x80) //判断发送位
SDA=1;
else
SDA=0;
_Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
_Nop(); //保证时钟高电平周期大于4um
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0;
}
_Nop();
_Nop();
SDA=1; //8位发送后释放数据线,准备接收应答位
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
if(SDA==1)
ack=0;
else ack=1; 、 //判断是否接收到应答信号
SCL=0;
_Nop();
_Nop();
}
/*******************************************************
字节数据接收函数
函数原形:
BYTE recbyte();
功能:用来接收从器件传来的数据,并判断总线错误(不发生应答信号),发送后请用应答函数
参数:无
返回值:读到的数据
********************************************************/
BYTE recbyte()
{ BYTE recdata;
BYTE bitcount;
recdata=0;
SDA=1; //置数据线为输入方式
for(bitcount=0;bitcount<8;bitcount++)
{ _Nop();
_Nop();
SCL=0; 、//置时钟线为低,准备接收数据位
_Nop(); //保证时钟低电平周期大于4um
_Nop();
_Nop();
_Nop();
_Nop();
SCL=1; //置时钟为高使数据线上数据有效
_Nop();
_Nop();
_Nop();
recdata=recdata<<1;
if(SDA=1)
recdata=recdata+1; //读数据位,接收的数据位放入recdata中
_Nop();
_Nop();
_Nop();
}
SCL=0;
_Nop();
_Nop();
_Nop();
return(recdata);
、、
}
/*******************************************************
应答子函数
函数原形:void ack_i2c(bit a);
功能:主控器进行应答信号,可以是应答或非应答信号。
参数:a应答信号
返回值:无
********************************************************/
void ack_i2c(bit a)
{ if(a==0)
SDA=0;
else SDA=1;
_Nop();
_Nop();
_Nop();
_Nop();
SCL=1;
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
SCL=0; // 清除时钟线,以便继续接收
_Nop();
_Nop();
_Nop();
_Nop();
}
/**********************************************************************************
向无子地址器件发送字节数据函数
函数原形:
bit sendbytedata(BYTE slave,BYTE data);
功能:
从启动总线到发送地址、数据,结束总线的过程
参数:
Slave:从器件地址
Data:要发送的数据
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
bit sendbytedate(BYTE slave,BYTE Data)
{
start_I2C(); //启动总线
sendbyte(slave); //发送器件地址
if(ack==0)
return(0);
sendbyte(Data); //发送数据
if(ack==0)
return(0);
stop_I2C(); //结束总线
return(1);
}
/**********************************************************************************
向有子地址器件发送多字节数据函数
函数原形:
bit sendstr(BYTE slave,BYTE subaddress,BYTE *source,BYTE num);
功能:
从启动总线到发送地址,子地址,结束总线的过程
参数:
Slave:从器件地址
subaddress:子地址
source:发送内容的指针
num:发送字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
/* bit sendstr(BYTE slave,BYTE subaddress,BYTE *source,BYTE num)
{
BYTE i;
start_I2C(); //启动总线
sendbyte(slave); //发送器件地址
if(ack==0)
return(0);
sendbyte(subaddress); //发送器件子地址
if(ack==0)
return(0);
for(i=0;i<num;i++)
{
sendbyte(*source); //发送数据
if(ack==0)
return(0);
source++;
}
stop_I2C(); //结束总线
return(1);
}
*/
/**********************************************************************************
向有子地址器件发送多字节数据函数
函数原形:
bit sendstr(BYTE slave,BYTE subaddress,BYTE *source,BYTE num);
功能:
从启动总线到发送地址,子地址,结束总线的过程
参数:
Slave:从器件地址
subaddress:子地址
source:发送内容的指针
num:发送字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
bit sendstr(BYTE slave,BYTE subaddress,BYTE zuzhi)
{
BYTE i;
start_I2C(); //启动总线
sendbyte(slave); //发送器件地址
if(ack==0)
return(0);
sendbyte(subaddress); //发送器件子地址
if(ack==0)
return(0);
sendbyte(zuzhi); //发送数据
stop_I2C(); //结束总线
return(1);
}
/**********************************************************************************
向无子地址器件读字节数据函数
函数原形:
bit recbytedata(BYTE slave,BYTE *Data);
功能:
从启动总线到发送地址,读数据,结束总线的过程
参数:
Slave:从器件地址,返回值在Data
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
bit recbytedata(BYTE slave,BYTE *Data)
{ start_I2C(); // 启动总线
sendbyte(slave); //发送器件地址
if(ack==0)return(0);
*Data=recbyte(); //读取数据
ack_i2c(1) ; //发非应答位
stop_I2C(); //结束总线
return(1);
}
/**********************************************************************************
向有子地址器件读多字节数据函数
函数原形:
bit recstr(BYTE slave,BYTE subaddress,BYTE *source,BYTE num);
功能:
从启动总线到发送地址,子地址,读数据,结束总线的过程
参数:
Slave:从器件地址,subaddress:子地址,source:指向读出的内容放入的存储区的指针,num:读字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
bit recstr(BYTE slave,BYTE subaddress,BYTE *source,BYTE num)
』{BYTE i;
start_I2C(); // 启动总线
sendbyte(slave); //发送器件地址
if(ack==0)return(0);
sendbyte(subaddress); //发送器件子地址
if(ack==0)return(0);
for(i=0;i<num-1;num++)
{ source=recbyte(); //发送数据
ack_i2c(0); //发应答位
source++;
stop_I2C(); //结束总线
return(1);
}
}
void main()
{start_I2C();
sendstr(50H,90H,BYTE *source,BYTE num);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -