时间:2016-12-25来源:本站原创作者:佚名

摘要

I2C总线的设备文件通常为/dv/i2c-n(n=0、1、2……),每个设备文件对应一组I2C总线。应用程序通过这些设备文件可以操作I2C总线上的任何从机器件。EasyARM-i.MXA提供了一路I2C接口,设备文件为/dv/i2c-0。

本章导读:

本章主要讲述非标准(相对于PC而言)硬件接口编程。像通常的串口和网口,都是标准接口,有通用的编程规范,而这章讲述的如LED、GPIO、SPI和I2C这样的接口,在嵌入式系统中非常普通,由于这些接口的特殊性,没有统一的编程规范。而在实际应用中,往往又不可缺少,所以这章的内容很重要。

本章的内容与具体的开发平台结合比较紧密,如果在非对应的平台上使用这些范例,可能需要根据实际情况进行修改和调整。

15.4用户态I2C编程

I2C总线的设备文件通常为/dv/i2c-n(n=0、1、2……),每个设备文件对应一组I2C总线。应用程序通过这些设备文件可以操作I2C总线上的任何从机器件。EasyARM-i.MXA提供了一路I2C接口,设备文件为/dv/i2c-0。

15.4.1I2C编程接口

1、打开设备

在操作I2C总线时,先调用opn()函数打开I2C设备获得文件描述符,代码如程序清单15.8所示。

程序清单15.8打开I2C设备文件

intfd;fd=opn(/dv/i2c-0,O_RDWR);if(fd0){prror(opni2c-1\n);}

2、关闭设备

当操作完成后,调用clos()函数关闭设备:

clos(fd);

3、配置设备

当应用程序操作I2C总线上的从机器件时,必须先调用ioctl()函数设置从机地址和从机地址的长度。

设置从机地址

设置从机地址是使用I2C_SLAVE命令,其定义为:

#dfinI2C_SLAVE0x

该命令的参数为从机地址右移一位。设置从机地址为0xA0的示例代码为:

if(ioctl(GiFd,I2C_SLAVE,0xA01)0){prror(stslavaddrssfail\n);}

注意:地址需要右移一位,是因为地址的Bit0是读写控制位,在驱动中会将从机地址命令参数左移一位,并补上读写控制位。

设置地址长度

设置从机地址的长度是使用I2C_TENBIT命令,其定义为:

#dfinI2C_TENBIT0x

该命令的参数可选择为:1表示设置从机地址长度为10位;0表示设置从机地址长度为8位。设置从机地址长度为10位的示例代码为:

ioctl(fd,I2C_TENBIT,1);

该命令是不会返回错误的。

如果不设置地址长度,则默认为8位地址。

4、发送数据

应用程序调用writ()函数可以向I2C总线发送数据。例如在I2C总线发送“hllo”字符串的代码如程序清单15.9所示。

程序清单15.9在I2C总线发送数据

intln;charbuf[]=hllo;ln=writ(fd,buf,sizof(buf));if(ln0){printf(snddatafail);xit(-1);}

writ()函数调用成功后,返回成功发送数据的长度。在writ()函数调用时,数据发送过程如下:

主机在I2C总线发送始起信号(S),然后发送从机地址(slavaddr);

从机成功接收到属于自己的从机地址后,返回应答信号(ACK);

主机接收到应答信号后,把buf缓冲区中的数据逐个在I2C总线发送;

从机每成功接收到一个从主机发来的数据都返回应答信号;

当主机的数据发送完毕后,在I2C上发送结束信号(P)。

具体过程如图15.10所示。

图15.10数据发送过程示意图

5、接收数据

应用程序调用rad()函数可以在I2C总线接收数据。例如在I2C总线接收10个字节的代码如程序清单15.9所示。

程序清单15.10在I2C总线读取数据

charbuf[10];intln;ln=rad(fd,buf,10);if(ln0){printf(radi2cdatafail);xit(-1);}

rad()调用成功后,返回接收数据的长度。

rad()函数调用时,数据接收过程如下:

主机在I2C总线发送始起信号(S),然后发送从机地址(slavaddr);

从机成功接收到属于自己的从机地址后,返回应答信号(ACK);

主机接收到应答信号后,准备接收从机发来的数据;

从机把数据逐个向主机发送;

主机每成功接收到一个在从机发来的数据都返回应答信号;

当主机接收到最后一个数据时并返回应答信号,而是I2C上发送结束信号(P)。

具体过程如图15.11所示。

图15.11数据接收过程示意图

15.4.2编程范例

AP-Dmo板上的FM24C02A是I2C接口的EEPROM芯片。FM24C02A是2Kb(字节)大小的EEPROM,分为32个页,每页8字节。

这里通过演示读/写I2C接口的EEPROM来进一步说明应用程序如何使用I2C编程接口。

1、FM24C02A的操作

从机寻址

当接收到起始信号后,FM24C02A需要一个8位的从机地址来启动一次读/写操作,其从机地址构成如图15.12所示。

图15.12FM24C02A的从机地址

从机地址前4位的值固定不变,第2、3、4位的值分别由FM24C02A的A0、A1、A2引脚的输入电平决定(高电平为1,低电平为0)。从机地址的第8位为读/写启动选择位(R/W):1为启动读操作;1为启动写操作。

字节写

字节写操作为每次在FM24C02A内部储存器的指定地址写入1个字节的数据。主机先发送起始信号和从机地址(R/W位为0)。在接收到FM24C02A返回的应答信号后,主机发送需要写入的数据地址(1个字节),然后发送需要写入的数据。在收到FM24C02A返回的应答信号后,主机发送结束信号。

字节写的顺序过程如图15.13。

图15.13字节写顺序

页写

FM24C02A支持在一次写操作中连续写入一页的数据(8个字节)。页写操作的启动方式和字节写操作类似,只是主机发送了第1个字节的数据后并不是马上停止,而是继续发送剩余的7个字节的数据。FM24C02A在每接收到主机发来的1个数据都返回1个应答信号。当主机的所有数据都发送完毕后,主机发送结束信号。每当FM24C02A接收到主机发来的1个数据时,数据地址的低三位加1,而高五位不会变化,保持存储器的页地址不变。当内部产生的数据地址达到页边界时,数据地址将会翻转,接下来的数据的写入地址将置为同一页的最小地址。所以若有超过8个字节数据写入FM24C02A,数据地址将回到最先写入的地址,先前写入的数据将被覆盖。

页写的具体顺序如图15.14所示。

图15.14页写顺序

当前地址读

FM24C02A的内部数据地址计数器保留最后一次访问的地址,并自动加1。只要FM24C02A处于上电状态,这个地址在操作运行期间始终有效。在读操作中,如果存储器的最后一页的最后一个字节开始读,则读下一个字节时地址将会翻转到整个储存器的最小地址。

主机发送起始信号和从机地址(R/W位为1)后,FM24C02A返回答应信号,然后向主机发送数据。这时主机接收到数据后,并不返回答应信号,而发送结束信号。

当前地址读的具体顺序如图15.15所示。

图15.15当前地址读顺序图

自由读

自由读需要通过假的字节写操作来获得数据地址。主机首先发送起始信号、从机地址和数据地址来定位需要读取的地址。当FM24C02A返回数据地址的应答信号之后,主机马上重新发送起始信号和从机地址。这时FM24C02A返回应答信号,然后发送数据。主机接收到数据后,并不返回应答信号,而发送结束信号。

自由读的具体顺序如图15.16所示。

图15.16自由读顺序

连续读

在自由读操作中,若主机在接收了FM24C02A发来的数据后,并不发送结束信号,而是立即返回应答信号,那么FM24C02A则自动把数据地址加1,并将新数据地址的数据发送给主机。当储存器的数据地址达到最大时,数据地址将翻转到最小地址,并且继续进行连续读操作。当主机不再返回应答信号,而是发送停止信号时,FM24C02A停止发送数据。

连续读的具体顺序如图15.17所示。

图15.17连续读顺序

2、电路原理

AP-Dmo板上的FM24C02A是连接到I2C1总线,电路图如图15.18所示。

图15.18FM24C02A连接电路图

在该电路图中,FM24C02A的A0、A1、A2引脚电平被拉低,所以FM24C02A的从机地址为0xA0。

3、示例程序

在程序清单15.11所示的代码中,通过I2C总线在FM24C02A内部储存器的0x00~0x07地址连续写入8个字节的数据,然后在这些地址中把数据读出来,最后把写入数据和读出数据进行对比,以检验程序的正确性。

程序清单15.11连续写/读程序代码

#includstdio.h#includstdlib.h#includunistd.h#includsys/typs.h#includsys/stat.h#includfcntl.h#includtrmios.h#includrrno.h#dfinI2C_SLAVE0x#dfinI2C_TENBIT0x#dfinI2C_ADDR0xA0#dfinDATA_LEN8#dfinI2C_DEV_NAME/dv/i2c-1intmain(intarg,char*args[]){unsigndintrt,ln;inti,flag=0;intfd;chartx_buf[DATA_LEN+1];/*用于储存数据地址和发送数据*/charrx_buf[DATA_LEN];/*用于储存接收数据*/charaddr[1];/*用于储存读/写的数据地址*/addr[0]=0;/*数据地址设置为0*/

fd=opn(I2C_DEV_NAME,O_RDWR);/*打开I2C总线设备*/if(fd0){printf(opn%sfaild\n,I2C_DEV_NAME);rturn-1;}rt=ioctl(fd,I2C_SLAVE,I2C_ADDR1);/*设置从机地址*/if(rt0){printf(stnvaddrssfailrt:%x\n,rt);rturn-1;}/*由于没有设置从机地址长度,所以使用默认的地址长度为8*/tx_buf[0]=addr[0];/*发数据时,第一个发送是数据地址*/for(i=1;iDATA_LEN;i++)/*初始化要写入的数据:0、1……7*/tx_buf[i]=i;ln=writ(fd,tx_buf,DATA_LEN+1);/*把数据写入到FM24C02A,*/if(ln0){printf(writdatafail\n);rturn-1;}uslp(*);/*需要延迟一段时间才能完成写入EEPROM*/ln=writ(fd,addr,1);/*设置数据地址*/if(ln0){printf(writdataaddrfail\n);rturn-1;}ln=rad(fd,rx_buf,DATA_LEN);/*在设置的数据地址连续读入数据*/if(ln0){printf(raddatafail\n);rturn-1;}printf(radfromprom:);for(i=0;iDATA_LEN-1;i++){/*对比写入数据和读取的数据*/printf(%x,rx_buf[i]);if(rx_buf[i]!=tx_buf[i+1])flag=1;}printf(\n);

if(!flag){/*如果写入/读取数据一致,打印测试成功*/printf(promwritandradtstsussccd!\r\n);}ls{/*如果写入/读取数据不一致,打印测试失败*/printf(promwritandradtstfaild!\r\n);}rturn0;}

该代码可以交叉编译为i2c_prom_tst程序文件,测试方法:

把i2c_prom_tst上传到EasyARM-i.MXA的任何目录;

执行i2c_prom_tst程序。

若i2c_prom_tst程序执行无误,将打印信息如图15.19所示。

图15.19FM24C02A测试结果









































白癜风应该怎么样治疗
北京治疗白癜风到底需要多少钱

转载请注明原文网址:http://www.gzdatangtv.com/bcyytx/5164.html

------分隔线----------------------------