1、模拟IICIIC总线1、IIC总线简介IIC总线是Philips推出的一种串行总线方式,它的全称是Intel Integrate Circuit Bus,它通过SDA(串行数据线)和SCL(串行时钟线)两根线在连到总线上的器件之间传送信息,并通过软件寻址识别每个器件,而不需要片选线(结合图1说明)。IIC总线接口均为开漏或开集电极输出,因此需要为总线增加上拉电阻Rp。总线速率越高,总线上拉电阻就越小,对于100Kbit/s总线速率,通常使用5.1K欧姆的上拉电阻。 IIC总线上的通信通常发生在两个器件之间,其中一个是主机另一个是从机,从机和主机均能读和写,ads1110只能作为从机。2、数据方
2、式IIC总线有三种数据速率工作方式:标准方式:允许最高100KHz的时钟频率;快速方式:允许最高400KHz的时钟频率;高速方式:允许最高3.4MHz的时钟频率。3、数据传送一条IIC总线有两条线路构成:SDA线和SCL线,SDA线传送数据,SCL提供时钟,所用数据以8位为一组在总线上传送。在数据传送过程中,必须确认数据传送的开始和结束,这通过起始和结束信号识别,开始信号的条件是当时钟为高电平时,数据线从高到低的跳变;结束信号的条件是当时钟为高电平时,数据线从低到高的跳变。(结合图2说明)IIC的完整时序图,具体可参考ads1110的datasheet发送起始信号后传送的第一字节数据具有特别的
3、意义,其中前七位为从机地址,最后一位为读写方向位(0表示写,1表示读)。IIC总线数据传送时,每传送一个字节数据后都必须有应答信号(A)。主控器接收数据时,如果要结束通信时,将在停止位之前发送非应答信号( !A )。IIC总线是双向的:SDA用来发送数据和接收数据,当主机从从机中读取数据时,从机驱动数据线,当主机向从机发送数据时,主机驱动数据线,主机总是驱动时钟线。具有IIC接口的器件在通信中可以配置为主控器也可以作为被控器,那么它就具有4种操作模式:主发送模式、主接收模式、从发送模式和从接收模式。(结合图3说明) 多数时候总线是空闲的,不发生通信,两条线上均是高电平。只有主机才能发起一次通信
4、。为了开始通信,主机必须发起一个开始信号,通常在SCL为低的时候数据才允许改变,否则在SCL线为高电平的时候数据线改变了状态,则形成一个开始条件或结束条件。4 对于没有IIC接口的器件,比如MCS-51单片机,若想使用IIC进行串行通信,硬件上可以外扩IIC接口芯片,软件上可以模拟IIC总线时序进行通讯,在此我们采用第二种方法,这就需要软件模拟IIC的读、写时序,模拟在作为接收器时的应答信号和非应答信号。5、IIC程序构成及代码IIC程序一共分成7个子程序块:开始条件,结束条件,应答信号,发送连续读信号,发送不连续读信号,发送一个字节,接收一个字节。5.1 开始条件当时钟信号SCL处于高电平期
5、间数据线SDA有个由高到低的跳变则表示进入IIC通信。代码段:void start(void) /开始 SDA=1; _nop_(); SCL=1; _nop_(); SDA=0; _nop_(); SCL=0;_nop_();5.2 结束条件当时钟信号SCL处于高电平期间数据信号SDA有个由低到高的跳变表示IIC通信结束。代码段:void stop(void) /结束 SDA=0; _nop_(); SCL=1; _nop_(); SDA=1; _nop_(); SCL=0; _nop_();5.3 应答信号一个时钟周期内如果数据信号为低则产生一个应答信号,数据为高则没有应答。程序最后有返回
6、值。注意:在检查应答信号之前一定要先释放SDA的控制权:SDA=1;否则程序会出错。代码段:unsigned char check_ack(void) / 检查应答信号 SDA=1; /检测从机应答信号之前应释放对SDA线的控制权 SCL=0; SCL=1; _nop_(); if (SDA) ACK = 1; else ACK = 0; SCL=0; return(ACK);5.4发送连续读信号,即主机工作在主接收方式下,接收完一个字节数据后发送应答信号在读周期中,字节是8位为一组在总线上传送的,这就涉及到连续数据的传输。注意:主机发送完应答信号后要释放SDA。代码段:void write_
7、ack(void) / 发送连续读信号 SCL=0; SDA=0; SCL=1; _nop_(); SCL=0;SDA=1; /主发送机发送完应答信号后应释放SDA总线,否则/只能读出第一个字节 5.5发送非应答信号(也可作为不连续读信号),在要结束IIC通信时可发一个非应答信号在一个时钟周期内,数据线SDA始终为高,表示发送非应答信号。代码段:void write_nack(void) / 发送不连续读信号 SCL=0;SDA=1; SCL=1; _nop_(); SCL=0;5.6发送一个字节以8位一个字节为一组进行发送。代码段:void write_byte(unsigned char
8、date) / 发送一个字节 unsigned char i=8; /发送8位 do SCL=0; if(date&0x80)= =0x80) SDA=1; /写 1 else SDA=0; /写 0 SCL=1; _nop_(); SCL=0; date=date1; while(-i); SDA=1 ; /发送完一个字节数据后应在接收器发送应答信号前释放总线 5.7接收一个字节:有返回值。代码段:unsigned char read_byte(void) /接收一个字节 unsigned char date=0; unsigned char i=8; do SCL=0; SCL=1; _n
9、op_(); if(SDA) /读 1 date=date|0x01; SCL=0; if(i-1) date=date1; while(-i); return(date); 6、典型应用我们以16位A/D转换芯片ADS1110为例,说明其具体操作过程。 ADS1110的写操作是对配置寄存器进行的,首先要对ADS1110寻址,然后写入一个字节。这个字节是写入配置寄存器。输出寄存器不能被写入。ADS1110的读操作首先也要对ADS1110寻址,然后从器件中读取三个字节,前两个是输出寄存器内容,第三个为配置寄存器内容。ADS1110允许读少于三个的字节,但是多于三个字节是无效的。从第四个以后所有的
10、字节均为FF。 16位的输出寄存器包含了上次转换的结果,8位的配置寄存器是用来控制ADS1110的工作方式,数据速率和PGA的设置。默认设置为8C。具体信息参考datasheet中寄存器的说明部分。写操作过程:开始条件,对器件寻址,检查主机应答信号,有应答则继续。写入一个字节到配置寄存器,检查应答信号,有应答则继续,最后结束IIC的写操作。程序: start(); /开始一次通信 write_byte(0x90); /写器件地址(写) if(check_ack() /检测应答信号 return(0); write_byte(8c); /写配置字,8c为ads1110工作时的设置 if(chec
11、k_ack() /检测应答信号 return(0); stop();读操作过程:(ads1110是16位ad,转换结果分两次读出)开始条件,读器件地址,检查主机应答信号,有应答则继续。读高8位数据,主机发送连续读信号,读低8位数据,主机发送连续读信号,读配置寄存器状态,主机发送不连续读信号,结束IIC的读操作。程序: start(); write_byte(0x91); /写器件地址(读) if(check_ack() /检测应答信号 return(0); temp=read_byte(); / 读高8位 write_ack(); /连续读 tempL=read_byte(); /读低8位 w
12、rite_ack(); /连续读 config_s=read_byte(); /读配置寄存器的状态 write_nack(); stop(); /结束读 temp=(temp写从机地址(写操作)-检测应答信号(若有应答信号)-写配置字,设定从机工作方式-检测应答信号(若有应答信号)-写操作结束;开始-写从机地址(读操作)-检测应答信号(若有应答信号)-读高8位转换数据-发送应答信号即连续读信号-读低8位转换数据-发送应答信号即连续读信号-读配置寄存器(可选)-发送非应答信号信号准备结束IIC通信-结束读操作,可对读到的两个8位数据联接成一个16位的数据;一次读取转换数据结束。注意:在以下三个地
13、方单片机要释放对SDA总线的控制权1)单片机作为主发送机检查从机的应答信号之前要释放SDA总线2)单片机作为主接收机发送应答信号之后要释放SDA总线3)单片机作为主发送机发送完一个字节数据之后要释放SDA总线他们有一个共同的特点,即在对从机进行读操作之前释放SDA总线7、附ads1110完整程序清单如下:/ADS1110的驱动程序,采用IIC通讯方式sbit SDA=P13; /根据硬件实际连接作相应改动sbit SCL=P12;unsigned char ACK;void NOP()_nop_();_nop_();*void start(void) /开始 SDA=1;NOP(); SCL=
14、1;NOP(); SDA=0;NOP(); SCL=0;NOP();*void stop(void) /结束 SDA=0;NOP(); SCL=1; NOP(); SDA=1; NOP(); SCL=0; NOP();* unsigned char check_ack(void) / 检查应答信号 SDA=1; /检测应答信号前应释放对SDA线的控制权 SCL=0;SCL=1;NOP(); if (SDA)ACK = 1;elseACK = 0;SCL=0;return(ACK); *void write_ack(void) / 发送连续读信号 SCL=0;SDA=0;SCL=1;NOP();
15、SCL=0;SDA=1; /主发送机发送完应答信号后应释放SDA总线,否则只能读出第一个字节 *void write_nack(void) / 发送不连续读信号 SCL=0;SDA=1;SCL=1;NOP();SCL=0;* void write_byte(unsigned char date) / 发送一个字节unsigned char i=8; /发送8位do SCL=0; if(date&0x80) SDA=1; /写 1 else SDA=0; /写 0 SCL=1;NOP(); SCL=0; date=date1; while(-i); SDA=1 ; /发送完一个字节数据后应在接收
16、器发送应答信号前释放总线 *unsigned char read_byte(void) /接收一个字节 unsigned char date=0; unsigned char i=8; do SCL=0; /在时钟大于4u秒期间读数据 SCL=1; NOP(); if(SDA) /读 1 date=date|0x01; SCL=0; if(i-1) date=date1; while(-i);return(date); *float ads1110(unsigned char config) unsigned int config_s; /配置字状态 unsigned int temp; un
17、signed int tempL; float adc_value; start(); /开始写 write_byte(0x90); /写器件地址(写) if(check_ack() /检测应答信号 return(0); write_byte(config); /写配置字 if(check_ack() /检测应答信号 return(0); stop(); start(); write_byte(0x91); /写器件地址(读) if(check_ack() /检测应答信号 return(0); temp=read_byte(); / 读高8位 write_ack(); /连续读 tempL=read_byte(); /读低8位 write_ack(); /连续读 config_s=read_byte(); /读配置寄存器的状态 write_nack(); stop(); /结束读 temp=(temp8)+tempL; x=56; y=4; printf(%d ,temp); adc_value=temp; adc_value=adc_value*2.048/32768; return(adc_value);
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1