利用CodeVision AVR C中断程序实现AVR单片机的TWI读写

时间:2022-05-27 09:17:42

利用CodeVision AVR C中断程序实现AVR单片机的TWI读写

[摘 要]本文介绍AVR单片机中TWI总线的内部模块、工作模式和工作时序。并将AVR单片机中的TWI和传统的I2C总线做了对比分析。详细地综合了主发送和主接收的共同特点,给出一个利用CodeVision AVR C环境编制的中断程序实例,实现对TWI总线的高效访问,对AVR单片机应用具有现实的指导意义。

[关键词]两线串行总线TWII2CCodeVision AVR C中断

[中图分类号]TP[文献标识码]A[文章编号]1007-9416(2010)03-0124-03

产生于80年代的I2C(InterIntegratedCircuit)总线是由Philips公司开发的两线串行总线,用于连接微控制器和外部接口器件。I2C总线最主要的优点是其简单性和有效性。使用时仅需要两条线就可以将最多128个不同的接口器件互连到一起,实现数据的发送和接收,数据传输率为200kHz。因此,具有I2C总线接口功能的器件应运而生,I2C总线器件得到了广泛的应用,已经成为工业标准。

AVR系列的单片机内部大多集成了TWI(TwowireSerialInterface)总线接口单元。功能和引脚定义也与I2C总线相同。而TWI重新定义了自已的功能模块和寄存器,寄存器各位的功能定义与I2C总线却不尽相同,传输率提高到400kHz,使得TWI总线在使用上比Philips公司的I2C总线更为灵活方便。然而TWI总线具有I2C总线的所有特点,支持I2C总线的所有通讯协议和时序,用途也完全相同。由于商业原因Atmel公司称它为TWI总线接口。而目前广泛应用的MCS-51单片机内部没有集成I2C总线模块,MCS-51单片机用户只能采用很长的程序模拟I2C总线的时序来完成其操作。使得I2C总线性能大打折扣。而大多数AVR系列的单片机内部都集成了TWI总线模块,数据传送是由模块自动完成。使得I2C总线读写变得简单、高效。本文对TWI总线的内部模块和工作时序进行了详细分析。结合I2C器件的特点,仔细分析了读写过程。用一个CodeVisionAVRC实时中断实例加以说明,对正确使用TWI总线编程具有现实的指导意义。

1 TWI内部模块

TWI内部由总线接口单元、比特率发生器、地址匹配单元和控制单元等几个子模块组成,如图1所示。图中SCL、SDA为CPU的TWI接口引脚。具体功能请参考AVR单片机ATmega16中文说明。接口的SCL频率如下式表示。

2 I2C器件的特点

目前具备I2C接口的器件很多,例如外部E2PROM、24C01、24C02、实时时钟电路PCF8563、键盘接口电路ZLG7290等,这些器件具有一些共同的特点:

(1)每个器件有一个器件地址(),用来指明自身的器件标识。最低位()表明器件的读写性质。=1表明读操作,=0表明写操作。也可以说每个器件有两个地址。即读地址(SLA+R)和写地址(SLA+)。

(2)器件内部有1个8位内部单元地址寄存器(ADDRIN),用来指示将要访问的内部单元(下面的讨论以1个为例)。如果内部单元数大于256个时,需要2个8位内部单元寄存器。在读写过程中,内部单元寄存器(ADDRIN)自动加1,可以连续进行相邻单元的读写。

(3)在读写数据之前,要先寻址器件地址(SLA+R/)并明确(R/)是读还是写。再寻址器件内部单元地址(ADDRIN)、然后进行连续的数据(DATA)读写。

3 TWI的控制寄存器TWCR及工作模式和工作时序

TWI可以工作于4种不同的模式,即主机发送模式(MT)、主机接收模式(MR)、从机发送模式(ST)和从机接收器模式(SR)。即使同一应用也可以使用几种不同模式。在实际使用过程中,绝大多数单片机系统中只有一个CPU配置几个I2C总线器件。主要使用主机发送(MT)和主机接收(MR)模式。

TWI接口是面向字节和基于中断的。所有的总线事件(例如接收到一个字节或发送一个START信号等),都会使TWINT标志位置位并产生TWI中断。此时,TWI状态寄存器(TWSR)包含了前一个总线操作的状态码。中断程序可通过读取(TWSR)的状态码,并根据自己的进程决定下一步操作。典型的主机字节发送的工作时序如图2所示,主机字节接收的工作时序如图3所示,控制寄存器TWCR各位含义如图4所示,关键是在实际读写的读写过程中必须首先用主发送发出器件地址和内部单元的地址。因此,我们确定实际器件的完整读写过程如图5所示。

当需要发送START信号、STOP信号、接收应答ACK及非应答NACK信号时,用设置TWCR寄存器的相应的位即可完成(见图4)。而送出器件地址(SLA+R/)、内部单元地址(ADDRIN)、传送数据(DATA)等8位数据时,将其直接送到TWDR寄存器即可。对于TWI模块而言,送到TWDR中的都是数据。

通过分析I2C总线器件的读写特点,仔细观察TWI总线的时序要求,考虑到我们必须用统一的中断程序完成器件的访问,包括数据的发送和接收。我们分析无论对器件的读、还是写。都必须首先寻址器件地址SLA+,其次是寻址器件内部单元的地址ADDRIN,然后是重启动,下一步如果是读则发出SLA+R,如果是写则发出SLA+。

在连续的接收过程中,我们必须在收到数据的同时反馈ACK信号,并将收到的数据保存到数组中,如果接收最后一个数据时,应该反馈NACK信号,然后送出STOP信号,关闭中断允许,结束本次传送。

在连续的发送过程中,我们必须按照顺序从发送数组中送出数据,并收到对方的ACK信号。当数据送完之后,再送出STOP信号,关闭中断允许,结束本次传送。

最终我们确定图5 的操作时序。图5中的小圆圈上面的箭头表明已完成上一操作并进入中断的时刻,小圆圈内部的数值为返回的状态码。这就意味着图5中每得到一个状态码就应该做出相应的操作。分析图5 可以看到无论读写,前面的几个操作都是主发送过程。过程反馈的状态码也基本相同。后面的过程根据用途的不同,进入连续单元的读或写过程。每个过程的操作和返回的状态码也不同。为了利用同一个中断程序完成器件全部的读写过程,我们需要把主发送模式(MT)和主接收模式(MR)结合起来考虑。根据进程的不同,我们将进程分为四种状态,用OPSTEP变量来表示。最终形成图6的方框图。主程序只需要初始化变量,发出START信号即可。中断程序会自动完成整个传送,返回表示操作成功与否的RDWROK信号,最后关闭中断结束本次操作。

下面是需要设置的变量:

①datarry[]数组,作为数据缓冲区,发送和接收都用同一个数组。

②SLA变量,指出从器件的地址,以区别不同的I2C器件。

③R/位变量,指出本次操作是读还是写,R/=1读,R/=0写。放在器件地址的最低位。

④ADDRIN变量,保存将要访问的器件内部单元的地址。

⑤RDWROK变量,指示本次操作的成功与否,RDWROK=0成功,RDWROK=-1失败。

⑥MAX变量,指示本次访问的数据个数。

⑦count变量,表示发送或接收过程中的计数值。

⑧OPSTEP变量,为了区分本次操作的进程,设定一个进程变量。

本文为全文原貌 未安装PDF浏览器用户请先下载安装 原版全文

4 TWI的编程实例

下面是用CodeVisionAVRC写出完全可以实用的中断服务程序,说明如何在实际应用中对TWI进行编程。本程序的主要功能是向I2C器件写入数据和命令。如果该命令是主发送,则中断程序会将数组中的全部数据送出。如果是主接收,则中断程序会接收全部需要的数据到数组中。

若错误则返回I2C_rdwrok=-1;

若正确则返回I2C_rdwrok=0。

CodeVisionAVRC具有自动生成程序框架功能,本例程忽略了主程序细节,主要展示中断程序框架。

中断程序:

interrupt[TWI]voidtwi_isr(void)

{

unsignedcharI2C_STATE;//状态值变量

I2C_STATE=TWSR&0XF8;//返回状态值

I2C_rdwrok=-1;//开始设置为不成功

switch(I2C_opstep)//进程决定的操作

{

case0://发送器件和内部地址进程

{

if(I2C_STATE==0x08)//START成功发送

{TWDR=I2C_sla;//送出SLA+

TWCR=(1

elseif(I2C_STATE==0x18)//器件写地址成功发送

{TWDR=I2C_addrin;//写内部寄存器地址I2C_addrin

TWCR=(1

elseif(I2C_STATE==0x28)//器件内部单元发送成功

{TWCR=(1

//发送重启动信号

elseif(I2C_STATE==0x10)//其启动发送成功

{TWDR=I2C_sla|I2C_RD_WR;

TWCR=(1

I2C_opstep=1;}//根据主程序设置送出SLA+R或SLA+

else

{TWCR=(1

break;

}

case1://发送或接收预处理状态

{

if(I2C_STATE==0x18)//说明上一步发出的是SLA+

{I2C_count=0;

TWDR=I2C_datarry[I2C_count++];//发送第一个数据

TWCR=(1

I2C_opstep=3;}//下一步进入连续发送的状态

elseif(I2C_STATE==0x40)//说明上一步发出的是SLA+R

{TWCR=(1

I2C_count=0;

I2C_opstep=2;}//下一步进入连续接收的状态

else

{TWCR=(1

break;

}

case2://连续接收状态

{

if(I2C_STATE==0x50)

{I2C_datarry[I2C_count++]=TWDR;//保存收到的数据

if(I2C_count

TWCR=(1

Else//继续等待接收数据,送出ACK信号

TWCR=(1

}//接收最后一个字节,CPU将发送NACK

elseif(I2C_STATE==0x58)

{I2C_datarry[I2C_count++]=TWDR;

TWCR=(1

I2C_rdwrok=0;}//收到最后字节关闭中断,结束本次传送

else

{TWCR=(1

break;

}

case3://连续发送状态

{

if(I2C_STATE==0x28)

{

if(I2C_count

{TWDR=I2C_datarry[I2C_count++];//发送下一个字节

TWCR=(1

else

{TWCR=(1

I2C_rdwrok=0;}//数组发送完毕,结束本次传送

}

else

{TWCR=(1

break;

}

default:

{TWCR=(1

}

}//中断程序结束

voidmain(void)主程序

{

初始化变量、数组、设置工作环境等过程省略

}

5 结语

AVR系列单片机内部有可编程Flash,自带E2PROM,片内SRAM,片上8路10位A/D转换器,SPI串行接口,可编程的串行USART,四通道8/16位PWM,模拟比较器等支持JTAG接口,已成为众多单片机芯片的首选。同时,AVR系列单片机内部集成有TWI接口,弥补了其他型号单片机依靠时序模拟完成I2C芯片工作的缺陷。本文通过对TWI总线的详细介绍,旨在介绍一种对TWI总线进行编程的方法,对TWI的正确使用具有现实的指导意义。

[参考文献]

[1] 张友德编.飞利浦80C51系列单片机与应用技术手册.

北京航空航天大学出版社,1992.8

[2] 周俊杰等译.嵌入式C编程与AtmelAVR(美)RichardBarnett

北京:清华大学出版社,2003.9.

[3] ATmega16单片机中文手册ATMEL.

[4] CodeVisionAVRV1.25.3UserManualRevision

HPInfoTechS.R.L.2007.1.

[5] 郭祥军.AVR单片机的TWI总线的原理及应用.桂林电子科技大学,单片机与嵌入式系统应用,2006(8).

本文为全文原貌 未安装PDF浏览器用户请先下载安装 原版全文

上一篇:锁相环中电荷泵的研究 下一篇:基于二元矩阵的启发式属性约简算法