51单片机的模拟IIC总线程序
实验八 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单片机I2C总线
51单⽚机I2C总线I2C总线是飞利浦公司推出的⼀种串⾏总线,所有器件共⽤两根信号线,实现数据的传输。
总线接⼝接了上拉电阻,默认为⾼电平,所以就可以⽤“当低电平出现”来标记出⼀种起始信号。
我个⼈把它想象成:许多⼈在⼀条⾛廊上的不同房间(器件)⾥,⼤家都把门打开,连出两根长长的听筒(⼩时候玩的那种),每个⼈都从两根⼤主线上各接⼀根到⾃⼰房间⾥。
两根听筒平时都是安静的(1)。
如果有某房间的⼈叫了⼀声(0),那剩下的⼈就知道,我们准备开始通话了。
为了保证秩序,⼤家选出⼀个⼈当领队,由他来主导通话的过程。
这就是总线的主机,其他⼈就是从机。
从机有多个,主机只有⼀个。
两根信号线,⼀根叫数据线SDA,⼀根叫时钟线SCL。
顾名思义,数据线⽤来传输数据,时钟线⽤来管理顺序。
怎么样表⽰开始,怎么样表⽰结束,⽤下⾯的图表⽰。
注意有严格的时间规定。
⾸先,我们知道怎么样算是通话的开始和结束(起始信号和终⽌信号)。
然后,规定怎样算是回答“可以”,怎么算是回答“不可以”(应答和⾮应答)。
接着,我们要知道谁向谁喊话,所以要给每个房间的⼈都赋予⼀个名字,也就是地址。
再⽤⼀个0或1表⽰⽅向,从谁到谁。
因此,数据传输的过程,⼤体就是如此:领队喊出“开始”,说出⼀个房间名,同时,所有房间的⼈确认是不是⾃⼰的。
领队表明⽬的,说出是向他传数据,还是从他那读数据;然后,确认是⾃⼰房间的队员给出应答,可以就开始传输数据。
完成后,主机/从机给出应答,表明收到了没有。
下⾯就是SDA上传送的数据格式。
(a)主机向从机发送数据S表⽰起始信号。
阴影表⽰主机发送。
A表⽰应答,上加划线表⽰⾮应答。
P表⽰停⽌。
(b)主机发送数据后,从从机读数据(c)传输过程中,想改变⽅向⽅法是,重复⼀次起始信号和从机地址,加⼀个⽅向位来改变⽅向。
SCL是⽤来管秩序的。
只要SCL保持⾼电平状态,SDA正在传的数据就不能乱动,只有把它拉低以后,SDA才能变化。
这样确保数据传输不会乱套,所以在实际的传输过程中,SCL会不断地翻转。
C51单片机模拟I2C总线驱动程序设计
_nop_(); } SCL = 0; _nop_(); _nop_(); return(retc); } /************************************ I2C_Ackn ******************************** 函数名:void I2C_Ackn(bit a) 入口:0 或 1 出口: 功能描述:主控制器进行应答信号(可以是应答或非应答信号) 说明:作为接收方的时候,必须根据当前自己的状态向发送器反馈应答信号 调用函数: 全局变量: *******************************************************************************
//位
retc = 0; SDA = 1; //置数据总线为输入方式,作为接收方要释放 SDA. for(BitCnt=0;BitCnt<8;BitCnt++) { _nop_(); SCL = 0; //置时钟线为低准备接收数据位 SomeNOP(); //时钟低电平周期大于 4.7us SCL = 1; //置时钟线为高使数据有效 _nop_(); _nop_(); retc = retc<<1; if(SDA==1) { retc = retc + 1; //读数据位,接收的数据放入 retc 中 } _nop_();
//发送器件子地址
//发送数据
//结束总线
/********************************** I2C_IRcvB ********************************* 函数名:bit I2C_IRcvB(uchar sla, uchar suba, uchar *c) 入口:从器件地址 sla, 子地址 suba, 收到的数据在 c 出口:1(操作成功),0(操作有误) 功能描述:从启动总线到发送地址、读数据,结束总线的全过程。
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);}问题:本程序中未采用块读写的方法,显得有点‘笨’,这是由于项目原因,现项目已完成,程序已写好,短时不会修改,也不会花上一定的精力去做,虽然理论上已很成熟,就这样写一下,未必不对,但与我的本栏目要求不符,所以就未做上去,如果以后我做了,将再补上。
实验八 51系列单片机IIC
•
I_Delay(100);
•
SCL=HIGH;
•
I_Delay(100);
•
S);
•
SCL=LOW;
•
I_Delay(100);
•}
8.3.3 应答信号
• 应答信号用于表明数据传输的结束。I2C总线数据传送时,每传送一个字节 数据后都必须有应答信号。应答信号从主器件产生。主器件在第9个时钟 位上释放数据总线,使其处于高电平状态,此时从器件输出低电平拉低数 据总线为应答信号。
• 如果采用C语言进行程序设计,则发送应答位子程序示例如下:
• void I_Ack()
•{
•
SDA=LOW;
•
I_Delay(100);
•
SCL=HIGH;
•
I_Delay(100);
•
SCL=LOW;
•
I_Delay(100);
•
SDA=HIGH;
•
I_Delay(100);
•}
8.3.4 非应答信号
• 非应答信号用于数据传输出现异常而无法完成时。 在传送完一个字节数据后,在第9个时钟位上从器 件输出高电平为非应答信号。非应答信号的产生 有两种情况。
• 当从器件正在进行其他处理而无法接收总线上的 数据时,从器件不产生应答,此时从器件释放总 线,将数据线置为高电平。这样,主器件可产生 一个停止信号来终止总线数据传输。
51单片机综合学习系统之 IIC总线学习篇.
大家好,通过以前的学习,我们已经对51单片机综合学习系统的使用方法及学习方式有所了解与熟悉,学会了使用无线遥控模块的基本知识,体会到了综合学习系统的易用性与易学性,这一期我们将一起学习IIC总线的基本原理与应用实例。
先看一下我们将要使用的51单片机综合学习系统能完成哪些实验与产品开发工作:分别有流水灯,数码管显示,液晶显示,按键开关,蜂鸣器奏乐,继电器控制,IIC 总线,SPI总线,PS/2实验,AD模数转换,光耦实验,串口通信,红外线遥控,无线遥控,温度传感,步进电机控制等等。
上图是我们将要使用的51单片机综合学习系统硬件平台,如图1所示,本期实验我们用到了综合系统主机、板载的AT24C02芯片,综合系统其它功能模块原理与使用详见前几期《电子制作》杂志及后期连载教程介绍。
在很多电子设备中都有要随时存取数据作为历史记录或标志位。
目前常用的存储器有24CXX系列和93CXX系列,前者是I2C总线结构,后者是SPI总线结构,本小节先介绍I2C结构的EEPROM(24CXX)作用方法,在后面小节中再介绍SPI结构的EEPROM(93CXX)使用方法。
I2C总线基本概念I2C总线,是INTERINTEGRATEDCIRCUITBUS的缩写,即“内部集成电路总线”。
I2C总线是Philips公司推出的一种双向二线制总线。
目前Philips公司和其它集成电路制造商推出了很多基于I2C总线的外围器件。
I2C总线包括一条数据线(SDA)和一条时钟线(SCL)。
协议允许总线接入多个器件,并支持多主工作。
总线中的器件既可以作为主控器也可以作为被控器,既可以是发送器也可以是接收器。
总线按照一定的通信协议进行数据交换。
在每次数据交换开始,作为主控器的器件需要通过总线竞争获得主控权,并启动一次数据交换。
系统中各个器件都具有唯一的地址,各器件之间通过寻址确定数据接收方。
I2C总线的系统结构一个典型的I2C总线标准的IC器件,其内部不仅有I2C接口电路,还可将内部各单元电路划分成若干相对独立的模块,它只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。
单片机模拟IIC 规范(习霜)
I2C_WriteByte(address);//address为芯片内子地址
I2C_Ack();
for (i=0;i<ByteNum;i++) //写入多个字节
{
I2C_WriteByte(*WriteSerialData);
I2C_Ack();
I2C_Delay();
SCL = 1;
I2C_Delay(); /*时钟高电平周期大于4μs*/
while ((SDA = 1)&&(i < 250))i++;
SCL = 0; /*清时钟线,钳住I2C总线以便继续接收*/
_nop_();
_nop_();
}
/***********************************************************
3、当主机为接收设备时,主机对最后一个字节无应答,以向发送设备表示数据传送结束
***********************************************************/
void I2C_Ack(void)
{
uchar i = 0; //循环体控制变量
SDA = 0;
void I2C_WriteSerialData(uchar address, uchar *WriteSerialData, uchar ByteNum)
{
uchar i = 0; //循环体控制变量
I2C_Start();
I2C_WriteByte(0xa0);//向器件发送写操作控制字,0xa0是芯片的地址,这里是EEPROM的地址,1010(前四个固定)000(中间三个是可编程地址)0(最后一个0是R/W位写)
51单片机IO口线模拟IIC总线3部曲之第3部
本文是对第1,2部的使用说明。
若有错误之处请不吝赐教。
IIC底层驱动包使用说明一:说明:(1) 本软件包是使用51单片机IO口线来模拟IIC总线。
适用于12T周期单片机。
若想移植到单T周期单片机,请自行修改。
(2) IIC总线时钟是通过软件延时的方法产生的,所以对不同频率的时钟,需要做一些调整。
(3) 本驱动是IIC最底层的驱动函数,请勿随意改动本驱动。
(4) 本驱动对外只有两个函数可供使用。
一个是“写多字节函数”IICMCUSendStr(),另一个是“先写多字节,然后重新启动总线写一字节,最后接收多字节函数”IICMCUSendStrSendByteRcvStr()。
关于这两个函数的说明请见第三部分,函数详解。
(5) 针对不同的IIC器件读写时序的不同,您应该自己编写IIC器件的驱动。
二:移植方法:使用时有3个地方需要修改,以实现移植。
SDA,SCL和N_12MHz,这三个变量都在IICLowDriver.H文件中。
并且它们定义在文件最开始的位置。
SDA:IIC数据线。
请根据您的硬件设置来选择正确的IO口。
SCL:IIC时钟线。
请根据您的硬件设置来选择正确的IO口。
N_12MHz:所用时钟频率F(单位MHz)与12MHz的比值。
该变量关系到IIC总线时序的正确与否,一定要设置正确。
其取值见下表。
时钟频率F取值范围(MHz)0 ≤ F ≤ 1212 < F ≤ 2424 < F ≤ 3636 < F ≤ 48N_12MHz取值1234只要设置好这三个变量,就可以方便的使用IIC总线了。
为增加移植时的安全性,这三个变量用了预处理命令,移植时请勿改动预处理命令。
三:函数详解。
1、向IIC总线发送多字节数据函数(对外接口)本函数用于IIC器件的写操作。
//-------------------------------------------------------------------------------////函数名称:IICMCUSendStr//函数功能:向IIC总线发送多字节数据。
如何用51单片机实现IIC通信
如何用51单片机实现IIC通信在之前的MCS-51系列单片机中内部没有IIC通信资源,所如果要想用51单片机实现IIC通信,就只能通过软件模拟其时序,这样也能实现IIC通信的功能。
这个是IIC的头文件,便于使用调用:#ifndef _IIC_H_#define _IIC_H_/***ucahr和uint 的宏定义很重要,否则下面的函数无法正常运行******/#define uchar unsigned char //定义uchar型数据为无符号型#define uint unsigned int //定义uint型数据为无符号型sbit SCL = P2 ;sbit SDA = P2 ;/***申明外部函数****/extern void delay_1ms(void);extern void IIC_Init(void);//IIC初始化extern void Signal_Start(void);//IIC停止信号extern void Signal_Stop(void);//IIC停止信号extern void Write_Byte(uchar wdata);//写一个字节数据函数extern uchar Read_Byte();//读一个字节数据函数extern void Write_Add(uchar add,uchar wdata,uchar comd);//向某个IIC器件写指令,地址和数据extern uchar Read_Add(uchar add,uchar comd);//向某个IIC器件写指令读某个地址里面的数据#endif以下是IIC通信的C语言源代码:#include#include。
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 线的时钟信号是低电平时才能改变。
片机教程51系列单片机读写IIC总线
测试步骤和注意事项
测试步骤和注意事项
01
3. 发送IIC总线读写命令,检查数据传输是否正确。
02
4. 重复测试,验证稳定性。
注意事项
03
1. 确保电源稳定,避免因电源波动导致IIC总线不稳定。
2. 确保连接线缆质量良好,避免因线缆问题导致信号传输错误。
3. 在测试过程中,避免频繁开关电源或拔插线缆。
51系列单片机读写IIC总线调试与测试
软件工具
串口调试助手、IIC调试器等。
调试方法
通过观察IIC总线的信号波形、电压值等参数,判断IIC总线是否正常工作。
硬件工具
万用表、示波器、逻辑分析仪等。
调试工具和方法
1
2
3
测试步骤
1. 连接IIC总线,确保单片机、传感器等设备正确连接。
2. 配置单片机IIC总线参数,如地址、速率等。
是8051的改进版,增加了一些功能,如更多的I/O端口、定时器等。
是8051的增强版,具有更高的处理速度和更大的内存。0302源自0151系列单片机介绍
SDA(串行数据):用于传输数据。
SCL(串行时钟):用于同步数据传输。
双向数据线:SDA线是双向的,可以用于发送和接收数据。
IIC总线硬件接口
为单片机提供稳定的电源。
工业控制实例
在医疗设备中,以血压计为例,通过51单片机读写IIC总线,实现血压数据的采集、处理和显示,同时可将数据传输至云平台进行分析。
医疗设备实例
应用实例解析
应用前景展望
随着物联网技术的不断发展,51系列单片机读写IIC总线的应用将更加广泛,特别是在智能家居、工业控制等领域,具有广阔的市场前景。
IIC总线具有寻址能力,可以通过地址码识别目标设备。
51单片机IO口线模拟IIC总线3部曲之第2部
// 51单片机IO口线模拟IIC总线3部曲之第2部 IICLowDriver.H// 把本文全部复制保存为IICLowDriver.H//**************************************************************************** // 文件名 IICLowDriver.H// 简介:// 使用51单片机IO口线来模拟IIC总线。
适用于12T周期单片机,不能用于单T周期单片机。
// 本文件中是IIC最底层的驱动函数//// 这些底层驱动函数包括IIC总线的起动(IICStart)与关闭(IICStop),MCU对应答信号// 的发送(IICMCUSendACK)与接收(IICMCURcvACK),1字节数据的发送(IICMCUSendSDAByte)// 与接收(IICMCURcvSDAByte)这6个函数。
这6个函数是相互独立的,没有互相调用。
// 针对不同的IIC器件读写时序的不同,您应该自己编写IIC器件的驱动。
// 另外为了适应不同频率的时钟,本驱动中作了相关的设置。
// 详细使用说明请参见《IIC底层驱动包使用说明》。
// 移植说明:// 请修改本文件中的“移植修改”部分来完成移植。
仅需要改动3个地方,SCL// SDA和N_12MHz。
其他预处理命令请不要改动。
//*********************************************************************#define uchar unsigned char//--------------------------头文件包含------------------------------//#include<reg52.h>//-----------------------------移植修改-----------------------------////-----------------------------信号定义-----------------------------//#if defined(SDA_ON)sbit SDA = P1^7; // 模拟I2C数据传送位,移植时请修改此处的IO口#endif#if defined(SCL_ON)sbit SCL = P1^6; // 模拟I2C时钟控制位,移植时请修改此处的IO口#endif//-----------------------------晶振频率之比-------------------------//// N_12MHz:所用晶振频率F(单位MHz)与12MHz的比值。
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() //等待从机应答信号,如果从机迟迟没有应答,则结束总线。
IIC总线原理及其在51单片机中的简单应用
IIC 总线原理及其在51 单片机中的简单应用
1. IIC 总线基本概念
1.1 总线概述
IIC 总线是PHLIPS 公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。
1.2 总线结构
IIC 总线是由数据线SDA 和时钟线SCL 构成的串行总线,可发送和接收数据。
在CPU 与被控IC 之间、IC 与IC 之间可以进行双向传送,最高传送速率100kbps。
各种被控制电路均并联在这两条总线上。
2. IIC 总线协议
2.1 数据传输中的主/从机
在多主机系统中,可能同时有几个主机企图启动总线传送数据。
为了避免混乱,IIC 总线要通过总线仲裁,以决定由哪一台主机控制总线。
连在每一个总线上的电路和模块都有一个唯一地址,它们彼此之间只有简单的。
51单片机的模拟IIC总线程序
#include <reg764.h> /*头文件的包含*/#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned int#define _Nop() _nop_() /*定义空指令*//* 常,变量定义区 *//*端口位定义*/ sbit SDA=P1^3; /*模拟I2C数据传送位*/sbit SCL=P1^2; /*模拟I2C时钟控制位*//*状态标志*/ bit ack; /*应答标志位*/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/_Nop();SCL=1;_Nop(); /*起始条件建立时间大于4.7us,延时*/_Nop();_Nop();_Nop();_Nop();SDA=0; /*发送起始信号*/_Nop(); /* 起始条件锁定时间大于4μs*/_Nop();_Nop();_Nop();_Nop();SCL=0; /*钳住I2C总线,准备发送或接收数据 */_Nop();_Nop();}void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/_Nop(); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4μs*/_Nop();_Nop();_Nop();_Nop();_Nop();SDA=1; /*发送I2C总线结束信号*/_Nop();_Nop();_Nop();_Nop();}void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/{if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/else SDA=0;_Nop();SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();_Nop(); /*保证时钟高电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0;}_Nop();_Nop();SDA=1; /*8位发送完后释放数据线,准备接收应答位*/ _Nop();_Nop();SCL=1;_Nop();_Nop();_Nop();if(SDA==1)ack=0;else ack=1; /*判断是否接收到应答信号*/SCL=0;_Nop();_Nop();}uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; /*置数据线为输入方式*/for(BitCnt=0;BitCnt<8;BitCnt++){_Nop();SCL=0; /*置时钟线为低,准备接收数据位*/_Nop();_Nop(); /*时钟低电平周期大于4.7μs*/_Nop();_Nop();_Nop();SCL=1; /*置时钟线为高使数据线上数据有效*/_Nop();_Nop();retc=retc<<1;if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();_Nop();}SCL=0;_Nop();_Nop();return(retc);}/********************************************************************应答子函数原型: void Ack_I2c(bit a);功能:主控器进行应答信号,(可以是应答或非应答信号)********************************************************************/ void Ack_I2c(bit a){if(a==0)SDA=0; /*在此发出应答或非应答信号 */else SDA=1;_Nop();_Nop();_Nop();SCL=1;_Nop();_Nop(); /*时钟低电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/_Nop();_Nop();}/*******************************************************************向无子地址器件发送字节数据函数函数原型: bit ISendByte(uchar sla,ucahr c);功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.如果返回1表示操作成功,否则操作有误。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
#include <reg764.h> /*头文件的包含*/#include <intrins.h>#define uchar unsigned char /*宏定义*/#define uint unsigned int#define _Nop() _nop_() /*定义空指令*//* 常,变量定义区 *//*端口位定义*/ sbit SDA=P1^3; /*模拟I2C数据传送位*/sbit SCL=P1^2; /*模拟I2C时钟控制位*//*状态标志*/ bit ack; /*应答标志位*/void Start_I2c(){SDA=1; /*发送起始条件的数据信号*/_Nop();SCL=1;_Nop(); /*起始条件建立时间大于4.7us,延时*/_Nop();_Nop();_Nop();_Nop();SDA=0; /*发送起始信号*/_Nop(); /* 起始条件锁定时间大于4μs*/_Nop();_Nop();_Nop();_Nop();SCL=0; /*钳住I2C总线,准备发送或接收数据 */_Nop();_Nop();}void Stop_I2c(){SDA=0; /*发送结束条件的数据信号*/_Nop(); /*发送结束条件的时钟信号*/SCL=1; /*结束条件建立时间大于4μs*/_Nop();_Nop();_Nop();_Nop();_Nop();SDA=1; /*发送I2C总线结束信号*/_Nop();_Nop();_Nop();_Nop();}/*******************************************************************字节数据传送函数函数原型: void SendByte(uchar c);功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对此状态位进行操作.(不应答或非应答都使ack=0 假)发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/ void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt++) /*要传送的数据长度为8位*/{if((c<<BitCnt)&0x80)SDA=1; /*判断发送位*/else SDA=0;_Nop();SCL=1; /*置时钟线为高,通知被控器开始接收数据位*/ _Nop();_Nop(); /*保证时钟高电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0;}_Nop();_Nop();SDA=1; /*8位发送完后释放数据线,准备接收应答位*/_Nop();_Nop();SCL=1;_Nop();_Nop();_Nop();if(SDA==1)ack=0;else ack=1; /*判断是否接收到应答信号*/SCL=0;_Nop();_Nop();}/*******************************************************************字节数据传送函数函数原型: uchar RcvByte();功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),发完后请用应答函数。
********************************************************************/ uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; /*置数据线为输入方式*/for(BitCnt=0;BitCnt<8;BitCnt++){_Nop();SCL=0; /*置时钟线为低,准备接收数据位*/_Nop();_Nop(); /*时钟低电平周期大于4.7μs*/_Nop();_Nop();_Nop();SCL=1; /*置时钟线为高使数据线上数据有效*/_Nop();_Nop();retc=retc<<1;if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */ _Nop();_Nop();}SCL=0;_Nop();_Nop();return(retc);}/********************************************************************应答子函数原型: void Ack_I2c(bit a);功能:主控器进行应答信号,(可以是应答或非应答信号)********************************************************************/ void Ack_I2c(bit a){if(a==0)SDA=0; /*在此发出应答或非应答信号 */else SDA=1;_Nop();_Nop();_Nop();SCL=1;_Nop();_Nop(); /*时钟低电平周期大于4μs*/_Nop();_Nop();_Nop();SCL=0; /*清时钟线,钳住I2C总线以便继续接收*/_Nop();_Nop();}/*******************************************************************向无子地址器件发送字节数据函数函数原型: bit ISendByte(uchar sla,ucahr c);功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/ bit ISendByte(uchar sla,uchar c){Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(c); /*发送数据*/if(ack==0)return(0);Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向有子地址器件发送多字节数据函数函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/ bit ISendStr(uchar sla,uchar suba,uchar *s,uchar no){uchar i;Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(suba); /*发送器件子地址*/if(ack==0)return(0);for(i=0;i<no;i++){SendByte(*s); /*发送数据*/if(ack==0)return(0);s++;}Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向无子地址器件读字节数据函数函数原型: bit IRcvByte(uchar sla,ucahr *c);功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地址sla,返回值在c.如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/bit IRcvByte(uchar sla,uchar *c){Start_I2c(); /*启动总线*/SendByte(sla+1); /*发送器件地址*/if(ack==0)return(0);*c=RcvByte(); /*读取数据*/Ack_I2c(1); /*发送非就答位*/Stop_I2c(); /*结束总线*/return(1);}/*******************************************************************向有子地址器件读取多字节数据函数函数原型: bit ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否则操作有误。
注意:使用前必须已结束总线。
********************************************************************/bit IRcvStr(uchar sla,uchar suba,uchar *s,uchar no){uchar i;Start_I2c(); /*启动总线*/SendByte(sla); /*发送器件地址*/if(ack==0)return(0);SendByte(suba); /*发送器件子地址*/ if(ack==0)return(0);Start_I2c();SendByte(sla+1);if(ack==0)return(0);for(i=0;i<no-1;i++){*s=RcvByte(); /*发送数据*/Ack_I2c(0); /*发送就答位*/ s++;}*s=RcvByte();Ack_I2c(1); /*发送非应位*/Stop_I2c(); /*结束总线*/return(1);}/* 完毕 */。