第3节 GB60的IIC模块的编程基础
推荐给好友
打印
加入收藏
更新于2008-07-25 19:54:01

MC9S08GB60微控制器提供了一个IIC模块用于与其他IC设备通信。与IIC模块相关的两个引脚SDA和SCL分别与通用I/O口C口的2、3引脚复用。当使能IIC模块时,这两个引脚上的数据传送方向可以通过相关的模块配置来设置。当禁止IIC模块后,这两个引脚就作为通用I/O引脚使用。MCU复位后,IIC模块将被禁止。

11.3.1 GB60 IIC模块寄存器

1.IIC分频寄存器(Frequency Divider Register,IICF)
IIC总线波特率是由CPU总线频率分频得来,该分频寄存器IICF就用于产生相应的分频因子。编程时应根据需要和要与MCU通信的从机设备的IIC总线频率范围来确定具体的波特率值,并设置该分频寄存器。一般IIC总线频率设定在100kbps左右,可以通过减少IIC总线上的负载,使其总线最大波特率达到CPU总线频率的二十分之一。IICF的地址为$0059。
数据位 D7 D6 D5 D4 D3 D2 D1 D0
定 义 MULT ICR
复 位 0 0 0 0 0 0 0 0
IIC分频寄存器的高2位MULT定义了增频因子a,a和SCL的分频因子配合使用,产生IIC波特率。当MULT为00、01、10时,a的值分别为1、2、4;MULT = 11不使用。
IIC的低6位定义了IIC时钟速率(ICR),这6位用来定义SCL分频因子b和SDA保持值,分频因子b乘增频因子a的值用于产生IIC总线波特率,公式如下:
IIC总线波特率 = CPU总线频率(Hz) / (a * b)
SDA保持时间是从SCL线上时钟的下降沿开始到SDA线上数据稳定这段时间,SDA保持值就是用来计算SDA保持时间的,公式如下:
SDA保持时间 = CPU总线周期 * SDA保持值
ICR中不同的内容对应着不同的SCL分频因子值和不同的SDA保持值,具体的对应关系如表11-1所示。
下面举例说明IIC总线波特率和SDA保持时间计算方法:


设CPU总线频率为8MHz,MULT设置为01(a = 2),要想得到100kbps的IIC总线波特率,则计算过程如下:

①根据公式:IIC总线波特率 = CPU总线频率(Hz) / (a * b),将已知相应值带入得:
100000 = 8000000 / (2 * b)
b = 40
②根据SCL分频因子b的值,在表11-1中查找相应的ICR值和SDA保持值,可以看到,当b = 40时,ICR = $07或$0B,而相应的SDA保持值 = 10或9。
③根据公式:SDA保持时间 = CPU总线周期 * SDA保持值,算得:
ICR = $07,SDA保持值 = 10时,SDA保持时间 = 1 / 8000000 *10 = 1.25us
ICR = $0B,SDA保持值 = 9时,SDA保持时间 = 1 / 8000000 * 9 = 1.125us
④较长的SDA保持时间,会降低通信速率,但同时也增加了稳定性,并且能延长设备间的通信距离。编程时应以通信的可靠性为原则,选择合适的SDA保持时间来确定ICR值。如程序中选用SDA保持值 = 10,就能得到可靠的通信,那么将ICR设定为$07即可;如果当SDA保持值 = 10时通信不稳,就选择另一个为9的值进行实验,若通信仍不稳定,在保持IIC总线频率不变的前提下,可通过改变MULT位来调整SDA保持时间。

2.IIC控制寄存器(Control Register,IICC)
地址为:0x005A
数据位 D7 D6 D5 D4 D3 D2 D1 D0
定 义 IICEN IICIE MSTPT TX TXAK 0/RSTA 0/不用 0/不用
复 位 0 0 0 0 0 0 0 0
D7—IICEN(IIC Enable),IIC使能位。IICEN = 1,允许IIC;IICEN = 0,禁止IIC。
D6—IICIE(IIC Interrupt Enable),IIC中断请求允许位。IICIE = 1,允许IIC中断请求;IICIE = 0,禁止IIC中断请求。
D5-MST(Master Mode Select),主模式选择位。当该位从0变到1,MCU被确定为主模式,并在IIC总线上产生开始信号;当该位从1变到0,MCU将在IIC总线上产生停止信号,操作模式也将从主模式变为从模式。MST = 1,主机模式;MST = 0,从机模式。
D4—TX(Transmit Mode Select),发送模式选择位。该位用来选择主机和从机的数据传送方向。TX = 1,发送模式;TX = 0,接收模式。当MCU在主机模式下,该位可根据数据传送需求来确定,如果MCU要在总线上发送从机地址寻址从机,那么在整个地址周期,该位将始终为1。当MCU为从机时,该位将根据状态寄存器的SRW位来确定。
D3—TXAK(Transmit Acknowledge Enable),发送应答使能位。TXAK = 1,不发送应答信号;TXAK=0,在接收完一个字节后发送应答信号。
D2—RSTA(Repeat START),当MCU在主机模式下,向该位写1,将产生一个重新开始信号。该位读出时总是0。
D1-D0—读IICC时,D1、D0位为0;写IICC时,D1、D0位不使用。

3.IIC状态寄存器(IIC Status Register,IICS)
地址为:0x005B
数据位 D7 D6 D5 D4 D3 D2 D1 D0
读 TCF IAAS BUSY ARBL 0 SRW IICIF RXAK
写 未定义 未定义 未定义 未定义 未定义
复 位 0 0 0 0 0 0 0 0
D7—TCF(Transfer Complete Flag),发送完成标志位。一个字节传送完毕后,该位将被置位。TCF是只读位,在接收模式下,读IIC数据寄存器(IICD),在发送模式下,写IICD,都可以清除该位。TCF = 1,发送已经完成;TCF = 0,发送中。
D6—IAAS(Addressed as a Slave),地址被选择标志位。当MCU作为从机,并且它的地址与IIC总线上由主机发送的寻址地址吻合时,该位被置位。IAAS位可读可写,IAAS = 1,MCU作为从机被主机寻址;IAAS = 0,MCU未被寻址。
D5—BUSY(Bus Busy),总线忙标志位。该位是只读位,不论MCU作为主机还是从机,该位都用来标志IIC总线上的状态。当检测到开始信号,该位被置位,标志总线忙;当检测到停止信号,该位被清零,标志总线空闲。
D4—ARBL(Arbitration Lost),仲裁丢失标志位。当仲裁处理丢失,该位被硬件置位。ARBL可读可写,必须通过软件的方法向ARBL写1来清除该位。ARBL = 1,仲裁丢失;反之正常。
D3—读IICS时,D3位为0;写IICS时,D3位不使用。
D2—SRW(Slave Read/Write),从机读写标志位。SRW是只读位,当MCU作为从机被寻址时,该位被设为主机发送的寻址地址的第8位即主机读/写控制位的值。SRW = 1,表示从机为发送模式,主机从从机读数据;SRW = 0,表示从机为接收模式,主机向从机写数据。
D1—IICIF(IIC Interrupt Flag),IIC中断标志位。IICIF位可读可写。下列3个事件之一可以置位IICIF:一个字节传送完毕、从地址被选中、仲裁丢失。必须通过向IICIF写1,清除该标志。
D0—RXAK(Receive Acknowledge),接收应答标志位。该位为只读位。RXAK = 0,表示在IIC总线上传送完一个字节后,接收到了应答信号;RXAK = 1,表示没有检测到应答信号。

4.IIC数据输入/输出寄存器(IIC Data I/O Register,IICD)
地址为:0x005C
数据位 D7 D6 D5 D4 D3 D2 D1 D0
数据 数据
复 位 0 0 0 0 0 0 0 0
在主机发送模式下,将数据写入IICD就初始化了数据发送,先发送数据字节的最高位。在主机接收模式下,读该寄存器,准备接收从机发往总线上的数据字节。该寄存器在MCU为从机模式时仍具有相同功能。值得注意的是,当MCU要从主接收模式变为主发送模式时,应在从IICD寄存器读取数据之前,进行模式转换。

5.IIC地址寄存器(IIC Address Register,IICA)
地址为:0x0058
数据位 D7 D6 D5 D4 D3 D2 D1 D0
数 据 地址 0/不用
复 位 0 0 0 0 0 0 0 0
IIC地址寄存器的D7~D1位存放的是MCU作为从机时的地址。当主机在IIC总线上发送从机地址寻址从机时,MCU作为从机设备,将该地址与IICA的高7位比较,查看自己是否被主机选重。读IICA时,D0位为0;写IICA时,D0位不使用。

11.3.2 GB60 IIC模块编程

下表给出了GB60通过IIC总线与从机通信程序的头文件,可以清楚的看到,通信程序主要由IIC模块初始化子函数,GB60从从机读一个字节、读N个字节数据子函数,GB60向从机写一个字节、写N个字节数据子函数,等5个子函数组成。该头文件主要是对这5个函数进行声明并包含了IIC通信程序所需的头文件。
//[IIC.h]IIC通信头文件-----------------------------------------------------*
//说明:本文件与具体的芯片型号有关 *
//-------------------------------------------------------------------------*

//头文件
#include "GB60C.h" //GP60 MCU映像寄存器名定义
#include "Type.h" //类型别名定义

//IIC通信函数声明
//IIC初始化
void IICinit(void);
//从从机读1个字节数据
INT8U IICread1(INT8U DeviceAddr, INT8U AccessAddr, INT8U *Data);
//从从机读N个字节数据
INT8U IICreadN(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data[], INT8U N);
//向从机写1个字节数据
INT8U IICwrite1(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data);
//向从机写N个字节数据
INT8U IICwriteN(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data[], INT8U N);

1.IIC模块初始化
IIC相关寄存器地址宏定义已经在头文件GB60C.h中给出,IICF、IICA、IICC等寄存器名可以直接使用。
对SCI进行初始化,最少由以下三步构成。
①设置IIC分频寄存器,定义IIC总线波特率和SDA保持时间。具体的设置方法已在讲解GB60 IIC分频寄存器时详细介绍过,这里不再敖述。
②设置IIC地址寄存器,定义MCU作为从机时的地址。当主机在IIC总线上发送从机地址寻址从机时,MCU就将该地址与IICA的高7位比较,查看自己是否被主机选中。MCU在主机模式下是不使用这7位从机地址的。
③设置IIC控制寄存器,定义通信模式、允许或禁止IIC模块、允许或禁止IIC中断以及是否发送应答信号等。

2.接收一个数据与发送一个数据
一般情况下,对IIC的初始化只在程序的初始化部分进行一次,IIC通信的基础编程是接收与发送数据。接收和发送一个字节数据的过程现简述如下,具体时序请参见IIC总线原理一节。

(1) 接收一个字节数据:
①置IIC控制寄存器的发送模式选择位TX为1,将MCU设为发送模式。
②MCU初始化之后被设为从机模式,这时将IIC控制寄存器的主机模式选择位MST由0变为1,MCU被设为主机模式并由此产生开始信号。
③发送与MCU通信的从机地址(发送字节的高7位),并通知从机接收数据(发送字节的最低位置0)。只需将要发送的字节置于IICD,就初始化了此次发送。接着就等待这个字节发送完成。发送成功后,还需等待从机的应答信号。
④发送要访问的具体的从机中寄存器地址,并等待发送完成,发送成功后,需等待从机的应答信号。
⑤在改变通信模式之前,要置IIC控制寄存器的RSTA位产生重新开始信号,来为之做准备。接下来,MCU要由先前的发送数据(包括控制信号和从机地址等)变为接收数据,从机也要由接收数据变为发送数据。所以此时MCU要发送一个重新开始信号。
⑥发送从机地址字节,此时最低位为1,通知从机准备发送数据。等待该字节发送完成,等待从机的应答信号。
⑦置IIC控制寄存器的TX位为0,MCU被设置为接收模式。
⑧读IICD,清除该寄存器,准备接收数据。等待从机发送数据完成,从机发完数据后,MCU将IIC控制寄存器的主机模式选择位MST由1变为0,MCU被设为从机模式并由此产生停止信号,结束一次数据接收过程。
⑨读IICD寄存器,MCU最终得到从机发来的一个字节数据。

(2) 发送一个字节数据:
①与接收一个字节数据的前四步一致。
②将要发送给从机的一个字节数据写入IICD,初始化数据发送。接着就等待数据发送完成,等待从机的应答信号。收到应答后,表明数据已成功写入从机。
③将IIC控制寄存器的主机模式选择位MST由1变为0,MCU被设为从机模式并由此产生停止信号,结束一次数据发送过程。

3.接收N个数据与发送N个数据
通过循环调用接收一个字节数据函数与发送一个字节数据函数,来分别实现接收与发送N个字节数据。值得注意的是每一次数据字节的传送之间要有适当的时间间隔。
下面给出GB60与从机的IIC通信程序IIC.c。
//[IIC.c]IIC总线通信-------------------------------------------------------*
//外部函数: *
// (1)IICinit:IIC模块初始化 *
// (2)IICread1:MCU从从机读1个字节 *
// (3)IICwrite1:MCU向从机写1个字节 *
// (4)IICreadN:MCU从从机读N个字节 *
// (5)IICwriteN:MCU向从机写N个字节 *
//内部函数: *
// (1) SendSignal:在IIC总线上发送起停信号 *
// (2) Wait:等待应答或一个字节数据的传送完成 *
//硬件连接: *
// MCU的IIC接口与从机的IIC接口相连,GB60的IIC模块的引脚SDA和SCL分别与PTC2*
// 和PTC3引脚复用,这两个引脚应分别与从机的IIC模块的SDA和SCL相连 *
//说明:本文件与具体的芯片型号有关 *
//-------------------------------------------------------------------------*

//头文件
#include "IIC.h"

//IICinit:IIC模块初始化----------------------------------------------------*
//功 能:对IIC模块进行初始化,默认为允许IIC,IIC总线频率:62.5KHz,禁止IIC中 *
// 断,从机接收模式,不发送应答信号 *
//参 数:无 *
//返 回:无 *
//-------------------------------------------------------------------------*
void IICinit(void)
{
IICF = 0b00100101;//IIC总线频率:62.5KHz,SDA保持时间:2.45us
//||||||||___ICR
//||_________MULT
IICA = 0xF0; //D7-D1位是MCU作为从机时的地址,最低位不使用
IICC = 0b10001000;
//||||||||___不用
//||||||
//||||||_____RSTA位
//|||||______不发送应答信号
//||||_______接收模式
//|||________从机模式
//||_________禁止IIC中断
//|__________使能IIC模块
}

//SendSignal:在IIC总线上发送起停信号---------------------------------------*
//功 能:根据需要产生开始或停止信号 *
//参 数:Signal = 'S'(Start),产生开始信号;Signal = 'O'(Over),产生停止信号 *
//返 回:无 *
//-------------------------------------------------------------------------*
void SendSignal(INT8U Signal)
{
if (Signal == 'S')
IICC |= 0x20; //主机模式选择位MST由0变为1,可以产生开始信号
else if (Signal == 'O')
IICC &= ~0x20; //主机模式选择位MST由1变为0,可以产生停止信号
}

//Wait:等待应答或一个字节数据的传送完成------------------------------------*
//功能:在时限内,循环检测接收应答标志位,或传送完成标志位,判断MCU是否接收到应*
// 答信号或一个字节是否已在总线上传送完毕 *
//参数:x = 'A'(Ack),等待应答;x = 'T'(Transmission),等待一个字节数据传输完成*
//返回:0:收到应答信号或一个字节传送完毕;1:未收到应答信号或一个字节没传送完 *
//-------------------------------------------------------------------------*
INT8U Wait(INT8U x)
{
INT8U ErrTime, i;
ErrTime = 255; //定义查询超时时限
for (i = 0;i < ErrTime;i++)
{
if (x == 'A') //等待应答信号
{
if ((IICS & 0x01) == 0)
return 0; //传送完一个字节后,收到了从机的应答信号
}
else if (x == 'T') //等待传送完成一个字节信号
{
if ((IICS & 0x02) != 0)
{
IICS |= 0x02; //清IICIF标志位
return 0; //成功发送完一个字节
}
}
}
if (i >= ErrTime)
return 1; //超时,没有收到应答信号或发送完一个字节
}

//IICread1:从从机读1个字节数据---------------------------------------------*
//功 能:从从机读1个字节数据 *
//参 数: *
// (1) DeviceAddr:设备地址 *
// (2) AccessAddr:访问地址 *
// (3) Data:带回收到的一个字节数据 *
//返 回:为0,成功读一个字节;为1,读一个字节失败 *
//内部调用:SendSignal,Wait *
//-------------------------------------------------------------------------*
INT8U IICread1(INT8U DeviceAddr, INT8U AccessAddr, INT8U *Data)
{
IICC |= 0x10; //TX = 1,MCU设置为发送模式
SendSignal('S'); //发送开始信号
IICD = DeviceAddr & 0xfe; //发送设备地址,并通知从机接收数据
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,读一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,读一个字节失败
IICD = AccessAddr; //发送访问地址
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,读一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,读一个字节失败
IICC |= 0x04; //主机模式下,RSTA位置1,产生重复开始信号
IICD = DeviceAddr | 0x01; //通知从机改为发送数据
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,读一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,读一个字节失败
IICC &= 0xef; //TX = 0,MCU设置为接收模式
*Data = IICD; //读出IICD,准备接收数据
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,读一个字节失败
SendSignal('O'); //发送停止信号
*Data = IICD; //读出接收到的一个数据
return 0; //正确接收到一个字节数据
}

//IICwrite1:向从机写1个字节数据--------------------------------------------*
//功 能:向从机写1个字节数据 *
//参 数: *
// (1) DeviceAddr:设备地址 *
// (2) AccessAddr:访问地址 *
// (3) Data:要发给从机的1个字节数据 *
//返 回:为0,成功写一个字节;为1,写一个字节失败 *
//内部调用 :SendSignal, Wait *
//-------------------------------------------------------------------------*
INT8U IICwrite1(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data)
{
IICC |= 0x10; //TX = 1,MCU设置为发送模式
SendSignal('S'); //发送开始信号
IICD = DeviceAddr & 0xfe; //发送设备地址,并通知从机接收数据
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,写一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,写一个字节失败
IICD = AccessAddr; //发送访问地址
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,写一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,写一个字节失败
IICD = Data; //写数据
if (Wait('T')) //等待一个字节数据传送完成
return 1; //没有传送成功,写一个字节失败
if (Wait('A')) //等待从机应答信号
return 1; //没有等到应答信号,写一个字节失败
SendSignal('O'); //发送停止信号
return 0;
}

//IICreadN:从从机读N个字节数据---------------------------------------------*
//功 能:从从机读N个字节数据 *
//参 数: *
// (1) DeviceAddr:设备地址 *
// (2) AccessAddr:访问地址 *
// (3) Data:读出数据的缓冲区 *
// (4) N:从从机读的字节个数 *
//返 回:为0,成功读N个字节;为1,读N个字节失败 *
//内部调用:IICread1 *
//-------------------------------------------------------------------------*
INT8U IICreadN(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data[], INT8U N)
{
INT8U i, j;
for (i = 0;i < N;i++)
{
for(j = 0;j < 15;j++); //最小延时(发送的每个字节之间要有时间间隔)
if (IICread1(DeviceAddr, AccessAddr + i, &Data[i]))
return 1; //其中一个字节没有接收到,返回失败标志:1
}
if (i >= N)
return 0; //成功接收N个数据,返回成功标志:0
}

//IICwriteN:向从机写N个字节数据--------------------------------------------*
//功 能:向从机写N个字节数据 *
//参 数: *
// (1) DeviceAddr:设备地址 *
// (2) AccessAddr:访问地址 *
// (3) Data:要写入的数据 *
// (4) N:写入数据个数 *
//返 回:为0,成功写N个字节;为1,写N个字节失败 *
//内部调用:IICwrite1 *
//-------------------------------------------------------------------------*
INT8U IICwriteN(INT8U DeviceAddr, INT8U AccessAddr, INT8U Data[], INT8U N)
{
INT8U i, j;
for (i = 0;i < N;i++)
{
for(j = 0;j < 15;j++); //最小延时(发送的每个字节之间要有时间间隔)
if (IICwrite1(DeviceAddr, AccessAddr + i, Data[i]))
return 1; //其中一个字节没有发送出去,返回失败标志:1
}
if (i >= N)
return 0; //成功发送N个数据,返回成功标志:0
}

<<上一节 下一节>>




 
关于我们 | 诚邀加盟 | 客户服务 | 相关法律 | 网站地图 | 友情链接 | 服务信箱:service@eefocus.com
© 2006 与非门科技信息咨询(北京)有限公司 All Rights Reserved.