单片机模拟I2C总线及AT24C01应用实例(格式整理版)
实验八 51系列单片机IIC
I2C总线上的所有器件连接在一个公共的总线上,因此,主器件在进行数据传输前选择需要通信的从器件,即进行总线寻址。 I2C总线上所有外围器件都需要有惟一的地址,由器件地址和引脚地址两部分组成,共7位。器件地址是I2C器件固有的地址编码,器件出厂时就已经给定,不可更改。引脚地址是由I2C总线外围器件的地址引脚(A2,A1,A0)决定,根据其在电路中接电源正极、接地或悬空的不同,形成不同的地址代码。引脚地址数也决定了同一种器件可接入总线的最大数目。 地址位与一个方向位共同构成I2C总线器件寻址字节。寻址字节的格式如表所示。方向位(R/)规定了总线上的主器件与外围器件(从器件)的数据传输送方向。当方向位R/=1,表示主器件读取从器件中的数据;R/=0,表示主器件向从器件发送数据。
从地址中读取一个字节的数据
INT8U read_random(INT8U RomAddress) { INT8U Read_data; I_Start(); I_Write8Bit(WriteDeviceAddress); I_TestAck(); I_Write8Bit(RomAddress); I_TestAck(); I_Start(); I_Write8Bit(ReadDeviceAddress); I_TestAck(); Read_data=I_Read8Bit(); I_NoAck(); I_Stop(); return (Read_data); }
8.4.1 串行EEPROM存储器简介
串行EEPROM存储器是一种采用串行总线的存储器,这类存储器具有体积小、功耗低、允许工作电压范围宽等特点。目前,单片机系统中使用较多的EEPROM芯片是24系列串行EEPROM。其具有型号多、容量大、支持I2C总线协议、占用单片机I/O端口少,芯片扩展方便、读写简单等优点。 目前,Atmel、MicroChip、National等公司均提供各种型号的I2C总线接口的串行EEPROM存储器。下面以Atmel公司的产品为例进行介绍。 AT24C01/02/04/08系列是Atmel公司典型的I2C串行总线的EEPROM。这里以AT24C08为例介绍。AT24C08具有1024×8位的存储容量,工作于从器件模式,可重复擦写100万次,数据可以掉电保存100年。8引脚DIP封装的AT24C08的封装结构,如图所示。
I2C总线AT24C01读写程序(汇编和C)
NOP
NOP
MOV C,SDA
RLC A
CLR SCL
DJNZ B,I2C_RECEIVE8IT_A
RET
C语言写的24C01 单字节读写程序
LCALL I2C_SEND8BIT
LCALL I2C_ACK
JC I2C_READ_A ;=1,表示无确认,再次发送
MOV A,Address
LCALL I2C_SEND8BIT
LCALL I2C_ACK
unsigned char i2c_read(unsigned char Address)
{
unsigned char c;
do{
i2c_start();
i2c_send8bit(0xA0);
}while(i2c_ack()); //=1,表示无确认,再次发送
; 24C01存储器I2C总线实验 汇编语言例子
; =======================================================
SDA EQU P2.0
SCL EQU P2.1
i2c_write(地址,数据),写一个字节
=======================================================*/
void i2c_write(unsigned char Address,unsigned char Data)
{
do{
I2C总线AT24C01读写程序(汇编和C)
--------------------------------------------------------------------------------
单片机模拟I2C总线及AT24C01应用实例(格式整理版)
单片机模拟I2C总线及AT24C01应用实例(格式整理版) I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。
例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
1.I2C总线特点I2C总线最主要的优点是其简单性和有效性。
由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。
I2C总线的另一个优点是,它支持多主控(multimastering),其中任何能够进行发送和接收的设备都可以成为主总线。
一个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有一个主控。
2.I2C总线工作原理2.1总线的构成及信号类型I2C总线是一种串行数据总线,只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。
2.2位的传输SDA线上的数据必须在时钟的高电平周期保持稳定数据线的高或低电平状态只有在SCL 线的时钟信号是低电平时才能改变,见图1:图12.3开始信号SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
I2C总线原理及应用实例
I2C总线原理及应用实例I2C总线是一种串行通信总线,全称为Inter-Integrated Circuit,是Philips(飞利浦)公司在1982年推出的一种通信协议。
它可以用于连接各种集成电路(Integrated Circuits,ICs),如处理器、传感器、存储器等。
I2C总线的原理是基于主从架构。
主设备(Master)负责生成时钟信号,并发送和接收数据,从设备(Slave)通过地址识别和响应主设备的命令。
I2C总线使用两根线来传输数据,一根是时钟线(SCL),用于主设备生成的时钟信号;另一根是数据线(SDA),用于双向传输数据。
1. 主设备发送起始位(Start)信号,将SDA线从高电平拉低;然后通过SCL线发送时钟信号,用于同步通信。
2.主设备发送从设备的地址,从设备通过地址识别确定是否响应。
3.主设备发送要传输的数据到从设备,从设备响应确认信号。
4. 主设备可以继续发送数据,或者发送停止位(Stop)信号结束通信。
停止位是将SDA线从低电平拉高。
1.温度监测器:I2C总线可以连接到温度传感器上,通过读取传感器的输出数据,进行温度的监测和控制。
主设备可以设置警报阈值,当温度超过阈值时,可以触发相应的措施。
2.显示屏:很多智能设备上的显示屏都采用了I2C总线,如液晶显示屏(LCD)或有机发光二极管(OLED)等。
主设备通过I2C总线发送要显示的信息,并控制显示效果,如亮度、对比度、清晰度等参数。
3.扩展存储器:I2C总线可以用于连接外部存储器,如电子存储器(EEPROM)。
通过I2C总线,可以读取和写入存储器中的数据,实现数据的存储和传输。
4.触摸屏控制器:许多触摸屏控制器也使用了I2C总线,主要用于将触摸信号传输给主设备,并接收主设备的命令。
通过I2C总线,可以实现对触摸屏的操作,如单击、滑动、缩放等。
5.电源管理器:一些电源管理器也采用了I2C总线,用于控制和监测电池电量、充电状态、电压、电流等参数。
用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);
串行i2c总线e2prom at24cxxx的应用.
9.串行I2C总线E2PROM AT24CXXX的应用这一篇介绍I2C存储器的使用。
主要是介绍AT24CXX系列器件,它分为两类,主要是通过被存储容量地址来分的,一类是AT24C02-AT24C16,它的存储容量从256字节到2048字节。
另一类是AT24C32-AT24C1024,容量从4K-128K。
(理论上好像可以达到最高512K字节容量,但现在网上最高也就能看到AT24C1024也就是128K字节容量)原理:I2C总线是一种用于IC器件之间连接的二线制总线。
它通过SDA(串行数据线)及SCL(串行时钟线)两根线在连到总线上的器件之间传送信息,并根据地址识别每个器件:不管是单片机、存储器、LCD驱动器还是键盘接口。
I2C总线接口电路结构如图所示。
SDA和SCL均为双向I/O线,通过上拉电阻接正电源。
当总线空闲时,两根线都是高电平。
连接总线的器件的输出级必须是集电极或漏极开路,以具有线“与”功能。
I2C总线的数据传送速率在标准工作方式下为100kbit/s,在快速方式下,最高传送速率可达400kbit/s。
在I2C总线技术规范中,开始和结束信号(也称启动和停止信号)的定义如图所示。
当时钟线SCL为高电平时,数据线SDA由高电平跳变为低电平定义为“开始”信号;当SCL 线为高电平时,SDA线发生低电平到高电平的跳变为“结束”信号。
开始和结束信号都是由主器件产生。
在开始信号以后,总线即被认为处于忙状态;在结束信号以后的一段时间内,总线被认为是空闲的。
I2C总线的数据传送格式是:在I2C总线开始信号后,送出的第一个字节数据是用来选择从器件地址的,其中4-7位为器件码,如1010就是代表串行E2PROM器件。
1-3位为存储器的片选地址或存储器内的块地址码,如何区分?后面再做详细说明,第8位为方向位(R/W)。
方向位为“0”表示发送,即主器件把信息写到所选择的从器件;方向位为“1”表示主器件将从从器件读信息。
单片机模拟I2C总线读写EEPROM(24CXX)程序一
单片机模拟I2C总线读写EEPROM(24CXX)程序一下面是一个最简单的读写程序,可以用来检测线路状况。
先附上程序和电路,后面附有说明。
电路:说明:P2 口的LED 都是我用来检测电路执行到哪一步的,个人觉得一目了然。
程序:#include #define unit unsigned int#define uchar unsigned charint ok;sbit scl=P0;sbit sda=P0;sb it led0=P2;sbit led1=P2;sb it led2=P2 ;sbit led3=P2;sb it led4=P2;sb it led5=P2 ;sbit led6=P2;sb it led7=P2;delay(void) //delay{ int i; led1=1; for(i=0;istart(void) //start{ sda=1; scl=1; delay(); sda=0; delay(); scl=0; led0=0;}stop(void) //stop{ sda=0; scl=1; delay(); sda=1; delay(); scl=0;}checkanswer(void) //check answer{ sda=1; scl=1; if(sda==1) { F0=1; led7=0; } scl=0; led3=0;}sendabyte(int temps) //send a byte{ uchar n=8; while(n--) { led2=1; if((temps&0x80)==0x80){ sda=1; scl=1; delay(); scl=0;}else{ sda=0; scl=1; delay(); scl=0;}temps=tempsreciveabyte() //recive a byte{ uchar n=8,tempr; while(n--) {//uchar idata *abyte scl=1;tempr=temprmain(void) //MAIN{start();sendabyte(0xa0);checkanswer();if(F0==1) return;sendabyte(0x00);checkanswer();if(F0==1) return;sendabyte(0x11);checkanswer();if(F0==1) return;/*-----------------------*/start(); sendabyte(0xa0);checkanswer();if(F0==1) return;。
51单片机模拟I2C总线的C语言实现
51单片机模拟I2C总线的C语言实现电路原理图EEPROM为ATMEL公司的AT24C01A。
单片机为ATMEL公司的AT89C51。
软件说明C语言为Franklin C V3.2。
将源程序另存为testi2c.c,用命令C51 testi2c.cL51 TESTI2C.OBJOHS51 TESTI2C编译,连接,得到TESTI2C.HEX文件,即可由编程器读入并进行写片,实验。
3.源程序#include <reg51.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define AddWr 0xa0 /*器件地址选择及写标志*/#define AddRd 0xa1 /*器件地址选择及读标志*/#define Hidden 0x0e /*显示器的消隐码*//*有关全局变量*/sbit Sda= P3^7; /*串行数据*/sbit Scl= P3^6; /*串行时钟*/sbit WP= P3^5; /*硬件写保护*/void mDelay(uchar j){ uint i;for(;j>0;j--){ for(i=0;i<125;i--){;}}}/*发送起始条件*/void Start(void) /*起始条件*/{Sda=1;Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Sda=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();}void Stop(void) /*停止条件*/{Sda=0;Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Sda=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();}void Ack(void) /*应答位*/ {Sda=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=0;}void NoAck(void) /*反向应答位*/{Sda=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=0;}void Send(uchar Data) /*发送数据子程序,Data为要求发送的数据*/ {uchar BitCounter=8; /*位数控制*/uchar temp; /*中间变量控制*/do{temp=Data;Scl=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();if((temp&0x80)==0x80)/* 如果最高位是1*/Sda=1;elseSda=0;Scl=1;temp=Data<<1; /*RLC*/Data=temp;BitCounter--;}while(BitCounter);Scl=0;}uchar Read(void) /*读一个字节的数据,并返回该字节值*/ {uchar temp=0;uchar temp1=0;uchar BitCounter=8;Sda=1;do{Scl=0;_nop_ ();_nop_ ();_nop_ ();_nop_ ();Scl=1;_nop_ ();_nop_ ();_nop_ ();_nop_ ();if(Sda) /*如果Sda=1;*/temp=temp|0x01; /*temp的最低位置1*/elsetemp=temp&0xfe; /*否则temp的最低位清0*/ if(BitCounter-1){ temp1=temp<<1;temp=temp1;}BitCounter--;}while(BitCounter);return(temp);}void WrToROM(uchar Data[],uchar Address,uchar Num) {uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start(); /*发送启动信号*/Send(0xa0); /*发送SLA+W*/Ack();Send(Address+i); /*发送地址*/Ack();Send(*(PData+i));Ack();Stop();mDelay(20);}}void RdFromROM(uchar Data[],uchar Address,uchar Num) {uchar i;uchar *PData;PData=Data;for(i=0;i<Num;i++){Start();Send(0xa0);Ack();Send(Address+i);Ack();Start();Send(0xa1);Ack();*(PData+i)=Read();Scl=0;NoAck();Stop();}}void main(){uchar Number[4]={1,2,3,4};WP= 1;WrToROM(Number,4,4); /*将初始化后的数值写入EEPROM*/mDelay(20);Number[0]=0;Number[1]=0;Number[2]=0;Number[3]=0; /*将数组中的值清掉,以验证读出的数是否正确*/RdFromROM(Number,4,4);}问题:本程序中未采用块读写的方法,显得有点‘笨’,这是由于项目原因,现项目已完成,程序已写好,短时不会修改,也不会花上一定的精力去做,虽然理论上已很成熟,就这样写一下,未必不对,但与我的本栏目要求不符,所以就未做上去,如果以后我做了,将再补上。
I2C总线编程实例(k1-k4:写入、读取、加+、清零)【EEPROM-AT24C02】
I2C总线编程实例(k1-k4:写⼊、读取、加+、清零)【EEPROM-AT24C02】(1)AT24C02是⼀种EEPROM元器件,是⼀种只读寄存器,断电保持,可保存数据100年, 是⼀种可擦除读写的芯⽚,相当于ROM硬盘,在下⾯实验中充当从机⾓⾊;(2)51在下⾯实验中充当主机⾓⾊;(3)在IIC总线标准协议上,进⾏51单⽚机(主机)和AT24C02(从机)的相互读写数据的操作。
⼩结:51单⽚机和各种EEPROM芯⽚之间可以通过IIC总线标准协议进⾏数据交互(通信)的。
实验:四个独⽴按键对应四个不同的功能,k1:将数据写⼊单⽚机,断电保存k2:读取上次保存的数据,断电后仍可读取上次保存的数据k3:当前数据+1k4:当前数据清零------------------------------------------------------------- 采⽤多⽂件的框架模式 -------------------------------------------------------------i2c.h:/*这个⽂件进⾏宏定义:定义I2C串⾏总线的相关数据端⼝、⽅法函数,以及定义⼀些使⽤频率较⾼的元素*/#ifndef _I2C_H_ // 如果没有定义宏#define _I2C_H_ // 定义⼀个宏// 需要⽤到51单⽚机的管脚,所以需要引⼊库⽂件#include <reg52.h>// 查单⽚机原理图可知(其中,SCL是时钟线,SDA是数据线)sbit SCL=P2^1;sbit SDA=P2^0;/* 相关函数 */// I2C的起始信号函数void I2cStart();// I2C的终⽌信号函数void I2cStop();// I2C发送(写⼊)字节函数,成功返回1,失败返回0unsigned char I2cSendByte(unsigned char dat);// I2C接收(读取)字节函数,返回读取的数据unsigned char I2cReadByte();// AT24C02芯⽚的写⼊数据函数void At24c02Write(unsigned char addr, unsigned dat);// AT24C02芯⽚的读取数据函数,返回读取的数据unsigned char At24c02Read(unsigned char addr);#endif // 结束i2c.c:/* 这个⽂件专门针对I2C模块的编程,其他模块可以新建另外⼀个⽂件 */#include <i2c.h> // 引⼊I2C的库⽂件/******************************************************************************** 函数名 : Delay10us()* 函数功能 : 延时10us* 输⼊ : ⽆* 输出 : ⽆*******************************************************************************/void Delay10us() //误差 0usunsigned char a,b;for(b=1;b>0;b--)for(a=2;a>0;a--);}/******************************************************************************** 函数名 : I2cStart()* 函数功能 : 起始信号:在SCL时钟信号在⾼电平期间SDA信号产⽣⼀个下降沿* 输⼊ : ⽆* 输出 : ⽆* 备注 : 起始之后SDA和SCL都为0,表⽰总线被主机占⽤*******************************************************************************/void I2cStart(){// 根据各个单⽚机的时序图来写SDA=1;Delay10us();SCL=1;Delay10us(); // 建⽴时间是SDA保持时间>4.7usSDA=0;Delay10us(); // 保持时间是>4usSCL=0;Delay10us();}/******************************************************************************** 函数名 : I2cStop()* 函数功能 : 终⽌信号:在SCL时钟信号⾼电平期间SDA信号产⽣⼀个上升沿* 输⼊ : ⽆* 输出 : ⽆* 备注 : 结束之后保持SDA和SCL都为1;表⽰总线处于空闲状态*******************************************************************************/void I2cStop(){// 根据各个单⽚机的时序图来写SDA=0;Delay10us();SCL=1;Delay10us(); // 建⽴时间是SDA保持时间>4.7usSDA=1;Delay10us(); // 保持时间是>4us}/******************************************************************************** 函数名 : I2cSendByte(unsigned char dat)* 函数功能 : 通过I2C发送⼀个字节。
以AT24C02为例介绍I2C总线与单片机的连接
DB 0,0,0,0,0
RET
;;===================================================================
RD24C021:
MOV R3,#1
ACALL STR_24C021 ;I2C 总线开始信号
NoAck: DJNZ R6,WaitLoop
SETB C ;NO ACK
CLR A24C_SCL
RET
;;===================================================================
MOV R1,#30H ;要利用的是间址
MOV A,#0
INPUT1: Байду номын сангаасOV @R1,A
INC A
INC R1
DJNZ R2,INPUT1
RD_ACK: ;发送应答信号
DB 0,0,0,0
SETB A24C_SCL
DB 0,0,0,0,0,0
CLR A24C_SCL
DB 0,0,0,0
CLR F0
CLR A24C_SDA
RET
;===================================================================
SJMP $
;名称:STR_24C021
;描述:启动I2C总线子程序-发送I2C起始条件
;--------------------------------------------------------------------
IC卡24C01资料
I2C总线器件应用单片机应用系统正向小型化、高可靠性、低功耗等方向发展。
在一些设计功能较多的系统中,常需扩展多个外围接口器件。
若采用传统的并行扩展方式,将占用较多的系统资源,且硬件电路复杂,成本高、功耗大、可靠性差。
为此,Philips公司推出了一种高效、可靠、方便的串行扩展总线—I2C总线。
单片机系统采用I2C总线后将大大简化电路结构,增加硬件的灵活性,缩短产品开发周期,降低成本,提高系统可靠性。
I2C总线(Inter IC BUS)是Philips推出的芯片间串行传输总线。
它以两根连线实现了完善的全双工同步数据传送,可以极方便地构成多机系统和外围器件扩展系统。
I2C总线采用了器件地址的硬件设置方法,通过软件寻址完全避免了器件的片选线寻址方法,从而使硬件系统具有最简单而灵活的扩展方法。
第一节I2C总线器件应用概述一、I2C总线器件目前许多单片机厂商引进了Philips公司的I2C总线技术,推出了许多带有I2C总线接口的单片机。
Philips公司除了生产具有I2C总线接口的单片机外,还推出了许多具备I2C总线的外部接口芯片,如24XX系列的E2PROM 、128字节的静态RAM芯片PCF8571、日历时钟芯片PCF8563、4位LED驱动芯片SAA1064、160段LCD驱动芯片PCF8576等多种类多系列接口芯片。
二、I2C总线工作原理采用I2C总线系统结构如图7-1所示。
图7-1 I2C总线系统结构图其中,SCL是时钟线,SDA是数据线。
总线上的各器件都采用漏极开路结构与总线相连,因此,SCL、SDA均需接上拉电阻,总线在空闭状态下均保持高电平。
I2C总线支持多主和主从两种工作方式,通常为主从工作方式。
在主从工作方式中,系统中只有一个主器件(单片机),总线上其它器件都是具有I2C总线的外围从器件。
在主从工作方式中,主器件启动数据的发送(发出启动信号),产生时钟信号,发出停止信号。
为了实现通信,每个从器件均有唯一一个器件地址,具体地址由I2C总线委员会分配。
51单片机模拟iic总线协议使用EEPROM器件AT24C02
51单片机软件实现iic总线的工作时序所用EEPROM芯片AT24C02,实现向AT24C02中写入数据,然后将其中数据读出赋予P0口,实现流水灯的按数据亮灭,PS:附MCU图,AT24C02图于最后。
嘤其鸣矣,求其友声如若不弃,加我QQ:2447104957,高山流水,共同学习!#include <reg51.h>#define uchar unsigned char#define uint unsigned intsbit sda=P2^0;sbit scl=P2^1;//mcu原理图void delay(){;;}//微秒延时void init() //初始化,释放总线各线至高电平,SCL=0时,SDA可以改变{scl=0;delay();//微秒延时sda=1;delay();scl=1;delay();}void start() //起始信号{scl=0;delay();sda=1;delay();scl=1;delay();sda=0;delay();sda=1;//释放数据总线}void write_byte(uchar date)//字节写{uchar i,temp;temp=date;//由高位一位一位的写入for(i=0;i<8;i++)temp=temp<<1;//左移溢出到PSW寄存器CY位scl=0;//允许sda进行的变化delay();sda=CY;//进行一位一位的送入数据总线delay();scl=1;//符合读走数据总线上数据的要求delay();//稳定一段时间}scl=0;//允许sda变化,以便于接受应答信号delay();sda=1;//释放数据总线,准备接收应答信号delay();}void response()//应答,可以看书page181,由接收设备发出的第九位数据,要经由sda传输给发送设备{uchar i;scl=1;delay();while((sda==1)&&(i<250)){i++;//等待应答有一定的时间限制,sda被拉低表示有应答,由硬件控制}scl=0;delay();}void stop()//停止信号,scl=1,sda形成一个正跳变{scl=0;//允许sda变化delay();sda=0;//准备形成正跳变delay();scl=1;//信号有效前提1delay();sda=1;//形成正跳变delay();//信号有效前提1}void delay1(uint z)//毫秒级延时{for(x=z;x>0;x--)for(y=110;y>0;y--);}uchar read_byte()//带有返回值,将所读到的数据作为返回值{uchar i,d;//d=0x00;//清空存储变量的空间for(i=0;i<8;i++){scl=0;//允许变化,即允许传送数据,sda是serial dual date busdelay();scl=1;//允许读走数据delay();d=(d<<1)|sda;//将sda上数据放入存储变量d,也是8位ucharscl=0;delay();}return d;/*scl=0;delay();sda=1;//释放数据总线,准备接受应答,被拉低delay();*/}void main(){init();//初始化//例子先写入EEPROM器件AT24C16数据,然后进行读取赋予流水灯是对应数据亮灭start();//起始信号write_byte(0xa0);/*写入EEPROM器件地址,写入分为数据,地址数据,地址又分为器件地址和内部存储地址,例如某班级某学生座位*/response();//等待应答write_byte(0x03);//内部存储地址response();write_byte(0x55);//写入真正意义上的数据response();//等待应答stop();//停止读取数据信号delay1(500);//毫秒延时//第一部分结束,写入EEPROM器件AT24C16数据start();write_byte(0xa0);//申明所读器件地址response();write_byte(0x03);//申明该器件中所要求读数据的位置response();start();write_byte(0xa1);response();P0=read_byte();//进行读数据操作后,非应答,budaixingcan,而是将返回值直接赋予变量stop();//第二部分内容;读即操作理解为,主机对器件写;告诉从机我要对你进行读操作,所以先写,后读while(1);//将程序终止于此}。
I2C总线上接两个AT24C02读写实例
I2C总线上接两个AT24C02读写实例、本例对I2C总线上关节两个AT24C02进行读写操作,想将数据0xaa写入第一个at24c02的指定地址,再将该数据读出后存入第二个AT24C02的指定地址,最后读出该数据并送P1口用8位LED显示验证2、实现方法:1)两个器件地址的确定由于第一个AT24C02的3位地址位(A0A1A2)均接地(低电平),第二个AT24C02的三个地址位(A0A1A2)均接电源(高电平),因此第一个AT24C02的地址为000,第二个AT24C02的地址为111.在写命令时,指名要操作的器件地址,即可对不同的AT24C02进行操作3、在keil c51中新建工程ex54,编写如下程序代码,编译并生成ex54.hex文件//对I2C总线上挂接多个AT24C02的读写操作#include <reg51.h> // 包含51单片机寄存器定义的头文件#include <intrins.h> //包含_nop_()函数定义的头文件#define OP_READ1 0xa1 // 器件1地址以及读取操作,0xa1即为1010 0001B#define OP_WRITE1 0xa0 // 器件1地址以及写入操作,0xa1即为1010 0000B#define OP_READ2 0xaf // 器件2地址以及读取操作,0xa1即为1010 1111B#define OP_WRITE2 0xae // 器件2地址以及写入操作,0xa1即为1010 1110B页脚内容1sbit SDA=P3^4; //将串行数据总线SDA位定义在为P3.4引脚sbit SCL=P3^3; //将串行时钟总线SDA位定义在为P3.3引脚/***************************************************** 函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/ void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++);}/***************************************************** 函数功能:延时若干毫秒入口参数:n***************************************************/页脚内容2void delaynms(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/*************************************************** 函数功能:开始数据传送***************************************************/ void start()// 开始位{SDA = 1; //SDA初始化为高电平“1”SCL = 1; //开始数据传送时,要求SCL为高电平“1”_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SDA = 0; //SDA的下降沿被认为是开始信号页脚内容3_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递) _nop_(); //等待一个机器周期}/***************************************************函数功能:结束数据传送***************************************************/void stop()// 停止位{SDA = 0; //SDA初始化为低电平“0”_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 1; //结束数据传送时,要求SCL为高电平“1”页脚内容4_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SDA = 1; //SDA的上升沿被认为是结束信号}/*************************************************** 函数功能:从AT24Cxx读取数据出口参数:x***************************************************/ unsigned char ReadData()// 从AT24Cxx移入数据到MCU{unsigned char i;unsigned char x; //储存从AT24Cxx中读出的数据页脚内容5for(i = 0; i < 8; i++){SCL = 1; //SCL置为高电平x<<=1; //将x中的各二进位向左移一位x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中 SCL = 0; //在SCL的下降沿读出数据}return(x); //将读取的数据返回}/***************************************************函数功能:向AT24Cxx的当前地址写入数据入口参数:y (储存待写入的数据)***************************************************///在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0 bit WriteCurrent(unsigned char y){unsigned char i;页脚内容6bit ack_bit; //储存应答位for(i = 0; i < 8; i++) // 循环移入8个位{SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S//因为传送时高位在前,低位在后_nop_(); //等待一个机器周期SCL = 1; //在SCL的上升沿将数据写入AT24Cxx_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲 y <<= 1; //将y中的各二进位向左移一位}SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,//以让SDA线转由接收设备(AT24Cxx)控制_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期页脚内容7SCL = 1; //根据上述规定,SCL应为高电平_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节//若送高电平,表示没有接收到,传送异常SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递) return ack_bit;// 返回AT24Cxx应答位}/***************************************************函数功能:向第一个AT24Cxx中的指定地址写入数据入口参数:add (储存指定的地址);dat(储存待写入的数据)***************************************************/void WriteSet1(unsigned char add, unsigned char dat)// 在指定地址addr处写入数据WriteCurrent{页脚内容8start(); //开始数据传递WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(add); //写入指定地址WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据stop(); //停止数据传递delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上}/***************************************************函数功能:向第二个AT24Cxx中的指定地址写入数据入口参数:add (储存指定的地址);dat(储存待写入的数据)***************************************************/void WriteSet2(unsigned char add, unsigned char dat)// 在指定地址addr处写入数据WriteCurrent{start(); //开始数据传递WriteCurrent(OP_WRITE2); //选择要操作的AT24Cxx芯片,并告知要对其写入数据WriteCurrent(add); //写入指定地址页脚内容9WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据stop(); //停止数据传递delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上}/***************************************************函数功能:从第一个AT24Cxx中的当前地址读取数据出口参数:x (储存读出的数据)***************************************************/unsigned char ReadCurrent1(){unsigned char x;start(); //开始数据传递WriteCurrent(OP_READ1); //选择要操作的第一个AT24Cxx芯片,并告知要读其数据 x=ReadData(); //将读取的数据存入xstop(); //停止数据传递return x; //返回读取的数据}页脚内容10/***************************************************函数功能:从第二个AT24Cxx中的当前地址读取数据出口参数:x (储存读出的数据)***************************************************/unsigned char ReadCurrent2(){unsigned char x;start(); //开始数据传递WriteCurrent(OP_READ2); //选择要操作的第二个AT24Cxx芯片,并告知要读其数据 x=ReadData(); //将读取的数据存入xstop(); //停止数据传递return x; //返回读取的数据}/***************************************************函数功能:从第一个AT24Cxx中的指定地址读取数据入口参数:set_addr出口参数:x页脚内容11***************************************************/unsigned char ReadSet1(unsigned char set_addr)// 在指定地址读取{start(); //开始数据传递WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(set_addr); //写入指定地址return(ReadCurrent1()); //从第一个AT24Cxx芯片指定地址读出数据并返回}/***************************************************函数功能:从第二个AT24Cxx中的指定地址读取数据入口参数:set_addr出口参数:x***************************************************/unsigned char ReadSet2(unsigned char set_addr)// 在指定地址读取{页脚内容12start(); //开始数据传递WriteCurrent(OP_WRITE2); //选择要操作的第二个AT24Cxx芯片,并告知要对其写入数据 WriteCurrent(set_addr); //写入指定地址return(ReadCurrent2()); //从第二个AT24Cxx芯片指定地址读出数据并返回}/***************************************************函数功能:主函数***************************************************/main(void){unsigned char x;SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态SCL = 1;WriteSet1(0x36,0xaa); //将数据"0xaa"写入第一个AT24C02的指定地址"0x36"x=ReadSet1(0x36); //从第二个AT24C02中的指定地址"0x36"读出数据WriteSet2(0x48,x); //将读出的数据写入第二个AT24C02的指定地址"0x48"?P1=ReadSet2(0x48); //将从第二个AT24C02的指定地址读出的数据送P1口显示验证页脚内容13}4、在proteus中新建仿真文件ex54.dsn,电路原理图如下所示5、将ex54.hex文件载入at89c51中,启动仿真,观察运行结果。
AT24Cxx芯片读写--IIC总线
AT24Cxx芯片读写--IIC总线AT24Cxx芯⽚读写--IIC总线型号容量器件寻址字节(8位) ⽚次装载字节数AT24C01 128×8 1010A2A1A0 R/W 8AT24C02 256×8 1010A2A1A0 R/W 8AT24C04 512×8 1010A2A1P0 R/W 16AT24C08 1024×8 1010A2P1P0 R/W 16AT24C16 2048×8 1010P2P1P0 R/W 16AT24C32 4096*8 1010A2A1A0 R/W 32AT24C64 8192*8 1010A2A1A0 R/W 32AT24C128 16384*8 1010A2A1A0 R/W 64AT24C256 16384*8 1010A2A1A0 R/W 64AT24C系列 E2PROM接⽚及地址选择设备地址:24xx系列的可以通过修改外的地址引脚来设置不同的地址.IIC地址的确定,AT24C系列的,24c01,02 1K/2K EEPROM 在⽚条IIC总线上可以挂8个,地址由A2,A1,A0确定;24C04 4k EEPROM 只有A2,A1的做地址位,这样⽚条IIC总线上能挂4个设备,A0是⽚来确定内部页地址的,A0在芯⽚上没有线连接的(NA); 24C08, 8k EEPROM 使⽚A2来确定地址线,A1,A0位是在确定内部页地址的,⽚条IIC总线能扩展2⽚; 24C16 16k,A2A1A0都是确定内部页地址的;⽚条总线上只能挂1个⽚个这样的设备.但在AT24C32 ,24C64中⽚有改变,32,64中发送的内部地址都是发2次,⽚地址和低地址,这样有16位地址位可以确定内部地址,就不需要⽚A2A1A0来确定地址了.控制器的读写时序AT24C01---AT24C16读: 发设备地址---> 送8位地址---->发设备地址--->读取--->NOACK--->停⽚;写:发设备地址--->送8位地址----->写数据--->停⽚;AT24C32.AT24C64读:发设备地址--->送⽚8位地址--->送低8位地址--->发设备地址--->读取----->NOACK--->停⽚写:发设备地址--->送⽚8位地址----->送低8位地址---->写数据--->停⽚;。
16模拟I2C总线及AT24C01应用
void delay() { ;; }
void delay1(uchar x) { uchar a,b; for(a=x;a>0;a--) for(b=100;b>0;b--); } void start() { sda=1; delay(); scl=1; delay(); sda=0; delay();
MSC-51 单片机 C 语言简单入门教程
技术支持群:11313486
I2C 串行总线概述
I2C 总线是 PHLIPS 公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高 低速器件同步功能的高性能串行总线。 I2C 总线只有两根双向信号线。一根是数据线 SDA,另一根是时钟线 SCL。
I2C 总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器 件输出的低电平,都将使总线的信号变低,即各器件的 SDA 及 SCL 都是线“与”关系。
start(); //起始信号 write_byte(0xA0); //设备地址,写方向 respons(); //应答 write_byte(3); //存贮空间地址 respons(); //应答 start(); //开始 write_byte(0xA1);//设备地址,读方向
http://www.hfmcu 红峰电子学习室
由于某种原因从机不对主机寻址信号应答时 (如从机正在进行实时性的处理工作而无法接收 总线上的数据) ,它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数 据传送。 如果从机对主机进行了应答, 但在数据传送一段时间后无法继续接收更多的数据时, 从机可 以通过对无法接收的第一个数据字节的“非应答”通知主机, 主机则应发出终止信号以结束数 据的继续传送。 当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这
单片机中I2C总线接口技术应用案例分析
单片机中I2C总线接口技术应用案例分析I2C总线接口技术是一种广泛应用于单片机系统中的通信协议。
它具有简单、灵活、可靠的特点,可以用于连接多个外设,实现数据的传输和互动。
在本文中,我们将通过分析几个实际案例,探讨I2C总线接口技术在单片机系统中的应用。
案例一:温度传感器假设我们有一个温度传感器,希望将其与单片机相连,以便读取当前环境温度。
这时,我们可以使用I2C总线接口技术来实现数据的传输。
首先,我们需要连接传感器的SCL(时钟线)和SDA(数据线)引脚到单片机相应的引脚。
然后,在单片机的代码中,我们可以通过编写相应的I2C通信协议,向传感器发送读取温度数据的指令,并接收传感器返回的温度数值。
通过这种方式,我们可以轻松地获取环境温度,实现相应的温度控制策略。
案例二:智能显示屏假设我们有一个智能显示屏,希望将其与单片机连接,实现数据的双向传输。
这时,我们可以使用I2C总线接口技术来实现。
首先,我们需要连接显示屏的SCL和SDA引脚到单片机的相应引脚。
然后,在单片机的代码中,我们可以通过编写I2C通信协议,向显示屏发送显示内容的指令,并接收显示屏返回的用户操作指令。
通过这种方式,我们可以实现与智能显示屏之间的数据交互,从而实现更加智能化的用户界面。
案例三:扩展存储设备假设我们需要为单片机系统提供额外的存储空间,以便存储更多的数据。
这时,我们可以使用I2C总线接口技术连接一个外部的存储设备。
首先,我们需要连接存储设备的SCL和SDA引脚到单片机相应的引脚。
然后,在单片机的代码中,我们可以通过编写I2C通信协议,向存储设备发送写入数据的指令,并接收存储设备返回的读取数据的指令。
通过这种方式,我们可以扩展单片机系统的存储容量,提供更大的数据存储空间。
案例四:外部设备控制假设我们需要控制一个外部设备,例如LED灯或者电机。
这时,我们可以使用I2C总线接口技术连接外设的控制接口到单片机。
首先,我们需要接线连接外设的SCL和SDA引脚到单片机相应的引脚。
EEPROM------AT24C01A_IIC总线驱动读写程序
/*河北工程大学信电学院自动化系调试成功EEPROM------A T24C01A_IIC总线驱动读写程序晶振:6MHz目标板:STC90C52AD编译环境:Keil C uVision V2.38a*/#include <reg52.h>#include <intrins.h>//由于是01A,1Kbit,故此这里第一个字节的读写格式是1010,A2,A1,A0,R/W #define Read_Addr 0xa1#define Write_Addr 0xa0#define uchar unsigned char//总线的定义,时钟线P1.0,数据线P1.1sbit SCL=P1^0;sbit SDA=P1^1;//短码数组uchar tab[]={2,5,6};void Start(){SDA=1;_nop_();SCL=1;_nop_();SDA=0;_nop_();SCL=0; //可以视作第一个SCL=0}void Stop(){SDA=0;_nop_();SCL=1;_nop_();SDA=1;}//------------------------------------------------------------------------- bit Write_Byte(uchar DA TA){bit Ack;uchar i;for(i=0;i<8;i++){SDA=(bit)(DA TA&0x80);_nop_();SCL=1;_nop_();_nop_();SCL=0; //第九个SCL=0DA TA<<=1;}SDA=1; //主机释放SDA_nop_();_nop_();SCL=1; //第九个SCL=1_nop_();//SDA=1; //对程序好像没出来影响Ack=SDA; //前面是否先置1,特别注意是否是准双向口SCL=0; //下一个字节的第一个SCL=0return (Ack);}uchar Read_Byte(){uchar DA TA,i;for(i=0;i<8;i++){SCL=1;DA TA<<=1;//注意强制类型转换SDA=1; //对程序好像没出来影响DA TA|=(uchar)SDA;//前面是否先置1,特别注意是否是准双向口SCL=0;}return(DA TA);}//-------------------------------------------------------------------------//读当前地址的数据uchar Read_Current_Addr(){uchar DA TA;Start();Write_Byte(Read_Addr);DA TA=Read_Byte();Stop();return(DA TA);}//向指定地址读数据uchar Read_Random_Addr(uchar addr) //256*8byte=1024Kbit,uchar类型正好合适{uchar DA TA;Start();Write_Byte(Write_Addr);Write_Byte(addr);DA TA=Read_Current_Addr();return(DA TA);}/*-------------------------------------------------------------功能:从EEPROM中给定一个地址连续读NLEN个字节数据存放在以指针nContent开头的往下内容。
I2C总线上接两个AT24C02读写实例
I2C总线上接两个AT24C02读写实例、本例对I2C总线上关节两个AT24C02进行读写操作,想将数据0xaa写入第一个at24c02的指定地址,再将该数据读出后存入第二个AT24C02的指定地址,最后读出该数据并送P1口用8位LED显示验证2、实现方法:1)两个器件地址的确定由于第一个AT24C02的3位地址位(A0A1A2)均接地(低电平),第二个AT24C02的三个地址位(A0A1A2)均接电源(高电平),因此第一个AT24C02的地址为000,第二个AT24C02的地址为111.在写命令时,指名要操作的器件地址,即可对不同的AT24C02进行操作3、在keil c51中新建工程ex54,编写如下程序代码,编译并生成ex54.hex文件//对I2C总线上挂接多个AT24C02的读写操作#include <reg51.h> // 包含51单片机寄存器定义的头文件#include <intrins.h> //包含_nop_()函数定义的头文件#define OP_READ1 0xa1 // 器件1地址以及读取操作,0xa1即为1010 0001B#define OP_WRITE1 0xa0 // 器件1地址以及写入操作,0xa1即为1010 0000B#define OP_READ2 0xaf // 器件2地址以及读取操作,0xa1即为1010 1111B#define OP_WRITE2 0xae // 器件2地址以及写入操作,0xa1即为1010 1110Bsbit SDA=P3^4; //将串行数据总线SDA位定义在为P3.4引脚sbit SCL=P3^3; //将串行时钟总线SDA位定义在为P3.3引脚/*****************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/void delay1ms(){unsigned char i,j;for(i=0;i<10;i++)for(j=0;j<33;j++);}/***************************************************** 函数功能:延时若干毫秒入口参数:n***************************************************/ void delaynms(unsigned char n){unsigned char i;for(i=0;i<n;i++)delay1ms();}/***************************************************函数功能:开始数据传送***************************************************/ void start()// 开始位{SDA = 1; //SDA初始化为高电平“1”SCL = 1; //开始数据传送时,要求SCL为高电平“1”_nop_(); //等待一个机器周期SDA = 0; //SDA的下降沿被认为是开始信号_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)_nop_(); //等待一个机器周期}/***************************************************函数功能:结束数据传送***************************************************/void stop()// 停止位{SDA = 0; //SDA初始化为低电平“0”_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 1; //结束数据传送时,要求SCL为高电平“1”_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SDA = 1; //SDA的上升沿被认为是结束信号}/***************************************************函数功能:从AT24Cxx读取数据出口参数:x***************************************************/unsigned char ReadData()// 从AT24Cxx移入数据到MCU{unsigned char i;unsigned char x; //储存从AT24Cxx中读出的数据for(i = 0; i < 8; i++){SCL = 1; //SCL置为高电平x<<=1; //将x中的各二进位向左移一位x|=(unsigned char)SDA; //将SDA上的数据通过按位“或“运算存入x中SCL = 0; //在SCL的下降沿读出数据}return(x); //将读取的数据返回}/***************************************************函数功能:向AT24Cxx的当前地址写入数据入口参数:y (储存待写入的数据)***************************************************///在调用此数据写入函数前需首先调用开始函数start(),所以SCL=0bit WriteCurrent(unsigned char y){unsigned char i;bit ack_bit; //储存应答位for(i = 0; i < 8; i++) // 循环移入8个位{SDA = (bit)(y&0x80); //通过按位“与”运算将最高位数据送到S//因为传送时高位在前,低位在后_nop_(); //等待一个机器周期SCL = 1; //在SCL的上升沿将数据写入AT24Cxx_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 0; //将SCL重新置为低电平,以在SCL线形成传送数据所需的8个脉冲y <<= 1; //将y中的各二进位向左移一位}SDA = 1; // 发送设备(主机)应在时钟脉冲的高电平期间(SCL=1)释放SDA线,//以让SDA线转由接收设备(AT24Cxx)控制_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期SCL = 1; //根据上述规定,SCL应为高电平_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期_nop_(); //等待一个机器周期ack_bit = SDA; //接受设备(AT24Cxx)向SDA送低电平,表示已经接收到一个字节//若送高电平,表示没有接收到,传送异常SCL = 0; //SCL为低电平时,SDA上数据才允许变化(即允许以后的数据传递)return ack_bit;// 返回AT24Cxx应答位}/***************************************************函数功能:向第一个AT24Cxx中的指定地址写入数据入口参数:add (储存指定的地址);dat(储存待写入的数据)***************************************************/void WriteSet1(unsigned char add, unsigned char dat)// 在指定地址addr处写入数据WriteCurrent{start(); //开始数据传递WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据WriteCurrent(add); //写入指定地址WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据stop(); //停止数据传递delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上}/***************************************************函数功能:向第二个AT24Cxx中的指定地址写入数据入口参数:add (储存指定的地址);dat(储存待写入的数据)***************************************************/void WriteSet2(unsigned char add, unsigned char dat)// 在指定地址addr处写入数据WriteCurrent{start(); //开始数据传递WriteCurrent(OP_WRITE2); //选择要操作的AT24Cxx芯片,并告知要对其写入数据WriteCurrent(add); //写入指定地址WriteCurrent(dat); //向当前地址(上面指定的地址)写入数据stop(); //停止数据传递delaynms(4); //1个字节的写入周期为1ms, 最好延时1ms以上}/***************************************************函数功能:从第一个AT24Cxx中的当前地址读取数据出口参数:x (储存读出的数据)***************************************************/unsigned char ReadCurrent1(){unsigned char x;start(); //开始数据传递WriteCurrent(OP_READ1); //选择要操作的第一个AT24Cxx芯片,并告知要读其数据x=ReadData(); //将读取的数据存入xstop(); //停止数据传递return x; //返回读取的数据}/***************************************************函数功能:从第二个AT24Cxx中的当前地址读取数据出口参数:x (储存读出的数据)***************************************************/unsigned char ReadCurrent2(){unsigned char x;start(); //开始数据传递WriteCurrent(OP_READ2); //选择要操作的第二个AT24Cxx芯片,并告知要读其数据x=ReadData(); //将读取的数据存入xstop(); //停止数据传递return x; //返回读取的数据}/***************************************************函数功能:从第一个AT24Cxx中的指定地址读取数据入口参数:set_addr出口参数:x***************************************************/unsigned char ReadSet1(unsigned char set_addr)// 在指定地址读取{start(); //开始数据传递WriteCurrent(OP_WRITE1); //选择要操作的第一个AT24Cxx芯片,并告知要对其写入数据WriteCurrent(set_addr); //写入指定地址return(ReadCurrent1()); //从第一个AT24Cxx芯片指定地址读出数据并返回}/***************************************************函数功能:从第二个AT24Cxx中的指定地址读取数据入口参数:set_addr出口参数:x***************************************************/unsigned char ReadSet2(unsigned char set_addr)// 在指定地址读取{start(); //开始数据传递WriteCurrent(OP_WRITE2); //选择要操作的第二个AT24Cxx芯片,并告知要对其写入数据WriteCurrent(set_addr); //写入指定地址return(ReadCurrent2()); //从第二个AT24Cxx芯片指定地址读出数据并返回}/***************************************************函数功能:主函数***************************************************/main(void){unsigned char x;SDA = 1; // SDA=1,SCL=1,使主从设备处于空闲状态SCL = 1;WriteSet1(0x36,0xaa); //将数据"0xaa"写入第一个AT24C02的指定地址"0x36" x=ReadSet1(0x36); //从第二个AT24C02中的指定地址"0x36"读出数据 WriteSet2(0x48,x); //将读出的数据写入第二个AT24C02的指定地址"0x48"?P1=ReadSet2(0x48); //将从第二个AT24C02的指定地址读出的数据送P1口显示验证}4、在proteus中新建仿真文件ex54.dsn,电路原理图如下所示5、将ex54.hex文件载入at89c51中,启动仿真,观察运行结果。
单片机模拟I2C总线及24C02(I2C EEPROM)读写实例
/*发送1,在SCL为高电平时使SDA信号为高*/
SDA=1;
SCL=1;
DELAY(DELAY_TIME);
SCL=0;
DELAY(DELAY_TIME);
}
bit Check_Acknowledge(void)
/* Language: C51单片机编程语言 */
/* Platform: Win98,Intel Celeron 433 Processor,伟福仿真器,仿真8751 */
/* Author: StephenZhu javasdk@ */
for(i=0;i<7;i++)
{
WriteI2CByte(buffer[i]);
if(!Check_Acknowledge())
{
I2C_Stop();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
WriteI2CByte(thedata);/*thedata*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa0);
acktemp=Check_Acknowledge();
WriteI2CByte(addr);/*address*/
acktemp=Check_Acknowledge();
I2C_Start();
WriteI2CByte(0xa1);
acktemp=Check_Acknowledge();
for(i=0;i<n;i++)
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
单片机模拟I2C总线及AT24C01应用实例(格式整理版) I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。
I2C总线产生于在80年代,最初为音频和视频设备开发,如今主要在服务器管理中使用,其中包括单个组件状态的通信。
例如管理员可对各个组件进行查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、网络、系统温度等多个参数,增加了系统的安全性,方便了管理。
1.I2C总线特点I2C总线最主要的优点是其简单性和有效性。
由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。
总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。
I2C总线的另一个优点是,它支持多主控(multimastering),其中任何能够进行发送和接收的设备都可以成为主总线。
一个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有一个主控。
2.I2C总线工作原理2.1总线的构成及信号类型I2C总线是一种串行数据总线,只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。
2.2位的传输SDA线上的数据必须在时钟的高电平周期保持稳定数据线的高或低电平状态只有在SCL 线的时钟信号是低电平时才能改变,见图1:图12.3开始信号SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
2.4结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
图22.5应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。
CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。
若未收到应答信号,由判断为受控单元出现故障。
2.6总线基本操作I2C规程运用主/从双向通讯。
器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。
主器件和从器件(本文为AT24C01)都可以工作于接收和发送状态。
总线必须由主器件(通常为微控制器CPU)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。
SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。
参见图2。
3.I2C应用实例AT24C01AT24C系列串行E2PROM具有I2C总线接口功能,功耗小,宽电源电压(根据不同型号2.5V~6.0V),工作电流约为3mA,静态电流随电源电压不同为30μA~110μA。
3.1AT24C系列E2PROM接口及地址选择由于I2C总线可挂接多个串行接口器件,在I2C总线中每个器件应有唯一的器件地址,按I2C总线规则,器件地址为7位数据(即一个I2C总线系统中理论上可挂接128个不同地址的器件),它和1位数据方向位构成一个器件寻址字节,最低位D0为方向位(读/写)。
器件寻址字节中的最高4位(D7~D4)为器件型号地址,不同的I2C总线接口器件的型号地址是厂家给定的,如AT24C系列E2PROM的型号地址皆为1010,器件地址中的低3位为引脚地址A2A1A0,对应器件寻址字节中的D3、D2、D1位,在硬件设计时由连接的引脚电平给定。
图3对于E2PROM的片内地址,容量小于256字节的芯片(AT24C01/02),8位片内寻址(A0~A7)即可满足要求。
然而对于容量大于256字节的芯片,则8位片内寻址范围不够,如AT24C16,相应的寻址位数应为11位(211=2048)。
若以256字节为1页,则多于8位的寻址视为页面寻址。
在AT24C系列中对页面寻址位采取占用器件引脚地址(A2、A1、A0)的办法,如AT24C16将A2、A1、A0作为页地址。
凡在系统中引脚地址用作页地址后,该引脚在电路中不得使用,作悬空处理。
AT24C系列串行E2PROM的器件地址寻址字节如图4所示,表中P0P1P2表示页面寻址位。
图43.2AT89S51单片机与AT24C01E2PROM通讯的硬件实现图5是用AT89S51P2口模拟I2C总线与E2PROM连接电路图(以AT24C01为例),由于AT24C01是漏极开路,图中R1、R2为上拉电阻(5.1k)。
A0~A2地址引脚脚均接地。
图5AT24C01与51单片机接口3.3AT24C系列E2PROM读写操作软件实现方法对AT24C系列E2PROM的读写操作完全遵守I2C总线的主收从发和主发从收的规则。
3.3.1AT24C01的写操作写操作分为字节写和页面写两种操作,对于页面写根据芯片的一次装载的字节不同有所不同。
关于页面写的地址、应答和数据传送的时序参见图6和图7。
连续写操作是对E2PROM连续装载n个字节数据的写入操作,n随型号不同而不同,一次可装载字节数也不同。
AT24C01/028字节/每页,AT24C04/08/1616字节/每页。
图6写一个字节的时序图图7写一页的时序图3.3.2AT24C01的读操作读操作有三种基本操作:当前地址读、随机读和顺序读。
图10给出的是顺序读的时序图。
应当注意的是:最后一个读操作的第9个时钟周期不是“不关心”。
为了结束读操作,主机必须在第9个周期间发出停止条件或者在第9个时钟周期内保持SDA为高电平、然后发出停止条件。
AT24C系列片内地址在接收到每一个数据字节地址后自动加1,故装载一页以内规定数据字节时,只须输入首地址,若装载字节多于规定的最多字节数,数据地址将“上卷”,前面的数据被覆盖。
连续读操作时为了指定首地址,需要两个伪字节写来给定器件地址和片内地址,重复一次启动信号和器件地址(读),就可读出该地址的数据。
由于伪字节写中并未执行写操作,地址没有加1。
以后每读取一个字节,地址自动加1。
在读操作中接收器接收到最后一个数据字节后不返回肯定应答(保持SDA高电平)随后发停止信号。
图8读当前地址内容图9读任意地址内容图10读连续地址内容4 汇编写的24C01 单字节读写程序;======================================================= ;24C01存储器I2C总线实验 汇编语言例子;======================================================= ;;ew51仿真编程器 配套实验板学习例程;;中山单片机学习网 诚电科技站长:逸风;;;E-mail:ew51@;======================================================= SDA EQU P2.0SCL EQU P2.1Address EQU 08HI2CData EQU 09HORG 0000HSTART:MOV SP,#60HMOV Address,#00HMOV I2CData,#55HCALL I2C_WRITE ;写入数据MOV I2CDATA,#0AAHMOV Address,#00HCALL I2C_READMOV I2CData,A ;读出数据NOPNOPMAIN:JMP MAIN;=======================================================; 写一个字节 Address地址 I2CDatata写入的数据;=======================================================I2C_WRITE:I2C_WRITE_A:LCALL I2C_STARTMOV A,#10100000BLCALL I2C_SEND8BITLCALL I2C_ACKJC I2C_WRITE_A ;=1,表示无确认,再次发送MOV A,AddressLCALL I2C_SEND8BITLCALL I2C_ACKMOV A,I2CDataLCALL I2C_SEND8BITLCALL I2C_ACKLCALL I2C_STOPRET;=======================================================; 读一个字节 Address地址 Data读出的数据;=======================================================I2C_READ:I2C_READ_A:LCALL I2C_STARTMOV A,#10100000BLCALL I2C_SEND8BITLCALL I2C_ACKJC I2C_READ_A ;=1,表示无确认,再次发送MOV A,AddressLCALL I2C_SEND8BITLCALL I2C_ACKI2C_READ_B:LCALL I2C_STARTMOV A,#10100001BLCALL I2C_SEND8BITLCALL I2C_ACKJC I2C_READ_BLCALL I2C_RECEIVE8BITMOV I2CData,ALCALL I2C_ACKLCALL I2C_STOPRET;======================================================= ; 发送开始信号;======================================================= I2C_START:SETB SCLSETB SDANOPNOPCLR SDANOPNOPCLR SCLRET;======================================================= ; 发送结束信号;======================================================= I2C_STOP:CLR SDANOPNOPSETB SCLNOPNOPSETB SDARET;======================================================= ; 发送/接收确认信号;======================================================= I2C_ACk:SETB SDASETB SCLNOPNOPJB SDA,I2C_ACK0CLR CSJMP I2C_ACK_ENDI2C_ACK0:SETB CI2C_ACK_END:CLR SCLRET;======================================================= ; 送八位数据;======================================================= I2C_SEND8BIT:MOV B,#08HI2C_SEND8BIT_A:RLC AMOV SDA,CSETB SCLNOPNOPCLR SCLDJNZ B,I2C_SEND8BIT_ARET;======================================================= ; 接收八位数据;======================================================= I2C_RECEIVE8BIT:MOV B,#08HCLR ASETB SDAI2C_RECEIVE8IT_A:SETB SCLNOPNOPMOV C,SDARLC ACLR SCLDJNZ B,I2C_RECEIVE8IT_ARET5. C语言写的24C01 单字节读写程序/*======================================================= 24C01存储器I2C总线实验 C语言例子======================================================= ew51仿真编程器 配套实验板学习例程中山单片机学习网 诚电科技 站长:逸风E-mail:ew51@=======================================================*/ #i nclude#i ncludesbit SDA=0x90;sbit SCL=0x91;//函数声明unsigned char i2c_read(unsigned char);void i2c_write(unsigned char,unsigned char);void i2c_send8bit(unsigned char);unsigned char i2c_receive8bit(void);void i2c_start(void);void i2c_stop(void);bit i2c_ack(void);//======================================================= void main(void){unsigned char dd;i2c_write(0x00,0x55);_nop_();dd=i2c_read(0x00);for(;;){}}/*======================================================= i2c_write(地址,数据),写一个字节=======================================================*/ void i2c_write(unsigned char Address,unsigned char Data){do{i2c_start();i2c_send8bit(0xA0);}while(i2c_ack());i2c_send8bit(Address);i2c_ack();i2c_send8bit(Data);i2c_ack();i2c_stop();return;}/*======================================================= i2c_read(地址,数据),写一个字节=======================================================*/ unsigned char i2c_read(unsigned char Address){unsigned char c;do{i2c_start();i2c_send8bit(0xA0);}while(i2c_ack()); //=1,表示无确认,再次发送i2c_send8bit(Address);i2c_ack();do{i2c_start();i2c_send8bit(0xA1);}while(i2c_ack());c=i2c_receive8bit();i2c_ack();i2c_stop();return(c);}//======================================================= //发送开始信号void i2c_start(void){SDA = 1;SCL = 1;SDA = 0;SCL = 0;return;}//发送结束信号void i2c_stop(void){SDA = 0;SCL = 1;SDA = 1;return;}//发送接收确认信号bit i2c_ack(void){bit ack;SDA = 1;SCL = 1;if (SDA==1)ack = 1;elseack = 0;SCL = 0;return (ack);}//送八位数据void i2c_send8bit(unsigned char b) {unsigned char a;for(a=0;a<8;a++){if ((b << a ) & 0x80)SDA = 1;elseSDA = 0;SCL = 1;SCL = 0;}return;}//接收八位数据unsigned char i2c_receive8bit(void) {unsigned char a;unsigned char b=0;for(a=0;a<8;a++){SCL = 1;b=b<<1;if (SDA==1)b=b 0x01; //按位或SCL = 0;}return (b);}6.在I 2 C总线的应用中应注意的事项总结为以下几点 :1)严格按照时序图的要求进行操作2)若与口线上带内部上拉电阻的单片机接口连接,可以不外加上拉电阻。