IIC 总线接口
IIC 总线简介
I IIC 总线接口特性
1.单片机串行接口的发送和接收一般都各用一条线,如的TXD 和RXD,而I 2.当某个器件向总线上发送信息时,它就是发送器(也叫主器件),而当其从总线上接收信息时,又成为接收器(也叫从器件)。 3.主器件用于启动总线上传送数据并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。I 4.总线上主和从(即发送和接收)的关系不是一成不变的,而是取决于此时数据传送的方向。 5.I 6.在I 7.当所有器件的时钟信号都上跳为高电平时,低电平期结束,SCL 线被释放返回高电平,即所有的器件都同时开始它们的高电平期。其后,第一个结束高电平期的器件又将SCL 线拉成低电平。这样就在SCL 线上产生一个同步时钟。可见,时钟低电平时间由时钟低电平期最长的器件确定,而时钟高电平时间由时钟高电平期最短的器件确定。 8.在I 9.当时钟线SCL 为高电平时,数据线SDA 由高电平跳变为低电平定义为“开始”信号; 10.当SCL 线为高电平时,SDA 线发生低电平到高电平的跳变为“结束”信号。 11.开始和结束信号都是由主器件产生。 12.在开始信号以后,总线即被认为处于忙状态;在结束信号以后的一段时间内,总线被认为是空闲的。 IIC 总线数据传送格式
1.在I (1) 其中前7 位为地址码; (2) 第8 位为方向位(R/W)。方向位为“ 2. 在I 为了完成一个字节的传输,接收方应该向发送方发送一个ACK位。ACK应该发生在SCL线的第九个脉冲期间。当接受到ACK信号时,发送方应该释放SDA线使SDA线电平为高。接收方应该驱动SDA线为低在ACK脉冲过程中。因此,在第九个SCL脉冲的高电平期间SDA保持为低(因为信号是“与”的)。ACK的传输可以由软件通过IICSTAT寄存器控制是否禁止,但它仍然是需要产生的。 IIC 总线数据传送过程
1.每次都是先传最高位,通常从器件在接收到每个字节后都会做出响应,即释放SCL线返回高电平,准备接收下一个数据字节,主器件可继续传送。 2.如果从器件正在处理一个实时事件而不能接收数据时,(例如正在处理一个内部中断,在这个中断处理完之前就不能接收I 读写操作
在发送模式下,当一个数据传输时,IIC总线接口将等待直到IICDS寄存器收到一个新数据。在一个新数据写入IICDS寄存器前,SCL信号将保持为低。在数据被写入之后,信号线被释放(为高)。ARM需要保持中断信号来辨别当前数据发送完成。在ARM接到一个中断请求后,它将写一个新的数据到IICDS。 在接收模式下,当一个数据接收时,IIC总线接口将等待直到IICDS寄存器数据被读出。在新数据被读出之前,SCL信号保持为低。在数据被读出后,信号线被释放(为高)。ARM应保持中断信号以辨别接收数据操作完成。在ARM收到一个中断请求时,它将从IICDS读出数据。 IIC 总线竞争和仲裁机制
1. 总线上可能挂接有多个器件,有时会发生两个或多个主器件同时想占用总线的情 况。 2. I 3. 其仲裁原则为:当多个主器件同时想占用总线时,如果某个主器件发送高电平, 而另一个主器件发送低电平,则发送电平与此时SDA 总线电平不符的那个器件将 自动关闭其输出级。 IIC 总线工作流程
开始:信号表明传输开始。 地址:主设备发送地址信息,包含7 位的从设备地址和1 位的指示位(表明读或者写,即数据流的方向)。 数据:根据指示位,数据在主设备和从设备之间传输。数据一般以8 位传输,最重要的位放在前面;具体能传输多少量的数据并没有限制。接收器上用一位的ACK 表明每一个字节都收到了。传输可以被终止和重新开始。 停止:信号结束传输。 S
|
Register |
Address |
R/W |
Description |
Reset Value |
IICCON |
0x54000000 |
R/W |
总线控制寄存器 |
0x0X |
IICCON |
Bit |
Description |
|
Acknowledge generation (note 1) |
[7] |
IIC总线确认位使能 0 = 禁止, 1 =使能 在Tx模式,IICSDA在确认时间内是任意的,在Rx 模式中= IICSDA 在确认时间内是低 |
0 |
Tx clock source selection |
[6] |
IIC总线传输时间对于资源时间的分频位 0 = IICCLK = fPCLK /16 1 = IICCLK = fPCLK /512 |
0 |
Tx/Rx Interrupt (note 5) |
[5] |
IIC总线 Tx/Rx中断使能/禁止位 0 = Disable, 1 = Enable |
0 |
Interrupt pending flag (note 2), (note 3) |
[4] |
IIC总线Tx/Rx中断未决标志位. 该位不能被写为1,当该位读为1的时候,IICSCL信号为低并且IIC停止,要恢复操作,只需将该位清零 0 = 1) 没有中断未决(读)2)清除未决状态 &恢复操作 (写). 1 = 1) 中断未决(读) 2) N/A (写) |
0 |
Transmit clock value (note 4) |
[3:0] |
IIC总线传输时钟预分频 IIC总线传输时钟频率由这个四位的值决定,由下列公式决定 Tx clock =IICCLK/(IICCON[3:0]+1). |
未定义 |
注意:
1.下面的几种情况将产生一个IIC 中断:
1) 当一个字节传输或接受操作完成的时 ;
2) 一个普通调用或一个从地址匹配产生时;
3) 总线仲裁失败时;
2. 为了在IISSCL信号的上升沿之前调整IICSDA的设置时间,IICDS必须要在IIC的中断位清零之前写入。
3.IICLK 由IICCON[6]决定;
Tx时钟会因为SCL时间的转换而改变
IIC 状态寄存器(IICSTAT)
Register |
Address |
R/W |
Description |
Reset Value |
IICSTAT |
0x54000004 |
R/W |
IIC总线状态寄存器 |
0x0 |
IICSTAT |
Bit |
Description |
|
Mode selection |
[7:6] |
IIC总线主/从 Tx/Rx模式选择位. 00: 从设备接受模式 01: 从设备发送模式 10: 主设备接受模式 11: 主设备发送模式 |
00 |
Busy signal status / START STOP condition |
[5] |
IIC总线忙信号状态位 0 = 读) 空闲 写) STOP 信号产生 1 = 读) 忙 写) START信号产生. IICDS中的数据在START信号后自动传输 |
|
Serial output |
[4] |
IIC总线数据输出使能/禁止位 0 =禁止 Rx/Tx, 1 = 使能 Rx/Tx |
0 |
Arbitration status flag |
[3] |
IIC总线过程仲裁状态位 0 =总线仲裁成功 1 = 在连续I/O 中总线仲裁失败 |
0 |
Address-as-slave status flag |
[2] |
IIC总线从地址状态标志位. 0 = 当START/STOP信号探测到时清零 1 =接收到的slave地址匹配IICADD的值 |
0 |
Address zero status flag |
[1] |
IIC总线地址零状态标志位 0 =当START/STOP信号探测到时清零. 1 =接收到的从地址为 00000000b. |
0 |
Last-received bit status flag |
[0] |
IIC总线IIC-bus上一次接收到的状态标志位. 0 =上一次接收到的位是0 (ACK was received). 1 =上一次接收到的位是1 (ACK was not received). |
0 |
地址寄存器(IICADD)
Register |
Address |
R/W |
Description |
Reset Value |
IICADD |
0x54000008 |
R/W |
IIC总线地址寄存器 |
0xXX |
IICADD |
Bit |
Description |
|
Slave address |
[7:0] |
7位从地址,从IIC总线中锁存 |
XXXXXXXX |
|
|
当IICSTAT 串行输出允许为0,IICADD 为写允许的时候 |
|
|
|
IICADD的值可以在任何时候被读取, 而不用管当前串行 |
|
|
|
输出允许位(IICSTAT)的设置 |
|
|
|
从地址 = [7:1] |
|
|
|
Not mapped = [0] |
|
移位数据寄存器(IICDS)
Register |
Address |
R/W |
Description |
Reset Value |
IICDS |
0x |
R/W |
IIC总线移位数据寄存器 |
0xXX |
IICDS |
Bit |
Description |
|
Data shift |
[7:0] |
IIC总线Tx/Rx 操作的8位移位寄存器 |
XXXXXXXX |
|
|
当IICSTAT 串行输出允许为1,IICADD 为写允许的时候 |
|
|
|
IICDS的值可以在任何时候被读取, 而不用管当前串行输 |
|
|
|
出允许位(IICSTAT)的设置. |
|
根据前面的原理介绍,编写一个程序来实现IIC的读写操作。
1. 阅读相关原理介绍,了解IIC协议发送和接收的基本过程。
2. 阅读本实验的源代码,更深层次理解IIC的实现细节,时序要求等。
3. 自己动手编写一个程序来实现IIC的读写操作。
主函数Main
#include "2410header.h"
#include "2410IIC.h"
void
{
sysinit(); //系统初始化代码,主要完成串口的初始化工作
Delay(0); //calibrate Delay()
Uart_Printf("IIC Test Pol:\n"); //串口打印数据
while (1)
{
Test_Iic2(); //IIC测试程序
Delay(1000);
Uart_Printf("\n\nPress Any Key To Continue\n\n");
Uart_Getch();
}
}
测试函数Test_Iic2
void Test_Iic2(void)
{
unsigned int i,j,save_E,save_PE;
static U8 data[256];
Uart_Printf("[ IIC Test(Polling) using KS
save_E = rGPECON; //保存寄存器的原来的值,等程序结束后恢复原值。
save_PE = rGPEUP;
rGPEUP |= 0xc000; //上拉禁止
rGPECON |= 0xa00000; //GPE15:IICSDA , GPE14:IICSCL
//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICADD = 0x10; //2410 slave address = [7:1]
rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
Uart_Printf("\nWrite test data into KS
for(i=0;i<256;i++)
_Wr
for(i=0;i<256;i++)
data[i] = 0; //初始化数组的值为0,
Uart_Printf("\nRead test data from KS
for(i=0;i<256;i++)
_Rd
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS
for(i=0;i<256;i++)
_Wr
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS
for(i=0;i<256;i++)
_Rd
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS
for(i=0;i<256;i++)
_Wr
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS
for(i=0;i<256;i++)
_Rd
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
Uart_Printf("\nWrite test data into KS
for(i=0;i<256;i++)
_Wr
for(i=0;i<256;i++)
data[i] = 0;
Uart_Printf("\nRead test data from KS
for(i=0;i<256;i++)
_Rd
for(i=0;i<16;i++)
{
for(j=0;j<16;j++)
Uart_Printf("%2x ",data[i*16+j]);
Uart_Printf("\n");
}
rGPEUP = save_PE;
rGPECON = save_E;
}
写EEPROM函数_Wr
void _Wr
{
_iicMode = WRDATA;
_iicPt = 0;
_iicData[0] = (U8)addr;
_iicData[1] = data;
_iicDataCount = 2;
rIICDS = slvAddr; //0xa0
//Master Tx mode, Start(Write), IIC-bus data output enable
//Bus arbitration sucessful, Address as slave status flag Cleared,
//Address zero status flag cleared, Last received bit is 0
rIICSTAT = 0xf0;
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(_iicDataCount!=-1)
Run_IicPoll();
_iicMode = POLLACK;
while(1)
{
rIICDS = slvAddr;
_iicStatus = 0x100; //To check if _iicStatus is changed
rIICSTAT = 0xf0; //Master Tx, Start, Output Enable, Sucessful, Cleared, Cleared, 0
rIICCON = 0xaf; //Resumes IIC operation.
while(_iicStatus==0x100)
Run_IicPoll();
if(!(_iicStatus & 0x1))
break; //When ACK is received
}
rIICSTAT = 0xd0; //Master Tx condition, Stop(Write), Output Enable
rIICCON = 0xaf; //Resumes IIC operation.
Delay(1); //Wait until stop condtion is in effect.
//Write is completed.
}
读EEPROM函数_Rd
void _Rd
{
_iicMode = SETRDADDR;
_iicPt = 0;
_iicData[0] = (U8)addr;
_iicDataCount = 1;
rIICDS = slvAddr;
rIICSTAT = 0xf0; //MasTx,Start
//Clearing the pending bit isn't needed because the pending bit has been cleared.
while(_iicDataCount!=-1)
Run_IicPoll();
_iicMode = RDDATA;
_iicPt = 0;
_iicDataCount = 1;
rIICDS = slvAddr;
rIICSTAT = 0xb0; //Master Rx,Start
rIICCON = 0xaf; //Resumes IIC operation.
while(_iicDataCount!=-1)
Run_IicPoll();
*data = _iicData[1];
}
|