可以通过IO口模拟IIC
#include "iic.h"
/******************************************************************* 起动总线函数 函数原型: void Start_I2c(void); 功能: 启动I2C总线即发送I2C起始条件. ********************************************************************/ void Start_I2c(void) { SDA=1; //发送起始条件的数据信号 delay_iic(2);//起始条件建立时间大于4.7us延时 SCL=1; delay_iic(5);//起始条件建立时间大于4.7us延时 SDA=0; //发送起始信号 delay_iic(4);//起始条件建立时间大于4us延时 SCL=0; //钳住I2C总线,准备发送或接收数据 delay_iic(4); } /******************************************************************* 结束总线函数 函数原型: void Stop_I2c(); 功能: 结束I2C总线即发送I2C结束条件. ********************************************************************/ void Stop_I2c(void) { SDA=0; //发送结束条件的数据信号 delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=1; //结束条件建立时间大于4μs delay_iic(5);//起始条件建立时间大于4.7us延时 SDA=1; //发送I2C总线结束信号 delay_iic(5);//起始条件建立时间大于4.7us延时 } /******************************************************************* 字节数据发送函数 函数原型: void SendByte(uchar c); 功能: 将数据c发送出去可以是地址也可以是数据发完后等待应答并对 此状态位进行操作.(不应答或非应答都使ack=0) 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。 ********************************************************************/ void SendByte(uint8_t c) { uint8_t BitCnt; for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位 { if((c<<BitCnt)&0x80)SDA=1; //判断发送位 else SDA=0; delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=1; //置时钟线为高,通知被控器开始接收数据位 delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=0; } delay_iic(6);//起始条件建立时间大于4.7us延时 SDA=1; //8位发送完后释放数据线,准备接收应答位 delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=1; delay_iic(5);//起始条件建立时间大于4.7us延时 if(SDA==1)ack=0; else ack=1; //判断是否接收到应答信号 SCL=0; delay_iic(5);//起始条件建立时间大于4.7us延时 } /******************************************************************* 字节数据接收函数 函数原型: uchar RcvByte(); 功能: 用来接收从器件传来的数据并判断总线错误(不发应答信号), 发完后请用应答函数应答从机。 ********************************************************************/ uint8_t RcvByte() { uint8_t retc; uint8_t BitCnt; retc=0; SDA=1; //置数据线为输入方式 for(BitCnt=0;BitCnt<8;BitCnt++) { SCL=0; //置时钟线为低,准备接收数据位 delay_iic(6);//起始条件建立时间大于4.7us延时 SCL=1; //置时钟线为高使数据线上数据有效 delay_iic(5);//起始条件建立时间大于4.7us延时 retc=retc<<1; if(SDA==1)retc=retc+1; //读数据位接收的数据位放入retc中 delay_iic(5);//起始条件建立时间大于4.7us延时 } SCL=0; delay_iic(5);//起始条件建立时间大于4.7us延时 return(retc); } /******************************************************************** 应答子函数 函数原型: void Ack_I2c(bit a); 功能: 主控器进行应答信号(可以是应答或非应答信号,由位参数a决定) ********************************************************************/ void Ack_I2c(bit a) { if(a==0)SDA=0; //在此发出应答或非应答信号 else SDA=1; delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=1; delay_iic(5);//起始条件建立时间大于4.7us延时 SCL=0; //清时钟线,钳住I2C总线以便继续接收 delay_iic(5);//起始条件建立时间大于4.7us延时 } /******************************************************************* 用户接口函数 *******************************************************************/ /******************************************************************* 向有子地址器件发送多字节数据函数 函数原型: bit ISendStr(uchar slauchar subaucahr *suchar no); 功能: 从启动总线到发送地址,子地址数据,结束总线的全过程从器件 地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。 如果返回1表示操作成功,否则操作有误。 注意: 使用前必须已结束总线。 ********************************************************************/ bit ISendStr(uint8_t slauint8_t subauint8_t *suint8_t no) { uint8_t i; Start_I2c(); //启动总线 SendByte(sla); //发送器件地址 if(ack==0)return(0); SendByte(suba); //发送器件子地址 if(ack==0)return(0); for(i=0;i<no;i++) { SendByte(*s); //发送数据 if(ack==0)return(0); s++; DELAY_MS1(10); } Stop_I2c(); //结束总线 return(1); } /******************************************************************* 向有子地址器件读取多字节数据函数 函数原型: bit ISendStr(uchar slauchar subaucahr *suchar no); 功能: 从启动总线到发送地址,子地址读数据,结束总线的全过程从器件 地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。 如果返回1表示操作成功,否则操作有误。 注意: 使用前必须已结束总线。 ********************************************************************/ bit IRcvStr(uint8_t slauint8_t subauint8_t *suint8_t no) { uint8_t i; Start_I2c(); //启动总线 SendByte(sla); //发送器件地址 if(ack==0)return(0); SendByte(suba); //发送器件子地址 if(ack==0)return(0); Start_I2c(); //重新启动总线 SendByte(sla+1); if(ack==0)return(0); for(i=0;i<no-1;i++) { *s=RcvByte(); //发送数据 Ack_I2c(0); //发送就答位 s++; DELAY_MS1(5); } *s=RcvByte(); Ack_I2c(1); //发送非应位 Stop_I2c(); //结束总线 return(1); }
51单片机可以用io来模拟IIC
51单片机的IIC就是使用普通的IO口进行模拟的,只要符合IIC协议就可以正常的痛通信了,这个不难写,但是还是会花一段时间。
下面的程序是我以前学习蓝桥杯的板子的时候写的,比较简单,是一个使用IIC写EEPROM的程序
#include<reg52.h>#include<intrins.h>#define uchar unsigned char#define uint unsigned intsbit scl=P2^0;sbit sda=P2^1;uchar code table[]={0xc00xf90xa40xb00x990x920x820xf80x800x90};uchar aaccb=0;void yan(){ _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_();}void y4(){ P2|=0xe0; P2&=0x80;}void y5(){ P2|=0xe0; P2&=0xa0;}void y6(){ P2|=0xe0; P2&=0xc0; }void y7(){ P2|=0xe0; P2&=0xe0;}void init(){ scl=1; yan(); sda=1; yan();}void start(){ sda=1; yan(); scl=1; yan(); sda=0; yan();}void respons(){ uchar i=0; scl=1; yan(); while((sda==1)&&(i<255)) i++; scl=0; yan();}void stop(){ sda=0; yan(); scl=1; yan(); sda=1; yan();}void xsj(uchar dat){ uchar itemp; temp=dat; for(i=0;i<8;i++) { temp=temp<<1; scl=0; yan(); sda=CY; //单片机自动储存进CY yan(); scl=1; yan(); } scl=0; yan(); sda=1; yan();}uchar read(){ uchar ik; scl=0; yan(); sda=1; for(i=0;i<8;i++) { scl=1; yan(); k=(k<<1)|sda; scl=0; yan(); } yan(); return k;}void noack(){ sda=1; yan(); scl=1; yan(); scl=0; yan();} void write(uchar adduchar dat){ start(); xsj(0xa0); respons(); xsj(add); respons(); xsj(dat); respons(); stop();}uchar ready(uchar add){ uchar a; start(); xsj(0xa0); respons(); xsj(add); respons(); start(); xsj(0xa1); respons(); a=read(); stop(); return a;}void yan1(uint i){ uchar j; for(;i>0;i--) for(j=110;j>0;j--);}void display(){ y6();P0=0x01; y7();P0=table[b/10]; yan1(70); y6();P0=0x02; y7();P0=table[b%10];}void main(){ TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; EA=1;TR0=1;ET0=1; init(); b=ready(7); while(1) { write(7b); display(); }}void DS()interrupt 1{ TH0=(65536-50000)/256; TL0=(65536-50000)%256; aa++;cc++; if(aa==12) { aa=0; b++; if(b>=100) { b=0; } } if(cc/10%2==0) { y4();P0=0x55; }}
51单片机系列没有硬件IIC 都是用模拟的IIC 注意时序就行了