51单片机模拟I2C总线的数据传送
51单片机的I2C底层驱动程序(IO口模拟)

51单片机的I2C底层驱动程序(IO口模拟)/*Title:I2C for 80C51Author:yuyouliang51单片机(本人使用STC89C52单片机,12T模式)的I2C驱动程序,使用逻辑分析仪对该协议进行分析,发现波形比较美观,SCL 的频率在70KHz左右(11.0592M晶振),低于标准的100K,可以适应大多数的I2C器件。
如果感觉速度过快或过慢,可以自行修改延时。
希望可以给读者一个参考,给读者一些帮助!*//*i2c.h文件 */#ifndef __I2C_H_#define __I2C_H_sbit SCL = P2^1;sbit SDA = P2^0;void start_i2c(); //启动I2C总线:SCL高电平期间,SDA由高变低void stop_i2c(); //停止I2C总线:SCL高电平期间,SDA由低变高void send_i2c(unsigned char c); //主机发送一个字节,先发送最高位unsigned char receive_i2c(); //主机接收一个字节,先接收最高位void master_ack(bit ack); //主机非应答信号(填参数0)或应答信号(填参数1)void slave_ack(); //等待从机应答信号#endif/* i2c.c文件 */#include#include#include#define nop() _nop_()void start_i2c() //启动I2C总线:SCL高电平期间,SDA由高变低{SDA=1;SCL=1;nop();nop();nop();nop();SDA=0;SCL=0;}void stop_i2c() //停止I2C总线,SCL高电平期间,SDA由低变高{SDA=0;SCL=1;nop();nop();nop();nop();SDA=1;}void slave_ack() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
实验八 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的封装结构,如图所示。
51单片机模拟IIC工作时序,以EEPROM器件进行掉电保护数据

51单片机软件模拟I2C时序,进行掉电保护数据在数码管上按顺序显示数据0—f(十六进制)模拟断电-切断单片机电源复位后接着断电前数据显示#include<reg51.h>#define uchar unsigned char#define uint unsigned intsbit sda=P2^0;sbit scl=P2^1;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39 ,0x5e,0x79,0x71} ;uchar num,sec,panju;//由定时器进行计数,计时,以数组的形式显示于数码管每隔1S读一次AT24C16中的数据//-------------------------------定时器0进行精确的计时,由AT24C16进行掉电保护----------------------------------//void delay(){;;}void init_timer0()//定时器初始化{TMOD=0X01;//工作方式1,GATE=0,C/~T=0,M0=0,M1=1;TH0=15536/256;//求模TL0=15536%256;//求余装入初值EA=1;ET0=1;//中断允许寄存器TR0=1;//TCON寄存器}//------------------------------------------------------------------------------------------------------------//void init_AT()//EEPROM器件初始化释放总线{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 s,temp;//局部变量temp=date;//由高位一位一位的写入for(s=0;s<8;s++){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 t;//局部变量scl=1;delay();while((sda==1)&&(t<250)){t++;//等待应答有一定的时间限制,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=10;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;}//----------------------------------------------------------------------------------------------------------//void write_add(uchar address,uchar date) //任意位置,写任意内容{start();//起始信号write_byte(0xa0);//写入EEPROM器件地址,写入分为数据,地址数据,地址又分为器件地址和内部存储地址,例如某班级某学生座位response();//等待应答write_byte(address);//内部存储地址实际参数addressresponse();write_byte(date);//写入真正意义上的数据,由引入的实际参数dateresponse();//等待应答stop();//停止读取数据信号delay1(1);}//-------------------------------------------------------------------------------------------------------//uchar read_add(uchar address){uchar shu;start();write_byte(0xa0);//申明所读器件地址response();write_byte(address);//申明该器件中所要求读数据的位置response();start();write_byte(0xa1);response();shu=read_byte();//进行读数据操作后,非应答,budaixingcan,而是将返回值直接赋予变量stop();}//------------------------------------------------------------------------------------------------------------// void main(){P0=0X00;init_AT();sec=read_add(0X03);//将芯片中数据读出;作为基数init_timer0();//定时器初始化设置if(sec==16)sec=0;while(1){P0=table[sec];if(panju==1){panju=0;write_add(0x03,sec);}}}//---------------------------------------------------------------------------------------------------------// void timer0_break() interrupt 1{TH0=15536/256;//求模TL0=15536%256;//求余装入初值num++;if(num==20){num=0;sec++;panju=1;if(sec==16) sec=0;}}。
在51上用P1口模拟I2C

在51上用P1口模拟I2C在51上用P1口模拟I2C原文:下面是用普通C51实现的I2C基本电平模拟函数和通用函数。
/* 电平模拟函数和基本读写函数void IIC_Start(void);void IIC_Stop(void);void SEND_0(void);void SEND_1(void);bit Check_Acknowledge(void);void Write_Byte(uchar b)reentrant;bit Write_N_Bytes(uchar *buffer,uchar n)reentrant;bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer); uchar Read_Byte(void)reentrant;*/#include<string.h>#include<reg52.h>#include<intrins.h>#include"aiic_51.h"sbit SCL=P1^6;sbit SDA=P1^7;void DELAY(uint t){while(t!=0)t--;}void IIC_Start(void){//启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变SDA=1;SCL=1;DELAY(DELAY_TIME);SDA=0;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void IIC_Stop(void){//终止I2C总线,当SCL为高电平时使SDA产生一个正跳变SDA=0;SCL=1;DELAY(DELAY_TIME);SDA=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_0(void){//发送0,在SCL为高电平时使SDA信号为低SDA=0;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}void SEND_1(void){//发送1,在SCL为高电平时使SDA信号为高SDA=1;SCL=1;DELAY(DELAY_TIME);SCL=0;DELAY(DELAY_TIME);}bit Check_Acknowledge(void){//发送完一个字节后检验设备的应答信号SDA=1;SCL=1;DELAY(DELAY_TIME/2);F0=SDA;DELAY(DELAY_TIME/2);SCL=0;DELAY(DELAY_TIME);if(F0==1)return FALSE;return TRUE;}void Write_Byte(uchar b)reentrant{//向IIC总线写一个字节uchar i;for(i=0;i<8;i++)if((b<<i)&0x80)SEND_1();elseSEND_0();}bit Write_N_Bytes(uchar *buffer,uchar n)reentrant {//向I2C总线写n个字节uchar i;IIC_Start();for(i=0;i<n;i++){Write_Byte(buffer);if(!Check_Acknowledge()){IIC_Stop();return(i==n);}}IIC_Stop();return TRUE;}uchar Read_Byte(void)reentrant{//从I2C总线读一个字节uchar b=0,i;for(i=0;i<8;i++){SDA=1; //释放总线SCL=1; //接受数据DELAY(10);F0=SDA;DELAY(10);SCL=0;if(F0==1){b=b<<1;b=b|0x01;}elseb=b<<1;}return b;}bit Read_N_Bytes(uchar SlaveAdr,uchar n,uchar *buffer) {//从I2C总线读n个字节uchar i;IIC_Start();Write_Byte(SlaveAdr); //向总线发送接收器地址if(!Check_Acknowledge()) //等待接收器应答信号return FALSE;for(i=0;i<n;i++){buffer=Read_Byte();if(i!=n)SEND_0(); //发送应答elseSEND_1(); //发送非应答}IIC_Stop();return TRUE;}使用上述代码,你可以在51上用P1口模拟I2C。
C51实现I2C总线单主多从通信

设计论文
C51 实现 I2C 单主多从通信
专业: 航空电子信息
班级:
航电 1203
姓名:
陈瑞金
指 导 老 师 : 鄢立、程秀玲
时 间:
2014.04
1
陈瑞金
________________________________________________________________________________________________________________
五、程序的编写
1、设计思路--------------------------------------------------------------12
2、参考程序
a.主机程序------------------------------------------------------------14
2、关于 24C02 的读写---------------------------------------------------7
四、硬件电路
1、Proteurs 绘制的电路图----------------------------------------------8
2、Proteurs 仿真效果图------------------------------------------------10
当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机 的“非应答”来实现的。然后,从机释放 SDA 线,以允许主机产生终止信号。
(2)数据帧率格式 I2C 总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。在起始信号后必须传送一个
单片机之间 i2c通信

单片机之间 i2c通信
6. 结束通信:通信完成后,主设备发送停止条件(Stop)来结束通信。
需要注意的是,不同的单片机可能会有不同的I2C模块和寄存器配置。在编程时,需要根 据具体的单片机型号和硬件设计来进行相应的配置和操作。
2. 初始化:在每个单片机中,需要初始化I2C模块。这通常包括设置I2C时钟频率、使能 I2C模块等。单片机之间 Nhomakorabeai2c通信
3. 主从模式选择:在I2C通信中,一个单片机可以充当主设备(Master),而其他单片机 则充当从设备(Slave)。主设备负责发起通信,从设备则响应主设备的请求。
4. 发送数据:主设备通过发送起始条件(Start)开始通信,并发送从设备的地址和读/写 位。然后,主设备发送要传输的数据到从设备。
单片机之间 i2c通信
I2C(Inter-Integrated Circuit)是一种串行通信协议,常用于单片机之间的通信。在单 片机中,I2C通信可以实现多个设备之间的数据传输和控制。
以下是单片机之间进行I2C通信的基本步骤:
1. 硬件连接:将多个单片机连接到同一条I2C总线上。I2C总线由两根信号线组成:SDA (数据线)和SCL(时钟线)。所有的设备都共享这两根信号线。
在Keil中,可以使用相应的库函数来实现I2C通信,例如使用STM32的HAL库函数来进行 I2C通信。具体的代码实现会依赖于所使用的单片机型号和开发环境。
描述i2c总线数据传输的过程

i2c总线数据传输的过程概述i2c(Inter-Integrated Circuit)总线是一种串行通信接口,用于在电路板上的不同芯片之间传输数据。
i2c总线由两根线组成:SDA(Serial Data Line)和SCL (Serial Clock Line)。
在i2c总线中,数据是通过主设备和从设备之间的双向通信进行传输的。
本文将详细介绍i2c总线数据传输的过程。
i2c总线传输层级i2c总线数据传输的过程可以分为以下几个层级:物理层、传输层、总线层。
物理层物理层是指i2c总线的硬件部分,包括SDA和SCL线以及外部上拉电阻。
SDA线用于传输数据,而SCL线用于传输时钟信号。
物理层的主要任务是提供一个可靠的电气连接。
传输层传输层主要负责通过i2c总线传输数据。
在传输层中,数据被分为字节序列。
每个字节都由8个位组成,包括一个起始位、8位数据位、一个可选的应答位和一个停止位。
数据是按照字节的顺序传输的。
总线层总线层在传输层之上实现了多主机的功能。
i2c总线允许多个主设备和从设备同时连接在同一条总线上。
总线层的主要任务是协调主设备和从设备之间的通信。
主设备负责发起通信并提供时钟信号,而从设备则负责接收主设备的命令并返回数据。
数据传输过程i2c总线数据传输的过程可以分为以下几个步骤:总线初始化、起始条件、地址传输、数据传输、停止条件。
总线初始化在开始使用i2c总线进行数据传输之前,必须先进行总线初始化。
初始化包括设置通信速率、配置主设备和从设备的地址以及初始化相关寄存器等操作。
起始条件在i2c总线上开始传输数据之前,需要发送起始条件。
起始条件是指将SDA从高电平切换到低电平之后,将SCL从高电平切换到低电平。
地址传输在发送起始条件之后,主设备需要发送从设备的地址。
地址包括从设备的地址以及读/写位。
主设备发送地址后,从设备会检测自己的地址是否与接收到的地址匹配。
如果匹配成功,从设备进入接收模式或发送模式。
软件模拟I2C总线的C51实现.

软件模拟I2C总线的C51实现摘要:介绍51系列单片机上的I2C总线主节点模拟程序,从而实现与具有I2C接口的器件通信。
1I2C总线简介1.1硬件结构I2C串行总线支持所有NMOS、CMOS、I2L工艺制造的器件。
从物理上看由两根双向I/O线组成,一根为数据线(SDA),一根为时钟线(SCL),通过这两根线把所有器件连接到总线上,并通过SDA和SCL在各器件间传递信息(根据地址识别每个器件)。
SDA和SCL通过上拉电阻接正电源,总线空闲时,两根线都是高电平。
这两根I/O线在电气上允许“线与”操作,其输出的驱动形式为集电极开路或漏极开路。
根据通信速度的不同,I2C总线分为三种工作模式:标准模式、快速模式和高速模式。
它们分别对应不同的波特率:100kb/s、400kb/s和3.4Gb/s。
总线上允许的设备数以总线上的电容量不超过400pF为限。
1.2数据传输I2C总线上数据为同步传输。
挂在I2C总线上的每一个器件都有一个独立的地址,而且在传输过程中有主节点和从节点的区分,主节点的作用是启动和结束一次通信,并负责控制总线时钟,总线上可以有多个主节点或多个从节点,但是在一次通信中只能有一个节点作为主节点。
主从机之间一次数据的传输称为一帧,由启动信号、地址信息、应答位及停止位组成。
其传送格式见图1。
2MCS-51与I2C总线芯片接口及程序2.18051经I2C总线扩展存储器PCF8582对于内部没有硬件I2C总线接口的51系列单片机,可以采用软件模拟的方法实现I2C总线接口功能。
硬件连接如图2所示。
用8051的P1.6和P1.7作为I2C总线的SCL利SDA信号,在总线上连接256*8的EEPROM芯片PCF8582。
8051单片机与PCF8582进行数据传递时,首先传送器件的从机地址SLA,格式如下:START为起始信号,从机地址的固定部分是4位——1010,可编程部分由,则该片的从机地址为引脚A2、A1、A0确定。
描述i2c总线数据传输的过程

描述i2c总线数据传输的过程I2C总线是一种串行通信协议,用于连接微控制器和外设。
它是由Philips公司于1980年代开发的,现在已经成为一种标准的总线协议。
I2C总线可以连接多个设备,并且可以通过软件进行编程,实现数据传输、控制和监测等功能。
在本文中,我们将详细描述I2C总线数据传输的过程。
一、I2C总线的基本概念1. I2C总线的定义I2C总线是一种简单、高效、低成本的串行通信协议,用于连接微控制器和外设。
它采用双向传输方式,可以实现多主机、多从机的通信。
2. I2C总线的基本构成I2C总线由两根信号线组成:SCL(时钟)和SDA(数据)。
其中SCL为时钟信号线,SDA为数据信号线。
时钟信号由主机产生,并且同步所有设备的操作。
3. I2C总线的工作原理I2C总线采用主从式通信方式。
主机发送起始位和停止位,在此期间,从机只能被动响应。
主机发送数据时,从机必须进行确认应答;反之亦然。
二、I2C总线数据传输的过程1. I2C总线的起始位和停止位I2C总线的起始位是SDA从高电平变为低电平,同时SCL保持高电平。
停止位是SDA从低电平变为高电平,同时SCL保持高电平。
2. I2C总线的数据传输方式I2C总线采用两种数据传输方式:字节传输和位传输。
字节传输是指每次传输8个二进制数位,即一个字节;而位传输是指每次只传输一个二进制数位。
3. I2C总线的主机发送数据过程主机发送数据时,首先发送器件地址和读写标志。
如果要读取设备的数据,则读写标志为1;如果要向设备写入数据,则读写标志为0。
然后主机发送数据,并等待从机响应确认应答。
4. I2C总线的从机接收数据过程当从机接收到主机发送的地址和读写标志后,如果地址匹配,则向主机发送确认应答信号。
然后从机接收主机发送的数据,并返回确认应答信号。
5. I2C总线的从机发送数据过程当从机需要向主机发送数据时,首先等待主机请求,并返回确认应答信号。
然后从机将需要发送的数据通过SDA信号线依次发送给主机,并等待主机响应确认应答。
[信息与通信]MCS-51单片机指令系统-数据传送类指令
![[信息与通信]MCS-51单片机指令系统-数据传送类指令](https://img.taocdn.com/s3/m/dfc60e766edb6f1afe001f5d.png)
2000H
0
ADD A,#02H ;用加法指令 进 2001H
1 4
行地址调整
9
MOVC A,@A+PC ;
16 25
(A)←(A+PC+1)
36
执行结果为:(PC)=1FFEH, (A)=09。
49
64 2009H 81
h
15
(2) 读、写片外RAM 指令
• MCS-51单片机CPU对片外扩展的数据存储 器RAM或I/O口进行数据传送,必须采用寄 存器间接寻址的方法,通过累加器A来完成。 这类指令共有以下4条单字节指令,指令 操作码助记符都为MOVX。
h
16
(2) 读、写片外RAM 指令
1) 读片外RAM MOVX A,@DPTR MOVX A,@Ri
2) 写片外RAM MOVX @DPTR,A MOVX @Ri,A
h
17
• 例 设外部RAM(0203H)= 0FFH,分析以下指 令执行后的结果。
• MOV DPTR,#0203H • MOVX A,@DPTR • MOV 30H,A • MOV A,#0FH • MOVX @DPTR,A • 执行结果为:(DPTR)=0203H,(30H)=FFH,
写出能完成下列数据传送的指令?r1的内容传送到r0?内部ram20h单元中的内容送到30h单元?内部ram20h单元中的内容送到30h单元?外部ram2000h单元中的内容送到内部ram20h单元?外部rom2000h单元中的内容送到内部ram20h单元?外部rom2000h单元中的内容送到外部ram3000h单元?3movdptr2000h?movxadptr?mov20ha?4movdptr2000h?mova00h?movcadptra?mov20ha?movdptr3000h?movxdptra已知20hx21hy22hz请用图示说明下列程序执行后堆栈中的内容是什么
STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码

STC51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码STC 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码原文:(改自周立功软件包)#include <reg51.h>#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned intextern void Delay1us(unsigned char );sbit SDA=P1^6; /*模拟I2C数据传送位*/sbit SCL=P1^7; /*模拟I2C时钟控制位*/bit ack; /*应答标志位*//************************************************************** *****起动总线函数函数原型: void Start_I2c();功能: 启动I2C总线,即发送I2C起始条件.*************************************************************** *****/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/Delay1us(1);SCL=1;Delay1us(5); /*起始条件建立时间大于4.7us,延时*/SDA=0; /*发送起始信号*/Delay1us(5); /* 起始条件锁定时间大于4μs*/SCL=0; /*钳住I2C总线,准备发送或接收数据 */Delay1us(2);}/************************************************************** *****结束总线函数函数原型: void Stop_I2c();功能: 结束I2C总线,即发送I2C结束条件.*************************************************************** *****/void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/Delay1us(1); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4us*/Delay1us(5);SDA=1; /*发送I2C总线结束信号*/Delay1us(4);}/*******************************************************************字节数据发送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
51单片机i2c读写程序的详细讲解

51单片机i2c读写程序的详细讲解下载提示:该文档是本店铺精心编制而成的,希望大家下载后,能够帮助大家解决实际问题。
文档下载后可定制修改,请根据实际需要进行调整和使用,谢谢!本店铺为大家提供各种类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by this editor. I hope that after you download it, it can help you solve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you! In addition, this shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts, other materials and so on, want to know different data formats and writing methods, please pay attention!《51单片机i2c读写程序的详细讲解》一、概述51单片机是一种常用的单片机,在很多应用中使用的最多的是i2c接口,那么如何在51单片机上进行i2c的读写操作呢?下面将详细讲解i2c读写操作的程序设计过程。
模拟I_2C总线实现AVR与MCS_51单片机通讯

中图分类号 : TN 913 文献标识码 : A 文3
Simu la ting th e I2 C to Realize AVR and the M CS- 51 Comm unication GAN H u i (T echnical Institute of YiChun University, YiChun J iangX i 336000, China ) Abstrac : t T he I C has the connection si m ply , the easy tooperate , T his techno logy obta ined the w idespread app lication in the industry
第 30 卷
2 uchar rdbyt ( ) /* 从 I C 总线上读 取 1 个数据字节 * /
{ ucha r nn= 0x f,f mm = 0x80 , uu= 0x7 ; f uchar ; j for ( j= 0; SDA = 1; nn= else nn= } re turn ( nn); } ( nn | mm ); nn= cro l ( nn, 1) ; SCL = 0;
2 2 2 2 2 2 2
( 或接收器 ), 这取决 于它所 要完成 的功能。 CPU 发出 的控 制信号分为 地址码 和控 制量两 部分 , 地 址码 用来选 址 , 即 接通需要控 制的电 路 , 确定 控制 的种类 ; 控制量 决定 该调 整的类别及 需要调 整的 量。这样 , 各 控制 电路虽 然挂 在同 一条总线上 , 却彼此独立 , 互不相关。 I2 C 总线在传 送数据 过程中共有三种 类型 信 号 , 它们 分别 是 : 起 始 信号、 结束 信号和应答信 号。起始 信 号 : 电平时 , SCL 为高 电平 时 , SDA 由高 SCL 为低 电平向低电平跳 变 , 开 始 传送 数据。 结束 信 号 :
51单片机模拟I2C总线的汇编源代码

NOP
NOP
NOP
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
NOP
NOP
NOP
SJMP WLP1
;启动IIC总线子程序
START:SETB SDA
NOP
NOP
SETB SCL ;起始条件建立时间大于4.7us
NOP
NOP
NOP
NOP
NOP
CLR SDA ;起始条件锁定大于4us
NOP
SETB SCL ;结束总线时间大于4us
NOP
NOP
NOP
NOP
NOP
SETB SDA ;结束总线
NOP ;保证一个终止信号和起始信号的空闲时间大于4.7us
NOP
RET
;发送字节子程序
;字节数据放入ACC
;每发送一个字节调用一次CACK子程序,取应答位
WRBYTE: MOV R0,#08H
WLP: RLC A ;取数据位
JC WR1
SJMP WR0 ;判断数据位
NOP
NOP
NOP
NOP
CLR SCL
NOP
NOP
NOP
NOP
NOP
SJMP WLP1
IWRNBYTE1:LCALL STOP
IWRNBYTE:LCALL START ;启动总线
MTD EQU 32H ;发送的数据
ORG 0000H
LJMP MAIN
;延时子程序,12M,125mS秒
DELAY:MOV R6,#00H
51单片机模拟I2C总线的C语言实现

51单⽚机模拟I2C总线的C语⾔实现I2C(Inter-Integrated Circuit)总线是⼀种由PHILIPS公司开发的两线式串⾏总线,⽤于连接微控制器及其外围设备。
I2C总线产⽣于在80年代,最初为⾳频和视频设备开发,如今主要在服务器管理中使⽤,其中包括单个组件状态的通信。
例如管理员可对各个组件进⾏查询,以管理系统的配置或掌握组件的功能状态,如电源和系统风扇。
可随时监控内存、硬盘、⽹络、系统温度等多个参数,增加了系统的安全性,⽅便了管理。
⼀、I2C总线特点 I2C总线最主要的优点是其简单性和有效性。
由于接⼝直接在组件之上,因此I2C总线占⽤的空间⾮常⼩,减少了电路板的空间和芯⽚管脚的数量,降低了互联成本。
总线的长度可⾼达25英尺,并且能够以10Kbps的最⼤传输速率⽀持40个组件。
I2C总线的另⼀个优点是,它⽀持多主控 (multimastering), 其中任何能够进⾏发送和接收的设备都可以成为主总线。
⼀个主控能够控制信号的传输和时钟频率。
当然,在任何时间点上只能有⼀个主控。
⼆、I2C总线⼯作原理2.1、总线的构成及信号类型I2C 总线是⼀种串⾏数据总线,只有⼆根信号线,⼀根是双向的数据线SDA,另⼀根是时钟线SCL。
在CPU与被控IC之间、IC与IC之间进⾏双向传送,最⾼传送速率100kbps。
各种被控制电路均并联在这条总线上,但就像电话机⼀样只有拨通各⾃的号码才能⼯作,所以每个电路和模块都有唯⼀的地址,在信息的传输过程中,I2C总线上并接的每⼀模块电路既是主控器(或被控器),⼜是发送器(或接收器),这取决于它所要完成的功能。
CPU发出的控制信号分为地址码和控制量两部分,地址码⽤来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对⽐度、亮度等)及需要调整的量。
这样,各控制电路虽然挂在同⼀条总线上,却彼此独⽴,互不相关。
2.2、位的传输SDA 线上的数据必须在时钟的⾼电平周期保持稳定数据线的⾼或低电平状态只有在SCL 线的时钟信号是低电平时才能改变。
I2C模拟程序

2.1 虚拟I2C总线汇编程序软件包2.1.1 概述为了非常方便地对I2C从器件进行快速的、正确的读写操作,我们为此而设计出虚拟I2C总线操作平台软件包。
本软件包是主方式下的虚拟I2C总线软件包,只要用户给子程序提供几个主要的参数,即可轻松地完成任何I2C总线外围器件的应用程序设计。
2.1.2I2C串行总线I2C总线是PHILIPS公司推出的芯片间串行数据传输总线,2根线(SDA、SCL)即可实现完善的全双工同步数据传送,能够十分方便地地构成多机系统和外围器件扩展系统。
I2C器件是把I2C的协议植入器件的I/O接口,使用时器件直接挂到I2C总线上,这一特点给用户在设计应用系统带来了极大的便利。
I2C器件无须片选信号,是否选中是由主器件发出的I2C从地址决定的,而I2C器件的从地址是由I2C总线委员会实行统一发配。
我们推出的I2C总线的操作平台软件包,只要你给出器件从地址[,子地址(注:PCF8574无子地址)],即可进行字节读,字节写,多字节读,多字节写,能够非常方便地使用I2C器件,无须你介入底层的I2C操作协议。
2.1.3汇编软件包说明此软件包是用在单主I2C总线上,硬件接口是SDA,SCL,使用MCU的I/O口来模拟SDA/SCL总线。
设计有/无子地址的子程序是根据I2C器件的特点,目的在于将地址和数据彻底分开。
软件包的接口界面为:IRDBYTE (无子地址)读单字节数据(现行地址读)IWRBYTE (无子地址)写单字节数据(现行地址写)IRDNBYTE (有子地址)读N字节数据IWRNBYTE (有子地址)写N字节数据说明:现行地址读/写即专指无子地址的器件,不给定子地址的读/写操作。
;平台占用内部资源:R0,R1,R2,R3,ACC,Cy。
;使用前须定义变量:SLA 器件从地址,SUBA器件子地址,NUMBYTE读/写的字节数,位变量ACK ;使用前须定义常量:SDA 、SCL 总线位,MTD 发送数据缓冲区首址,MRD 接收数据缓冲区首址;(※子程序出口参数ACK为0时表示从器件无应答)2.1.4软件包清单;--------------------------------------------------------------------------------------------------------;VI2C_ASM.ASM;I2C 软件包的底层子程序,使用前要定义好SCL和SDA。
C51单片机10(I2C总线)

启动I2C总线
void start(void) { sda = 1; flash(); scl = 1; flash(); sda = 0; //在SCL高电平期间,SDA下降沿启动I2C总线 flash(); scl = 0; flash(); }
停止I2C总线
void stop() { sda = 0; flash(); scl = 1; flash(); sda = 1; //在SCL高电平期间,SDA上升沿停止I2C总线 flash(); }
CAT24WCXX系列E2PROM框图
CAT24WCXX系列E2PROM写入方式
• 字节写入 • 页写入——在一个写周期内编程写入一页
型号 CAT24WC01 CAT24WC02 CAT24WC04 CAT24WC08 CAT24WC16
容量(Kb) 1 2 4 8 16
类型码 1010 1010 1010 1010 1010
//把最高位移入CY //SCL低电平期间才允许SDA数据变化 //把CY送上SDA
uchar readx(void) { uchar i, j, k = 0; scl = 0; flash(); sda = 1; for(i=0; i<8; i++) { flash(); scl = 1; flash(); if(sda == 1) { j = 1; } else j = 0; k = (k << 1) | j; scl = 0; } flash(); return(k); }
4. 主器件发送“停止”信号,从器件启动内部写周期,
将数据写到数据区
I2C总线信息传送时序——页写
1. 2. 3. 4. 5. 6. 主器件发送“开始”信号和从器件地址,等待从器件送 回应答信号 主器件收到应答信号后,再发送器件内单元地址,写入 从器件,等待从器件送回应答信号 主器件收到应答信号后,发送1字节数据,写入从器件 指定存储单元,等待从器件送回应答信号 主器件收到应答信号后,再发送1字节数据,写入从器 件内部地址修正的后续存储单元 ……持续上述过程 一页写完后,主器件发送“停止”信号,从器件启动内 部写周期,将数据写到数据区(页长度见后续内容)
51单片机I2C通信程序

51单片机I2C通信程序#include#include#define ACK 0#define NOACK 1#define OUTPUT 1#define INPUT 0#define WRITE 0#define READ 1#define TRIALS 100#define ERR_CRC 2#define ERR_BUSY 1#define ERR_OK 0#define uchar unsigned char#define uint unsigned int#define uchar unsigned char#define uint unsigned intuchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr);uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr);uchar ReceiveRand(uchar DevAdr, uchar MemAdr, uchar* Chr);uchar PageWrite(uchar DevAdr, uchar MemAdr, uchar* Chr, uchar Siz); uchar SeqRead(uchar DevAdr, uchar MemAdr, uchar* ReceivedChr,uchar Siz);static void Delay(void);static void Write(uchar Data);static uchar Read(void);static bit GetAck(void); static void SetAck(bit Ack); static void start(void); static void stop(void);sbit SDA = P2^5;sbit SCL = P3^6;static void Delay(void){_nop_();_nop_();_nop_();}static void Write(uchar Data) {uchar Shift;uchar I;uchar timeout;Shift = 128;for (I = 8; I != 0; I--) {if (Data & Shift) {SDA = 1;}else {SDA = 0;}Shift >>= 1;SCL = 1;Delay();timeout = 255;while((SCL == 0)&&(timeout!=0)) {timeout--;}SCL = 0;Delay();}}static uchar Read(void){uchar Shift;uchar I;uchar timeout;Shift = 0;SDA = 1;for (I = 8; I != 0; I--) {SCL = 1;Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}Shift <<= 1;if (SDA) {Shift++;}SCL = 0;Delay();}return Shift;}static bit GetAck(void){uint timeout;SDA = 1; /* SDA HIGH */SCL = 1; /* CLOCK HIGH PULSE */Delay();timeout = 255;while((SCL==0)&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}return(SDA); /* ACKNOWLEDGE V ALUE */}static void SetAck(bit Ack){uint timeout;if (Ack) {SDA = 1; /* MASTER NOACKNOWLEDGE - SDA HIGH */}else {SDA = 0; /* MASTER ACKNOWLEDGE - SDA LOW */ }SCL = 1; /* HIGH CLOCK PULSE */Delay();timeout = 255;while((SCL ==0 )&&(timeout!=0)) { /* WAIT FOR CLOCK HIGH PULSE */ timeout--;}SCL = 0; /* LOW CLOCK PULSE */SDA = 1; /* ACKNOWLEDGE END - SDA HIGH */}static void start(void){SDA = 1; /* SDA HIGH - START SETUP*/SCL = 1; /* CLOCK HIGH PULSE */Delay(); /* CLOCK HIGH PULSE & BUS FREE TIME */ SDA = 0; /* START CONDITION */Delay(); /* START HOLD TIME */SCL = 0; /* CLOCK LOW PULSE */Delay();}static void stop(void){SDA = 0; /* STOP SETUP */SCL = 1; /* CLOCK HIGH PULSE + STOP SETUP TIME */Delay();SDA = 1; /* STOP CONDITION */}uchar EI2C1_SendChar(uchar DevAdr,uchar MemAdr,uchar Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + WRITE));Acknowledge = GetAck();--Trial;} while (Trial && Acknowledge);if (Acknowledge) { /* WRONG ACKNOWLEDGE */SCL = 0; /* CLOCK LOW PULSE */return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(MemAdr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}Write(Chr);if (GetAck()) { /* WRONG ACKNOWLEDGE */ SCL = 0; /* CLOCK LOW PULSE */stop();return ERR_BUSY;}else {SCL = 0; /* CLOCK LOW PULSE */Delay();}stop();return ERR_OK;}uchar EI2C1_RecvChar(uchar DevAdr, uchar *Chr){uchar Trial;bit Acknowledge;Trial = TRIALS;do {start();Write((uchar)(DevAdr + READ)); //写设备地址。
用Proteus学习51单片机之I2C

在学习单片机的过程中,我常有这样的烦恼:随随便便一个芯片,少则占用三五个IO口,一般的就占用8个,稍微想用多一点芯片吧,老觉得IO口不够用。
学串口的时候觉得串口是个好东西,连两条线就够了,现在学到I2C,觉得这也是一个非常好的东西,也是两条线,还能给每个总线上的设备设立地址,简直就是一个小网络了。
I2C总线使用两条线,一条是时钟线,称为SCL,一条是数据线,称为SDA,各个设备就并在总线上,每一个总线上的设备都有一个自己的地址,主机在操作设备的时候,都会先发送一个地址码,告诉被操作机,接下来的命令由它接收。
接下来说一下I2C总线的数据有效性。
I2C总线进行数据传送时,要求SCL为高电平时,SDA上的数据必需保持稳定,换言之,当SCL为高电平时,SDA的电平不能变换,只有当SCL为低电平时,SDA的电平才能变。
I2C总线通信时,需要遵照一定的协议,以下为一次通信过程:1.由主机发送起始信号,启动I2C总线。
时序为,在SCL为高电平期间,SDA出现一个下降沿。
2.主机发送寻址信号,即告诉特定的设备,接下来的命令是发给它的。
地址分为7位和10位,以7位为例,高7位为设备地址,最低位表示读或写,1表示读,0表示写。
3.应答信号,I2C协议规定,每传送一个字节数据(包括地址及命令)后,都要有一个接收设备返回的应答信号,以确定信号是否被接收设备正确接收到了。
其时序为,在SCL信号为高电平期间,接收设备把SDA电平拉低。
4.数据传输,当主机发送发址并收到应答后,就可以发送数据了,但是发送数据只能每次发送一位,并且每发送一位后都需要收到接收机的应答。
或主机为接收设备时,主机对最后一个字节不应答,表示向发送设备说,数据传送结束。
5.发送停止信号,在全部数据传送完毕后,主机发送停止信号,时序为,在SCL为高电平期间,SDA上产生一个上升沿。
前面讲到,I2C协议要求数据的发送,要求SCL为低电平时,SDA才能变换,看一下上面的时序,可以看到,命令都是SCL为高电平时对SDA的操作,而发送数据则是SCL为低电平时对SDA操作。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
51单片机模拟I2C总线的数据传送
学习交流QQ群——126500542(验证信息:千寻琥珀心)本文主要介绍I2C总线的数据传送、数据传输的协议以及传输的格式并对单片机与I2C总线的接口予以说明,并给出单片机口模拟I2C主机的时序,其实时序一看懂了,程序也就出来了。
汇编和C.在将单片机模拟I2C之前,先来了解一下I2C。
I2c总线是由一根数据线SDA和一根时钟线SCL组成,他们都是双向传输线,既可用于发送也可用于接收。
一般总线挂接在主器件上时处于备用状态即处于空闲状态,要求I2C总是显示为高电平,故需要在电路中对这两总线加上拉电阻。
将其拉为高电平,只用当需要关闭I2C总线时,SCL线才会变为低电平。
在I2C总线上,SDA是数据线,SCL为时钟线,注意每传送一位数据,都要有一个对应的SCL线上的脉冲信号。
即SDA和SCL是一一对应的,总线又规定,在传送数据的时候,SCL为高电平时要求SDA线上的数据稳定。
也就是说当SCL为高电平时,不允许SDA线上的数据发生变化。
当SCL线为低电平时,才允许SDA线上的数据发生变化。
注意数据传送时,先传送最高位,好I2C总线上的数据信号基本上就这样了,简单的说了一下,下面我们就来看看其他几个信号。
起始信号、停止信号、应答信号和非应答信号。
起始信号顾名思义,即为发送数据的开始,停止信号即为发送数据的结束。
应答信号,由于i2c总线是双总线,数据线只有SDA,所以总线规定,要求每发送完一个字节的数
据,就得产生一个应答信号,但需要注意的是,这里的应答信号不是有从机产生的,而是像起始信号和停止信号一样是由主机产生的。
发送设备在应答时钟脉冲高电平期间释放SDA线(高电平),转由接收器控制。
接收设备在这个时钟内必须将SDA拉为低电平,以产生有效地应答信号。
下面将给出时序图。
(简言之就是有主机控制的SDA线转由从机控制,以相应主机数据已成功发送)但是如果从机不能接收下一个字节,(注意此处是下一个字节,说明上一字节已经接收完成并产生应答)比如正在处理一个外部中断,则可以先把SCL线拉低,是主机处于等待状态。
当从机准备好时,即中断处理完成时再释放SCL线,是数据传送继续进行。
但是当数据传送完但是没有产生应答信号时,如一个从机正在处理一个实时时间,不能接受(或不能产生应答信号时),从机必须使SDA线保持高电平,此时主机产生一个信号,即为非应答信号,是传送异常结束。
但是当主机作为接收器时,主机对最后一个字节不予应答(非应答信号),以向从机之处数据传送结束,从机释放SDA线使其变为高电平,使主机产生一个结束信号。
晕,感觉上面写的看着挺乏的,没办法,美工不好,又不是写小说。
只以作为一个参考资料罢了。
当然主要是为我自己服务。
以后用着稍微方便点。
虽然不敢说方便。
也可稍微加深了一下对I2C的理解与记忆。
何乐而不为。
好,下面我们来看看I2C总西安的传输协议。
传输协议吗,
一样,顾名思义,任何一事物他都有自己内在的规律,只有理解了这种规律和他们相处才会更融洽些,而不会陌生的很尴尬。
在上面我们已经对I2C总线的传输协议小坐了一点介绍,下面我们继续接着,当主机发送一个起始信号后,接着他就得发送数据了,发送的第一个字节数据位寻址字节,此字节决定了选取从机中的哪一个从机,相当于片选信号,在这8位字节中,其中高7位为从机地址,最后一位为读写方向控制位,何为读写方向,简言之就是控制主机是读信息还是写信息,当此位为0时,主机写,当此位为1时,主机读。
好,我们还是看看他的高7位吧,当主机发送一个寻址自节后,系统中的每个从机都会将从7位数据与自己的地址进行比较,若相同则从机会应答主机寻址。
在这7位数据中,高四位为固有地址,我们是不能对其进行操作编程的,但是后三位是可操作,可编程的。
所以可以设置这三位来选择哪个从机被主机选中,这三位的排列方式有2^3=8种,故总线上可挂接8个I2C器件。
对于主控器件也就是主机的读写操作,这里就不做介绍了,您可以根据上述的起始信号、应答信号、非应答信号、停止信号7个位和R/W自行思考(注意每发送完一个字节都要有一个应答位,在发送完寻址字节之后,就是发送数据了,数据为8位。
之后也要寻址信号,如果之后不发送数据了,可以直接一停止信号结束,但是如果还想发送或者改变发送方向,可以重新一个起始信号,然后在寻址通过改变R/W来改变传送方向。
)再次指出
的是如果主机作为接收器件即读取从机的信息,最后一个字节,主机不发送应答信号即发送非应答信号,以向从机说明接收完毕,让从机停止发送。
哎,要命啊,没办法,人家规定的,线少了,规矩也就多了。
综上部分描述,以下是别人给出的结论
·无论总线处于何种方式,起始信号、终止信号和寻址字节均由主控器件发送和被控器件接收。
·寻址字节中7位地址为器件地址,即被寻址的被控器件的固有地址,R/W方向由于指定SDA线上数据传送的方向,R/W=0为主控器件写被控器件收,R/W=1为主控器件收被控器件写。
·总线上传输的每个字节后必须跟一个应答或非应答。
感觉上面总结的比较好,几句就概括了我写的大部分内容。
可是这几句,呵呵,就这几句,呵呵,几乎没多少用,就像,有钱花不出去一样,不过,没事,留着,总有会用到的。
好,下面我们就来看看各个信号的时序,并给出相应的程序起始信号:
根据上面的时序直接写程序就行了,从SDA开始,假设使用12MHZ晶振,则每个机器周期为1us。
则程序如下(一下程序也按此)
STA:
SETB SDA
SETB SCL//SDA起始条件建立为大于4.7US
NOP
NOP
NOP
NOP
NOP
CLR SDA//按时序图拉低
NOP
NOP
NOP
NOP
NOP//SCL在SDA拉低时延时大于4US
CLR SCL
RET
C程序
V oid i2c_start()
{
SDA=1;
SCL=1;
NOP;//此处的NOP将会在最后给出宏定义
SDA=0;
NOP;
SCL=0;
}
停止信号:
汇编:STOP: CLR SDA SETB SCL NOP NOP NOP NOP NOP SETB SDA NOP NOP NOP NOP
NOP
CLR SDA CLR SCL RET
C语言
V oid i2c_stop() {
SDA=0;
SCL=1;
NOP;
SDA=1;
NOP;
SDA=0;
SCL=0;
}
应答信号:
汇编YINGDA:
CLR SDA SETB SCL NOP
NOP
NOP
NOP
NOP
CLR SCL SETB SDA
RET
C语言:
V oid i2c_yingda()
{
SDA=0;
SCL=1;
NOP;
SCL=0;
SDA=1 }
非应发信号:
汇编:FEI:
SETB SDA SETB SCL NOP
NOP
NOP
NOP
NOP
CLR SCL
CLR SDA
C语言:
V oid i2c_fei()
{
SDA=1;
SCL=1;
NOP;
SCL=0;
SDA=0;
}
好,本文到此也就告一段落了,置于下面的发送接收单个字节,发送接收多个字节,以及应答位检测的问题,在这里就不在将程序贴出了,感兴趣的话,可以百度一下,其实上述的时序知道怎么写了,下面的就好做了,就当作为一个作业留给你们了。
嘻嘻。
如果还有疑问的话,可加上面的QQ群进行讨论。
最后我将上面的C语言及汇编时的端口定义一下。
当然这只对需要的人的。
SCL BIT 80H.0(即P0.0)
SDA BIT 80H.1(即P0.1)
C部分的定义
#define NOP {_nop_();_nop_();_nop_();_nop_();_nop_();} Sbit SCL=P0^0;
Sbit SDA=P0^1;
其中要向使用_nop_()函数必须得有头文件intrins.h
即要有:#include <intrins.h>。