AVR单片机TWI读写过程实例
简要对比TWI总线与I2C总线
简要对比TWI总线与I2C总线摘要在简要对比TWI总线与I2C总线的基础上,详细介绍TWI总线的内部模块、工作时序和工作模式,并给出一个编程实例加以说明.对TWI总线和传统的I2C总线的正确区分及使用具有现实的指导意义。
关键词两线串行总线TWI I2CAVR系列的单片机内部集成了TWI(Two-wire SerialInterface)总线。
该总线具有I2C总线的特点,即接线简单,外部硬件只需两个上拉电阻,使用时钟线SCL和数据线SDA就可以将128个不同的设备互连到一起;而且支持主机和从机操作,器件可以工作于发送器模式或接收器模式,数据传输率高达400 kHz。
正因为TWI总线具有这么多的优点,因此受到了使用者的青睐。
由于该总线与传统的I2C总线极其相似。
因此不少人误以为TWI总线就是I2C总线,其实这只是一种简单化的理解。
TWI总线是对I2C总线的继承和发展。
它定义了自已的功能模块和寄存器,寄存器各位功能的定义与I2C总线并不相同;而且TWI总线引入了状奁寄存器,使得TWI总线在操作和使用上比I2C总线更为灵活。
在实际应用上,由于大部分单片机内部没有集成I2C总线,因此单片机的控制是通过模拟I2C总线的时序来完成其操作的。
AVR系列的单片机内部集成了TWI总线,而且其用法也比I2C更为灵活。
本文结合一个实例对TWI总线的内部模块、工作时序和工作模式进行了详细介绍,目的在于正确区分TWI 总线和传统的I2C总线,对如何正确使用TWI总线编程也具有现实的指导意义。
1 TWI内部模块TWI内部由总线接口单元、比特率发生器、地址匹配单元和控制单元等几个子模块组成,如罔1所示。
图中,SCL、SDA为MCU的TWI接口引脚。
引脚的输出驱动器包含一个波形斜率限制器以满足TWI规范;引脚的输入部分包含尖峰抑制单元,以去除小于50ns的毛刺。
总线接口单元包括数据与地址寄存器TWDR、START/STOP控制器和总线仲裁判定硬件电路。
09-IIC_TWI实验
第9章TWI|IIC注:HJ-2G V3.0版没有集成24C02芯片,如果需要做本实验的同学,请自己购一片24C02芯片,用杜邦线接到开发板上的IO口就可以了。
9.1概述TWI或者IIC是两线的总线。
这原本是前几章的笔记,但是一开始因为觉得IIC太复杂了所以延迟到最后在练习。
其实不是这样的,AVR的IIC硬件,从手册上看是很复杂。
但是只要慢慢的分类再分类就觉得很容易了。
当然一开始确实要下一点功夫,但是原理理解了,程式跑起来后。
你就会觉得,IIC很有趣。
这一篇笔记AT24C02A作为我们的主角。
9.2IIC总线概念IIC的总线是由SDA(串行数据)和SCL(串行时钟)组成,有从机和主机之分。
总线空闲时为高电平,所以SDA和SCL都必须使用上拉电阻将电平拉上高电平。
IIC总线又有起始信号(START),终止信号(STOP),重复起始信号(REPEAT START)。
起始信号:SCL持续高电平的时候,SDA从高电平变成低电平。
终止信号:SCL持续高电平的时候,SDA从低电平变成高电平。
重复起始信号:这个比较难明白,在访问一个设备为了改变访问方向而不写入终止信号,第二次的起始信号称为重复起始信号9.2IIC总线仲裁(寻址)当主机要寻找从机时,会发送寻址,我习惯称为硬件地址。
该地址包如下:最高七位为从机地址,而最低位为硬件地址的行为。
最低位逻辑1为读从机设备,逻辑0为写从机设备。
不同的从机设备都有不同的硬件地址,硬件地址是由硬件厂商设定定的。
如AT24C02A,ATMEL公司的串行EEPROM。
AT24C02A硬件地址的区分HJ-2G的AT24C02A的A0~2编程AT24C02A硬件地址是这样区分的:高四位(BIT4~7)为不可编程,AT24C02A是1010。
低四位(BIT0~3)中的BIT1~3,亦即A0~A2为可编程地址。
HJ-2G将A0~A2引脚连地,所以该AT24C02的硬件地址为1010000x。
ATmega8TWI读写AT24C64
#define TWI_START() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))
#define TWI_RESTART() (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))
#define TWI_STATUS() (TWSR&0xf8)
if(TWI_SendData(addr)!=TW_MT_DATA_ACK) return 0;
if(TWI_ReStart()!=TW_REP_START)return 0;
if(TWI_SendData(TWI_SLA_RW|0X01)!=TW_MR_SLA_ACK) return 0;
uint8 TWI_WriteByte(uint16 addr ,uint8 data);
#else
uint8 TWI_WriteNByte(uint8 TWI_SLA_RW, uint16 addr ,uint8 *pdata, uint8 size);
uint8 TWI_WriteByte(uint8 TWI_SLA_RW, uint16 addr ,uint8 data);
#ifndef __TWI_H__
#define __TWI_H__
#define TWI_SLA_RW 0XA0
#define TWI_CHECK 1
#ifdef __TWI_C__
void twi_init(void);
#ifdef TWI_SLA_RW
uint8 TWI_WriteNByte(uint16 addr,uint8 *pdata, uint8 size);
利用Code Vision AVR C中断程序实现AVR单片机的TWI读写
利用Code Vision AVR C中断程序实现AVR单片机的TWI读写在AVR单片机的开发过程中,TWI(Two-Wire Interface)总线通信协议是较为常用的一种方式。
我们可以利用CodeVision AVR C中断程序来实现AVR单片机的TWI读写。
首先,我们需要了解一下TWI通信协议的基本原理。
TWI总线上有两条线路,一条为SCL时钟线,另一条为SDA数据线。
两条线路上都有上拉电阻,数据传输时由主机(如AVR单片机)控制SCL时钟线和SDA数据线的电平变化来进行数据传输。
在Code Vision AVR C中,我们可以利用TWI库函数进行TWI通信的操作。
在进行TWI读写时,我们需要先发送起始信号,然后发送设备地址和读写指令,接着进行数据传输,最后发送停止信号。
这一系列操作可以使用TWI库函数中的相应函数来完成。
在使用中断程序时,我们需要使TWI模块开启中断功能,并定义好中断服务程序。
在TWI传输过程中,当一个操作完成后,TWI模块会触发中断,执行相应的中断服务程序。
在中断服务程序中,我们可以处理TWI传输过程中出现的各种情况,如传输完成、传输错误等。
下面以TWI读取一个EEPROM芯片中的数据为例,说明如何利用Code Vision AVR C中断程序实现TWI读写。
假设EEPROM芯片的I2C地址为0xA0,我们需要读取从地址0x00开始的8个字节的数据。
首先,我们需要在程序的头文件中引用Code Vision AVR C提供的TWI库。
#include <mega328p.h>#include <delay.h>#include <twi.h>接着,定义TWI芯片地址和读写指令。
#define EEPROM_WRITE 0xA0#define EEPROM_READ 0xA1定义存储数据的缓冲区。
unsigned char EEPROM_Buffer[8];在主函数中初始化TWI模块,并开启TWI中断。
用AVR单片机IO口模拟I2C总线操作AT24CXX的通用程序
*c=ret;
return(ret);
}
以下为AT24CXX的操作函数实现:
at24cxx.h:
//AT24CXX.H
#ifndef AT24CXX_H
#define AT24CXX-H
void At24cxxWaitBusy(void);
#include <util/delay.h>
#include <stdint.h>
/*注:
AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻
这样可通过改变I/O口输入输出方向的方式来设置高低
输出口保持不变(0)
此时如DDRX寄存器为1则变成输出0
若DDRX为0,则I/O口程高阻,但因外部的上拉电阻,总线相当于设置高
#define TW_READ 1
#define TW_ACK 1
#define TW_NOACK 0
Hale Waihona Puke /*以下两个宏控制AT24CXX的WP引脚,如未连接可定义为空:
#define EEPROM_WRITE_ENABLE
#define EEPROM_WRITE_DISABLE
AT24CXX中WP引脚接地时写允许,接电源(高)时写保护,
如不接,器件内部有接地电阻,即写允许. */
//在CA-M8X板上该引脚通过S7(3)连接MEGA8的PC3
#define EEPROM_WRITE_ENABLE PORTC&=~_BV(PC3),DDRC|=_BV(PC3)
void At24cxxConfig(uint8_t device_addr,uint8_t page_size);
AVR TWI程序
// return values
#define I2C_OK 0x00
#define I2C_ERROR_NODEV 0x01
AVR TWI程序
i2c.h
/****************************************************************************
Title : C include file
Software: AVR-GCC with AVR-AS
#define I2C_SEND_DATA_BUFFER_SIZE 0x10
#define I2C_RECEIVE_DATA_BUFFER_SIZE 0x10
//#define F_CPU 8000000
#define TRUE 1
#define FALSE 0
/*######################################################################################################*/
i2c.c
/****************************************************************************
}
inline void i2cReceiveByte(unsigned char ackFlag)
{
//开始通过 i2c 接收
if( ackFlag ){
// ackFlag = TRUE: 数据接收后回应ACK
TWCR = (TWCR&TWCR_CMD_MASK)|(1<<TWINT)|(1<<TWEA);
IAR For AVR 两线串行接口 TWI 应用
发送:1,设定数据传输波特率2,发送START信号,等待应答==》《== 应答信号3,发送芯片地址,等待应答==》《==应答信号4,发送数据的绝对地址,等待应答==》《==应答信号5,发送要写入的数据,等待应答==》《==应答信号6,发送STOP信号,释放总线==》数据写入成功接收:1,设定数据传输波特率2,发送START信号,等待应答==》《== 应答信号3,发送芯片地址,等待应答==》《==应答信号4,发送数据的绝对地址,等待应答 ==》《==应答信号5,发送RESTART信号,等待应答==》《==应答信号6,发送芯片地址并注明读操作,等待应答==》《==应答信号7,读取数据,等待应答==》《==应答信号8,发送STOP信号,释放总线==》数据读操作成功#include <iom16.h>#define uchar unsigned char#define uint unsigned int//########################################################### /*串口初始化函数*/void Uart_Init(void){UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);//允许发送和接收UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);//8位数据位+1位停止位UBRRH=0x00;//设置波特率寄存器低位字节UBRRL=47;//9600//设置波特率寄存器高位字节DDRD_Bit1=1;//配置TX为输出(很重要)}//########################################################### /*发送一个字符数据,查询方式*/void Uart_Transmit(uchar data){while(!(UCSRA&(1<<UDRE)));//while(UCSRA_UDRE==0); /* 等待发送缓冲器为空*/UDR = data; /* 发送数据*/}@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#include <iom16.h>#include "IAR_DELAY.H"#define uchar unsigned char#define uint unsigned intvoid Uart_Init(void);void Uart_Transmit(uchar data);//变量声明#define EEPROM_BUS_ADDRESS 0xA0//器件地址/*从器件地址位定义:______________________________________-------------*//*AT24C02| 1 | 0 | 1 | 0 | A2 | A1 | A0 | R/~W |------------*///主机发送模式时各状态字的后续动作#define TW_START 0x08 //开始信号已发出#define TW_REP_START 0x10 //重复开始信号已发出#define TW_MT_SLA_ACK 0x18 //写字节已发出并受到ACK信号#define TW_MT_SLA_NACK 0x20 //写字节已发出并受到NACK信号#define TW_MT_DATA_ACK 0x28 //数据已发出并受到ACK 信号#define TW_MT_DATA_NACK 0x30 //数据已发出并受到NACK 信号#define TW_MT_ARB_LOST 0x38 //丢失总线控制权//主机接收模式时各状态字的后续动作#define TW_MR_ARB_LOST 0x38//丢失总线控制权,未收到应答信号#define TW_MR_SLA_ACK 0x40//读命令已发出并受到ACK#define TW_MR_SLA_NACK 0x48 //读命令已发出并受到NACK#define TW_MR_DATA_ACK 0x50 //数据已收到,ACK已发出#define TW_MR_DATA_NACK 0x58 //数据已收到,NACK已发出#define IIC_Start() TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)// TWINT位通过写1进行清零,一旦清零则TWI开始工作,当相应硬件工作完成后 TWINT位会重新置位为1//TWSTA位会让硬件在总线上产生一个START的信号,声明自己希望成为主机//TWEN位使能TWI功能,将PC0和PC1管脚切换到第二功能上来,如果清零则为中断TWI的传输#define IIC_Stop() TWCR =(1<<TWINT)|(1<<TWSTO)|(1<<TWEN) // TWSTO位在主机模式下,会让硬件在总线上产生一个STOP得信号,并且SCL和SDA两个引脚位高阻态#define IIC_Wait() while(!(TWCR&(1<<TWINT))) // TWINT位经过一次置位使硬件TWI开始工作,然后再检测TWCR寄存器的TWINT位是不是被置位,如果置位为1则表示工作完成可以向下进行//################################################################### ###########/*I2C总线单字节写入*/unsigned char twi_write(unsigned char addr, unsigned char dd){TWBR =10;//设定波特率/*start 启动*/IIC_Start();//硬件发送START信号,并且清零TWINT位,使能硬件TWI,使TWI 开始工作IIC_Wait();//等待发送START完成 TWINT位置位if((TWSR&0xF8)!=0x08) return 0;//检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0/*SLA_W 芯片地址*/TWDR=EEPROM_BUS_ADDRESS;//芯片地址0xA0,赋值给数据寄存器TWDR,等待发送TWCR=(1<<TWINT)|(1<<TWEN);//对控制寄存器TWCR的TWINT位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕TWINT重新置位if((TWSR&0xF8)!=0x18) return 0;//检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0/*addr 操作地址*/TWDR=addr;//将写入数据的绝对地址,赋值给数据寄存器TWDR,等待发送TWCR=(1<<TWINT)|(1<<TWEN);//对控制寄存器TWCR的TWINT位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕TWINT重新置位if((TWSR&0xF8)!=0x28) return 0;//检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回0/*dd 写入数据*/TWDR=dd;//将要写入的数据,赋值给数据寄存器 TWDR,等待发送TWCR=(1<<TWINT)|(1<<TWEN);//对控制寄存器TWCR的TWINT位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕 TWINT重新置位if ((TWSR & 0xF8) != 0x28) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0/*stop 停止*/IIC_Stop();//数据传输完成,发送STOP信号,释放对总线的控制return 1;//写入数据成功,返回1 ,用来判断是否成功写入数据}//################################################################### /*I2C总线单字节读取*/unsigned char twi_read(unsigned char addr){unsigned char Receive_Byte;TWBR=2;//设定波特率/*start 启动*/IIC_Start(); //硬件发送START信号,并且清零TWINT位,使能硬件TWI,使TWI开始工作IIC_Wait(); //等待发送START完成 TWINT位置位if ((TWSR & 0xF8) != 0x08) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0/*SLA_W 芯片地址*/TWDR = EEPROM_BUS_ADDRESS; //芯片地址 0xA0 ,赋值给数据寄存器 TWDR ,等待发送TWCR=(1<<TWINT)|(1<<TWEN); //对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送 TWDR寄存器中的数据IIC_Wait(); //等待数据发送完毕 TWINT重新置位if ((TWSR & 0xF8) != 0x18) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回 0/*addr 操作地址*/TWDR=addr;//将写入数据的绝对地址,赋值给数据寄存器 TWDR ,等待发送TWCR=(1<<TWINT)|(1<<TWEN);//对控制寄存器TWCR的 TWINT 位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送 TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕 TWINT重新置位if ((TWSR & 0xF8) != 0x28) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回0/*restart 重启动*/IIC_Start();//硬件发送 RESTART 信号,并且清零TWINT位,使能硬件TWI,使TWI开始工作IIC_Wait();//等待数据发送完毕 TWINT重新置位if((TWSR&0xF8)!=0x10) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回0/*SLA_R 芯片地址*/TWDR = 0xA1; //芯片地址 0xA0 并注明是读取操作(最后一位为1),赋值给数据寄存器 TWDR ,等待发送TWCR=(1<<TWINT)|(1<< TWEN);//对控制寄存器TWCR的TWINT位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕TWINT重新置位if((TWSR&0xF8)!=0x40) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回0/*读取数据*/TWCR=(1<<TWINT)|(1<<TWEN);//对控制寄存器TWCR的TWINT位软件写1进行清零,然后使能TWI硬件接口,让TWI进行工作,发送TWDR寄存器中的数据IIC_Wait();//等待数据发送完毕TWINT重新置位if((TWSR&0xF8)!=0x58) return 0; //检测到TWINT位置位,比对TWSR寄存器内的状态量,如果正确则向下进行数据传输,错误返回0Receive_Byte = TWDR; //读取到的数据放到局部变量里/*stop 停止*/IIC_Stop();//数据传输完成,发送STOP信号,释放对总线的控制return Receive_Byte; //将读取到的数据作为函数的输出}//################################################################### /*主函数*/void main(void){uchar c,d;Uart_Init();//串口初始化delay_us(20);Uart_Transmit(0x55); //测试串口c = twi_write(0x51,0xf8); //在地址0x51里写入数据0x22Uart_Transmit(c); //将返回值发送到串口测试是否写入成功delay_ms(2);d = twi_read(0x51); //将地址0x51里的数据读出来Uart_Transmit(d); //将读取到的数据发送串口while(1);}。
AVR TWI总线学习笔记
AVR TWIATMEL公司的AVR芯片上的TWI总线兼容I2C总线。
如何利用该硬件功能读写I2C设备网上的资料不多,而且很多很难得懂。
因此我查阅了ATMEL公司的技术文档,在学习的过程中,写下这篇笔记。
TWI接口是两线制的串口,与I2C接口一样,2线的名称都是SDA(串行数据地址线)和SCL(串行时钟线)。
在与设备相连时,2线都需要有上拉电阻相连。
如果设备输出为高阻时,上拉电阻10K将电平拉高。
一、地址包格式所有在TWI总线上传送的地址包均为9位,包括7位地址位,1个R/W控制位和1个应答位,如果R/W为1,则执行读操作。
如果R/W为0,则执行写操作。
从机被寻址后,必须在第9个SCL(ACK)周期通过拉低SDA做出应答,若从机忙或者无法响应主机,则应该在ACK周期保持SDA为高。
然后主机可以发出STOP状态或者REP START状态重新开始发送。
地址包包括从机地址和称为SLA+R或者SLA+W的READ或者WRITE位。
地址字节的MSB首先被发送。
所有1111xxxx的地址均保留,以便将来使用。
二、数据包格式所有在TWI总线上传送的数据包均为9位,包括8个数据位和一个应答位。
在数据传送中,主机产生时钟及START与STOP状态,而接收器响应接收。
应答是ACK在第9个SCL周期拉低SDA实现的。
如果接收器使SDA为高,则发送NACK信号。
如果接收器由于某种原因不能接受更多数据,应在最后一个数据字节后发出NACK信号告诉发送器停止发送。
数据的MSB首先发送。
三、地址包和数据包组合成一个完整的传输过程发送主要由START状态,SLA+R/W,至少一个数据包和STOP状态组成。
只有START与STOP状态的空信息是非法的。
四、比特率发生单元TWI工作于主机模式时,比特率发生器控制时钟信号SCL的周期。
具体数值由TWI状态寄存器TWSR的预分频系数以及比特率寄存器TWBR设定。
当TWI工作在从机模式时,不需要对比特率或者预分频系数进行设定,但从机CPU时钟频率必须大于TWI时钟线SCL频率的16倍。
AVR单片机的TWI总线的原理及应用
5结论
AVR系列单片机内部有可编程Flash,自带EEPROM,支持JTAG接口
片内调试和对Flash、EEPROM、熔丝位和锁定位的编程,因此成为众多单片
机芯片的首选。同时,AVR系列单片机内部集成有TWI接口,弥补了其他型
号单片机依靠时序模拟完成I2C芯片工作的缺陷。本文通过对TWI总线的详细
发送START信呼;紧接着的地址包格式决定是进入MT或MR模式。如果发
送SLA+W,则进入MT模式;如果发送SLA+R,则进入MR模式。主机发送
模式的格式和状态如4 TWI的编程实例
下面将通过一个具体的实例来说明如何在实际应用中对TWl进行编程。
本程序的主要功能是向PCA9554中写入数据,若错误则返回一1;否则返回
模式从EEPROM读取数据。如果系统中有其他主机存在,则它们可能给TWI
发送数据,此时可以用SR模式。由应用程序决定采用何种模式。由于在实际
使用过程中,多使用主机发送模式,所以只对主机发送模式作详细介绍,其它
模式下格式和状态可以依此类推。
在主机发送模式下,主机向从机发送数据。为了进入主机模式,必须先
介绍,旨在介绍一种对TWI总线进行编程的方法,对ips:感谢大家的阅读,本文由我司收集整编。仅供参阅!
决定应用程序是否响应TWINT标志位产生的中断请求。如果TWIE被清零,
则应用程序只能采用轮询TWINT标志位的方法来检测TWI总线状态;如果
TWINT标志位被置位,则表示TWI接口完成了当前的操作,等待应用程序响
应。在这种情况下,TWI状态寄存器TWSR包含了当前TWI总线的状态值。
应用程序可读取TWCR的状态码,判别此时的状态码是否正确,并通过设置
AVR单片机学习九iic总线及TWI模块的使用方法
AVR 单片机学习(九)iic总线及TWI模块的使用方法IIC总线定义与特点I2C总线的工作原理AVR的TWI模块的使用方法AT24C02IIC inter integrated circuit 总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。
例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如:电源和系统风扇,可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
TWI:ATMega系列单片机内集成两线制串行接口模块,ATmegl文档称为TWI接口事实上TWI与PHILIOS的I2C总线是同一回事,之所以叫它TWI是因为这样命名可使ATmel避免交术语版税。
所以,TWI是兼容I2C的一种说法。
I2C总线最只要的优点是其简单性和有效性。
由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
总线的长度可高达25英尺,并且能够以10KPS的最大传输率支持40个组件,I2C总线的另一个优点是,它支持多主控(MULTIMASTERING),其中任何能够进行发送和接受的设备都可以称为主总线,一个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有一个主控。
由于AVR 有上拉电阻所以 R1 R2可以不要。
其实还的共地应该是3根线。
在多主控上有个总线总裁的知识可以参阅相关文档学习。
呵呵、初学者不用了解。
I2C总线是由数据线SDA和时钟线SCL构成的串行总线,可发送和接受数据。
在CPU与被控IC之间、IC与IC之间进行双向传送、最高传送速率100KBPS.各种被控制电路均并联在这条总线上,最高传送速率100KBPS.各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能,CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定调整的类别(如对比度、亮度等)及需要调整的量。
AVR单片机TWI通信接口在广播机微控制器中的应用
A VR 单片机T WI 通信接口在广播机微控制器中的应用马惠锋,韩震宇(四川大学制造科学与工程学院,四川成都610065)摘 要:功能所需,本广播发射机微控制器应用了多片AVR 单片机和片外EEPROM ,单片机之间、单片机与外部EEPROM 之间的通信,采用了两总线串行通信接口(T WI )。
本文对T WI 通信接口作了概述,重点论述了T WI 通信接口在本微控制器中的应用,包括主机与从机的通信过程,主机读写片外EEPROM 的工作过程。
关键词:单片机;T WI 通信;主机;从机中图分类号:T N93113 文献标识码:A 文章编号:167224984(2005)022*******Application of TWI in the controller of broadcast transmitterM A Hui 2feng ,H AN Zhen 2yu(School of Manu facturing Science and Engineering ,S ichuan University ,Chengdu610065,China )Abstract :The controller of Broadcast T ransmitter usess ome AVR microcontrollers and the serial EEPROM in order to meet thedemands 1T WI is used in the communications am ong devices 1This paper discusses the application of T WI in the microcontroller ,including the communications between master and slave ,between the microcontroller and the serial EEPROM 1K ey w ords :Microcontroller ;T WI communications ;Master ;S lave收稿日期:2004208231;收到修改稿日期:20042102161 引 言本微控制器是基于单片机的计算机控制系统,它能对广播发射机的工作状态进行在线监控和检测,实时采集发射机的各个参数(模拟量、开关量),进行处理分析后,及时地发出控制指示信号。
AVR与AT24C256I2C程序(TWI)
AVR与AT24C256I2C程序(TWI)/*调试通过2013020224c256连续读取多个数据.多写,可单读单写*/#include#include//数据类型预定义8位,16位整数#define INT8U unsigned char#define INT16U unsigned int# define F_CPU 7372800UL/* TWSR values (not bits) *//* Master */#define I2C_START 0x08#define I2C_RESTART 0x10/* Master Transmitter */#define I2C_MT_SLA_ACK 0x18 //?#define I2C_MT_SLA_NACK 0x20 //? #define I2C_MT_DA TA_ACK 0x28#define I2C_MT_DA TA_NACK 0x30 //?#define I2C_MT_ARB_LOST 0x38 //? /* Master Receiver */#define I2C_MR_ARB_LOST 0x38 //? #define I2C_MR_SLA_ACK 0x40#define I2C_MR_SLA_NACK 0x48 //? #define I2C_MR_DA TA_ACK 0x50 //? #define I2C_MR_DA TA_NACK 0x58 //?/* Slave Transmitter */#define I2C_ST_SLA_ACK 0xA8 //?#define I2C_ST_ARB_LOST_SLA_ACK 0xB0 //?#define I2C_ST_DA TA_ACK 0xB8 //? #define I2C_ST_DA TA_NACK 0xC0 //?#define I2C_ST_LAST_DATA 0xC8 //?/* Slave Receiver */#define I2C_SR_SLA_ACK 0x60 //?#define I2C_SR_ARB_LOST_SLA_ACK 0x68 //? #define I2C_SR_GCALL_ACK 0x70 //?#define I2C_SR_ARB_LOST_GCALL_ACK 0x78//? #define I2C_SR_DA TA_ACK 0x80 //? #define I2C_SR_DA TA_NACK 0x88 //?#define I2C_SR_GCALL_DATA_ACK 0x90 //? #define I2C_SR_GCALL_DATA_NACK 0x98 //? #define I2C_SR_STOP 0xA0 //?/* Misc */#define I2C_NO_INFO 0xF8 //?#define I2C_BUS_ERROR 0x00 //?/** The lower 3 bits of TWSR are reserved on the ATmega163.* The 2 LSB carry the prescaler bits on the newer ATmegas.*/#define I2C_STATUS_MASK(_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))#define I2C_STATUS (TWSR & I2C_STA TUS_MASK)/** R/~W bit in SLA+R/W address field.*/#define I2C_READ 1#define I2C_WRITE 0#define I2CStart() (TWCR=(1<<twint)|(1<<twsta)|(1<<="" bdsfid="110" p=""></twint)|(1<<twsta)|(1<#define I2CStop() (TWCR=(1<<twint)|(1<<twsto)|(1<<twen))< bdsfid="112" p=""></twint)|(1<<twsto)|(1<<twen))<>#define I2CWaitAck() {while(!(TWCR&(1<<twint)));}< bdsfid="114" p=""></twint)));}<>#define I2CChkAck() (TWSR&0xf8) //check ack#define I2CSendAck() (TWCR|=(1<<twea))< bdsfid="117" p=""></twea))<>#define I2CSendNoAck() (TWCR&=~(1<<twea))< bdsfid="119" p=""></twea))<>#define I2CSendByte(x) {TWDR=(x);TWCR=(1<<twint)|(1<<twen);}< bdsfid="121" p=""></twint)|(1<<twen);}<>#define I2CRcvNckByte() (TWCR=(1<<twint)|(1<<twen))< bdsfid="123" p=""></twint)|(1<<twen))<>#define I2CRcvAckByte() (TWCR=(1<<twint)|(1<<twen)|(1<<twea))< bdsfid="125" p=""></twint)|(1<<twen)|(1<<twea))<>/* For Program */#define I2C_Stop() I2CStop()#define I2C_SendAck() I2CSendAck()#define I2C_SendNoAck() I2CSendNoAck()#define I2C_WaitAck() I2CWaitAck()/* I2C Config */#define I2C_ERR 0#define I2C_CRR 1//char data1;//为观察读取的数据的临时观察变量#ifndef WR_DADR#define WR_DADR 0xa0 //write device-address#endif#ifndef RD_DADR#define RD_DADR 0xa1 //read device-address#endif//#define AT24CXX_ERR 0//#define AT24CXX_CRR 1//****************************** twi 初始化************************************* // TWCR: 控制寄存器,用来控制TWI操作,说明如下:// Bit 7-TWINT:中断标志位,Bit 6-TWEA:使能应答位,Bit 5-TWSTA:START状态位// Bit 4-TWSTO:STOP状态位,Bit 3-TWWC: 写冲突标志,Bit 2-TWEN:TWI使能位// Bit 1-RES:保留,Bit 0-TWIE:中断使能// TWSR: 状态寄存器,Bits 7..3:表示了TWI总线的当前状态,读取时需屏蔽低三位的值,Bits 1..0-TWPS:TWI预分频位// TWBR: 比特率寄存器,用来设置TWI的工作频率,计算公式为:SCL=CPU频率/(16+2*(TWBR)*4TWPS),TWPS在4的指数位置// TWAR: 从机地址寄存器,Bits 7..1:存放从机地址,Bit 0:最低位为广播识别使能位// TWDR: 数据寄存器,用来存放接收或要发送的地址和数据//************************************************************* **************** *void twi_init(void){TWBR=1;TWSR=0;TWCR=0x44;}/*--------------------------------------------------------------------程序名称:I2C Start程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_Start(){I2CStart();I2CWaitAck(); //202页第二步等待if( I2CChkAck()!=I2C_START ) //202页第三步开始启动传输return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C ReStart程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_Restart(){I2CStart();I2CWaitAck();if( I2CChkAck()!=0x10 )return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)发送7位器件写地址: XXXX XXX0程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_SendWrDAdr(INT8U wrDAdr) //wrDAdr相当于202页表中提到的sla_w{I2CSendByte(wrDAdr); //202页第四步1 .将SLA_W载入到TWDR 寄存器,TWINT位清零,启动发送地址设置器件写地址I2CWaitAck(); //202页第四步2 等待TWINT 置位,TWINT置位表示总线命令SLA+W 已发出,及收到应答信号ACK/NACK if((TWSR&0xf8) != 0x18) //202页表中第5步检验TWI 状态寄存器,屏蔽预分频位,如果状态字不是MT_SLA_ACK 转出错处理return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)发送10位器件写地址: 1111 0XX0, XXXX XXXX程序功能:注意事项:提示说明:兼容发送7位器件写地址: XXXX XXX0输入:返回:--------------------------------------------------------------------*/INT8U I2C_SendWrDAdr_(INT16U wrDAdr){if((wrDAdr & 0xf000) == 0xF000) //判断是否为10位器件地址if(I2C_SendWrDAdr((INT8U)wrDAdr>>8 )==I2C_ERR) //设置(高位)器件写地址return I2C_ERR;if( I2C_SendWrDAdr((INT8U)wrDAdr)==I2C_ERR) //设置(低位)器件写地址return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)发送7位器件读地址: XXXX XXX1程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_SendRdDAdr(INT8U rdDAdr){I2CSendByte(rdDAdr); //设置器件读地址I2CWaitAck();if( I2CChkAck()!=I2C_MR_SLA_ACK )//I2C_MR_SLA_ACK=0x4 0return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)发送10位器件读地址: 1111 0XX0, XXXX XXXX程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_SendRdDAdr_(INT8U rdDAdr){if( rdDAdr&0xf000 ==0xf000 ) //判断是否为10位器件地址if( I2C_SendWrDAdr((INT8U)rdDAdr>>8)==I2C_ERR) //设置(高位)器件读地址return I2C_ERR;if( I2C_SendWrDAdr((INT8U)rdDAdr)==I2C_ERR) //设置(低位)器件读地址return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)发送数据程序功能:注意事项:提示说明:输入:返回:--------------------------------------------------------------------*/INT8U I2C_SendDat(INT8U configDat) //原先位16位{I2CSendByte(configDat);I2CWaitAck();if( I2CChkAck()!=I2C_MT_DATA_ACK )return I2C_ERR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)接收数据且不产生应答程序功能:只读一个字节,然后停止读取注意事项:提示说明:读取一个字节后,发送不响应,用于读取1个字节输入:返回:--------------------------------------------------------------------*/INT8U I2C_RcvNAckDat(INT8U *pRdDat){I2CRcvNckByte();I2CWaitAck();if(I2CChkAck()!=I2C_MR_DATA_NACK)//接收到数据0x58return I2C_ERR;*pRdDat=TWDR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)接收数据且产生应答程序功能:用于连续读取,读取单个字节后,在读下一个字节.最后读取n个字节后,再停止. 注意事项:提示说明:读取一个字节后,发送响应,用于读取多个字节输入:返回:--------------------------------------------------------------------*/INT8U I2C_RcvAckDat(INT8U *pRdDat){I2CRcvAckByte();I2CWaitAck();if( I2CChkAck()!=0x50)return I2C_ERR;*pRdDat=TWDR;return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)写器件,写一个数据程序功能:注意事项:提示说明:输入:wrDAdr: write device-address 写器件地址wordAdr: word address 字地址dat: data 数据返回:INT8U I2CWriteByte(INT8U wrDAdr,INT16U wordAdr,INT8U dat){if( I2C_Start()==I2C_ERR )return I2C_ERR;if( I2C_SendWrDAdr_(wrDAdr)==0)return I2C_ERR;if( I2C_SendDat((wordAdr&0xff00)>>8)==I2C_ERR )return I2C_ERR;if( I2C_SendDat(wordAdr&0x00ff)==I2C_ERR )return I2C_ERR;if( I2C_SendDat(dat)==0 )return I2C_ERR;I2C_Stop();return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)写器件,写N个数据程序功能:注意事项:提示说明:输入:wrDAdr: write device-address 写器件地址wordAdr: word address 存储数据的起始地址*pWrDat: p->write data 写入数据指针num: number 写入数据个数返回:--------------------------------------------------------------------*/INT8U I2CWriteStr(INT8U wrDAdr,INT16U wordAdr,INT8U *pWrDat,INT8U num) {INT16U i;if( I2C_Start()==I2C_ERR )if( I2C_SendWrDAdr_(wrDAdr)==0)return I2C_ERR;if( I2C_SendDat((wordAdr&0xff00)>>8)==I2C_ERR )return I2C_ERR;if( I2C_SendDat(wordAdr&0x00ff)==I2C_ERR )return I2C_ERR;for (i=0;i<num;i++)< bdsfid="346" p=""></num;i++)<>if(I2C_SendDat(*(pWrDat+i))==0)return I2C_ERR;I2C_Stop();return I2C_CRR;}程序名称:I2C(TWI)读器件,读一个数据程序功能:注意事项:提示说明:输入:wrDAdr: write device-address 写器件地址wordAdr: word address 字地址rdDAdr: read device-address 读器件地址*pRdDat: p->read data 读取数据指针返回:--------------------------------------------------------------------*/INT8U I2CReadByte(INT8U wrDAdr,INT16U wordAdr,INT8U rdDAdr,INT8U *pRdDat){if( I2C_Start()==I2C_ERR )return I2C_ERR;if( I2C_SendWrDAdr_(wrDAdr)==I2C_ERR )////16位地址拆分if( I2C_SendDat((wordAdr&0xff00)>>8)==I2C_ERR )return I2C_ERR;if( I2C_SendDat(wordAdr&0x00ff)==I2C_ERR )return I2C_ERR;if( I2C_Restart()==I2C_ERR )return I2C_ERR;if( I2C_SendRdDAdr(rdDAdr)==I2C_ERR )return I2C_ERR;if( I2C_RcvNAckDat(pRdDat)==I2C_ERR )return I2C_ERR;I2C_Stop();return I2C_CRR;}/*--------------------------------------------------------------------程序名称:I2C(TWI)读器件,读N个数据程序功能:注意事项:提示说明:输入:wrDAdr: write device-address 写器件地址wordAdr: word address 存储数据的起始地址rdDAdr: read device-address 读器件地址*pRdDat: p->read data 读取数据指针num: number 读取数据个数返回:--------------------------------------------------------------------*/INT8U I2CReadStr(INT8U wrDAdr,INT16U wordAdr,INT8UrdDAdr,INT8U *pRdDat,INT8Unum){INT8U i;if( I2C_Start()==I2C_ERR )return I2C_ERR;if( I2C_SendWrDAdr_(wrDAdr)==I2C_ERR )return I2C_ERR;//16位24c256存储空间地址拆分if( I2C_SendDat((wordAdr&0xff00)>>8)==I2C_ERR ) return I2C_ERR;if( I2C_SendDat(wordAdr&0x00ff)==I2C_ERR ) return I2C_ERR;if( I2C_Restart()==I2C_ERR )return I2C_ERR;if( I2C_SendRdDAdr(rdDAdr)==I2C_ERR )return I2C_ERR;for(i=0;i<num-1;i++)< bdsfid="410" p=""></num-1;i++)<> if( I2C_RcvAckDat(pRdDat+i)==I2C_ERR )return I2C_ERR;if( I2C_RcvNAckDat(pRdDat+i)==I2C_ERR )return I2C_ERR;I2C_Stop();return I2C_CRR;}//int main(void){int i;INT8U data2[256]={0};INT8U data21[256]={0};INT8U data3[]={0x11,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x2e, 0x65,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x3e,0x75,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x4e,0x85,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x5e,0x95,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x6e,0x05,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x11,0x54,0x88,0x1,0x1,0x11,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x2e, 0x65,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x3e,0x75,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x4e,0x85,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x5e,0x95,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x6e,0x05,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x11, 0x54,0x88,0x1,0x1,0x11,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x2e, 0x65,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x3e, 0x75,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x4e, 0x85,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x5e, 0x95,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x6e, 0x05,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x11, 0x54,0x88,0x1,0x1,0x11,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x2e, 0x65,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x3e, 0x75,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x4e, 0x85,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x5e, 0x95,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x6e, 0x05,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x11, 0x54,0x88,0x1,0x1};INT8U data4[64]={0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa, 0x11,0x22,0x33,0x44//0x14,0x1a,0x1b,0x1c,0x1d,0x1e};INT8U data5[64]={0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xaa,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,0x11, 0xbb,0xcc,0xdd,0xee//0x14,0x1a,0x1b,0x1c,0x1d,0x1e};INT8U data6[64]={0x55,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x2e, 0x65,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x3e, 0x75,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x4e, 0x85,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x5e, 0x95,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x6e, 0x05,0x68,0xde,0xab,0xc4,0xaa,0xbb,0xcc,0xdd,0x7e, 0x55,0x12,0x4,0x4};INT8U dat1[1];char c;while(1){twi_init();_delay_ms(400);I2CWriteStr(0xa0,0x0000,data4,64);_delay_ms(400);I2CWriteStr(0xa0,0x0040,data5,64);_delay_ms(400);I2CWriteStr(0xa0,0x0080,data6,64);_delay_ms(400);I2CReadStr(0xa0,0x0000,0xa1,data2,64);//多读_delay_ms(400);I2CReadStr(0xa0,0x0040,0xa1,data2,64);//多读_delay_ms(400);I2CReadStr(0xa0,0x0080,0xa1,data2,64);//多读_delay_ms(400);I2CReadStr(0xa0,0x0000,0xa1,data2,64);//多读_delay_ms(400);for (i=0;i<192;i++){I2CWriteByte(0xa0,0x2000+i,0x05);//写入地址0x0001中一个数据0x64 _delay_ms(250);//延时十分必要}I2CReadStr(0xa0,0x2000,0xa1,data2,192);//多读_delay_ms(400);I2CReadStr(0xa0,0x2000,0xa1,data2,256);//多读_delay_ms(400);I2CReadStr(0xa0,0x2000,0xa1,data2,256);//多读_delay_ms(400);}}。
AVR单片机与传感器基础第九章
上一页 下一页 返回
9.4 TWI 模块综述
• 3. 总线接口单元 • 该单元包括数据与地址移位寄存器TWDR、START/STOP 控制器和
总线仲裁检测电路。 • TWDR 寄存器用于存放发送或接收的数据或地址。除了8 位的TWDR,
的地址。TWI 协议解决了总线仲裁的问题。
上一页 下一页 返回
9.1 TWI 接口特点及总线定义
• 2. 电气连接 • 如图9.1 所示,两根传输线都通过上拉电阻与正电源连接。所有TWI
兼容设备的总线驱动都是漏极开路或集电极开路,这样可以实现对接 口操作非常关键的“线与”功能:任一个TWI 器件输出为“0”时, TWI 总线即为低电平“0”。“线与”功能对TWI 协议非常重要,主 机仲裁与时钟同步都需要依靠它来实现。当所有的TWI 器件输出为三 态时,总线会输出高电平,允许上拉电阻将电压拉高。工作时,为保 证所有的总线操作,凡是与TWI 总线连接的AVR 器件必须上电。
上一页 下一页 返回
9.2 数据传输与帧格式
• 4. 将地址包和数据包合成为一次传输过程
• 一次数据传输主要由START 信号、SLA+R/W、至少一个数据包及 STOP 信号组成。只有START 与STOP 信号的空信息是非法的。通 常,由于收发双方都有些准备工作要处理,在地址包之后,数据包不 会在紧接着的第10 个时钟脉冲立刻输出。收发双方准备工作所需要 的时间可能不一样,那怎么让二者协调一致呢?这需要用到SCL 的 “线与”功能,来实现主机与从机的握手与同步。从机可通过拉低 SCL 来延长SCL 低电平的时间。当主机设定的时钟速度相对于从机 太快,或从机需要额外的时间来处理数据时,这一特性是非常有用的。 从机延长SCL 低电平的时间不会影响SCL 高电平的时间,因为SCL 高电平时间是由主机决定的。由上述可知,通过改变SCL 的占空比 可降低TWI 数据传送速度。图9.6 说明了典型的数据传送。注意 SLA+R/W 与STOP 之间传送的字节数由应用程序的协议决定。从机 可以拉低SCL 以延长低电平时间,此时SDA 线上数据可以先出现, 然后等待时钟。
AVR单片机TWI读写过程实例
TWI:是一种全双工的串行通讯协议,与I2C工作方式相同,由一条数据传输线SDL,一条时钟线SCL组成,对应单片机的外部引脚PC1,PC0。
由于只有两条总线,简化了系统设计。
特点:• 简单,但是强大而灵活的通讯接口,只需要两根线• 支持主机和从机操作• 器件可以工作于发送器模式或接收器模式• 7 位地址空间允许有128 个从机• 支持多主机仲裁• 高达400 kHz 的数据传输率• 斜率受控的输出驱动器• 可以抑制总线尖峰的噪声抑制器• 完全可编程的从机地址以及公共地址• 睡眠时地址匹配可以唤醒AVR主机:控制启动和停止传输的设备。
主机同时要产生SCL 时钟从机:被主机寻址的设备发送器:将数据放到总线上的设备接收器:从总线读取数据的设备TWI工作模式: 主机发送模式(MT)主机接收模式(MR)从机发送模式(ST)从机接收器模式(SR)例如,TWI 可用MT 模式给TWIEEPROM 写入数据,用MR 模式从EEPROM 读取数据。
如果系统中有其它主机存在,它们可能给TWI 发送数据,此时就可以用SR 模式。
应用程序决定采用何种模式。
模式状态缩写:S:START 状态Rs:REPEATED START 状态R:读一个比特(SDA 为高电平)W:写一个比特(SDA 为低电平)A:应答位(SDA 为低电平)A:无应答位(SDA 为高电平)Data:8 位数据P:STOP 状态SLA:从机地址一、主机模式:可以向从机发送数据,进入主机模式,首先发送一个START信号,接着的从机地址决定了进入MT还是MR模式主机发送(MT): S+SLA+W, 主机接收(MR): S+SLA+R1、波特率设置:TWBR=100;2、分频设置:TWSR|=(1<<TWPS1)|(1<<TWPS0);写过程:1)、发送启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA);2)、等待应答信号:while ((TWCR&(1<<TWINT))==0);3)、进入主机写模式:TWDR=0Xa0;// TWDR=SLA+W; //通过在TWDR中写入SLA+W进入主机写模式,SLA+R进入主机读模式TWCR=(1<<TWINT)|(1<<TWEN);while ((TWCR&(1<<TWINT))==0);//如果TWINT为0就原地等待4)、发送要写入的地址:TWDR=adress;TWCR=(1<<TWINT)|(1<<TWEN); //启动发送while(!(TWCR&(1<<TWINT)));5)、发送要写入的数据:TWDR=data;TWCR=(1<<TWINT)|(1<<TWEN); //启动发送while(!(TWCR&(1<<TWINT)));6)、发送停止信号:TWC(1<<TWINT)|(1<<TWEN)|(1<<TWST0); //写过程结束读过程:1)、启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA)while(!(TWCR&(1<<TWINT)));2)、进入主机写模式:TWDR=0Xa0;//TWDR=SLA+W;TWCR=(1<<TWINT)|(1<<TWEN);while(!(TWCR&(1<<TWINT)));3)、写入要读的地址:TWDR=address;TWCR=(1<<TWINT)|(1<<TWEN);while(!(TWCR&(1<<TWINT)));4)、发送启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA)while(!(TWCR&(1<<TWINT)));5)、进入主机读模式:TWDR=0Xa1 ;//TWDR=SLA+R;TWCR=(1<<TWINT)|(1<<TWEN);while(!(TWCR&(1<<TWINT)));6)、开始读数据:TWCR=(1<<TWINT)|(1<<TWEN);while(!(TWCR&(1<<TWINT)));temp=TWDR; //读取的数据送到变量temp中。
AVR单片机TWI读写读写范例讲解
state=ST_WDATA-1; //下一步将跳到WDATA分支
TWCR=TW_ACT; //触发下一步动作
}
}
else
{//发送eeprom地址出错
state=ST_FAIL;
}
break;
case ST_RESTART: //RESTART状态检查,只有读操作模式才能跳到这里
(大部分IIC接口器件都是这种类型,常见的例如AT24C01/02/04/08/16,DS1307,DS1721等)
对于有两个字节数据地址的IIC器件(例如AT24C32/64/128/256等大容量EEPROM),请稍作改动
//根据strTWI.SLA的最低位决定
//bit0=1 TW_READ读
state=strTWI.STATE;
status=TWSR&0xF8; //屏蔽预分频位
if ((status>=0x60)||(status==0x00))
{//总线错误或从机模式引发的中断,不予处理
return;
}
switch(state)
{
case ST_START: //START状态检查
#define SLA_24CXX 0xA0 //24Cxx系列的厂商器件地址(高四位)
#define ADDR_24C02 0x00
// AT24C02的地址线A2/1/0全部接地,SLAW=0xA0+0x00<<1+0x00,SLAR=0xA0+0x00<<1+0x01
//TWI_操作状态
#define TW_BUSY 0
if (strTWI.DATALEN--)
ATmega16 _TWI主从机
* twi.c** Created: 2015/2/19 19:55:38* Author: Administrator*//************************************************************************/ /* 常用头文件及宏定义*/ /************************************************************************/#include <avr/io.h>#include <util/delay.h> //延时文件#include <avr/sleep.h> //睡眠文件#include <avr/interrupt.h> //中断文件#include <avr/eeprom.h> //eeprom#define BIT(x) 1<<x#define uchar unsigned char#define uint unsigned int/************************************************************************/ /* TWI程序*/ /************************************************************************//* 引脚说明*/ /* PC0 SCL PC1 SDA */#define START() TWCR|=BIT(TWSTA)|BIT(TWINT)//发送START#define DIZHI_CONGJI (1<<1) //从机地址//READ_WRITE=0写,=1读key=0发送中,=1空闲中uchar DIZHI_TWI=0,SHUJU_WRITE_TWI=0,SHUJU_READ_TWI=0,READ_WRITE=0,key=1; void chushihua_twi(){DDRC&=0xfc;PORTC|=BIT(0)|BIT(1);TWBR=20; //波特率cli();TWCR=BIT(TWEN)|BIT(TWIE)|BIT(TWEA);//中断sei();TWAR=BIT(TWGCE)|DIZHI_CONGJI; //从机地址:}ISR(TWI_vect)switch(TWSR&0xf8){/////////////////////// 主机发送/////////////////////////////////case 0x08: //START发送成功{if (READ_WRITE) //读写控制1读,0写{TWDR=(DIZHI_TWI<<1)+1; //发送SLA+RTWCR=(TWCR|BIT(TWINT))&~(BIT(TWSTA));//清标志}else{TWDR=DIZHI_TWI<<1; //发送SLA+WTWCR=(TWCR|BIT(TWINT))&~(BIT(TWSTA));//清标志}}break;case 0x10: //重复START发送成功{if (READ_WRITE) //读写控制1读,0写{TWDR=(DIZHI_TWI<<1)+1; //发送SLA+RTWCR=(TWCR|BIT(TWINT))&~(BIT(TWSTA));//清标志}else{TWDR=DIZHI_TWI<<1; //发送SLA+WTWCR=(TWCR|BIT(TWINT))&~(BIT(TWSTA));//清标志}}break;case 0x18: //SLA+W已发送,收到ACK{TWDR=SHUJU_WRITE_TWI; //发送数据TWCR|=BIT(TWINT); //清标志}break;case 0x20: //SLA+W已发送,收到NOT ACK {START(); //发送重复START}break;case 0x28: //数据已发送,收到ACKcase 0x30: //数据已发送,收到NOT ACK {key=1;TWCR=BIT(TWINT)|BIT(TWSTO)|BIT(TWEN)|BIT(TWIE);//发送STOP,清标志}break;case 0x38: //SLA+W 或数据的仲裁失败{START(); //总线空闲时发送START}break;/////////////////////// 主机接收//////////////////////case 0x40: //SLA+R 已发送接收到ACK{TWCR=(TWCR|BIT(TWINT))&~(BIT(TWEA));//接收数据,返回NOT ACK }break;case 0x48: //SLA+R 已发送接收到NOT ACK{START(); //将发送重复START}break;case 0x50: //接收到数据ACK 已返回{SHUJU_READ_TWI=TWDR;TWCR|=BIT(TWINT); //接收数据,返回NOT ACK}break;case 0x58: //接收到数据NOT ACK 已返回{SHUJU_READ_TWI=TWDR;TWCR|=BIT(TWINT)|BIT(TWSTO);//将发送STOP,TWSTO 将复位}break;/////////////////////// 从机接收//////////////////////case 0x60: //自己的SLA+W 已经被接收ACK 已返回case 0x68: //SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收ACK 已返回case 0x70: //接收到广播地址ACK 已返回case 0x78: //SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK 已返回case 0x80: //以前以自己的SLA+W 被寻址;数据已经被接收ACK 已返回{TWCR=(TWCR|BIT(TWINT))&~(BIT(TWEA));//接收数据,返回NOT ACK }break;case 0x88: //以前以自己的SLA+W 被寻址;数据已经被接收NOT ACK 已返回{SHUJU_READ_TWI=TWDR; //读数据TWCR|=BIT(TWINT)|BIT(TWEA); //切换到未寻址从机模式;能够识别自己的SLA;若TWGCE = “1”,GCA 也可以识别}break;case 0x90: //以前以广播方式被寻址;数据已经被接收ACK 已返回{SHUJU_READ_TWI=TWDR; //读数据TWCR|=BIT(TWINT); //接收数据,返回NOT ACK}break;case 0x98: //以前以广播方式被寻址;数据已经被接收NOT ACK 已返回{SHUJU_READ_TWI=TWDR;TWCR|=BIT(TWINT)|BIT(TWEA); //切换到未寻址从机模式;能够识别自己的SLA;若TWGCE = “1”,GCA 也可以识别}break;case 0xa0: //在以从机工作时接收到STOP或重复START{TWCR|=BIT(TWINT)|BIT(TWEA); //切换到未寻址从机模式;能够识别自己的SLA;若TWGCE = “1”,GCA 也可以识别}break;/////////////////////// 从机发送//////////////////////case 0xa8: //自己的SLA+R 已经被接收ACK 已返回{TWDR=SHUJU_WRITE_TWI;TWCR=(TWCR|BIT(TWINT))&~(BIT(TWEA));//发送一字节的数据,接收NOT ACK }break;case 0xb0: //SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回{TWDR=SHUJU_WRITE_TWI;TWCR=(TWCR|BIT(TWINT))&~(BIT(TWEA));//发送一字节的数据,接收NOT ACK }break;case 0xb8: //TWDR 里数据已经发送接收到ACK{TWDR=SHUJU_WRITE_TWI;TWCR=(TWCR|BIT(TWINT))&~(BIT(TWEA));//发送一字节的数据,接收NOT ACK }break;case 0xc0: //TWDR 里数据已经发送接收到NOT ACK{TWCR|=BIT(TWINT)|BIT(TWEA);//切换到未寻址从机模式;能够识别自己的SLA;若TWGCE = “1”,GCA 也可以识别}break;case 0xc8: //TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK{TWCR|=BIT(TWINT)|BIT(TWEA);//切换到未寻址从机模式;能够识别自己的SLA;若TWGCE = “1”,GCA 也可以识别}break;case 0xf8: //没有相关的状态信息;TWINT = “0”{//等待或进行当前传输}break;case 0x00: //由于非法的START 或STOP 引起的总线错误{TWCR|=BIT(TWINT)|BIT(TWSTO);//只影响内部硬件;不会发送STOP 到总线上。
ATMEGA16读写iic(TWI)(24c02)C语言程序
ATMEGA16 读写iic(24c02) C 语言程序测试通过nclude <iom16v.h>#i nclude "I2C.h"#in clude "1602.h"#in clude "delay.h"/*通过AVR往I IC写数据,并通过串口把数据读出显示出来*///===============================================================void UAR_i nit(void) //UART 初始化{ DDRD = 0x02;PORTD = 0x00;UCSRA = 0x02; /* 无倍速*/UCSRB = 0x18; /*允许接收和发送*/U(SRC= 0x06; 1*8位数据,1位停止位,无校验*/UBRRH = 0x00;UBRRL = 12; /*9600*/}//===============================================================void USART_TXD(float data) // 发送采用查询方式{while( !(UCSRA & BIT(UDRE)));UDR=data;while( !(UCSRA & BIT(TXC )));UCSRA|=BIT(TXC);}void mai n(void){un sig ned char i;// LCDinit();uart_i ni t();//TART 初始化SEI(); // 全局中断使能while(1){/*I2C_Write('n',0x00); I2C_Write('c',0x01); I2C_Write('e',0x02);I2C_Write('p',0x03); I2C_Write('u',0x04);*/ i=I2C_Read(0x00); //LCD_write_char(0,0,i); USART_TXD(i); i=I2C_Read(0x01);//LCD_write_data(i); USART_TXD(i); i=I2C_Read(0x02); //LCD_write_data(i); USART_TXD(i);i=I2C_Read(0x03); //LCD_write_data(i); USART_TXD(i); i=I2C_Read(0x04); //LCD_write_data(i); USART_TXD(i);}}/* 上面上主函数部分*/#include <macros.h>#include "delay.h"//I2C 状态定义//MT 主方式传输MR 主方式接受#define START 0x08#define RE_START 0x10#define MT_SLA_ACK 0x18 #define MT_SLA_NOACK 0x20 #define MT_DATA_ACK 0x28 #defineMT_DATA_NOACK 0x30 #define MR_SLA_ACK 0x40 #define MR_SLA_NOACK 0x48 #define MR_DATA_ACK 0x50 #define MR_DATA_NOACK 0x58#define RD_DEVICE_ADDR 0xA1 // 前4位器件固定,后三位看连线,最后1位是读写指令位#define WD_DEVICE_ADDR 0xA0//常用TWI操作(主模式写和读)#define Start() (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)) // 启动I2C #define Stop()(TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)) // 停止I2C #define Wait() {while(!(TWCR&(1<<TWINT)));} // 等待中断发生#define TestAck() (TWSR&0xf8) // 观察返回状态#define SetAck (TWCR|=(1<<TWEA)) // 做出ACK应答#define SetNoAck (TWCR&=~(1<<TWEA)) // 做出Not Ack 应答#define Twi() (TWCR=(1<<TWINT)|(1<<TWEN)) // 启动I2C#define Write8Bit(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);} // 写数据到TWDRunsigned char I2C_Write(unsigned char Wdata,unsigned char RegAddress); unsigned charI2C_Read(unsigned RegAddress);/*********************************************I2C 总线写一个字节返回0: 写成功返回1: 写失败**********************************************/unsigned char I2C_Write(unsigned char Wdata,unsigned char RegAddress){Start(); //I2C 启动Wait();if(TestAck()!=START)return 1; //ACKWrite8Bit(WD_DEVICE_ADDR); // 写I2C 从器件地址和写方式Wait(); if(TestAck()!=MT_SLA_ACK) return 1; //ACKWrite8Bit(RegAddress); // 写器件相应寄存器地址Wait();if(TestAck()!=MT_DATA_ACK)return 1; //ACKWrite8Bit(Wdata); // 写数据到器件相应寄存器Wait();if(TestAck()!=MT_DATA_ACK)return 1; //ACKStop(); //I2C 停止delay_nms(10); // 延时return 0;}/*********************************************I2C 总线读一个字节返回0: 读成功返回1: 读失败**********************************************/unsigned char I2C_Read(unsigned RegAddress){ unsigned char temp;Start();//I2C 启动Wait();if (TestAck()!=START) return 1; //ACKWrite8Bit(WD_DEVICE_ADDR); // 写I2C 从器件地址和写方式Wait(); if (TestAck()!=MT_SLA_ACK) return 1; //ACKWrite8Bit(RegAddress); // 写器件相应寄存器地址Wait();if (TestAck()!=MT_DATA_ACK) return 1;Start(); //I2C 重新启动Wait();if (TestAck()!=RE_START) return 1;Write8Bit(RD_DEVICE_ADDR); // 写I2C 从器件地址和读方式Wait(); if(TestAck()!=MR_SLA_ACK)return 1; //ACKTwi(); // 启动主I2C 读方式Wait(); if(TestAck()!=MR_DATA_NOACK) return 1; //ACKtemp=TWDR;// 读取I2C 接收数据Stop();//l2C 停止return temp;}/*以上是IlC.h头文件部分,需要对照技术文档好好研究*/延时函数编译器:I CC-AVR V6.31A 日期:2005-11-24 20:29:57 目标芯片:M16 时钟:8.0000M Hz作者:arche ng504------------------------------------------------- */#ifndef __delay_h#defi ne __delay_hvoid delay_ nus(un sig ned int n);void delay_ nms(un sig ned int n);void delay_1us(void);void delay_1ms(void);void delay_1us(void) //1us 延时函数{asm( "n op");}void delay_ nus(un sig ned int n) 〃N us 延时函数{un sig ned in t i=0;for (i=0;i <n ;i++)delay_1us();}void delay_1ms(void) //1ms 延时函数{un sig ned in t i;for (i=0;i<1140;i++);}void delay_ nms(un sig ned int n) //N ms 延时函数{un sig ned in t i=0;for (i=0;i <n ;i++)delay_1ms();}#en dif/*以上是delay.h 部分,再加上IIC中自带的iom16v.h和macros.h就可以编译通过*//*注意点:本程序在实验板ATMEGA1上测试通过,在示波器把SCL, SDA信号线有数据,移值到自己电路上可以放心使用,在ATMEGA3上一样使用,本人24C02的A2, A1, A0都是接地,若地址不一样,在程序相应位置改一下就可以,串口上调试单片机的基础,所以它一定要会用*//*本程序调试软件环境是ICC6.31*/。
TWI接口和TWI接口器件使用
TWI接口和TWI接口器件使用A VR单片机的很多型号也具有两线制接口,即TWI接口。
实际上TWI接口时序和常I2总线是兼容的。
我们这本书结合讲的单片机Atmega16就有这种接口。
这种接口的见的C使用也十分广泛。
比如本文会结合介绍的EEPROM A T24C64;MAXIM公司的温度传感器(查出型号);有的A/D转换器;菲利普还有专门的用这种总线的I/O扩展芯片。
TWI电路接线简单,占用I/O,并且可以很多期间共享一个总线,使用比较方便,系统也很简洁。
A VR单片机用硬件实现了这种总线的时序,省去了很多编程工作。
同时支持一条总线多个主设备的通讯。
我们只需要控制相关寄存器就能实现通过TWI传输数据。
很大程度I2的基本知上减少了我们的工作量,从而使代码更简洁,开发更容易。
下面我们会介绍CI2接口的EEPROM的例识,A VR的TWI接口的功能和使用,给出一个用TWI接口读写C子,最后给出适用于A VR-GCC编译器的示例程序。
I2总线的基本知识一、CI2总线的信号线有两条,一条是时钟线SCL,另一条是数据线SDA。
总线连接起来的时候,C需要两个上拉电阻,器件内部这两个信号引脚是集电极开路(或者是漏极开路)的。
这样总线上的器件只要有一个输出低电平总线就会被拉低(实际上就是所谓线与的逻辑),这主要用于总线仲裁。
I2总线上,有几个状态表示特殊的总线信号。
1.在C开始和停止信号时序如下图所示:图上可以看出,在SCL位高电平时SDA的变化将产生总线开始和停止信号。
SDA从高电平跳变到低电平表示开始,从低电平跳变到高电平表示停止。
数据的建立和有效:上图表示在传输数据时,SCL高电平的时候,SDA上的数据不能变化,因为前面已经说明,这是数据的变化将会认为是开始或者结束的信号。
在SCL低电平时数据可以改变。
2.主器件和从器件总线上可以有很多设备但是同时只能有一个主设备进行传输,从设备都有设备地址,当总线上的地址和从设备设置的地址一致时,传输在主设备和被寻址的从设备之间进行,其他设备相当于和总线分离。
基于TWI接口实现AVR单片机主从机通信
基于TWI接口实现A VR单片机主从机通信【摘要】Atmel公司的TWI(Two-wire Serial Interface)接口具有硬件实现简单、软件设计方便、运行可靠和成本低廉的优点。
提出了一种以A VR单片机ATmega8为平台基于TWI接口的主从机通信的实现方法,给出了该系统主从机进行通信的硬件结构和软件设计。
该方法对于简化硬件电路、提高系统可靠性、缩短开发周期、降低成本是可行的。
【关键词】A VR;TWI;主机模式;从机模式Master-slave Communication of A VR Microcontroller Based on TWI Interface ZHOU Yong-gang(The 41st Institute of China Electronics Technology Group Corporation,Qingdao Shandong,266555)【Abstract】The TWI interface of ATMEL Corporation has simple hardware,software design has the advantages of convenient,reliable operation and low cost. This article presents the design of master-slave communication system for A VR microcontroller based on TWI interface on the platform of ATmega8,give the structure of the system’s hardware and software desi gn. The method is feasible to simplify the hardware circuit,improve system reliability,shorten development cycles,reduce costs.【Key words】A VR;TWI;Master mode;Slave mode0 引言A VR ATmega系列单片机片内集成两线串行接口TWI模块。
五、ATmega16通过TWI(兼容I2C)操作24C02
12
#define I2C_SetAck (TWCR|=(1<<TWEA)) //做出 ACK 应答 #define I2C_SetNoAck (TWCR&=~(1<<TWEA)) //做出 Not Ack 应答 #define I2C_Twi() (TWCR=(1<<TWINT)|(1<<TWEN)) //启动 I2C #define I2C_Write8Bit(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);} //写数据到 TWDR #define RD_DEVICE_ADDR 0xA1 #define WD_DEVICE_ADDR 0xA0 //前 4 位器件固定,后三位看连线,最后 1 位是读写指令位
6
if(Flag[3]==1) Flag[3]=I2C_Write('D',0x80+0x03); if(Flag[3]==0) break; } while(1) { Flag[4]=I2C_Write('E',0x80+0x04); if(Flag[4]==1) Flag[4]=I2C_Write('E',0x80+0x04); if(Flag[4]==0) break; } DDRC&=~(1<<PC1); Delay_ms(1000);//写和读之间的延时 Flag[0]=0;Flag[1]=0;Flag[2]=0;Flag[3]=0;Flag[4]=0; while(1) { Flag[0]=I2C_Read(0x80+0x00); if(Flag[0]==0) Flag[0]=I2C_Read(0x80+0x00); else {k[0]=Flag[0];break;} }Delay_ms(20); while(1)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
TWI:是一种全双工的串行通讯协议,与I2C工作方式相同,由一条数据传输线SDL,一条时钟线SCL组成,对应单片机的外部引脚PC1,PC0。
由于只有两条总线,简化了系统设计。
特点:• 简单,但是强大而灵活的通讯接口,只需要两根线
• 支持主机和从机操作
• 器件可以工作于发送器模式或接收器模式
• 7 位地址空间允许有128 个从机
• 支持多主机仲裁
• 高达400 kHz 的数据传输率
• 斜率受控的输出驱动器
• 可以抑制总线尖峰的噪声抑制器
• 完全可编程的从机地址以及公共地址
• 睡眠时地址匹配可以唤醒AVR
主机:控制启动和停止传输的设备。
主机同时要产生SCL 时钟
从机:被主机寻址的设备
发送器:将数据放到总线上的设备
接收器:从总线读取数据的设备
TWI工作模式: 主机发送模式(MT)
主机接收模式(MR)
从机发送模式(ST)
从机接收器模式(SR)
例如,TWI 可用MT 模式给TWIEEPROM 写入数据,用MR 模式从EEPROM 读取数据。
如果系统中有其它主机存在,它们可能给TWI 发送数据,此时就可以用SR 模式。
应用程序决定采用何种模式。
模式状态缩写:
S:START 状态
Rs:REPEATED START 状态
R:读一个比特(SDA 为高电平)
W:写一个比特(SDA 为低电平)
A:应答位(SDA 为低电平)
A:无应答位(SDA 为高电平)
Data:8 位数据
P:STOP 状态
SLA:从机地址
一、主机模式:可以向从机发送数据,进入主机模式,首先发送一个START信号,接着的从机地址决定了进入MT还是MR模式
主机发送(MT): S+SLA+W, 主机接收(MR): S+SLA+R
1、波特率设置:TWBR=100;
2、分频设置:TWSR|=(1<<TWPS1)|(1<<TWPS0);
写过程:
1)、发送启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
2)、等待应答信号:while ((TWCR&(1<<TWINT))==0);
3)、进入主机写模式:TWDR=0Xa0;// TWDR=SLA+W; //通过在TWDR中写入SLA+W进入主机写模式,SLA+R进入主机读模式
TWCR=(1<<TWINT)|(1<<TWEN);
while ((TWCR&(1<<TWINT))==0);//如果TWINT为0就原地等待
4)、发送要写入的地址:TWDR=adress;
TWCR=(1<<TWINT)|(1<<TWEN); //启动发送
while(!(TWCR&(1<<TWINT)));
5)、发送要写入的数据:TWDR=data;
TWCR=(1<<TWINT)|(1<<TWEN); //启动发送
while(!(TWCR&(1<<TWINT)));
6)、发送停止信号:TWC(1<<TWINT)|(1<<TWEN)|(1<<TWST0); //写过程结束
读过程:
1)、启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA)
while(!(TWCR&(1<<TWINT)));
2)、进入主机写模式:TWDR=0Xa0;//TWDR=SLA+W;
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
3)、写入要读的地址:TWDR=address;
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
4)、发送启动信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWSTA)
while(!(TWCR&(1<<TWINT)));
5)、进入主机读模式:TWDR=0Xa1 ;//TWDR=SLA+R;
TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
6)、开始读数据:TWCR=(1<<TWINT)|(1<<TWEN);
while(!(TWCR&(1<<TWINT)));
temp=TWDR; //读取的数据送到变量temp中。
7)、发送停止信号:TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWST0); //读过程结束
小企鹅diy 科学探究学习网
更多文章转到/wqb_lmkj/blog文章分类单片机。