AVR单片机TWI读写读写范例讲解

合集下载

ATMEGA16读写iic(TWI)(24c02)C语言程序

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*/。

09-IIC_TWI实验

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

ATmega8TWI读写AT24C64
#endif
#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读写

利用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中断。

基于TWI接口实现AVR单片机主从机通信

基于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模块。

TWI接口和TWI接口器件使用

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.主器件和从器件总线上可以有很多设备但是同时只能有一个主设备进行传输,从设备都有设备地址,当总线上的地址和从设备设置的地址一致时,传输在主设备和被寻址的从设备之间进行,其他设备相当于和总线分离。

单片机-AVR-EEPROM的读写分析

单片机-AVR-EEPROM的读写分析

1.单片机(AVR)EEPROM的读写分析由于AVR的EEPROM写周期比较长(一般为毫秒级),因此在编程使用过程中要特别注意.对于读EEPROM没什么好说的,读一个字节的数据要耗费4个时钟周期,可以忍受,写就比较麻烦了,虽然放在EEPROM的数据都不是频繁访问的;虽然可以用读-比较-写的机制降低EEPROM的写操作频度,但在写入过程中,过长的写入周期还是会造成一些问题,下面就分析一下几种方式的EEPROM写操作.1.1.循环查询式将地址和数据写入EEPROM相关的寄存器,置写标志后就循环不断查询写完成标志,直到写完成,退出循环,顺序执行其他程序.在置写入标志到写完成的这段时间,程序除了不断查询写完成标志和响应硬件中断之外什么也不干,这段时间就这么浪费了,如果是个实时性要求比较高的应用,浪费的就不仅是时间了,很可能在这段时间里I/O状态的变化不能得到及时的响应,如果一下子要进行多个字节的EEPROM的写入操作,那情况会更糟.针对这种情况,有种解决办法就是,这个写完成查询放在软件的死循环中(无操作系统的情况下,系统启动后都要进入一个死循环),每循环一次查询一次写完成标志,这样就不必一直等待写操作完成而可以干别的事情了,但是这样会带来两个问题.一是,如果死循环周期无法保证,则每一次的EEPROM写操作的完成标志查询也得不到保证,从而进行一次EEPROM写操作的周期也无法保证(最长延迟时间就是一个死循环周期的最长时间);二是,在执行一次EEPROM写入操作到写完成这段时间里死循环里其它的子程序不能进行EEPROM读写操作.第一个问题如果能保证最大循环周期在延迟允许范围内就不是问题了,否则就得采取下面讲到的方式二了;第二个问题的解决方法是每次EEPROM读写操作都要在其中加入对EEPROM写完成标志寄存器的判断,如果有数据正在写入,则等待或退出,但等待和退出又会造成等待延迟和写入操作不成功的问题,解决办法是先放入一个数据缓冲区,待上一次写入操作完成,再从缓冲区里拽出一个字节进行下一次写入周期,但这又会涉及到选择合适的缓冲区大小以及的问题,这个问题在下面中断式操作里继续讨论.1.2.定时查询式在写入EEPROM地址和数据寄存器置写标志后启动定时器,定时查询写完成标志,这种方法继承了方式1的大部分优缺点,唯一的进步就是能够确定写操作延迟时间为定时周期.1.3.中断式编写EEPROM写完成中断子程序,设置一个FIFO缓冲区,要写入的数据先放入这个FIFO,如果EEPROM操作空闲,则从FIFO中揪一字节数据出来写EEPROM,置完写完成标志就返回,然后去干别的事情,EEPROM写完成产生一个中断,在中断服务程序中再从FIFO中揪一个字节去写EEPROM,如此循环直到FIFO空,这种方式虽然能在第一时间完成一次写操作,但是还是有个和和方式1中提到一样的问题,怎么选择这个FIFO的大小.小了,待写入数据可能溢出丢失,大了,多大算大,1K够不够,10K够不够,硬件上有这么多RAM空间么,这就需要根据实际资源和系统需求来定了.如果EEPROM写操作频率很低,比一次EEPROM写操作间隔还要长得多,那么几个单位的FIFO就足够了;如果EEPROM写操作频率可能很高或一次大批量连续写入数据就要求很大的FIFO,达到能够保证数据不丢失,这就要根据批量数据大小和写频率来定了,另外还要考虑可用RAM空间的限制来找出最佳值,同时有FIFO溢出一定要制定相应的应对措施.最后注意两点:1.读写之前一定要检测是否已经有EEPROM写操作;在写完成之后一定要再读出写入的数据校验写入操作是否成功,不成功则EEPROM损坏,要做好应对措施.2.如果要保存一个16位的数据,一定要保证在这16位数据分成的两字节都成功写入了EEPROM再去读该数据,否则在刚写完一个字节就去读该数据,得到的数据显然不是你想要的,如果该数据是一重要参数,后果可想而知.。

AVR单片机TWI读写过程实例

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中。

五、ATmega16通过TWI(兼容I2C)操作24C02

五、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)

IAR For AVR 两线串行接口 TWI 应用

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 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单片机_教程_实例_附电路图

avr单片机_教程_实例_附电路图

AVR单片机特点每种MCU都有自身的优点与缺点,与其它8-bit MCU相比,AVR 8-bit MCU最大的特点是:● 哈佛结构,具备1MIPS / MHz的高速运行处理能力;● 超功能精简指令集(RISC),具有32个通用工作寄存器,克服了如8051 MCU采用单一ACC 进行处理造成的瓶颈现象;● 快速的存取寄存器组、单周期指令系统,大大优化了目标代码的大小、执行效率,部分型号FLASH非常大,特别适用于使用高级语言进行开发;● 作输出时与PIC的HI/LOW相同,可输出40mA(单一输出),作输入时可设置为三态高阻抗输入或带上拉电阻输入,具备10mA-20mA灌电流的能力;● 片内集成多种频率的RC振荡器、上电自动复位、看门狗、启动延时等功能,外围电路更加简单,系统更加稳定可靠;● 大部分AVR片上资源丰富:带E2PROM,PWM,RTC,SPI,UART,TWI,ISP,AD,Analog Comparator,WDT等;● 大部分AVR除了有ISP功能外,还有IAP功能,方便升级或销毁应用程序。

● 性价比高。

开发AVR单片机,需要哪些编译器、调试器?AVR Studio IDE、汇编编译器ATMEL AVR Studio集成开发环境(IDE),可使用汇编语言进行开发(使用其它语言需第三方软件协助),集软硬件仿真、调试、下载编程于一体。

ATMEL官方及市面上通用的AVR开发工具都支持AVRStudio。

GCCAVR (WinAVR) C编译器GCC是Linux的唯一开发语言。

GCC的编译器优化程度可以说是目前世界上民用软件中做的最好的,另外,它有一个非常大优点是,免费!在国外,使用它的人几乎是最多的。

但,相对而言,它的缺点是,使用操作较为麻烦。

ICC AVRC编译器(集烧写程序功能)市面上(大陆)的教科书使用它作为例程的较多,集成代码生成向导,虽然它的各方面性能均不是特别突出,但使用较为方便。

AVR单片机TWI(I2C)

AVR单片机TWI(I2C)
每一个字节必须保证是8位长度。数据传送时,先传 送最高位(MSB),每一个被传送的字节后面都必须跟 随一位应答位(即一帧共有9位)。
由于某种原因从机不对主机寻址信号应答时(如从机 正在进行实时性的处理工作而无法接收总线上的数据), 它必须将数据线置于高电平,而由主机产生一个终止信号 以结束总线的数据传送。 如果从机对主机进行了应答,但在数据传送一段时间后 无法继续接收更多的数据时,从机可以通过对无法接收的 第一个数据字节的“非应答”通知主机,主机则应发出终 止信号以结束数据的继续传送。 当主机接收数据时,它收到最后一个数据字节后,必须 向从机发出一个结束传送的信号。这个信号是由对从机的 “非应答”来实现的。然后,从机释放SDA线,以允许主 机产生终止信号。
SCL线为高电平期间,SDA线由高电平向低电平的 变化表示起始信号;SCL线为高电平期间,SDA线由 低电平向高电平的变化表示终止信号。
起始和终止信号都是由主机发出的,在起始信号 产生后,总线就处于被占用的状态;在终止信号产 生后,总线就处于空闲状态。 连接到I2C总线上的器件,若具有I2C总线的硬件 接口,则很容易检测到起始和终止信号IPS公司推出的一种串行总线,是具备多主机系
统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。
I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时 钟线SCL。
I2C总线通过上拉电阻接正电源。当总线空闲时,两 根线均为高电平。连到总线上的任一器件输出的低电平, 都将使总线的信号变低,即各器件的SDA及SCL都是线 “与”关系。
手册172页
三、I2C协议的AD5161
4、总线的寻址
I2C总线协议有明确的规定:采用7位的寻址字节 (寻址字节是起始信号后的第一个字节)。 (1)寻址字节的位定义

AVR单片机TWI读写读写范例讲解

AVR单片机TWI读写读写范例讲解
strTWI.DATALEN--;
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--)

AVR单片机的TWI总线的原理及应用

AVR单片机的TWI总线的原理及应用
O。其中参数command为命令字节,data为要写入的数据。
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模块的使用方法

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单片机与传感器基础第九章

	 AVR单片机与传感器基础第九章
• 式中,TWBR 为TWI 比特率寄存器TWBR 中的数值;TWPS 为TWI 状态寄存器TWSR 中的预分频数值;fCPU 为CPU 时钟频率。
上一页 下一页 返回
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通信接口在广播机微控制器中的应用

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 引 言本微控制器是基于单片机的计算机控制系统,它能对广播发射机的工作状态进行在线监控和检测,实时采集发射机的各个参数(模拟量、开关量),进行处理分析后,及时地发出控制指示信号。

ATmega16 _TWI主从机

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 到总线上。

AVR与AT24C256I2C程序(TWI)

AVR与AT24C256I2C程序(TWI)

/*调试通过2013020224c256连续读取多个数据.多写,可单读单写*/#include <avr/io.h>#include <avr/delay.h>//数据类型预定义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<<TWEN))//#define I2CStop() (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))#define I2CWaitAck() {while(!(TWCR&(1<<TWINT)));}#define I2CChkAck() (TWSR&0xf8) //check ack#define I2CSendAck() (TWCR|=(1<<TWEA))#define I2CSendNoAck() (TWCR&=~(1<<TWEA))#define I2CSendByte(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}#define I2CRcvNckByte() (TWCR=(1<<TWINT)|(1<<TWEN))#define I2CRcvAckByte() (TWCR=(1<<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/NACKif((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=0x40return 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 )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;for (i=0;i<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 )return 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,INT8U rdDAdr,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++)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//0x14,0x1a,0x1b,0x1c,0x1d,0x1e};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//0x14,0x1a,0x1b,0x1c,0x1d,0x1e};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);}}。

相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
TWCR=(1<<TWSTO)|TW_ACT; //发送停止信号,不会再产生中断了
strTWI.STATUS=TW_OK;
//启动写命令后需要10ms(最大)的编程时间才能真正的把数据记录下来
//编程期间器件不响应任何命令
}
}
else
{//写数据失败
state=ST_FAIL;
}
break;
default:
//AT24C02的读写函数(包括随机读,连续读,字节写,页写)
//根据sla的最低位决定(由中断程序中判断)
//bit0=1 TW_READ读
//bit0=0 TW_WRITE写
// sla器件地址(不能搞错)
// addr EEPROM地址(0~1023)
// *ptr读写数据缓冲区
// len读数据长度(1~1024),写数据长度(1 or 8 or 16)
***********************************************/
/*
本程序简单的示范了如何使用ATMEGA16的TWI读写AT24C02 IIC EEPROM
TWI协议
(即IIC协议,请认真参考IIC协议的内容,否则根本就不能掌握)
一主多从的应用,M16作主机
(M16做从机和多主多从的应用不多,请自行参考相关文档)
#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
{//TWI忙,不能进行操作
return OP_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;
if(status==TW_MR_SLA_ACK)
{//发送器件地址成功
if (strTWI.DATALEN--)
{//多个数据
TWCR=(1<<TWEA)|TW_ACT; //设定ACK,触发下一步动作
}
else
{//只有一个数据
TWCR=TW_ACT; //设定NAK,触发下一步动作
}
}
else
struct str_TWI //TWI数据结构
{
volatile unsigned char STATUS; //TWI_操作状态
unsigned char SLA; //从设备的器件地址
unsigned int ADDR; //从设备的数据地址
unsigned char *pBUF; //数据缓冲区指针
//bit0=0 TW_WRITE写
虽然中断服务程序很长,但每次只执行一个case,所以耗时并不长。
*/
SIGNAL(SIG_2WIRE_SERIAL)
{//IIC中断
unsigned char action,state,status;
action=strTWI.SLA&TW_READ; //取操作模式
#define ST_WADDR 3 //ADDR状态检查
//TWI读操作步骤
#define ST_RESTART 4 //RESTART状态检查
#define ST_SLAR 5 //SLAR状态检查
#define ST_RDATA 6 //读取数据状态检查,循环n字节
//TWI写操作步骤
#define ST_WDATA 7 //写数据状态检查,循环n字节
(大部分IIC接口器件都是这种类型,常见的例如AT24C01/02/04/08/16,DS1307,DS1721等)
对于有两个字节数据地址的IIC器件(例如AT24C32/64/128/256等大容量EEPROM),请稍作改动
//根据strTWI.SLA的最低位决定
//bit0=1 TW_READ读
strTWI.DATALEN--;
state=ST_WDATA-1; //下一步将跳到WDATA分支
TWCR=TW_ACT; //触发下一步动作
}
}
else
{//发送eeprom地址出错
state=ST_FAIL;
}
break;
case ST_RESTART: //RESTART状态检查,只有读操作模式才能跳到这里
#define TWBR_SET 10; //TWBR必须大于等于10
#else
#define TWBR_SET (F_CPU/fSCL-16)/2; //计算TWBR值
#endif
#define TW_ACT (1<<TWINT)|(1<<TWEN)|(1<<TWIE)
//TWCR只能IN/OUT,直接赋值比逻辑运算(|= &=)更节省空间
if(status==TW_REP_START)
{//发送restart信号成功
TWDR=strTWI.SLA; //发器件地址读SLAR
TWCR=TW_ACT; //触发下一步动作,同时清start发送标志
}
else
{//重发start信号出错
state=ST_FAIL;
}
break;
case ST_SLAR: //SLAR状态检查,只有读操作模式才能跳到这里
*/
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
//时钟定为外部晶振7.3728MHz,F_CPU=7372800
#include <compat/twi.h>
//定义了各种模式下的状态码列表(TWSR已屏蔽预分频位),本文后面附上中文描述
//错误状态
state=ST_FAIL;
break;
}
if (state==ST_FAIL)
{//错误处理
strTWI.FAILCNT++;
if (strTWI.FAILCNT<FAIL_MAX)
*strTWI.pBUF++=TWDR;
TWCR=(1<<TWSTO)|TW_ACT; //发送停止信号,不会再产生中断了
strTWI.STATUS=TW_OK;
}
else
{//读取数据出错
state=ST_FAIL;
}
break;
case ST_WDATA: //写数据状态检查,只有写操作模式才能跳到这里
//管脚定义
#define pinSCL 0 //PC0 SCL
#define pinSDA 1 //PC1 SDA
//为保险起见,最好在SCL/SDA接上1~10K的外部上拉电阻到VCC。
#define fSCL 100000 //TWI时钟为100KHz
//预分频系数=1(TWPS=0)
#if F_CPU < fSCL*36
//返回值是否能执行当前操作
unsigned char TWI_RW(unsigned char sla,unsigned int addr,unsigned char *ptr,unsigned int len)
{
unsigned char i;
if (strTWI.STATUS==TW_BUSY)
中断模式
(因为AVR的速度很高,而IIC的速度相对较低,
采用查询模式会长时间独占CPU,令CPU的利用率明显下降。
特别是IIC速度受环境影响只能低速通讯时,对系统的实时性产生严重的影响。
查询模式可以参考其它文档和软件模拟IIC的文档)
AT24C02/04/08的操作特点
出于简化程序考虑,各种数据没有对外输出,学习时建议使用JTAG ICE硬件仿真器
if(status==TW_START)
{//发送start信号成功
TWDR=strTWI.SLA&0xFE; //发送器件地址写SLAW
TWCR=TW_ACT; //触发下一步动作,同时清start发送标志
}
else
{//发送start信号出错
state=ST_FAIL;
}
break;
case ST_SLAW: //SLAW状态检查
#define TW_OK 1
#define TW_FAIL 2
//Tபைடு நூலகம்I_读写命令状态
#define OP_BUSY 0
#define OP_RUN 1
//TWI读写操作公共步骤
#define ST_FAIL 0 //出错状态
#define ST_START 1 //START状态检查
#define ST_SLAW 2 //SLAW状态检查
state--; //循环,直到写完指定长度数据
if(status==TW_MT_DATA_ACK)
{//写数据成功
if (strTWI.DATALEN)
{//还要写
TWDR=*strTWI.pBUF++;
相关文档
最新文档