AVR学习笔记九基于AT24C16的数据存储实验.docx

上传人:b****7 文档编号:9071502 上传时间:2023-02-03 格式:DOCX 页数:29 大小:255.99KB
下载 相关 举报
AVR学习笔记九基于AT24C16的数据存储实验.docx_第1页
第1页 / 共29页
AVR学习笔记九基于AT24C16的数据存储实验.docx_第2页
第2页 / 共29页
AVR学习笔记九基于AT24C16的数据存储实验.docx_第3页
第3页 / 共29页
AVR学习笔记九基于AT24C16的数据存储实验.docx_第4页
第4页 / 共29页
AVR学习笔记九基于AT24C16的数据存储实验.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

AVR学习笔记九基于AT24C16的数据存储实验.docx

《AVR学习笔记九基于AT24C16的数据存储实验.docx》由会员分享,可在线阅读,更多相关《AVR学习笔记九基于AT24C16的数据存储实验.docx(29页珍藏版)》请在冰豆网上搜索。

AVR学习笔记九基于AT24C16的数据存储实验.docx

AVR学习笔记九基于AT24C16的数据存储实验

Ema{@AVR学习笔记九、基于AT24C16的数据存储实验

-------基于LT_Mini_M16

9.1用I/O口模拟I2C总线实现AT24C16的读写

9.1.1、实例功能

I2C总线(InterIntegrateCircuitBUS)全称为芯片间总线,是Philips公司推出的一种双向二进制总线。

它在芯片间以两根连线实现全双工同步数据传送,一条数据线(SDA)和一条串行时钟线(SCL),可以很方便的构成外围器件扩展系统。

I2C总线协议允许总线介入多个期间,总线上的器件既可以作为主控制器也可以作为被控制器,既可以是发送器,也可以是接收器。

I2C总线在进行数据交换时,作为主控制器的器件需要通过总线竞争获得主控权,然后才可以启动数据传输。

系统中每个器件都具有唯一的芯片地址,数据传输时通过寻址可以确定数据接收方。

I2C总线自从出现以后,得到了广泛应用。

I2C总线结构简单,可靠性和抗干扰性好,可构成各种通用的硬件和软件模块。

方便重复利用,大大简化了系统的设计过程。

I2C总线的实现有两种方法:

一、软件模拟I2C通信协议实现数据传输,二、利用硬件I2C接口实现数据传输。

ATmega16单片机集成了硬件I2C模块,称为TWI接口,TWI电路结构简单,只占用两个I/O口,可以实现多个器件共享一条总线,使用比较方便,系统也很简洁。

AVR单片机用硬件实现了这种总线的时序,省去了很多编程工作。

只要控制相关的寄存器,就可以实现通过TWI总线传输数据。

但是使用硬件I2C接口的缺点是接口固定,在特定的系统里面,会增加硬件和软件设计的复杂程度。

在本例中我们采用模拟I2C总线时序的方法实现I2C通信。

软件模拟I2C时序的方法增加了软件的复杂程度,但是方便了硬件设计,模拟I2C接口可以使用单片机的如何普通I/O口。

本节首先介绍I2C总线的的一些基本知识:

特点、结构、原理、控制时序、与单片机的接口方法等。

最后通过一个实例实现模拟I2C接口。

本实例分为三个功能模块,分别描述如下:

●单片机系统:

利用ATmega16单片机与AT24C16实现数据传输,利用模拟I2C总线接口的方法读写AT24C16。

●外围电路:

外围电路分两部分:

LED显示部分(用于指示从AT24C16中读取的数值正确与否)、AT24C16接口电路电路(实现模拟I2C总线功能)。

●软件程序:

编写软件,实现对AT24C16的数据读写。

通过本实例的学习,掌握以下内容:

●理解AT24C16的特点、结构和原理和接口设计方法。

●掌握AT24C16的控制时序和控制方法流程。

●掌握模拟I2C总线的设计方法。

9.1.2器件和原理

1、I2C总线介绍

AT24C16的外形级封装和引脚说明如图9.1.1。

图9.1.1AT24C16的外形封装和引脚说明

I2C总线协议规定,任何将数据传送到总线的器件作为发送器。

任何从总线接收数据的器件为接收器。

主器件控制串行时钟和起始、停止信号的发生。

主器件何从期间都可以发送或接收数据,但是主器件控制数据传送模式(发送或者接收)。

通过器件地址输入端A0、A1、A2可以实现讲最多8个at24c01器件和a424c02器件、4个at24c04器件、2个at24c08器件、1个at24c16器件连接到总线上。

当总线上只有一个器件时,A0、A1、A2可以连接到地或者悬空。

WP写保护引脚:

当该引脚连接到VCC,I2C器件内的内容被写保护(只能读)。

如果允许对器件进行正常的读写,那么WP引脚需连接到地或者悬空。

2、I2C总线接口

I2C总线的信号线有两种:

●时钟线SCL。

●数据线SDA。

SCL和SDA都是双向总线,I2C总线为同步传输串行总线结构,及总线上的数据信号完全与时钟同步。

数据传输采用主从方式:

主器件寻址从器件,启动总线数据传输,并产生时钟脉冲。

总线传输中的所有状态及操作都有相应的编码,主器件依照这些协议编码自动地进行总线控制与管理。

从器件接收主器件的请求并应答。

数据传输结束后,主器件将总线释放。

当总线空闲时,SCL和SDA均为高电平。

连接到总线上的器件的输出端口必须是漏极开路,任一器件输出低电平时,总线信号变低。

即总线SCL和SDA上的信号都是线“与”的关系。

由于SDA和SCL的端口输出都是漏极开路,因此总线上必须连接上拉电阻。

上拉电阻的大小与电源电压、传输速率等有关系。

当传输速率为100KHz时,上拉电阻一般采用10K,对于400KHz的传输速率,上拉电阻可以采用2K欧姆。

9.1.3、I2C总线的寻址方式

I2C总线上的器件都是共用总线的,因此,主器件在进行数据传输前必须选择需要通信的从器件。

即进行总线寻址。

I2C总线上所有外围器件都有唯一的地址,这个地址由器件地址和引脚地址两部分组成。

共7位。

器件地址是I2C器件固有的地址编码,器件出厂时已经给定,不可更改。

引脚地址由I2C总线外围器件的地址引脚A0、A1、A2决定,根据其在电路中接电源正极、接地或者悬空的不同,形成不同的地址代码。

引脚地址数也决定了同一器件可接入总线的最大数目。

地址位与一个方向位共同构成I2C总线器件寻址字节。

寻址字节的格式如图所示;方向位(R/W)规定了总线上主器件与外围器件(从器件)的数据传输方向。

当方向位R/W=1时,表示主器件读取从器件的数据;R/W=0时,表示主器件向从器件发送数据。

9.1.4、I2C总线的数据传输协议

I2C总线的数据传输遵循严格的时序格式,下面分别介绍数据传输过程中的格式。

1、起始信号、终止信号

在时钟线SCL为高电平期间,数据线SDA上出现高电平向低电平变化的下降沿时,被认为是起始信号。

起始信号出现以后,后面才可以进行寻址或数据传输等。

在时钟信号SCL高电平期间,数据线SDA上出现由低电平到高电平变化的上升沿时,被认为是终止信号。

终止信号一出现,所有总线操作都结束,主器件释放总线控制权。

起始信号、终止信号的时序如下图所示。

2、数据读写

当SCL为高电平期间,SDA上的数据必须保持不变,如果此时SDA上的电平发生变化,则会被认为是起始或者终止信号。

只有在SCL为低电平期间,SDA上的数据才能发生变化。

所以在进行读取SDA上的数据时,必须使SCL处于低电平。

3、总线数据位

每次发送到I2C总线SDA上的数据必须是一个字节,传输的数据字节按照由高位到低位的顺序发送。

在I2C总先启动后或应答信号后的第1-8个时钟脉冲,对应于要传送字节的8位数据。

I2C总线上的数据是伴随着时钟脉冲,一位一位的传送的,每位数据占一个时钟脉冲。

在时钟线SCL高电平期间,数据线SDA的状态就表示要传送的数据,高电平为数据1,低电平为数据0.在数据传送时,数据线上数据的变化在时钟线为低电平时完成;而时钟线为高电平时,数据线必须保持稳定,否则数据线上的任何变化都被当成起始或者终止信号,从而导致数据传输停止。

4、应答信号、非应答信号

I2C总线数据传送时,每传送一个字节数据后都必须有应答信号。

应答信号由主器件产生。

主器件在第9个时钟位上释放数据总线,使其处于高电平状态,此时从器件输出低电平拉低数据线产生应答信号。

在传送完一个字节数据后,在第9个时钟位上,从器件输出高电平为非应答信号。

非应答信号的产生有两种情况:

●当从器件正在进行其他处理而无法接收总线上的数据时,从器件不产生应答,此时从器件释放总线,将数据线置为高电平。

这样,主器件可产生一个停止信号来终止总线传输数据。

●当主器件接收来自从器件的数据时,接收到最后一个字节数据后,必须给从器件发送一个非应答信号,使从器件释放数据总线。

这样,主器件才可以发送终止信号,从而终止数据传送。

5、数据传送格式

I2C总线协议规定了完整的数据传送格式。

按照协议规定,数据的传输以主器件发送起始信号开始,然后发送寻址从器件的寻址字节。

寻址字节共8位,前7位为被寻址的从器件(对于AT24C16来说,由于总线上只能连接1个AT24C16,所以对AT24C16的寻址字节,高4位固定为1010,1-3位则是其内部页地址的高3位),第0位是方向位。

在寻址字节后面跟着操作地址,操作地址指明了对被寻址器件内部的某一位或某几位进行操作。

操作地址之后跟的就是要传输的数据了,数据传输结束后,主器件发送一个终止信号以释放总线控制权。

数据可以单字节传输,也可以多字节传输,如果主器件希望继续占用总线,则可以不发送停止信号,马上再次发送起始信号,便可以进行新的操作。

9.1.5AT24C16的内部数据存储结构

AT24C16内部有2048*8位的存储容量,即可以存储2K字节的数据。

这2K字节被放在128个页内,每页存放16个字节。

所以对AT24C16内部的访问需要11位地址(0-7ff)。

对AT24C16访问时,按照页地址和页偏移量的方式进行访问。

比如要访问第100页的第3个字节,则在发送寻址的时候,就要发送0X0643,其中页地址的高三位放在器件地址中。

所以在编写程序对AT24C16第100页的第3个字节进行写数据的时候,步骤如下:

1)发送起始信号;2)发送器件地址0XA6(10100110,1010是固定地址,011是页地址的高三位,0表示写操作);3)发送操作地址0X43(01000011,0100是页地址的低四位,0011是页地址偏移量,即第100页内的第三个字节,4)发送要写的数据,5)发送终止信号。

  

  

9.1.6、电路和连接

LED发光二极管电路已经在第一个实例中介绍过,本例中不再重复。

本例中AT24C16与单片机的连接如图9.1.2所示,由于AT24C16的数据线、时钟线要求空闲状态为高电平,所以我在AT24C16的数据线和时钟线上分别加了4.7K的上拉电阻,如果不想接上拉电阻的话,可以使能PA2口的内部上拉功能,但是程序设计会有些不同。

AT24C16的数据线SDA、时钟线SCL分别连到单片机的PC1、PC0口。

图9.1.2AT24C16电路

7.1.4、程序设计

1、程序功能

程序的功能是使用单片机的PC1、PC0口的模拟I2C总线时序实现对AT24C16的数据读写操作,然后用LED的亮灭指示读取数据的正确性。

2函数说明

本程序多个功能函数,分别是:

●AT24C16操作相关函数:

voidI2C_Init(void);//I2C端口初始化

unsignedcharI2C_Start(void);//发送起始信号

voidI2C_Stop(void);//发送结束信号

unsignedcharI2C_WriteByte(unsignedchardat);//写一个字节

unsignedcharI2C_ReadByte(unsignedcharack);//读一个字节

unsignedcharEEPROM_ReadByte(unsignedintadd);//从固定地址读一字节

voidEEPROM_WriteByte(unsignedintadd,unsignedchardata);//向固定地址写一字节●延时相关函数:

voidDelayus(unsignedintlus);//us延时函数

voidDelayms(unsignedintlms);//ms延时函数

由于WINAVR自带函数库中的延时函数使用起来很不方便,并且晶振频率不同,延时时间也有区别,所以本实例中自己写了两个延时函数。

3、使用WINAVR开发环境,使用的是外部12M的晶振,所以需要将makefile文件中的时钟频率修改为12M。

另外在程序烧录到单片机的时候,熔丝位也要选择为外部12M晶振(注意是晶振,不是外部振荡器,一定不要选择错了,否则会导致单片机不能再烧写程序)。

4、程序说明。

在本实例中我们首先了解了I2C总线的原理和特点,用模拟I2C总线接口的方式实现了对AT24C16的读写操作。

5、程序代码

#include//io端口寄存器配置文件,必须包含

#include

//端口声明

/*注:

AVR单片机I/O口模拟I2C总线时建议在外部连接上拉电阻,这样可通过改变I/O口输入输出方向的方式

来设置高低电平,输出口保持不变(0),此时如DDRX寄存器为1则变成输出0,若DDRX为0,则I/O口

呈现高阻状态,但因外部的上拉电阻,总线相当于设置高电平,即通过设置DDRX的方式控制总线的高低

*/

#defineSCL_INPUT(DDRC&=~(1<

#defineSCL_OUTPUT(DDRC|=(1<

#defineSCL_LOW(PORTC&=~(1<

#defineSCL_HIGH(PORTC|=(1<

#defineSCL_INDATA(PINC&(1<

#defineSDA_INPUT(DDRC&=~(1<

#defineSDA_OUTPUT(DDRC|=(1<

#defineSDA_LOW(PORTC&=~(1<

#defineSDA_HIGH(PORTC|=(1<

#defineSDA_INDATA(PINC&(1<

//变量声明

#defineEEPROM_BUS_ADDRESS0xa0//器件地址

//函数声明

voidDelayus(unsignedintlus);//us延时函数

voidDelayms(unsignedintlms);//ms延时函数

voidI2C_Init(void);//I2C端口初始化

unsignedcharI2C_Start(void);//发送起始信号

voidI2C_Stop(void);//发送结束信号

unsignedcharI2C_WriteByte(unsignedchardat);//写一个字节

unsignedcharI2C_ReadByte(unsignedcharack);//读一个字节

unsignedcharEEPROM_ReadByte(unsignedintadd);//从固定地址读一字节

voidEEPROM_WriteByte(unsignedintadd,unsignedchardata);//向固定地址写一字节

intmain(void)//GCC中main文件必须为返回整形值的函数,没有参数

{

unsignedchari;

PORTB=0x00;

DDRB=0xFF;//端口PortB设为输出口,通过相应位LED的变化指示程序运行结果

I2C_Init();//I2C端口初始化

EEPROM_WriteByte(0x01aa,0x5a);

//向固定地址写一字节,向第26页的第十个字节写入数据0x5a

i=EEPROM_ReadByte(0x01aa);//从固定地址读一字节

if(i==0x5a)

{

PORTB|=0x01;//读出的数据正确,则LED0点亮

}

else

{

PORTB|=0x02;//读出的数据不正确,则LED1点亮

}

while

(1)

{

}

}

//I2C初始化函数

voidI2C_Init(void)

{

SCL_LOW;//SCL的PORT状态锁定为0,以后不再改变

SCL_INPUT;//SCL设置为输入口

SDA_LOW;//SDA的PORT状态锁定为0,以后不再改变

SDA_INPUT;//SDA设置为输入口

Delayus(10);

}

//I2C起始条件

unsignedcharI2C_Start(void)

{

Delayus(10);

SDA_INPUT;//SDA高电平

Delayus(10);//延时一段时间,使单片机时钟频率符合I2C时钟

SCL_INPUT;//SCL高电平

Delayus(10);

SDA_OUTPUT;//SDA变低,产生由高到低的变化

Delayus(10);

SCL_OUTPUT;//SCL变低,占用总线

Delayus(10);

return1;

}

//I2C结束条件

voidI2C_Stop(void)

{

Delayus(10);

SDA_OUTPUT;//SDA低电平

Delayus(10);

SCL_INPUT;//SCL高电平

Delayus(10);

SDA_INPUT;//SDA变为高电平,产生由低到高的变化

Delayus(10);

}

//向I2C写一个字节

unsignedcharI2C_WriteByte(unsignedchardat)

{

unsignedchari,ack;//ack为应答信号

for(i=0;i<8;i++)//写8位(1个字节)数据

{

if(dat&0x80)//写入数据,左移,从最高位写入

{

SDA_INPUT;//如果该位为1,SDA拉高电平

}

else

{

SDA_OUTPUT;//如果该位为0,SDA拉低电平

}

SCL_INPUT;//SCL高电平,保持数据

Delayus(10);

SCL_OUTPUT;//SCL低电平,数据被送入I2C

dat<<=1;//需要写入的数据左移一位,送最高位

Delayus(10);//

}

Delayus(10);

SDA_INPUT;//SDA拉高,同时变为输入口

Delayus(10);

SCL_INPUT;//SCL拉高,准备读取应答信号

Delayus(10);

if(SDA_INDATA)

{

ack=0;//如果此时SDA为高,说明没有应答信号

PORTB|=0x04;//没有应答信号,点亮LED2

}

else

{

ack=1;//如果此时SDA为低,说明有应答信号

PORTB|=0x08;//有应答信号,点亮LED3

}

SCL_OUTPUT;//SCL拉低

Delayus(10);

returnack;//返回应答信号

}

//从I2C读一个字节

unsignedcharI2C_ReadByte(unsignedcharack)

{

unsignedchari,dat=0;//dat为读出的数据

SDA_INPUT;//SDA变为输入口

for(i=0;i<8;i++)//读出8位(1个字节)数据

{

Delayus(10);

SCL_OUTPUT;//SCL低,这时允许从I2C发送数据到SDA上

Delayus(10);

SCL_INPUT;//SCL高,准备读取SDA上的数据

Delayus(10);

dat<<=1;//读取的数据左移一位,从最高位读起

if(SDA_INDATA)

{

dat++;//如果DSA为高,则读取的数据加1

}

Delayus(10);

}

SCL_OUTPUT;//SCL拉低,准备下一个数据变化

Delayus(10);

if(!

ack)//

{

SDA_INPUT;//发送NACK

}

else

{

SDA_OUTPUT;//发送ACK

}

Delayus(10);

SCL_INPUT;//SCL高

Delayus(10);

SCL_OUTPUT;//SCL低

Delayus(10);

return(dat);//返回读到的数据

}

//从固定地址读一字节

unsignedcharEEPROM_ReadByte(unsignedintadd)

{

unsignedchardata;

I2C_Start();//发送起始信号

I2C_WriteByte(EEPROM_BUS_ADDRESS|((add>>8)<<1));

//写器件地址和页地址的高3位

I2C_WriteByte(add);//写页地址的低4位和页地址内部偏移量

I2C_Start();//发送起始信号

I2C_WriteByte(EEPROM_BUS_ADDRESS|0x01);//发送读命令

data=I2C_ReadByte(0);//读一个字节

I2C_Stop();//发送结束信号

returndata;

}

//向固定地址写一字节

voidEEPROM_WriteByte(unsignedintadd,unsignedchardata)

{

I2C_Start();//发送起始信号

I2C_WriteByte(EEPROM_BUS_ADDRESS|((add>>8)<<1));

//写器件地址和页地址的高3位

I2C_WriteByte(add);//写页地址的低4位和页地址内部偏移量

I2C_WriteByte(data);//写一个字节数据

I2C_Stop();//发送结束信号

Delayms(10);

}

//us级别的延时函数

voidDelayus(unsignedintlus)

{

while(lus--)

{

_delay_loop_2(3);

//_delay_loop_2

(1)是延时4个时钟周期,参数为3则延时12

//个时钟周期,本实验用12M晶体,则12个时钟周期为12/12=1us

}

}

//ms级别的延时函数

voidDelayms(unsignedintlms)

{

while(lms--)

{

Delayus(1000);//延时1ms

}

}

 

9.2基于硬件接口的AT24C02的读写实验

9.2.1、实例功能

AVR单片机提供了实现标准2先串行总线通信TWI(兼容I2C总线)硬件接口。

其主要性能和特点有:

●简单,但是强大而灵活的串行通信接口,只需要两根线;

●支持主机和从机操作;

●器件可以作为发送器,也可以作为接收器;

●7位地址空间,最大允许有128个从机;

●支持多主机模式;

●最高可达400K的数据传输率;

●全可编程的从机地址

●地址监听中断可以是A

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

当前位置:首页 > 工程科技 > 能源化工

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

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