⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 模拟i2c总线.txt

📁 用单片机I/O口模拟总线形式的通用驱动程序
💻 TXT
字号:
在单片机应用中,I2C(I方C)总线一种简单,双向的二线制同步串行总线,它只需要两根串行线,脉冲线,就可以在总线与连接的器件之间传送信息, 它不外乎有以下几个特点:
a.每个连接到总线上的器件都可以进行唯一的寻址,还可建立起简单的主从关系,主器件既可作为发送器,也可作为接收器.
b.它带竞争电路和仲裁电路,可以接收多个主器件发送的数据,而这些数据不会产混乱.
c.同步脉冲可以允许器件可以通过总线以不同的波特率进行通信.
d.因为只有两根线,连接简单,方便.
     对于MCS51系列来讲,内部并没I2C总线接口,在这种情况下,可以采用软件模拟的方法来写出I2C总线的操作,下面我的程序就在开始处定义哪个引脚作为数据线SDA,哪个引脚作为脉冲线,请看我的程序(C51写的,总共有8个函数来模拟I2C总线):
Common.h File
#pragma  LA DB SB OE CD OT(SPEED,6)
//LA indicate LARGE Compling Mode-All local and global variables are located in external-ram. 
//DB indicate DEBUG 
//SB indicate SYMBOL
//OE indicate OBJECTEXTEND
//CD indicate CODE  //Generate ASM Code
//OT indicate OPTIMIZATION
#include <stdio.h>
#include <reg51.h>
#include <intrins.h>
#include <stdlib.h>
#pragma REGPARMS
#pragma SAVE
#define BOOL bit
#define BYTE unsigned char
#define UINT unsigned int
#define ULONG unsigned long
#define HIGH 1
#define LOW 0
#define TRUE 1
#define FALSE 0
#define MAXLONGS  2147483647
#define MINLONGS  -2147483648
#define MAXINTS   32767
#define MININTS   -32768
#define MAXLONGU  4294967295
#define MAXINTU   65535
#define BLOCKLOW 0x0000 //The start-address in AT24C64 is 0x0000
#define BLOCKSIZE 0x20 //Each block is 32 bytes
#define BLOCKNUM  0xC8 //At best 200,Only Save the newest 200 records.
#define BLOCKHIGH 0x18FF//The end-address in AT24C64 is 0x18FF
#define OSC       24000000 //Osillcator Frequency
#define BAUDRATE  9600
#define OTV    256-OSC/12/BAUDRATE/32 //character O represents Obtain,character T represents Timer,character V represents Value
//IMPORTANT ANNOUNCEMENT:I use a word 0x1FFC,0x1FFD to save the next block's address and 0x1FFE,0x1FFF to save the block's no.
sbit GUN=0x85;//PIN P05
sbit SCL=0xFF;     //Undefined bit-address,which will be defined in function:DEFI2C
sbit SDA=0xFF;     //Undefined bit-address,which will be defined in function:DEFI2C
sbit SHKL=0xFF;    //Undefined bit-address,which will be defined in function:DEFI2C
sbit SHKH=0xFF;    //Undefined bit-address,which will be defined in function:DEFI2C
sbit KH0=0xFF;     //Undefined bit-address,which will be defined in function:DEFI2C
sbit KH1=0xFF;     //Undefined bit-address,which will be defined in function:DEFI2C
sbit KH2=0xFF;     //Undefined bit-address,which will be defined in function:DEFI2C 
extern void DEFI2C(char *name) //To define which pin is SDA and which pin is SCL
extern void I2CInit()   //Initialization For I2C Bus
extern void I2CStart()  //Start I2C Bus
extern void I2CStop();  //Stop  I2C Bus
extern bit  I2CClock(); //return SDA while SCL is HIGH
extern void I2CDelay(); //Delay
extern void I2CAck();  //Answer 
extern bit  I2CSend(BYTE I2CData);//Send data with I2C Bus
extern BYTE I2CReceive();  //Receive data

Common.c
void DEFI2C(char *name)
{
    //Todo:add your codes here....
    //Announcement:If you question me why use the function DEFI2C?
    //Well,the function will be used to define which PIN is SCL and which PIN is SDA,especially there are more than 1 I2C 
    //equipment in your circuit.In this sitiuation,we write a function for defining I2C Bus named DEFI2C.... 
}
void I2CStart()
{
   SCL=HIGH;
   I2CDelay();
   SDA=LOW;
   I2CDelay();
   SCL=LOW;
   I2CDelay();
}
void I2CStop()
{
   SDA=LOW;
   I2CDelay();
   SCL=HIGH;
   I2CDelay();
   SDA=HIGH;
   I2CDelay();
   SCL=LOW;
   I2CDelay();
}
void I2CInit()
{
   SCL=LOW;
   I2CStop();
}
bit I2CClock() //return SDA while SCL is HIGH
{
   bit sample;
   SCL=HIGH;
   I2CDelay();
   sample=SDA;
   SCL=LOW;
   I2CDelay();
   return sample;
}
bit I2CSend(BYTE I2CData)
{
   BYTE i;
   for(i=0;i<8;i++)
   {
     SDA=(bit)(((I2CData) & 0x80) / 0x80) ;
     I2CData=I2CData << 1;
     I2CClock();
   }
   SDA=HIGH;
   return (~I2CClock());
}
void I2CAck()
{
   SDA=LOW;
   I2CClock();
   SDA=HIGH;
}
void I2CDelay()
{
   BYTE ll;
   for(ll=0;ll<100;ll++)
   {
      ;
   }
}
BYTE I2CReceive()
{
   BYTE I2CData=0;
   BYTE kk;
   for(kk=0;kk<8;kk++)
   {
      I2CData*=2;
      if(I2CClock())
      {
          I2CData++;
      }
   }
   return I2CData;
}





单片机模拟I2C总线及24C02(I2C EEPROM)读写实例(源代码) 
 
 
 
[ 作者:StephenZhu    转贴自:xnovo    点击数:393    更新时间:2005-6-19    文章录入:白桦 ] 
 
 
减小字体 增大字体

/* 51系列单片机在使用时,有时需要模拟I2C总线, */

/* 这里举出一个实例(读写串行EEPROM芯片at2402) */

/************************************************************************/

/* Name:AT24C02存储器的读写程序,用到I2C总线,含相对独立的I2C总线读写函数 */

/* Language: C51单片机编程语言 */

/* Platform: Win98,Intel Celeron 433 Processor,伟福仿真器,仿真8751 */

/* Author: StephenZhu javasdk@163.com */

/* Date: 2003年5月21日,5月22日,5月29日 */

/* Version: 1.1.1 */

/* Others: None */

/************************************************************************/

#include<string.h>

#include<reg52.h>

#include<intrins.h>

#define DELAY_TIME 60 /*经实验,不要小于50!否则可能造成时序混乱*/

#define TRUE 1

#define FALSE 0

sbit SCL=P1^7;/*假设由P1.7和P1.6控制*/

sbit SDA=P1^6;

/********** Function Definition 函数定义 ************/

void DELAY(unsigned int t) /*延时函数*/

{

while(t!=0)

t--;

}

void I2C_Start(void)

{

/*启动I2C总线的函数,当SCL为高电平时使SDA产生一个负跳变*/

SDA=1;

SCL=1;

DELAY(DELAY_TIME);

SDA=0;

DELAY(DELAY_TIME);

SCL=0;

DELAY(DELAY_TIME);

}

void I2C_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) /* SEND ACK */

{

/*发送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 WriteI2CByte(char b)reentrant

{

/*向I2C总线写一个字节*/

char i;

for(i=0;i<8;i++)

if((b<<i)&0x80)

SEND_1();

else

SEND_0();

}



char ReadI2CByte(void)reentrant

{

/*从I2C总线读一个字节*/

char 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;

}

else

b=b<<1;

}

return b;

}



/**********以下为读写24c02的函数**********/

void Write_One_Byte(char addr,char thedata)

{

bit acktemp=1;

/*write a byte to mem*/

I2C_Start();

WriteI2CByte(0xa0);

acktemp=Check_Acknowledge();

WriteI2CByte(addr);/*address*/

acktemp=Check_Acknowledge();

WriteI2CByte(thedata);/*thedata*/

acktemp=Check_Acknowledge();

I2C_Stop();

}

void Write_A_Page(char *buffer,char addr)

{

bit acktemp=1;

bit wrtmp;

int i;

/*write a page to at24c02*/

I2C_Start();

WriteI2CByte(0xa0);

acktemp=Check_Acknowledge();

WriteI2CByte(addr);/*address*/

acktemp=Check_Acknowledge();

for(i=0;i<7;i++)

{

WriteI2CByte(buffer[i]);

if(!Check_Acknowledge())

{

I2C_Stop();

}

}



I2C_Stop();





}

char Read_One_Byte(char addr)

{ bit acktemp=1;

char mydata;

/*read a byte from mem*/

I2C_Start();

WriteI2CByte(0xa0);

acktemp=Check_Acknowledge();

WriteI2CByte(addr);/*address*/

acktemp=Check_Acknowledge();

I2C_Start();

WriteI2CByte(0xa1);

acktemp=Check_Acknowledge();



mydata=ReadI2CByte();

acktemp=Check_Acknowledge();

return mydata;

I2C_Stop();

}

void Read_N_Bytes(char *buffer,char n,char addr)

{

bit acktemp=1;

int i=0;

/*read 8 bytes from mem*/

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++)

{

buffer[i]=ReadI2CByte();

if(i!=n-1)

SEND_0(); /*发送应答*/

else

SEND_1(); /*发送非应答*/

}

I2C_Stop();

}



void main()

{

int i;

char mybyte;

char myarray[8];

char myarray2[8];

char rdarray[16];



for(i=0;i<8;i++)

{

myarray[i]=i;

myarray2[i]=i+0x08; 

}

Write_One_Byte(0x20,0x28);

Write_A_Page(myarray,0x10);

Write_A_Page(myarray2,0x18);

mybyte=Read_One_Byte(0x20);

Read_N_Bytes(rdarray,16,0x10);

}
 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -