twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx

上传人:b****6 文档编号:5095948 上传时间:2022-12-13 格式:DOCX 页数:18 大小:24.56KB
下载 相关 举报
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx_第1页
第1页 / 共18页
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx_第2页
第2页 / 共18页
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx_第3页
第3页 / 共18页
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx_第4页
第4页 / 共18页
twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx

《twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx》由会员分享,可在线阅读,更多相关《twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx(18页珍藏版)》请在冰豆网上搜索。

twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word.docx

twimain基于avr系列单片机实现i2c通信搞i2c通信的用得上27页word

****AVRTWI读写读写范例***

****作者:

HJJourAVR***

****编译器:

WINAVR20050214***

****OurAVR2005.10.18***

本程序简单的示范了如何使用ATMEGA16的TWI读写AT24C02IICEEPROM

TWI协议

(即IIC协议,请认真参考IIC协议的内容,否则根本就不能掌握)

一主多从的应用,M16作主机

(M16做从机和多主多从的应用不多,请自行参考相关文档)

中断模式

(因为AVR的速度很高,而IIC的速度相对较低,

采用查询模式会长时间独占CPU,令CPU的利用率明显下降。

特别是IIC速度受环境影响只能低速通讯时,对系统的实时性产生严重的影响。

查询模式可以参考其它文档和软件模拟IIC的文档)

AT24C02/04/08的操作特点

出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAGICE硬件仿真器

/**********************ATEEPROM读写过程*********************************

字节写:

Start→器件地址&W→应答→选ROM地址→应答→写数据→应答→Stop

中断过程START→MT_SLA_ACK→MT_DATA_ACK(地址)→MT_DATA_ACK(数据)(STOP中止)

页面写:

Start→器件地址&W→应答→选ROM地址→应答→写数据→应答→写NEXT地址数据→应答→。

写NEXT地址数据→应答→Stop

中断过程START→MT_SLA_ACK→MT_DATA_ACK(地址)→MT_DATA_ACK(数据)→MT_DATA_ACK(数据)→。

MT_DATA_ACK(数据)(STOP中止)

字节读:

Start→器件地址&W→应答→选ROM地址→应答→Restart→器件地址&R→应答→读数据→无应答→Stop

中断过程START→MT_SLA_ACK→MT_DATA_ACK(地址)→RE_START→MR_SLA_ACK→MR_DATA_NOACK(STOP中止)

页面读:

Start→器件地址&W→应答→选ROM地址→应答→Restart→器件地址&R→应答→读数据→应答→读NEXT地址数据→应答→。

读NEXT地址数据→无应答→Stop

中断过程START→MT_SLA_ACK→MT_DATA_ACK(地址)→RE_START→MR_SLA_ACK→MR_DATA_ACK→MR_DATA_ACK→。

MR_DATA_NOACK(STOP中止)

#include

#include

#include

#include

//时钟定为外部晶振7.3728MHz,F_CPU=7372800

#include

//定义了各种模式下的状态码列表(TWSR已屏蔽预分频位),本文后面附上中文描述

//管脚定义

#definepinSCL0//PC0SCL

#definepinSDA1//PC1SDA

//为保险起见,最好在SCL/SDA接上1~10K的外部上拉电阻到VCC。

#definefSCL100000//TWI时钟为100KHz

//预分频系数=1(TWPS=0)

#ifF_CPU

#defineTWBR_SET10;//TWBR必须大于等于10

#else

#defineTWBR_SET(F_CPU/fSCL-16)/2;//计算TWBR值

#endif

#defineTW_ACT(1<

//TWCR只能IN/OUT,直接赋值比逻辑运算(|=&=)更节省空间

#defineSLA_24CXX0xA0//24Cxx系列的厂商器件地址(高四位)

#defineADDR_24C020x00

//AT24C02的地址线A2/1/0全部接地,SLAW=0xA0+0x00<<1+0x00,SLAR=0xA0+0x00<<1+0x01

//TWI_操作状态

#defineTW_BUSY0

#defineTW_OK1

#defineTW_FAIL2

//TWI_读写命令状态

#defineOP_BUSY0

#defineOP_RUN1

//TWI读写操作公共步骤

#defineST_FAIL0//出错状态

#defineST_START1//START状态检查

#defineST_SLAW2//SLAW状态检查

#defineST_WADDR3//ADDR状态检查

//TWI读操作步骤

#defineST_RESTART4//RESTART状态检查

#defineST_SLAR5//SLAR状态检查

#defineST_RDATA6//读取数据状态检查,循环n字节

//TWI写操作步骤

#defineST_WDATA7//写数据状态检查,循环n字节

#defineFAIL_MAX20//重试次数最大值

//定义全局变量

unsignedcharORGDATA[8]=

{0xAA,0xA5,0x55,0x5A,0x01,0x02,0x03,0x04};//原始数据

unsignedcharCMPDATA[8];//比较数据

unsignedcharBUFFER[256];//缓冲区,可以装载整个AC24C02的数据

structstr_TWI//TWI数据结构

volatileunsignedcharSTATUS;//TWI_操作状态

unsignedcharSLA;//从设备的器件地址

unsignedintADDR;//从设备的数据地址

unsignedchar*pBUF;//数据缓冲区指针

unsignedintDATALEN;//数据长度

unsignedcharSTATE;//TWI读写操作步骤

unsignedcharFAILCNT;//失败重试次数

structstr_TWIstrTWI;//TWI的数据结构变量

//仿真时在watch窗口,监控这些全局变量。

//AT24C02的读写函数(包括随机读,连续读,字节写,页写)

//根据sla的最低位决定(由中断程序中判断)

//bit0=1TW_READ读

//bit0=0TW_WRITE写

//sla器件地址(不能搞错)

//addrEEPROM地址(0~1023)

//*ptr读写数据缓冲区

//len读数据长度(1~1024),写数据长度(1or8or16)

//返回值是否能执行当前操作

unsignedcharTWI_RW(unsignedcharsla,unsignedintaddr,unsignedchar*ptr,unsignedintlen)

unsignedchari;

if(strTWI.STATUS==TW_BUSY)

{//TWI忙,不能进行操作

returnOP_BUSY;

strTWI.STATUS=TW_BUSY;

i=(addr>>8)<<1;

i&=0x06;//考虑了24C04/08的EEPROM地址高位放在SLA里面

strTWI.SLA=sla+i;

strTWI.ADDR=addr;

strTWI.pBUF=ptr;

strTWI.DATALEN=len;

strTWI.STATE=ST_START;

strTWI.FAILCNT=0;

TWCR=(1<

returnOP_RUN;

TWI中断函数

这个函数流程只是考虑了器件地址后有一个字节数据(命令)地址的IIC器件

(大部分IIC接口器件都是这种类型,常见的例如AT24C01/02/04/08/16,DS1307,DS1721等)

对于有两个字节数据地址的IIC器件(例如AT24C32/64/128/256等大容量EEPROM),请稍作改动

//根据strTWI.SLA的最低位决定

//bit0=1TW_READ读

//bit0=0TW_WRITE写

虽然中断服务程序很长,但每次只执行一个case,所以耗时并不长。

SIGNAL(SIG_2WIRE_SERIAL)

{//IIC中断

unsignedcharaction,state,status;

action=strTWI.SLA&TW_READ;//取操作模式

state=strTWI.STATE;

status=TWSR&0xF8;//屏蔽预分频位

if((status>=0x60)||(status==0x00))

{//总线错误或从机模式引发的中断,不予处理

return;

switch(state)

caseST_START:

//START状态检查

if(status==TW_START)

{//发送start信号成功

TWDR=strTWI.SLA&0xFE;//发送器件地址写SLAW

TWCR=TW_ACT;//触发下一步动作,同时清start发送标志

else

{//发送start信号出错

state=ST_FAIL;

break;

caseST_SLAW:

//SLAW状态检查

if(status==TW_MT_SLA_ACK)

{//发送器件地址成功

TWDR=strTWI.ADDR;//发送eeprom地址

TWCR=TW_ACT;//触发下一步动作

else

{//发送器件地址出错

state=ST_FAIL;

break;

caseST_WADDR:

//ADDR状态检查

if(status==TW_MT_DATA_ACK)

{//发送eeprom地址成功

if(action==TW_READ)

{//读操作模式

TWCR=(1<

else

{//写操作模式

TWDR=*strTWI.pBUF++;//写第一个字节

strTWI.DATALEN--;

state=ST_WDATA-1;//下一步将跳到WDATA分支

TWCR=TW_ACT;//触发下一步动作

else

{//发送eeprom地址出错

state=ST_FAIL;

break;

caseST_RESTART:

//RESTART状态检查,只有读操作模式才能跳到这里

if(status==TW_REP_START)

{//发送restart信号成功

TWDR=strTWI.SLA;//发器件地址读SLAR

TWCR=TW_ACT;//触发下一步动作,同时清start发送标志

else

{//重发start信号出错

state=ST_FAIL;

break;

caseST_SLAR:

//SLAR状态检查,只有读操作模式才能跳到这里

if(status==TW_MR_SLA_ACK)

{//发送器件地址成功

if(strTWI.DATALEN--)

{//多个数据

TWCR=(1<

else

{//只有一个数据

TWCR=TW_ACT;//设定NAK,触发下一步动作

else

{//发送器件地址出错

state=ST_FAIL;

break;

caseST_RDATA:

//读取数据状态检查,只有读操作模式才能跳到这里

state--;//循环,直到读完指定长度数据

if(status==TW_MR_DATA_ACK)

{//读取数据成功,但不是最后一个数据

*strTWI.pBUF++=TWDR;

if(strTWI.DATALEN--)

{//还有多个数据

TWCR=(1<

else

{//准备读最后一个数据

TWCR=TW_ACT;//设定NAK,触发下一步动作

elseif(status==TW_MR_DATA_NACK)

{//已经读完最后一个数据

*strTWI.pBUF++=TWDR;

TWCR=(1<

strTWI.STATUS=TW_OK;

else

{//读取数据出错

state=ST_FAIL;

break;

caseST_WDATA:

//写数据状态检查,只有写操作模式才能跳到这里

state--;//循环,直到写完指定长度数据

if(status==TW_MT_DATA_ACK)

{//写数据成功

if(strTWI.DATALEN)

{//还要写

TWDR=*strTWI.pBUF++;

strTWI.DATALEN--;

TWCR=TW_ACT;//触发下一步动作

else

{//写够了

TWCR=(1<

strTWI.STATUS=TW_OK;

//启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来

//编程期间器件不响应任何命令

else

{//写数据失败

state=ST_FAIL;

break;

default:

//错误状态

state=ST_FAIL;

break;

if(state==ST_FAIL)

{//错误处理

strTWI.FAILCNT++;

if(strTWI.FAILCNT

{//重试次数未超出最大值,

TWCR=(1<

else

{//否则停止

TWCR=(1<

strTWI.STATUS=TW_FAIL;

state++;

strTWI.STATE=state;//保存状态

intmain(void)

unsignedchari;

//上电默认DDRx=0x00,PORTx=0x00输入,无上拉电阻

PORTA=0xFF;//不用的管脚使能内部上拉电阻。

PORTB=0xFF;

PORTC=0xFF;//SCL,SDA使能了内部的10K上拉电阻

PORTD=0xFF;

//TWI初始化

TWSR=0x00;//预分频=0^4=1

TWBR=TWBR_SET;

TWAR=0x00;//主机模式,该地址无效

TWCR=0x00;//关闭TWI模块

sei();//使能全局中断

strTWI.STATUS=TW_OK;

TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_WRITE,0x10,&ORGDATA[0],8);

//从0x10地址开始写入8个字节数据

while(strTWI.STATUS==TW_BUSY);//等待操作完成

if(strTWI.STATUS==TW_FAIL)

//操作失败?

_delay_ms(10);//延时等待编程完成

while

(1)

i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x10,&CMPDATA[0],8);

//从0x10地址开始读出8个字节数据

while(strTWI.STATUS==TW_BUSY);//等待操作完成

//如果不加等待,则需要检测返回值i才能知道当前操作是否执行了

//0OP_BUSY之前的操作没完成,没执行当前操作

//1OP_RUN当前操作执行中

if(strTWI.STATUS==TW_FAIL)

//操作失败?

//读取成功,对比ORGDATA和CMPDATA的数据

i=TWI_RW(SLA_24CXX+(ADDR_24C02<<1)+TW_READ,0x00,&BUFFER[0],256);

//从0x00地址开始读出256个字节数据(整个ATC24C02)

while(strTWI.STATUS==TW_BUSY);//等待操作完成

两线串行接口总线定义

两线接口TWI很适合于典型的处理器应用。

TWI协议允许系统设计者只用两根双向传输线就可以将128个不同的设备互连到一起。

这两根线一是时钟SCL,一是数据SDA。

外部硬件只需要两个上拉电阻,每根线上一个。

所有连接到总线上的设备都(必须)有自己的地址。

注意:

就是说不能有两个相同地址的设备

TWI协议解决了总线仲裁的问题。

所有TWI兼容的器件的总线驱动都是漏极开路或集电极开路的。

这样就实现了对接口操作非常关键的线与功能。

TWI器件输出为"0”时,TWI总线会产生低电平。

当所有的TWI器件输出为三态时,总线会输出高电平,允许上拉电阻将电压拉高。

注意:

为保证所有的总线操作,凡是与TWI总线连接的AVR器件必须上电。

与总线连接的器件数目受如下条件限制:

总线电容要低于400pF,而且可以用7位从机地址进行寻址。

两个不同的规范,一种是总线速度低于100kHz,而另外一种是总线速度高达400kHz。

SCL和SDA引脚

SCL与SDA为MCU的TWI接口引脚。

引脚的输出驱动器包含一个波形斜率限制器以满足TWI规范。

引脚的输入部分包括尖峰抑制单元以去除小于50ns的毛刺。

当相应的端口设置为SCL与SDA引脚时,可以使能I/O口内部的10K上拉电阻,这样可省掉外部的上拉电阻

注意:

如果要作高速通讯或者从机数量较多,最好还是外接合适的上拉电阻

比特率发生器单元

TWI工作于主机模式时,比特率发生器控制时钟信号SCL的周期。

具体由TWI状态寄存器TWSR的预分频系数以及比特率寄存器TWBR设定。

当TWI工作在从机模式时,不需要对比特率或预分频进行设定,但从机的CPU时钟频率必须大于TWI时钟线SCL频率的16倍。

注意,从机可能会延长SCL低电平的时间,从而降低TWI总线的平均时钟周期。

SCL的频率根据以下的公式产生:

fSCL=fCPU/((16+2(TWBR)(4^TWPS))

TWBR=TWI比特率寄存器的数值

TWPS=TWI状态寄存器预分频的数值

Note:

TWI工作在主机模式时,TWBR值应该不小于10,否则主机会在SDA与SCL产生错误输出作为提示信号。

问题出现于TWI工作在主机模式下,向从机发送Start+SLA+R/W的时候(不需要真的有从机与总线连接)。

控制单元

控制单元监听TWI总线,并根据TWI控制寄存器TWCR的设置作出相应的响应。

当TWI总线上产生需要应用程序干预处理的事件时,TWI中断标志位TWINT置位。

在下一个时钟周期,TWI状态寄存器TWSR被表示这个事件的状态码字所更新。

在其它时间里,TWSR的内容为一个表示无事件发生的特殊状态字。

一旦TWINT标志位置"1”,时钟线SCL即被拉低,暂停TWI总线上的数据传输,让用户程序处理事件。

在下列状况出现时,TWINT标志位置位:

?

在TWI传送完START/REPEATEDSTART信号之后

?

在TWI传送完SLA+R/W数据之后

?

在TWI传送完地址字节之后

?

在TWI总线仲裁失败之后

?

在TWI被主机寻址之后(广播方式或从机地址匹配)

?

在TWI接收到一个数据字节之后

?

作为从机工作时,TWI接收到STOP或REPEATEDSTART信号之后

?

由于非法的START或STOP信号造成总线错误时

TWI寄存器说明

TWI比特率寄存器-TWBR

?

Bits7..0–TWI比特率寄存器

TWBR为比特率发生器分频因子。

比特率发生器是一个分频器,在主机模式下产生SCL时钟频率。

比特率计算公式请见前面的[比特率发生器单元]

TWI控制寄存器-TWCR

TWCR用来控制TWI操作。

它用来使能TWI,通过施加START到总线上来启动主机访问,产生接收器应答,产生STOP状态,以及在写入数据到TWDR寄存器时控制总线的暂停等。

这个寄存器还可以给出在TWDR无法访问期间,试图将数据写入到TWDR而引起的写入冲突信息。

?

Bit7–TWINT:

TWI中断标志

当TWI完成当前工作,希望应用程序介入时TWINT置位。

若SREG的I标志以及TWCR寄存器的TWIE标志也置位,则MCU执行TWI中断例程。

当TWINT置位时,SCL信号的低电平被延长。

TWINT标志的清零必须通过软件写"1”来完成。

执行中断时硬件不会自动将其改写为"0”。

要注意的是,只要这一位被清零,TWI立即开始工作。

因此,在清零TWINT之前一定要首先完成对地址寄存器TWAR,状态寄存器TWSR,以及数据寄存器TWDR的访问。

?

Bit6–TWEA:

使能TWI应答

TWEA标志控制应答脉冲的产生。

若TWEA置位,出现如下条件时接口发出ACK脉冲:

1.器件的从机地址与主机发出的地址相符合

2.TWAR的TWGCE置位时接收到广播呼叫

3.在主机/从机接收模式下接收到一个字节的数据

将TWEA清零可以使器件暂时脱离总线。

置位后器件重新恢复地址识别。

?

Bit5–TWSTA:

TWISTART状态标志

当CPU希望

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 军事

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1