做网站一共需要多少钱,中国空间站科幻作文1000字,如何创建网站的步骤,去哪个网站找建筑图纸前言#xff1a; I2C(Inter-Integrated Circuit)总线(也称 IIC 或 I2C) 是有PHILIPS公司开发的两线式串行总线#xff0c;用于连接微控制器及外围设备#xff0c;是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式#xff0c;具有接口线少、控制方式… 前言 I2C(Inter-Integrated Circuit)总线(也称 IIC 或 I2C) 是有PHILIPS公司开发的两线式串行总线用于连接微控制器及外围设备是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式具有接口线少、控制方式简单、器件封装形式小、通信速率较高等优点。 一、综述 Exynos4412精简指令集微处理器支持4个IIC总线控制器。为了能使连接在总线上的主和从设备之间传输数据专用的数据线SDA和时钟信号线SCL被使用他们都是双向的。 如果工作在多主机的IIC总线模式多个4412处理器将从从机那接收数据或发送数据给从机。在IIC总线上的主机端4412会启动或终止一个数据传输。4412的IIC总线控制器会用一个标准的IIC总线仲裁机制去实现多主机和多从机传输数据。 通过控制如下寄存器以实现IIC总线上的多主机操作 控制寄存器 I2CCON 状态寄存器 I2CSTAT Tx/Rx数据偏移寄存器 I2CDS 地址寄存器 I2CADD 如果I2C总线空闲那么SCL和SDA信号线将都为高电平。在SCL为高电平期间如果SDA有由高到低电平的跳变那么将启动一个起始信号如果SDA有由低到高电平的跳变将启动一个结束信号。 主机端的设备总是提供起始和停止信号的一端。在起始信号被发出后一个数据字节的前7位被当作地址通过SDA线被传输。这个地制值决定了总线上的主设备将要选择那个从设备作为传输对象bit8决定传输数据的方向(是读还是写)。 I2C总线上的数据(即在SDA上传输的数据)都是以8位字节传输的在总线上传输操作的过程中对发送或接收的数据字节数是没有限制的。I2C总线上的主/从设备发送数据总是以一个数据的最高位开始传输(即MSB方式)传输完一个字节后应答信号紧接其后。 二、I2C总线接口特性 9个通道多主、从I2C总线接口。其中8个通道作为普通接口(即I2C0、I2C1....)1个通道作为HDMI的专用接口。 7位地址模式。 串行8位单向或双向的数据传输。 在标准模式中每秒最多可以传输100k位即12.5kB的数据量。 在快速模式中每秒最多可以传输400k位即50kB的数据量。 支持主机端发送、接收从机端发送、接收操作。 支持中断和查询方式。 三、框图 从上图可以看出4412提供4个寄存器来完成所有的IIC操作。SDA线上的数据从IICDS寄存器经过移位寄存器发出或通过移位寄存器传入IICDS寄器IICADD寄存器中保存4412当做从机时的地址IICCON、IICSTAT两个寄存器用来控制或标识各种状态比如选择工作工作模式发出S信号、P信号决定是否发出ACK信号检测是否接收到ACK信号。 四、I2C总线接口操作 针对4412处理器的I2C总线接口具备4种操作模式 1 -- 主机发送模式 2 -- 主机接收模式 3 -- 从机发送模式 4 -- 从机接收模式 下面将描述这些操作模式之间的功能关系 0、数据有效性 SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态IIC位传输数据的有效性在SCL线的时钟信号是低电平才能改变。 1. 开始和停止条件 当4412的I2C接口空闲时它往往工作在从机模式。或者说4412的的i2c接口在SDA线上察觉到一个起始信号之前它应该工作在从机模式。当控制器改变4412的i2c接口的工作模式为主机模式后SDA线上发起数据传输并且控制器会产生SCL时钟信号。 开始条件通过SDA线进行串行的字节传输一个停止信号终止数据传输停止信号是指SCL在高电平器件SDA线有从低到高电平的跳变主机端产生起始和停止条件。当主、从设备产生一个起始信号后,I2C总线将进入忙状态。这里需要说明的是上述主从设备都有可能作为主机端。 当一个主机发送了一个起始信号后它也应该发送一个从机地址以通知总线上的从设备。这个地址字节的低7位表示从设备地址最高位表示传输数据的方向即主机将要进行读还是写。当最高位是0时它将发起一个写操作(发送操作)当最高位是1时它将发起一个读数据的请求接收操作。 主机端发起一个结束信号以完成传输操作如果主机端想在总线上继续进行数据的传输它将发出另外一个起始信号和从设备地址。用这样的方式它们可以用各种各样的格式进行读写操作。 下图为起始和停止信号 下面先提前讲一下具体应用中如何启动和恢复IIC的传输 启动或恢复4412的I2C传输有以下两种方法。 1 当IICCON[4]即中断状态位为0时通过写IICSTAT寄存器启动I2C操作。有以下两种情况。 1--在主机模式令IICSTAT[5:4]等于0b11将发出S信号和IICDS寄存器的数据寻址令IICSTAT[5:4]等于0b01将发出P信号。 2--在从机模式令IICSTAT[4]等于1将等待其他主机发出S信号及地址信息。 2当IICCON[4]即中断状态为1时表示I2C操作被暂停。在这期间设置好其他寄存器之后向IICCON[4]写入0即可恢复I2C操作。所谓“设置其他寄存器”有以下三种情况 1--对于主机模式可以按照上面1的方法写IICSTAT寄存器恢复I2C操作后即可发出S信号和IICDS寄存器的值寻址或发出P信号。 2--对于发送器可以将下一个要发送的数据写入IICDS寄存器中恢复I2C操作后即可发出这个数据。 3--对于接收器可以从IICDS寄存器读出接收到的数据。最后向IICCON[4]写入0的同时设置IICCON[7]以决定是否在接收到下一个数据后是否发出ACK信号。 2. 数据传输格式 放到SDA线上的所有字节数据的长度应该为8位在每次传输数据时对传输数据量没有限制。在起始信号后的第一个数据字节应该包含地址字段当4412的I2C接口被设置为主模式时地址字节应该有控制器端发出。在每个字节后应该有一个应答位。 如果从机要完成一些其他功能后例如一个内部中断服务程序才能继续接收或发送下一个字节从机可以拉低SCL迫使主机进入等待状态。当从机准备好接收下一个数据并释放SCL后数据传输继续。如果主机在传输数据期间也需要完成一些其他功能例如一个内部中断服务程序也可以拉低SCL以占住总线。 下面的图中将说明数据传输格式 上图中说明在传输完每个字节数据后都会有一个应带信号这个应答信号在第9个时钟周期。具体过程如下(注意下面描述的读写过程都是针对Tiny4412处理器而言当有具体的I2C设备与4412相连时数据表示什么需要看具体的I2C设备4412是不知道数据的含义的) 写过程主机发送一个起始信号S→发送从机7位地址和1位方向方向位表示写→主机释放SDA线方便从机给回应→有从机匹配到地址拉低SDA线作为ACK→主机重新获得SDA传输8位数据→主机释放SDA线方便从机给回应→从机收到数据拉低SDA线作为ACK告诉主机数据接收成功→主机发出停止信号。 读过程主机发送一个起始信号S→发送从机7位地址和1位方向方向位表示读→主机释放SDA线方便从机给回应→有从机匹配到地址拉低SDA线作为ACK→从机继续占用SDA线用SDA传输8位数据给主机→从机释放SDA线(拉高)方便主机给回应→主机接收到数据→主机获得SDA线控制并拉低SDA线作为ACK告诉从机数据接收成功→主机发出停止信号。 注意在具体的I2C通信时要看I2C设备才能确定读写时序比如下面即将描述的第七大点中的示例读写EEPROM中就会说道具体的数据含义读写过程。 3. 应答信号的传输 为了完成一个字节数据的传输接收方将发送一个应答位给发送方。应答信号出现在SCL线上的时钟周期中的第九个时钟周期为了发送或接收1个字节的数据主机端会产生8个时钟周期为了传输一个ACK位主机端需要产生一个时钟脉冲。 ACK时钟脉冲到来之际发送方会在SDA线上设置高电平以释放SDA线。在ACK时钟脉冲之间接收方会驱动和保持SDA线为低电平这发生在第9个时钟脉冲为高电平期间。 应答信号为低电平时规定为有效应答位ACK简称应答位表示接收器已经成功地接收了该字节应答信号为高电平时规定为非应答位NACK一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主控器则在它收到最后一个字节后发送一个NACK信号(即不发出ACK信号)以通知被控发送器结束数据发送并释放SDA线以便主控接收器发送一个停止信号P。 4. 读写操作 当I2C控制器在发送模式下发送数据后I2C总线接口将等待直到移位寄存器(I2CDS)接收到一个数据。在往此寄存器写入一个新数据前SCL线应该保持为低电平写完数据后I2C控制器将释放SCL线。当前正在传输的数据传输完成后4412会捕捉到一个中断然后cpu将开始往I2CDS寄存器中写入一个新的数据。 当I2C控制器在接收模式下接收到数据后I2C总线接口将等待直到I2CDS寄存器被读。在读到新数据之前SCL线会被保持为低电平读到数据后I2C控制器将释放掉SCL线。一个新数据接收完成后4412将收到一个中断cpu收到这个中断请求后它将从I2CDS寄存器中读取数据。 5. 总线仲裁机制 总线上可能挂接有多个器件有时会发生两个或多个主器件同时想占用总线的情况这种情况叫做总线竞争。I2C总线具有多主控能力可以对发生在SDA线上的总线竞争进行仲裁其仲裁原则是这样的当多个主器件同时想占用总线时如果某个主器件发送高电平而另一个主器件发送低电平则发送电平与此时SDA总线电平不符的那个器件将自动关闭其输出级。总线竞争的仲裁是在两个层次上进行的。首先是地址位的比较如果主器件寻址同一个从器件则进入数据位的比较从而确保了竞争仲裁的可靠性。由于是利用I2C总线上的信息进行仲裁因此不会造成信息的丢失。 6. 终止条件 当一个从接收者不能识别从地址时它将保持SDA线为高电平。在这样的情况下主机会产生一个停止信号并且取消数据的传输。当终止传输产生后主机端接收器会通过取消ACK的产生以告诉从机端发送器结束发送操作。这将在主机端接收器接收到从机端发送器发送的最后一个字节之后发生为了让主机端产生一个停止条件从机端发送者将释放SDA线。 7. 配置I2C总线 如果要设置I2C总线中SCL时钟信号的频率可以在I2CCON寄存器中设置4位分频器的值。I2C总线接口地址值存放在I2C总线地址寄存器(I2CADD)中默认值未知。 8. 每种模式下的操作流程图 在I2C总线上执行任何的收发Tx/Rx操作前应该做如下配置 1在I2CADD寄存器中写入从设备地址 2设置I2CCON控制寄存器 a. 使能中断 b. 定义SCL频率 3设置I2CSTAT寄存器以使能串行输出 下图为主设备发送模式 下图为主设备接收模式 下图为从设备发送模式 下图为从设备接收 模式 1-- I2C总线控制寄存器 IICCON寄存器用于控制是否发出ACK信号、设置发送器的时钟、开启I2C中断并标识中断是否发生 使用IICCON寄存器时有如下注意事项 1、发送模式的时钟频率由位[6]、位[3:0]联合决定。另外当IICCON[6]0时IICCON[3:0]不能取0或1。 2、位[4]用来标识是否有I2C中断发生读出为0时标识没有中断发生读出为1时标识有中断发生。当此位为1时SCL线被拉低此时所以I2C传输停止;如果要继续传输需写入0清除它。 中断在以下3中情况下发生 1 -- 当发送地址信息或接收到一个从机地址并且吻合时 2 -- 当总线仲裁失败时 3 -- 当发送/接收完一个字节的数据包括响应位时 3、基于SDA、SCL线上时间特性的考虑要发送数据时先将数据写入IICDS寄存器然后再清除中断。 4、如果IICCON[5]0IICCON[4]将不能正常工作所以即使不使用I2C中断也要将IICCON[5]设为1. 2 -- I2C状态寄存器 IICSTAT寄存器用于选择I2C接口的工作模式发出S信号、P信号使能接收/发送功能并标识各种状态比如总线仲裁是否成功、作为从机时是否被寻址、是否接收到0地址、是否接收到ACK信号等。 3 -- I2C数据发送/接收移位寄存器 下面是个IIC总线实例 用IIC总线实现CPU与MPU-6050的数据查询 具体代码如下 [cpp] view plaincopy #include exynos_4412.h //**************************************** // MPU6050内部地址 //**************************************** #define SMPLRT_DIV 0x19 //陀螺仪采样率典型值0x07(125Hz) #define CONFIG 0x1A //低通滤波频率典型值0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围典型值0x18(不自检2000deg/s) #define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率典型值0x01(不自检2G5Hz) #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6B //电源管理典型值0x00(正常启用) #define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68只读) #define SlaveAddress 0xD0 //IIC写入时的地址字节数据1为读取 void mydelay_ms(int time) { int i, j; while(time--) { for (i 0; i 5; i) for (j 0; j 514; j); } } /********************************************************************** * brief iic read a byte program body * param[in] slave_addr, addr, data * return None **********************************************************************/ void iic_read(unsigned char slave_addr, unsigned char addr, unsigned char *data) { I2C5.I2CDS slave_addr; //将从机地址写入I2CDS寄存器中 I2C5.I2CCON (1 7)|(1 6)|(1 5); //设置时钟并使能中断 I2C5.I2CSTAT 0xf0; //[7:6]设置为0b11主机发送模式 //往[54]位写0b11即产生启动信号,发出IICDS寄存器中的地址 while(!(I2C5.I2CCON (1 4))); // 等待传输结束传输结束后I2CCON [4]位为1标识有中断发生 // 此位为1时SCL线被拉低此时I2C传输停止 I2C5.I2CDS addr; //写命令值 I2C5.I2CCON I2C5.I2CCON (~(1 4)); // I2CCON [4]位清0继续传输 while(!(I2C5.I2CCON (1 4))); // 等待传输结束 I2C5.I2CSTAT 0xD0; // I2CSTAT[5:4]位写0b01,发出停止信号 I2C5.I2CDS slave_addr | 1; //表示要读出数据 I2C5.I2CCON (1 7)|(1 6) |(1 5) ; //设置时钟并使能中断 I2C5.I2CSTAT 0xb0; //[7:6]位0b10,主机接收模式 //往[54]位写0b11即产生启动信号,发出IICDS寄存器中的地址 //I2C5.I2CCON I2C5.I2CCON (~(1 4)); while(!(I2C5.I2CCON (1 4))); //等待传输结束接收数据 I2C5.I2CCON ~((17)|(1 4)); // I2CCON [4]位清0继续传输接收数据 // 主机接收器接收到最后一字节数据后不发出应答信号 no ack // 从机发送器释放SDA线以允许主机发出P信号停止传输 while(!(I2C5.I2CCON (1 4))); // 等待传输结束 *data I2C5.I2CDS; I2C5.I2CSTAT 0x90; I2C5.I2CCON ~(14); /*clean interrupt pending bit */ } /********************************************************************** * brief iic write a byte program body * param[in] slave_addr, addr, data * return None **********************************************************************/ void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data) { I2C5.I2CDS slave_addr; I2C5.I2CCON (1 7)|(1 6)|(1 5) ; I2C5.I2CSTAT 0xf0; while(!(I2C5.I2CCON (1 4))); I2C5.I2CDS addr; I2C5.I2CCON I2C5.I2CCON (~(1 4)); while(!(I2C5.I2CCON (1 4))); I2C5.I2CDS data; I2C5.I2CCON I2C5.I2CCON (~(1 4)); while(!(I2C5.I2CCON (1 4))); I2C5.I2CSTAT 0xd0; I2C5.I2CCON I2C5.I2CCON (~(1 4)); mydelay_ms(10); } void MPU6050_Init () { iic_write(SlaveAddress, PWR_MGMT_1, 0x00); iic_write(SlaveAddress, SMPLRT_DIV, 0x07); iic_write(SlaveAddress, CONFIG, 0x06); iic_write(SlaveAddress, GYRO_CONFIG, 0x18); iic_write(SlaveAddress, ACCEL_CONFIG, 0x01); } int get_data(unsigned char addr) { char data_h, data_l; iic_read(SlaveAddress, addr, data_h); iic_read(SlaveAddress, addr1, data_l); return (data_h8)|data_l; } /* * 裸机代码不同于LINUX 应用层 一定加循环控制 */ int main(void) { int data; unsigned char zvalue; GPB.CON (GPB.CON ~(0xff8)) | 0x338; // GPBCON[3], I2C_5_SCL GPBCON[2], I2C_5_SDA mydelay_ms(100); uart_init(); /*---------------------------------------------------------------------*/ I2C5.I2CSTAT 0xD0; I2C5.I2CCON ~(14); /*clean interrupt pending bit */ /*---------------------------------------------------------------------*/ mydelay_ms(100); MPU6050_Init(); mydelay_ms(100); printf(\n********** I2C test!! ***********\n); while(1) { //Turn on data get_data(GYRO_ZOUT_H); printf( GYRO -- Z ---:Hex: %x, data); data get_data(GYRO_XOUT_H); printf( GYRO -- X ---:Hex: %x, data); printf(\n); mydelay_ms(1000); } return 0; } 实验结果如下 [cpp] view plaincopy ********** I2C test!! *********** GYRO -- Z ---:Hex: 1c GYRO -- X ---:Hex: feda GYRO -- Z ---:Hex: fefc GYRO -- X ---:Hex: fed6 GYRO -- Z ---:Hex: fefe GYRO -- X ---:Hex: fed6 GYRO -- Z ---:Hex: fefe GYRO -- X ---:Hex: fedc GYRO -- Z ---:Hex: fefe GYRO -- X ---:Hex: feda GYRO -- Z ---:Hex: fefc GYRO -- X ---:Hex: fed6 GYRO -- Z ---:Hex: fefe GYRO -- X ---:Hex: feda GYRO -- Z ---:Hex: fcf2 GYRO -- X ---:Hex: 202 GYRO -- Z ---:Hex: ec GYRO -- X ---:Hex: faa0 GYRO -- Z ---:Hex: 4c GYRO -- X ---:Hex: e GYRO -- Z ---:Hex: fe GYRO -- X ---:Hex: fed8 GYRO -- Z ---:Hex: 0 GYRO -- X ---:Hex: fede GYRO -- Z ---:Hex: 0 GYRO -- X ---:Hex: feda