📄 iic.h
字号:
//虚拟iic操作
//iic.h
#include "REG52s.H"
#include "intrins.h"
#define numlen 5
#define flashadw 0xa0//定义操作对象的写地址
#define flashadr 0xa1//定义操作对象读地址
typedef unsigned char uchar;
typedef unsigned int uint;
sbit VSDA=P1^7;//iic虚拟数据线
sbit VSCL=P1^6;//iic虚拟时钟线
bit error0,ftemp;
bdata uchar bitdata;//定义到BDATA区,在移位操作时可方便实现位寻址
sbit bd7=bitdata^7;//bitdata.7,即最高位
sbit bd0=bitdata^0;//bitdata.0,即最低位
void iicstart(void);
void iicstop(void);
void mack(void);
void mnack(void);
void cack(void);
void wrbyt(uchar data0);
uchar rdbyt(void);
void delay1ms(uint time);
void config(void);
uchar flashrb(bit end);
uchar flashra(uchar adrh,uchar adrl,bit end);
void flashwa(uchar adrh,uchar adrl);
void flashwb(uchar dataw, bit end);
void delay1us();
void iicstart(void){//产生iic位起始信号(帧起始),具体可参见iic总线或SMBUS总线
VSDA=1;
VSCL=1;
delay1us();
VSDA=0;
delay1us();
VSCL=0;
}
void iicstop(void){//产生iic位停止信号(帧结尾)
VSDA=0;
VSCL=1;
delay1us();
VSDA=1;
delay1us();
}
void mack(void){//主机应答ACK信号,即单片机对操作对象的应答信号
VSDA=0;
VSCL=1;
delay1us();
VSCL=0;
}
void mnack(void){//主机不应答NACK信号,一般用于读控制时,告知对象产生帧结尾
VSDA=1;
VSCL=1;
delay1us();
VSCL=0;
}
void cack(void){//查询从机应答信号,若从机应答,则error0(全局变量)返回0,从机不应答,
//则返回1
VSDA=1;
VSCL=1;
_nop_();
error0=0;
ftemp=VSDA;
if(ftemp)
error0=1;
VSCL=0;
}
void wrbyt(uchar data0){//一字节写操作,先发送高位
idata uchar i;
bitdata=data0;//巧用bitdata处于BDATA区,能位寻址
for(i=0;i<8;i++){
if(bd7){
VSDA=1;
VSCL=1;
delay1us();
VSCL=0;
}
else{
VSDA=0;
VSCL=1;
delay1us();
VSCL=0;
}
bitdata<<=1;
}
}
uchar rdbyt(void){//一字节读操作
idata uchar i;
for(i=0;i<7;i++){
VSDA=1;
VSCL=1;
bd0=VSDA;//读操作时,位流中高字节在前,所以巧用左移可获取数据
bitdata<<=1;
VSCL=0;
}
VSDA=1;
VSCL=1;
bd0=VSDA;
VSCL=0;
return bitdata;
}
void flashwa(uchar adrh,uchar adrl){//对EEPROM写存储地址操作
restart:
iicstart();//产生位起始
wrbyt(flashadw);//写设备地址
cack();//检查从机应答情况
if(error0)
goto restart;//从机没应答则重发
wrbyt(adrh);//写入存储高字节地址
cack();
if(error0)
goto restart;
wrbyt(adrl);//写入存储第字节地址
cack();
if(error0){
iicstop();
goto restart;
}//注意地址写完后,没有写位结束,因而EEPROM一直处于写入模式
}
void flashwb(uchar dataw, bit end){//对EEPROM写入数据操作
//end控制是否产生位停止,停止当前帧,若bit=1,则产生位停止
//若bit=0,则当前帧没有结束,可继续写入地址,适用于页操作模式
//值得注意的是要考虑数据是否写入过多,要控制EEPROM换页操作
//换页之前要确保已经产生位停止操作,否则调用flashwa()写地址无效
wrbyt(dataw);
cack();
if(end)
iicstop();
}
uchar flashra(uchar adrh,uchar adrl,bit end){//读EEPROM地址为adrh-adrl的数据,且返回值为
//读取的数据值存在内在bug,若设备没有相应,则一直处于重发状态,相
//当于死机,对写操作也存在此bug若单数据读,则end为1,若多数据读,end为0
uchar i;
restart:
iicstart();
wrbyt(flashadw);//写入设备地址+写控制
cack();
if(error0)
goto restart;
wrbyt(adrh);//写入存储高字节地址
cack();
if(error0){
iicstop();
goto restart;
}
wrbyt(adrl);//写入存储低字节地址
cack();
if(error0){
iicstop();//产生位停止
goto restart;
}
//以上代码实质上可以直接调用flashwa(adrh,adrl);不过重写一遍避免了调用函数时
//参数传递,执行效率更高
restart2:
iicstart();//写完地址,重新发送起始位
wrbyt(flashadr);//写入设备地址+读控制
cack();
if(error0)
goto restart2;
i=rdbyt();//读取数据
if(end){
mnack();//若当前读取为最后一个数据,则发送NACK给从机,并产生位停止
iicstop();
}
else
mack();//当前读取不是最后一个数据,发送ACK给从机
return i;
}
uchar flashrb(bit end){//在多字节读取模式下,继续读取数据,若end为1,
//则当前操作为最后一个读取值
uchar i;
i=rdbyt();
if(end){
mnack();
iicstop();
}
else
mack();
return i;
}
void delay1ms(uint time){//延迟1ms
uint ii;
uint jj;
for (ii=0;ii<time;ii++){
for(jj=0;jj<300;jj++);
}
}
void config (void) {//可以不用
AUXR=0x1a;
} //End of config
void delay1us(){//修改该函数可以修改对IIC操作的时钟频率
uchar tt;
for(tt=0;tt<3;tt++);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -