关于IIC协议之详解,这里代码主要是用于蓝桥杯的开发板上(针对初学者)
2018-03-11 00:58
477 查看
网上关于IIC协议的讲解颇多,但是对于初学者而言,看网上的例程代码总是很模糊,因为总有一两个代码看不懂,而看不到过多的解释,我这里主要是针对自己初学的时候走的许多弯路,将自己的所有所有见解落实到代码上,将每一行代码为什么这么做说清楚,尽量使大家明白,少走弯路IIC协议简介:两线式串行总线,一根数据线SDA和时钟线SCL,下面直接是IIC的时
4000
序图,具体每一步的操作和IIC协议的详解我将在代码上给大家说清楚,时序图:
这里很简单,时钟线为高,数据线由高到低就是起始信号,时钟线为低,数据线由低到高就是终止信号
4000
序图,具体每一步的操作和IIC协议的详解我将在代码上给大家说清楚,时序图:
这里很简单,时钟线为高,数据线由高到低就是起始信号,时钟线为低,数据线由低到高就是终止信号
这张图非常重要,后面经常我会说这张图
读和写的时序图唯一值得注意的是,时钟线SCL为高的时候,不允许数据线SDA改变,这是因为时钟线为高的时候,对在IIC总线上的期间而言就是一个读数据的信号,SDA线要保持稳定,才能读取到正确的数据,时钟线SCL为低的时候,允许才允许SDA改变,此时就可以发送数据,IIC发送一个字节是先发送高位再发送低位,那么接受的时候也就是先接受的是高位然后就是低位话不多说,直接上代码//这个我们普通的51单片机是 十二分频的,一个机器周期就是1us,而我们蓝桥杯的是转接板,不十二分频,我们就不可以可以_nop_()延时一微秒 //很不精确的延时1us,但这里对时间的要求不是很严格 void delay_us(int n){ while(n--) { _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_();_nop_();_nop_();_nop_(); _nop_();_nop_(); } } /* IIC的起始和终止信号很简单就不多说了,但有两点值得强调 1.起始信号之后记得将SCL拉低,因为SCL为高根据时序图是不能改变SDA的,就不能传输数据 2.这里是延时都是10us,我们可以根据芯片手册看具体的延时时间,我是参考普中的用的10us,延时算是比较大的了,理论上来说延时比手册上说的稍微长一点要好一些,因为延时时间短了可定要出问题,而延时的时间稍微长点就没事 */ //IIC的起始信号 void IIC_Start(void){ IIC_SDA = 1; IIC_SCL = 1; delay_us(10); IIC_SDA = 0; delay_us(10); IIC_SCL = 0; } //IIC的终止信号 void IIC_Stop(void){ IIC_SCL = 0 ; IIC_SDA = 0 ; delay_us(10); IIC_SCL = 1; delay_us(10); IIC_SDA = 1; delay_us(10); } /* 主机和从机通信,这里的主机就是单片机,从机就是Eeprom或者PCF8591什么的,不管主机还是从机发送完一个字节要等待应答,接受一个到字节也要发送应答 所谓应答就是:(利用SDA)发送完一个字节是八个位,第九个位上是如果是低电平表示应答,高电平表示非应答 */ //IIC等待应答 unsigned char IIC_Wait_ack(){ unsigned char time=0; //我们首先将时钟线拉高,很明显,我们只有将SCL拉高,根据我上面说的SDA线上的数据是不允许随便改变的,读到的才是正确的 IIC_SCL = 1 ; delay_us(10); //将数据线拉高,又称 “释放总线”,由于单片机上电平关系满足线”与”,也就是只要有一方为低电平,另一方就是低电平,也就意味着对方改变不了SDA数据线,相当于你霸占了这根线,你拉高,对方就可以根据需求拉高和拉低,所以拉高数据线SDA又称为释放总线, //我们要这里等待对方的应答,也就是等待对方拉低数据线,这边肯定就是熬释放总线 IIC_SDA = 1 ; delay_us(10); //等待SDA被拉低,也就是变成低电平 while(IIC_SDA){ //这里有个数自加就是保证等待的时间不能过长 time++; if(time>200){ delay_us(1); //时间太长,就要直接发出终止信号,这是IIC协议规定的,对方没有应答就要终止 IIC_Stop(); return 0; } } //程序运行到这里说明已经应答了,我们需要拉低SCL时钟线,以便于进行数据传输,说了如果SCL为高的话,SDA线不允许改变,我们就传输不了数据 IIC_SCL = 0; return 1; } //IIC的应答函数 void IIC_ack(unsigned char ack){ //我们应答函数,要想发送数据(也就是要想改变SDA)就一定要将SCL拉低 IIC_SCL = 0; delay_us(10); //根据自己的需求应答或者非应答,(如果要应答就是ack=0) IIC_SDA = ack; delay_us(10); //将时钟线拉高,数据就被传输过去了,因为SCL为高对方才能检测SDA上的电平,SCL为低的时候IIC协议的规定就是SDA数据线按需求改变,SCL为高才能开始检测数据 IIC_SCL = 1; //再次拉低为了下次数据传输 delay_us(10); IIC_SCL = 0; } //下面其实的函数要想写出来,也就是根据一条原则,我前面也说了很多次,SCL为高的时钟才能进行检测SDA,SCL为低的时候才能改变SDA发送数据 //IIC总线发送一个字节 void IIC_sendByte(unsigned char dat){ unsigned char i; //这个地方是我唯一想强调的地方,也是我错了很多次,调试很多次才发现的bug,如果你开了中断,一定记得你发送和接受数据之前关闭中断,接受或发送完成之后再开启,否则数据传输被中断,就可能得不到你想要的结果 EA = 0; IIC_SCL = 0; for(i=0;i<8;i++){ IIC_SDA = dat>>7; dat<<=1; delay_us(10); IIC_SCL = 1; delay_us(10); IIC_SCL = 0; delay_us(10); } EA = 1; } //IIC总线接受一个字节 unsigned char IIC_RecByte(void){ unsigned char i,dat=0; EA = 0; IIC_SDA = 1; delay_us(10); for(i=0;i<8;i++){ dat<<=1; IIC_SCL = 0; delay_us(10); IIC_SCL = 1; delay_us(10); if(IIC_SDA)dat|=0x01; delay_us(10); } EA = 1; return dat; }以上的延时可以比较大,大家根据需求可以适当将10us改小
相关文章推荐
- jed命令_Linux jed 命令用法详解:主要用于编辑代码的编辑器
- 关于给php初学者一款文件上传代码(1/3)
- 关于HTTP协议基础知识详解
- 关于客户端和服务端聊天室的思路和代码(主要参考传智播客讲课)
- 关于HTTP协议中 GET, POST, PUT, DELETE等方法的详解
- 关于JAVA中RSA加签解签,私钥加密公钥解密和公钥加密私钥解密代码详解
- 【奔跑的FPGA】part nine IIC协议代码解析
- javascript中的this作用域详解——针对初学者
- 关于十六进制与ASCII转换用于硬件层与云服务器通信的代码
- 关于http协议的描述和curl使用详解
- UDP协议的两个主要方法sendto和recvfrom详解
- 针对初学者的A*算法入门详解(附带Java源码)
- 关于企业邮箱在outook express中的错误代码详解(mail.corpease.net)
- 蓝桥杯倒计时1——关于代码填空问题
- Mavlink 协议硬解析主要代码
- 【iOS开发-64】微博案例练习:用代码自定义cell,主要内容是针对不同高度的cell
- 关于用Java来写最大公约数和最小公倍数的问题详解及代码
- 关于IIC通信协议的理解
- 关于Lua中的一点小总结(主要针对的是C调用Lua)
- Websocket协议详解及简单实例代码