📄 z_i2c.c
字号:
#include<at89x52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define _Nop() _nop_() //定义空指令
//#define ADDRWR 0xa0
//#define ADDRRD 0xa1
/*定义变量*/
uchar ADDRWR=0xa0,ADDRRD=0xa1;
uchar bdata Rshu;
sbit Rshu_3=Rshu^3;
sbit SDA=P1^2;
sbit SCL=P1^1;
sbit WP=P1^0;
bit ack;
uchar code Wshujiu[]={0xff};
uchar code Rshujiu[]={0x00};
/******************************************
功能:读写存储卡需要一定的延时,此函数用来延时
参数:wtime
返回值:无
********************************************/
void delay (uchar wtime)
{
uchar i,j;
for(i=wtime;i>0;i--)
for(j=0;j<200;j++);
}
/******************************************
功能:固定时间延时
参数:无
返回值:无
********************************************/
void wait(void)
{_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
}
/**************************************************
启动总线函数
函数原形:
void start_I2C();
功能:
启动I2C总线,即发送I2C起始条件
参数:无
返回值:无
*****************************************************/
void start_I2C()
{ SCL=0;
wait();
SDA=1; //发送起始条件的数据信号
_Nop();
_Nop();
SCL=1; //起始条件建立时间大于4uS
wait();
SDA=0; //发送起始信号
wait(); //起始条件锁定时间大于4us
SCL=0; //准备发送或接受数据
_Nop();
_Nop();
_Nop();
_Nop();
}
/**************************************************
结束总线函数
函数原形:
void stop_I2C();
功能:
结束I2C总线,即发送I2C结束条件
参数:无
返回值:无
*****************************************************/
void stop_I2C()
{ SDA=0; //发送结束条件的数据信号
_Nop();
_Nop();
SCL=1; //发送结束条件的时钟信号
wait(); //结束条件建立时间大于4uS
SDA=1; //发送结束信号
_Nop(); //结束条件锁定时间大于4us
_Nop();
_Nop();
_Nop();
}
/*******************************************************
字节数据传送函数
函数原形:
void sendbyte(uchar data);
功能:
发送数据,可以是地址,发送后等待回应,并对此状态位进行操作.
应答或非应答都使ack=0,发送正常,ack=1;ack=0,表示接收器无应答或损坏
参数:
data:需要发送的数据
返回值:无
********************************************************/
void sendbyte(uchar Data)
{
uchar bitcount;
for(bitcount=0;bitcount<8;bitcount++) //要传送的数据长度为8位
{
if((Data<<bitcount)&0x80) //判断发送位
SDA=1;
else SDA=0;
_Nop();
_Nop();
SCL=1; //置时钟线为高,通知被控器开始接收数据位
wait(); //保证时钟高电平周期大于4um
SCL=0;
}
SDA=1;
_Nop();
_Nop();
// _Nop();
//8位发送后释放数据线,准备接收应答位
// _Nop();
// _Nop();
SCL=1;
_Nop();
_Nop();
// _Nop();
// _Nop();
// _Nop();
// _Nop();
// _Nop();
if(SDA==1)
ack=0;
else ack=1; //判断是否接收到应答信号
SCL=0;
_Nop();
_Nop();
_Nop();
_Nop();
}
/************************************************************
字节数据接收函数
函数原形:
uchar recbyte();
功能:用来接收从器件传来的数据,并判断总线错误(不发生应答信号),发送后请用应答函数
参数:无
返回值:读到的数据
***uchar*****************************************************/
uchar recbyte()
{ uchar recdata;
uchar bitcount;
recdata=0;
SDA=1; //置数据线为输入方式
for(bitcount=0;bitcount<8;bitcount++)
{ _Nop();
_Nop();
SCL=0; //置时钟线为低,准备接收数据位
wait(); //保证时钟低电平周期大于4um
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;
wait();
SCL=0; // 清除时钟线,以便继续接收
_Nop();
_Nop();
_Nop();
_Nop();
}
/**********************************************************************************
向有子地址器件发送多字节数据函数
函数原形:
bit sendstr(uchar subaddress1,uchar subaddress2,uchar *source,uchar num);
功能:
从启动总线到发送地址,子地址,结束总线的过程
参数:
subaddress1:子地址1
subaddress2:子地址2
source:发送内容的指针
num:发送字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
/**********************************************************************************/
bit sendstr(uchar subaddress1,uchar subaddress2,uchar *source,uchar num)
{
uchar i;
start_I2C(); //启动总线
sendbyte(ADDRWR); //发送器件地址
if(ack==0) return(0);
sendbyte(subaddress1); //发送器件高子地址
if(ack==0) return(0);
sendbyte(subaddress2); //发送器件低子地址
if(ack==0) return(0);
for(i=0;i<num;i++)
{
sendbyte(*source); //发送数据
if(ack==0) return(0);
source++;
}
stop_I2C(); //结束总线
return(1);
}
/**********************************************************************************
向有子地址器件读多字节数据函数
函数原形:
bit recstr(uchar subaddress1,uchar subaddress2,uchar *source,uchar num);
功能:
从启动总线到发送地址,子地址,读数据,结束总线的过程
参数:
subaddress1:子地址1,subaddress2:子地址2,source:指向读出的内容放入的存储区的指针,num:读字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
/*bit recstr(uchar subaddress1,uchar subaddress2,uchar *source,uchar num)
{ uchar i;
start_I2C(); // 启动总线
sendbyte(ADDRWR); //发送器件地址—写
if(ack==0)return(0);
sendbyte(subaddress1); //发送器件高子地址
if(ack==0)return(0);
sendbyte(subaddress2); //发送器件低子地址
if(ack==0)return(0);
start_I2C(); // 再次启动总线
sendbyte(ADDRRD); //再次发送器件地址—读
if(ack==0)return(0);
for(i=0;i<num-1;i++)
{*source=recbyte(); //接收数据
ack_i2c(0); //发应答位
source++;
}
ack_i2c(1); //发非应答位
stop_I2C(); //结束总线
return(1);
}*/
/**********************************************************************************
向有子地址器件读多字节数据函数
函数原形:
bit recstr(uchar subaddress1,uchar subaddress2,uchar *source,uchar num);
功能:
从启动总线到发送地址,子地址,读数据,结束总线的过程
参数:
subaddress1:子地址1,subaddress2:子地址2,source:指向读出的内容放入的存储区的指针,num:读字节个数
返回值:
如果返回1,表示操作成功;否则操作有误
注意:使用前必须已结束总线
**********************************************************************************/
bit recstr(uchar subaddress1,uchar subaddress2)
{
start_I2C(); // 启动总线
sendbyte(ADDRWR); //发送器件地址—写
if(ack==0)return(0);
sendbyte(subaddress1); //发送器件高子地址
if(ack==0)return(0);
sendbyte(subaddress2); //发送器件低子地址
if(ack==0)return(0);
start_I2C(); // 再次启动总线
sendbyte(ADDRRD); //再次发送器件地址—读
if(ack==0)return(0);
Rshu=recbyte(); //接收数据
ack_i2c(1); //发非应答位
stop_I2C(); //结束总线
return(1);
}
void main()
{
uchar *Point1,*Point2;
uchar ADDRWR=0xa0,ADDRRD=0xa1;
Point1=Wshujiu;
Point2=Rshujiu;
SDA=0;
SCL=0;
WP=0;
_Nop();
//sendstr(0x00,0x00,Point1,1);
//recstr (0x00,0x00);
while(1)
{
sendstr(0x00,0xee,Point1,1);
delay (200);
recstr (0x00,0xee);
P0=Rshu;
delay (100);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -