我想用lpc2114来模拟I2C总线(虽然lpc2114有自带的接口,不过这种模拟还是有普遍意义).<br />LPC2114的GPIO在应用中要么是输入,要么是输出,同时既是输入又是输出是不能的.<br />这就遇到一个问题,I2C中有应答机制,也就是说SDA是双向的,它同时发送信号,又要接收来自器件的应答信号,这怎么模拟?<br />我的想法是: <br /> 发送数据是设置模拟的SDA端口(比如P0.24)为GPIO,方向为输出;<br /> 在接收数据或判断应答信号时把SDA端口(比如P0.24)的方向设置为输入,读取IOPIN.<br /> 是不是要这样来回切换I/O口的方向.<br /> 还有一个问题就是对IOPIN寄存器的理解.手册中是这么说的,<br />IOPIN:GPIO引脚寄存器,不管方向和模式如何设定,引脚的当前状态都可以从该寄存器中读数.<br /> 如果果真是这样的话,我引脚设置成输出,外面输入信号,我不用切换状态,直接从IOPIN读端口状态不就可以拉吗? 如果这样的话,端口不是能拉双向的拉吗,同时既是输入又是输出.<br /> 希望大家帮我解惑,谢谢<br /><br />下面是我模拟I2C的关键程序,运行发现出错.<br />#define SDA 1<<24 //p0.24 作为输出<br />#define SDA1 0x00000000 //p0.24 作为输出<br />#define SCL 1<<25 //p0.25 作为输出<br /><br />void Delay1(uint16 x)<br />{<br /> for(;x>0;x--); <br />}<br /><br />void Start_I2c()<br />{<br /> IO0SET=SDA; /*发送起始条件的数据信号*/ <br /> IO0SET=SCL;<br /> Delay1(1000); /*起始条件建立时间大于4.7us,延时*/ <br /> IO0CLR=SDA; /*发送起始信号*/<br /> Delay1(1000); /* 起始条件锁定时间大于4μs*/ <br /> IO0CLR=SCL; /*钳住I2C总线,准备发送或接收数据 */<br /> Delay1(1000); <br />}<br /><br />void Stop_I2c()<br />{<br /> IO0CLR=SDA;<br /> IO0CLR=SCL; /*发送结束条件的数据信号*/<br /> Delay1(1000); /*发送结束条件的时钟信号*/<br /> IO0SET=SCL; /*结束条件建立时间大于4μs*/<br /> Delay1(1000);<br /> IO0SET=SDA; /*发送I2C总线结束信号*/<br /> Delay1(1000);<br />}<br />/*******************************************************************<br /> 字节数据传送函数 <br />函数原型: void SendByte(uint8 c);<br />功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对<br /> 此状态位进行操作.(不应答或非应答都使ack=0 假) <br /> 发送数据正常,ack=1; ack=0表示被控器无应答或损坏。<br />********************************************************************/<br />void SendByte(uint8 c)<br />{<br /> uint8 BitCnt;<br /> uint32 i;<br /> char s[40];<br /> for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/<br /> {<br /> if((c<<BitCnt)&0x80)IO0SET=SDA; /*判断发送位*/<br /> else IO0CLR=SDA; <br /> Delay1(1000);<br /> IO0SET=SCL; /*置时钟线为高,通知被控器开始接收数据位*/ <br /> Delay1(1000); /*保证时钟高电平周期大于4μs*/ <br /> IO0CLR=SCL; /*保证时钟低电平周期大于4.7μs*/<br /> Delay1(1000);<br /> }<br /> IO0SET=SDA; /*8位发送完后释放数据线,准备接收应答位*/<br /> Delay1(1000); <br /> IO0SET=SCL; //产生第9个时钟<br /> <br /> IO0DIR=SDA1|SCL; //切换SDA方向<br /> while(IO0PIN&SDA)<br /> { i++;<br /> if(i>2000) <br /> break;<br /> }<br /> <br /> if(i>2000) <br /> {sprintf(s,"NO ACK!,ERROR!");<br /> SendPCStr(40,20,s,0x30);ack=0;<br /> }<br /> else<br /> {sprintf(s,"OK!");<br /> SendPCStr(40,20,s,0x30);ack=1;}<br /> /*判断是否接收到应答信号*/<br /> IO0CLR=SCL;<br /> IO0DIR=SDA|SCL;<br /> <br /> Delay1(1000);<br />}<br />uint8 ISendByte(uint8 sla,uint8 c)<br />{<br /> Start_I2c(); /*启动总线*/<br /> SendByte(sla); /*发送器件地址*/<br /> if(ack==0)return(0);<br /> SendByte(c); /*发送数据*/<br /> if(ack==0)return(0);<br /> Stop_I2c(); /*结束总线*/ <br /> return(1);<br />}<br />main函数初始化后运行ISendByte(0xa0,0x55),发现总是显示NO ACK!ERROR!说明程序有问题.fclk=4*11.0592;Delay1(1000)这个延迟肯定是大于4.7us的.不知道什么问题,时序我看拉没问题啊. |
|