基于两线串行TWI技术实现两个ATmega16单片机通信
TWI,IIC总线

采用串行总线技术可以使系统的硬件设计大大简
化、系统的体积减小、可靠性提高。同时,系统 的更改和扩充极为容易。 常用的串行扩展总线有: I2C (Inter IC BUS) 总线、单总线(1-WIRE BUS)、SPI(Serial Peripheral Interface)总线及Microwire/PLUS 等。
c、在传送过程中,当需要改变传送方向时, 起始信号和从机地址都被重复产生一次,但两 次读/写方向位正好反相。
4、总线的寻址
I2C总线协议有明确的规定:采用7位的寻址字节 (寻址字节是起始信号后的第一个字节)。 (1)寻址字节的位定义
D7~D1位组成从机的地址。D0位是数据传送方向位, 为“0”时表示主机向从机写数据,为“1”时表示主机由从 机读数据。
每一个字节必须保证是8位长度。数据传送时,先传 送最高位(MSB),每一个被传送的字节后面都必须跟 随一位应答位(即一帧共有9位)。
由于某种原因从机不对主机寻址信号应答时(如从机 正在进行实时性的处理工作而无法接收总线上的数据), 它必须将数据线置于高电平,而由主机产生一个终止信号 以结束总线的数据传送。 如果从机对主机进行了应答,但在数据传送一段时间后 无法继续接收更多的数据时,从机可以通过对无法接收的 第一个数据字节的“非应答”通知主机,主机则应发出终 止信号以结束数据的继续传送。 当主机接收数据时,它收到最后一个数据字节后,必须 向从机发出一个结束传送的信号。这个信号是由对从机的 “非应答”来实现的。然后,从机释放SDA线,以允许主 机产生终止信号。
两线串行总线概述
两线串行总线采用TWI协议。对外只有两根线。一根数据线SDA,一根时 钟线SCL。可与128个从设备连接。连接方式如图所示:
基于ATmega16单片机的通用电机控制装置的设计

Vol.12No.7July.2010第12卷第7期2010年7月收稿日期:2010-03-05*资助项目:西南石油大学科技基金项目(2007XJZ110)。
doi:10.3969/j.issn.1563-4795.2010.07.001新特器件应用0引言电机的驱动与控制是现代电子技术中一个重要的研究课题,不同种类的电动机需要有不同的控制和驱动方法。
使用高性能单片机作为电机控制驱动装置的核心,可以有效降低电机驱动器的成本,扩展应用范围,提高使用灵活性。
ATmega16单片机是ATMEL 公司的一款高性能8位AVR 单片机,它内部带有功能强大的可编程定时和计数单元,通过编程可以很容易地产生各类交、直流电机以及步进电机的驱动波形,因此,利用这类功能强大的单片机作为电机控制器的核心,可以使控制器应用更加灵活、应用范围更广、维护成本更低。
本文设计出的电机通用控制装置功能齐全,其液晶显示装置和按键可以控制并显示电机的运行状态,而数字化的温度传感器则能有效准确地监控电机的运行温度,RS485/232总线通信接口可以将多个控制器进行联网,从而实现电机的智能化远程控制。
1电机控制及驱动电路设计图1所示是一种通用电机控制装置系统的总体结构图。
其整个单片机系统以ATmega16单片机为控制核心,其中从单片机和主单片机利用I 2C总线进行通信。
从单片机连接按键和液晶屏,可以实现人机接口的功能,这样即可以为主单片机节约宝贵的I/O 资源,又可以提高系统的运行效率。
另外,DS18B20采用单总线结构采集温度,可以实现对电机温度的监控。
1.1ATmega16主控电路ATmega16单片机具有3个PWM 功能的定时器/计数器T/C0、T/C1和T/C2,其中T/C0和T/C2是两个8位的定时器/计数器,而T/C1是16位具有输入捕获功能的定时器/计数器。
本系统的主控单片机电路如图2所示,它以mega16单片机为核心,配有外围复位电路和振荡器电路,单片机所有I/O 都可独立引出,以便与外部电路的连接和扩展。
两片单片机之间的串行通信(proteus仿真图+程序)

两片单片机之间的串行通信(proteus仿真图+程序)两片单片机之间的串行通信(仿真图+程序)AT89C51+MAX232功能:(1)甲机P1口的开关控制乙机P1口的发光二级管,开关闭合发光二级管亮,开关断开发光二级管灭。
(2)乙机P2口的开关控制甲机P2口的数码管,按下4*4矩阵键盘,显示对应的键值0~F (3)乙机P0^0口的开关控制甲机P2口的数码管,按下按键,数码管从0~9循环显示;乙机P0^2口的开关控制甲机P2口的数码管,按下按键,数码管清零。
/****************************甲机控制与接收*********************************/ #include#include#define uchar unsigned char#define uint unsigned intsbit K0=P1^0;sbit K1=P1^1;sbit K2=P1^2;sbit K3=P1^3;sbit K4=P1^4;sbit K5=P1^5;sbit K6=P1^6;sbit K7=P1^7;uchar i;uchar code tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71}; void delay(uint z){ uint x,y;for(x=z;x>0;x--)for(y=110;y<0;y--);}void send(uchar c) //向串口发送字符{ SBUF=c;while(TI==0);TI=0;}void main(){ uchar i;P2=0x00;SCON=0x50; //串口模式1TMOD=0x20; //T1工作模式2PCON=0x00; //波特率不倍增TH1=0xfd; //波特率设定6900TL1=0xfd;TI=RI=0;TR1=1; //启动定时器T1IE=0x90; //允许串口中断while(1){ if(K0==0) send('0'); else send('A');if(K1==0) send('1'); else send('B');if(K2==0) send('2'); else send('C');if(K3==0) send('3'); else send('D');if(K4==0) send('4'); else send('E');if(K5==0) send('5'); else send('F');if(K6==0) send('6'); else send('G');if(K7==0) send('7'); else send('H');}}void serial_int() interrupt 4 //甲机串口接收中断函数{ if(RI){ RI=0;if(SBUF>=0 &&SBUF<=15)P2=tab[SBUF];elseP2=0x00;if(SBUF=='x')if(i>=0&&i<9){i=i+1;P2=tab[i];}if(i==9) i=0;if(SBUF=='y'){P2=0x00;i=0;}}}/*****************************乙机控制与接收程序*****************************/ #include#include#define uchar unsigned char#define uint unsigned intsbit L0=P1^0;sbit L1=P1^1;sbit L2=P1^2;sbit L3=P1^3;sbit L4=P1^4;sbit L5=P1^5;sbit L6=P1^6;sbit L7=P1^7;sbit KEY1=P0^0;sbit KEY2=P0^2;void delay(uint z){ uint x,y;for(x=z;x>0;x--)for(y=110;y<0;y--);}void send(uchar c) //向串口发送字符{ SBUF=c;while(TI==0);TI=0;}uchar key() //按键扫描{ uchar keyon,temp;P2=0x0f;delay(1);temp=P2^0x0f;switch(temp){ case 1:keyon=3;break;case 2:keyon=2;break;case 4:keyon=1;break;case 8:keyon=0;break;default:keyon=16;}P2=0xf0;delay(1);temp=P2>>4^0x0f;switch(temp){ case 1:keyon+=0;break;case 2:keyon+=4;break;case 4:keyon+=8;break;case 8:keyon+=12;break;}return keyon;}void main(){ SCON=0x50; //串口模式1,允许接收TMOD=0x20; //T1 工作模式2PCON=0x00; //波特率不倍增TH1=0xfd; //波特率设定: 9600TL1=0xfd;TI=RI=0;TR1=1; //启动定时器T1IE=0x90; //允许串口中断delay(100);while(1){ P2=0xf0; //矩阵键盘if(P2!=0xf0)send(key());if(KEY1==1) //独立按键{ delay(20);if(KEY1==0)send('x');}if(KEY2==0) //清零send('y');}}void serial_int() interrupt 4 //乙机串口接收中断函数{ if(RI) { RI=0;switch(SBUF){ case '0':L0=0;break;case '1':L1=0;break;case '2':L2=0;break;case '3':L3=0;break;case '4':L4=0;break;case '5':L5=0;break;case '6':L6=0;break;case '7':L7=0;break;case 'A':L0=1;break;case 'B':L1=1;break;case 'C':L2=1;break;case 'D':L3=1;break;case 'E':L4=1;break;case 'F':L5=1;break;case 'G':L6=1;break;case 'H':L7=1;break;}}}。
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*/。
基于I_2C总线的单主多从单片机之间的通信

作者在程序流程的每个关键部分都设置了错误查询和错 误处理,使得 I2C 程序能够从错误中自动恢复,避免了由于 I2C 通信导致的错误而使得系统无法正常工作,文中还给出了部分 发送子程序和编程注意事项。对于图 2 和图 3 的 I2C 通信流 程,作者已在多个科研项目中进行了编程使用。实践证明,按上 述流程编写 I2C 通信程序,主从单片机之间的通信非常可靠。
技
1 引言
随着单片机控制系统的不断扩大以及控制功能不断增多, 有限的单个单片机通用 I/O 口已不能满足同一系统中控制多个 受控对象需要,随着 I2C 总线研究的深入,用 I2C 总线扩展单片 机 I/O 口的方法在全自动、半自动仪器的开发领域得到了广泛 应用,本文介绍了一个测试系统通过 I2C 总线扩展 I/O 口实现 了系统的多个功能。给出了系统的硬件连接以及 Atmega128 与 三个 Atmega168 之间的软件通信流程图。
2 系统的硬件结构
图 1 是作者所研究的测试系统的整体框图,本系统中主要 芯片 PHILIPS 公司的 LPC2292,在此系统中键盘上其中三个按 钮分别控制三个电机,系统的主要功能是 LPC2292 将扫描到的 键盘信息发给 Atmega128 单片机,Atmega128 单片机通过 I2C 总线寻址 Atmega168,并向被寻址的 Atmega168 发送电机控制 命令,最后,电机根据 Atmega168 控制策略正常运行。电机启动 同时,数据采集模块也开始正常运行,数据采集模块把采到数 据送到 LPC2292 的 A/D 转换接口,然后将 ADC 输出的数据发 送到 LCD。系统中的拨码开关用于设置相应的 Atmega168 单片 机的地址,当单片机 Atmega128 接收到 LPC2292 发来的控制命 令时,通过 I2C 总线寻址 Atmega168,当某个 Atmega168 的地址 与 Atmega128 广播地址相同时,它就开始根据 Atmega128 发送 的命令控制电机开始工作。
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单片机项目十二 ATmega16单片机I2C通信接口应用

【任务1】 项目知识点学习 二、I2C总线的协议
3、I2C总线的仲裁
图12-3 I2C总线的仲裁过程
【任务1】 项目知识点学习 二、I2C总线的协议
4、I2C总线的数据传输
图12-4 I2C总线的数据传输过程
【任务1】 项目知识点学习 二、I2C总线的协议
4、I2C总线的数据传输
图12-5 I2C总线的数据传输格式图
【任务1】 项目知识点学习 三、时钟芯片PCF8563的相关知识
3、时钟芯片PCF8563的基本原理及内部寄存器概述
所有16个寄存器设计成可寻址的8位并行寄存器,但不 是所有位都有用。前两个寄存器(内存地址00H,01H ) 用于控制寄存器和状态寄存器,内存地址02H~08H用于 时钟计数器(秒~年计数器),地址09H~0CH用于报警 寄存器(定义报警条件),地址0DH控制CLKOUT管脚的 输出频率,地址0EH 和0FH分别用于定时器控制寄存器和 定时器寄存器。秒、分钟、小时、日、月、年、分钟报警 、小时报警、日报警寄存器,编码格式为BCD,星期和星 期报警寄存器不以BCD格式编码。
单片机应用技术
项目十二
ATmega16单片机I2C通信接口应用
【知识目标】
掌握SPI串行通信协议 了解ATmega16单片机SPI串行通信接口结构 了解与SPI串行通信有关的寄存器的功能 了解TLC5615D/A芯片
【能力目标】 掌握ATmega16单片机的I2C串行通信接口相关寄 存器的配置方法 掌握PCF8563无线通信模块方法 掌握简单的单片机I2C串行通信总线系统程序的编 写、调试方法
【任务1】 项目知识点学习 三、时钟芯片PCF8563的相关知识
1、时钟芯片PCF8563概述 PCF8563 是PHILIPS 公司推出的一款工业级内含I2C 总线接口功能的具有极低功耗的多功能时钟/日历芯片。具 有多种报警功能、定时器功能、时钟输出功能以及中断输 出功能能完成各种复杂的定时服务,甚至可为单片机提供 看门狗功能。内部时钟电路内部振荡电路、内部低电压检 测电路1.0V 以及两线制I2C 总线通讯方式,不但使外围电 路及其简洁,而且也增加了芯片的可靠性。同时每次读写 数据后,内嵌的字地址寄存器会自动产生增量。当然作为 时钟芯片,亦解决了2000 年问题。已被广泛用于电表、水 表、电话、便携式仪器及电池供电的仪器仪表等产品领域。
基于AVR单片机--Atmega16的串口通信使用

基于AVR单片机--Atmega16的串口通信使用//以下程序经验正可以用,MCU:M16,晶振:8M,直接用USB转串口线上的公头(针头),//第2针(RXD)接M16上的PD1口(15脚TXD),第3针(TXD)接M16上的PD0口(14脚RXD),//第5针接地,此时若板上有MAX232,则需把MAX232芯片去掉,这样才能正常工作#include<avr/io.h>#include<avr/interrupt.h>#define uchar unsigned char#define uint unsigned int#define fosc 8000000//晶振频率#define BAUD 9600 //波特率void USART_send(uchar date)//发送一个字节{while(!(UCSRA&(1<<UDRE)));//等待USART数据寄存器为空,UDRE为1说明缓冲器为空,已准备好进行数据接收或发送UDR=date;//发送数据}void init(){DDRB=0xff;//设置PB口为输出PORTB&=~(_BV(PB4)|_BV(PB5)|_BV(PB6)|_BV(PB7));//让高4位的LED灭//波特率寄存器设置UBRRH=(fosc/BAUD/16-1)/256;UBRRL=(fosc/BAUD/16-1)%256;//UCSRB|=_BV(RXEN)|_BV(TXEN)|_BV(RXCIE);UCSRB|=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE);//使能发送,接收,接收完成中断sei();//开全局中断}int main(){init();USART_send('d');//发送数据'd'while(1);}volatile char date1;SIGNAL(SIG_UART_RECV){date1=UDR;//接收数据PORTB=date1;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于两线串行TWI技术实现两个ATmega16单片机通信靳宝强摘 要:AVR ATmega16单片机提供了实现标准两线串行总线通信的硬件接口TWI,该接口是面向字节和基于中断的。
通过一条数据线(SDA)和一条时钟线(SCL),按照TWI通信协议进行寻址和信息传输。
本文将具体介绍一种利用TWI技术实现两个ATmega16单片机通信的方法,该方法编程简单、实现可靠,非常具有推广和使用价值。
关键词:两线串行TWI接口;ATmega16单片机;控制寄存器;状态寄存器0 引言AVR ATmega 系列单片机片内集成两线串行接口TWI模块。
采用TWI协议,设计者可通过两根双向总线,即一根时钟线SCL和一根数据线SDA,连接128个从设备。
实现总线连接时唯一需要增加的外部设备是每条总线上的上拉电阻,见图1。
所有与总线相连的设备都需要定义各自的设备地址号。
实际上,TWI接口时序与常见的I2C总线是兼容的。
因此,只需要控制相关寄存器,就能实现通过TWI传输数据,这在很大程度上减少了工作量,从而使编程简单,开发更容易。
图1 TWI总线连接1 TWI 模块概述1.1 SCL和SDA引脚这两个引脚功能是和普通I/0复用的,当开始使用TWI接口传输数据时,硬件会覆盖原来对这两个引脚的I/O设置,自己控制输入/输出的方向。
由于总线需要上拉电阻,结合AVR I/0端口功能,在TWI 使能时可设置SCL 和SDA 引脚对应的I/O 口内部上拉电阻有效,这样可省去外部两个上拉电阻。
同时引脚输入部分还配有毛刺抑制单元,可去除高频干扰。
1.2 波特率发生器TWI工作在主控器模式下时,由该单元控制产生时钟信号并驱动时钟线SCL。
时钟SCL的周期由TWI状态寄存器TWSR中的预分频位和TWI波特率寄存器TWBR来确定。
当TWI工作在被控器模式下时,不需要对波特率和预分频进行设定,但要求作为被控器,其CPU的时钟频率必须大于TWI时钟线SCL频率的16倍。
SCL时钟频率依据以下等式产生:其中:TWBR为TWI波特率寄存器的值;TWPS为TWI状态寄存器TWSR中的预分频位的值。
在主机模式下,TWBR的值应大于10,否则会产生不正确的输出。
1.3 总线接口单元该单元包括:数据和地址移位寄存器TWDR,起始/终止信号(START/STOP)控制和总线仲裁判定的硬件电路。
TWDR寄存器用于存放传送或接收的数据和地址。
总线单元还有一个寄存器,含有用于传送或接收的应答信号——ACK/NACK,这个应答ACK/NACK的寄存器不能由程序直接读写。
当接收数据时,它可以通过TWI控制寄存器TWCR来置位或清零。
在发送数据时,ACK/NACK值由TWI状态寄存器TWSR的设置决定。
起始/终止信号(START/STOP)控制电路负责TWI总线上的START,REPEATED START和STOP逻辑时序的发生和检测。
1.4 地址匹配单元地址匹配单元将检测从总线上收到的地址是否与TWAR寄存器中的7位地址相匹配,一旦匹配成功,将通知控制单元转入适当的操作状态。
当TWI被设置为被控接收或被控发送器时,在TWAR中应设置被控器的寻址地址。
而TWI在主控器模式下,不需要设置TWAR。
TWAR寄存器的最低位用作通用呼叫识别位,置位时,将使能对TWI总线上所有设备地址的呼叫;清零时,只对地址匹配设备进行呼叫。
1.5 控制单元控制单元一直监视TWI总线,并根据TWI控制寄存器TWCR的设置做出相应的响应。
当在TWI总线上产生需要的中断事件时,先对TWI的中断标志位TWINT进行相应设置,在下一个时钟周期时,将表示事件的状态字写入TWI状态寄存器TWSR。
在其它情况下,TWSR中的内容为一个表示无事件发生的状态字。
一旦TWINT标志位置位,就会将时钟线SCL拉低,暂停TWI总线上的传送,执行用户中断处理程序。
在执行中断处理程序时,TWINT标志位不会由硬件自动清零,必须通过由软件给该位写入逻辑“1”来清零。
每次只有在TWINT标志位清零后才能重新开始对TWI总线的操作。
本篇将以AVR公司ATmega16芯片为例来说明TWI 接口的工作过程并介绍一种利用两线串行TWI技术实现两个ATmega16单片机通信的方法。
2 TWI总线的使用AVR ATmega 硬件TWI 接口是面向字节和基于中断的,相对软件模拟I2C总线有更好的实时性和代码效率。
在TWI双向总线上ATmega16 芯片既可扮演主控制器(主控模式)也能扮演从器件(被控模式)的角色。
不论主控模式还是被控模式都应将TWI 控制寄存器TWCR 的TWEN 位置位,从而使能TWI 模块。
TWEN 位被置位后I/O 引脚PC0 和PC1被转换成SCL 和SDA,该管脚上的斜率限制和毛刺滤波器时用类似如下的操作使能该管脚上的内部上拉电阻:DDRC&=0XF0;PORTC|=0X03;对TWI 控制寄存器TWCR 的操作可在总线上产生START ,STOP 信号和ACK应答信号,从一个START 到STOP 被认为是主控模式的行为,之后将进行寻址过程。
寻址过程通过主控制器发送一定格式的寻址命令进行。
寻址命令由7位从控制器地址、1位读/写标志构成。
格式如图2。
图2 寻址命令结构其中:SLA为TWI从控制器地址寄存器TWAR高7位地址字;R/W为1执行读操作,为0执行写操作。
将TWI 地址寄存器TWAR 的第一位TWGCE 置有效,同时将TWI 控制寄存器TWCR 的TWEA(应答允许)位置1,TWI 模块就可以对总线上对它的寻址做出应答,完成信息的发送或接收,并设置状态字。
对总线的操作或总线上产生事件后用户程序应当根据TWI 状态寄存器TWSR的值来确定下一步的操作。
TWI总线上的器件,根据用户不同使用状况,可分为主控发送器(MT)、主控接收器(MR)、被控发送器(ST)、被控接收器(SR)四种工作模式。
在实际应用中,器件的工作状态可根据需要进行转换。
关于不同模式下TWSR 状态值的详细描述请参考ATmega16 的数据手册。
在AVR编程软件中, AVR\twi.h文件定义了状态字的常量和一个返回状态字的宏。
3 利用两线串行TWI技术实现两个 ATmega16单片机通信下面以两个ATmega16单片机芯片相互通信为例,来具体介绍一种TWI总线通信的实现方法。
两个ATmega16单片机芯片硬件连接电路如图3所示。
图3 两个ATmega16单片机连接电路图工作要求:U1作为主控器件既要向U2发送一个字的数据,又要从U2接收一个字的数据;而U2作为被控器件既要接收U1发来的一个字的数据,同时也要向U1发送一个字的数据。
因此,U1将工作在主控发送和主控接收模式,U2将工作在被控接收和被控发送模式。
在应用程序中,主控器件U1 TWI通信将采用查询方式实现;被控器件U2 TWI通信将采用中断方式实现。
3.1 主控器件U1 C语言程序说明文件名:myprog1.c#include <avr/twi.h>#define SLA_W 0x04 //写从机寻址命令#define SLA_R 0x05 //读从机寻址命令#define fosc 8000000 //晶振8MHZ#define baud 9600 //波特率初始化部分:DDRC&=0XF0; //0b1111 0000 PC1,PC0定义为输入口PORTC|=0X03;//0b0000 0011 定义PC0,PC1为TWI引脚有内部上拉电阻TWBR=12; //用于设置TWI总线的SCL时钟频率先给出主控器件U1应用程序的工作时序图4。
图4 主控器U1 TWI总线工作时序图步骤1: 先执行主控器发送工作模式。
TWI 发送START信号。
通过对TWCR写入A4H,启动TWI硬件发送START信号,执行步骤2。
步骤2: 轮循等待TWINT置位,TWINT置位表示START信号已发出。
应用程序应检验状态寄存器TWSR的状态码,确定 TWSR=O8H 。
如果状态码等于08H,应用程序必须将SLA+W 载入TWDR。
TWDR载入SLA+W后,TWCR必须写入84H,清零TWINT,启动TWI 硬件发送SLA+W信号,执行步骤3。
步骤3: 轮循等待TWINT置位,TWINT置位表示寻址命令SLA+W已发出,以及收到被控器发出的应答信号ACK/NACK。
应用程序应检验状态寄存器TWSR的状态码,确定TWSR=18H/20H,如果状态码等于18H,则装入发送数据到TWDR数据寄存器,TWCR必须写入84H,清零TWINT,启动发送数据,执行步骤4。
步骤4: 轮循等待TWINT置位,TWINT置位表示总线数据DATA已发出,以及收到被控器发出的应答信号ACK/NACK。
应用程序应检验状态寄存器TWSR的状态码,确定TWSR=28H/30H,如果状态码等于28H,则应用程序需判断所发数据是否到最后一个数据,如不到最后一个数据,则再次装入下一个发送数据到TWDR数据寄存器,TWCR必须写入84H,清零TWINT,启动发送数据,继续执行步骤4;如到最后一个数据,则装入最后一个数据到TWDR数据寄存器,TWCR必须写入84H,清零TWINT,启动发送数据,执行步骤5。
步骤5: 轮循等待TWINT置位,TWINT置位表示总线数据DATA已发出,以及收到被控器发出的应答信号ACK/NACK。
应用程序应检验状态寄存器TWSR的状态码,确定TWSR=28H/30H,如果状态码等于30H,则主控器不再发送数据,此时TWCR必须写入A4H,清零TWINT,重新发送START信号,执行步骤6,进入主控器接收工作模式。
步骤6: 轮循等待TWINT置位,TWINT置位表示RE-PEATED START信号已发出。
应用程序应检验状态寄存器TWSR的状态码,确定 TWSR=10H 。
如果状态码等于10H,应用程序必须将SLA+R 载入TWDR。
TWDR载入SLA+R后,TWCR必须写入C4H,清零TWINT,启动TWI 硬件发送SLA+R信号,执行步骤7。
步骤7: 轮循等待TWINT置位,TWINT置位表示寻址命令SLA+R已发出,以及收到被控器发出的应答信号ACK/NACK。
应用程序应检验状态寄存器TWSR的状态码,确定TWSR=40H/48H,如果状态码等于40H,则TWCR必须写入C4H,清零TWINT,启动读取数据,执行步骤8。
步骤8: 轮循等待TWINT置位,TWINT置位表示总线数据DATA已收到,以及已向被控器发出应答信号ACK/NACK。
应用程序应检验状态寄存器TWSR的状态码,确定TWSR=50H/58H,如果状态码等于50H,则应用程序先读取数据到TWDR数据寄存器,然后再判断所收数据是否到最后一个数据,如不到最后一个数据,则准备读取下一个数据到TWDR数据寄存器,此时TWCR必须写入C4H,清零TWINT,启动接收数据,继续执行步骤8。