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

📄 i2c.c

📁 标准frescale单片机的I2C总线程序
💻 C
字号:
#include <hidef.h>
#include <MC68HC908JL8.h>
#include "flags.h"
#include "i2c.h"

#ifndef nop
  #define nop asm NOP
#endif
#define SDAOUT DDRD_DDRD3=1 //i2c数据线SDA为输出状态
#define SDAIN  DDRD_DDRD3=0 //i2c数据线SDA为输入状态

#define RegSecond   0x00  //秒
#define RegMinute   0x10  //分
#define RegHour     0x20  //时
#define RegWeek     0x30  //星期
#define RegDay      0x40  //天
#define RegMonth    0x50  //月
#define RegYear     0x60  //年
#define RegOffset   0x70  //精度调整量
#define RegAWM      0x80  //闹钟W模式,分
#define RegAWH      0x90  //闹钟W模式,时
#define RegAWW      0xA0  //闹钟W模式,星期
#define RegADM      0xB0  //闹钟D模式,分
#define RegADH      0xC0  //闹钟D模式,时
#define RegControl1 0xD0  //设置1
#define RegControl2 0xF0  //设置2

//--------------------------------------------------------------------

/********i2c标准子程序***********/
void nops(byte i)		  //9.8304M,i=1时接近1us
{
  while(i--){nop;nop;}
}
/*启动i2c*/
void I2CStart(void)
{
  DisableInterrupts;  //关闭中断

  SDAOUT;
  SDA =1; SCL =1; nops(2);    
  SDA =0; nops(2); SCL =0;   
}
/*停止i2c*/
void I2CStop(void)
{
  SCL =0; SDA =0; nops(2);
  SCL =1; nops(2); SDA =1;
  
  EnableInterrupts; //总线停止后可以打开中断
}
/*等待从机应答*/
void WaitAck(void)
{
  byte waittime =255;
  I2CERR =0;
    
  SDA =1;
  SDAIN; 
  nops(2); 
  SCL =1;
  while(SDA)
  {
    if(!waittime--)
    {
      I2CStop();
      I2CERR =1;  //在flags.h中定义的i2c总线出错标志
      break;
    }
  }
  SCL =0;

  SDAOUT;
}
/*发送应答位*/
void SendAck(void)
{
  SDA =0;nops(2);SCL =1;nops(2);SCL =0;
}
/*发送非应答位*/
void SendNotAck(void)
{
  SDA =1;nops(2);SCL =1;nops(2);SCL =0;
}
/*送出一个字节*/
void I2CSendByte(byte ch)
{
  byte i=8;
  
  while(i--)
  {
    SCL =0;nops(2);
    if (ch&0x80) 
      SDA =1;					//高位在前,低位再后的发送
    else SDA =0;
    ch <<=1;nops(2);SCL =1;nops(2);
  }
  SCL =0;
}
/*读进一个字节*/
byte I2CReceiveByte(void) 
{
  byte i=8;
  byte ddata=0;
  
  SDA =1;
  SDAIN;
  while(i--)
  {
    ddata <<=1;
    SCL =0;nops(2);
    SCL =1;nops(2);
    ddata |=SDA;
  }
  SCL =0;
  SDAOUT;
  return ddata;
}
//-----------------------------------------------------------------

/***************写一字节标准子程序**************/
/*-入口参数Device为器件编址,ComandAddr为命令模式, ByteData为数据-*/
void Write1Byte(byte Device,byte ComandAddr,byte ByteData)  
{
  byte i;
  
  for (i=0;i<5;i++)	 //试写5次
  {
      I2CStart();		//启动I2C
      I2CSendByte(Device); //发送器件地址/写
      WaitAck();				 //等待应答
      if (I2CERR ==0)
      {
          I2CSendByte(ComandAddr); //发送命令地址及模式
          WaitAck();
          if (I2CERR ==0)
          {
              I2CSendByte(ByteData);  //发送数据
              WaitAck();
              if (I2CERR ==0)
              {
                  I2CStop();
                  return;			//发送数据成功则跳出循环
              }
          }
      }
      I2CStop(); //如果没成功,则停止总线
      nops(10);
  }
}
/**************读一字节标准子程序**************/
/*-入口参数Device为器件编址,ComandAddr为命令模式-*/
/*-------返回一个字节-------------*/
byte Read1Byte(byte Device,byte ComandAddr)
{
  byte i;
  byte ddata;
  
  for(i=0;i<5;i++) //试读5次
  {
      I2CStart();
      I2CSendByte(Device);
      WaitAck();
      if (I2CERR ==0)
      {
          I2CSendByte(ComandAddr);
          WaitAck();
          if (I2CERR ==0)
          {
              I2CStart();				//i2c总线标准读模式
              I2CSendByte(Device|0x1); //读
              WaitAck();
              if (I2CERR ==0) 
              {
                  ddata =I2CReceiveByte();
                  SendNotAck();		 //发送非应答
                  I2CStop();
                  return(ddata);
              }
          }
      }
      I2CStop();
      nops(10);
  }
}
//-------------------------------------------------------------------
//---注意24C16一次最多只能写16字节,而且必须是以页地址为开头

/****************** 若干字节写子程序 ***************/
/*-入口参数Device为器件编址,ByteAddr为要写入的地址-*/ 
/*-PData为要写入数据的数据指针,Num为要写入的字节数-*/
void WriteBytes(byte Device,byte ByteAddr,byte *PData,byte Num)
{
  byte i,j;
  
  for (i=0;i<5;i++) //试写5次
  {
      I2CStart();		//启动I2C
      I2CSendByte(Device); //发送8025地址/写
      WaitAck();				 //等待应答
      if (I2CERR ==0)
      {
          I2CSendByte(ByteAddr); //发送页地址
          WaitAck();
          if (I2CERR ==0)
          {
              for (j=0;j<Num;j++) //一页允许写Num个字节
              {
                  I2CSendByte(*PData);  //发送数据
                  WaitAck();
                  PData++;
              }
              if (I2CERR ==0)
              {
                  I2CStop();
                  return;			//发送数据成功则跳出循环
              }
          }
      }
      I2CStop(); //如果没成功,则停止总线
      nops(10);
  }
}

/****************** 若干字节读子程序 ***************/
/*-入口参数Device为器件编址,ByteAddr为要读入的地址-*/ 
/*-PData为存读入数据的数据指针,Num为要读入的字节数-*/
void ReadBytes(byte Device,byte ByteAddr,byte *PData,byte Num)
{
  byte i,j;
  
  for(i=0;i<5;i++) //试读5次
  {
      I2CStart();
      I2CSendByte(Device);
      WaitAck();
      if (I2CERR ==0)
      {
          I2CSendByte(ByteAddr);
          WaitAck();
          if (I2CERR ==0)
          {
              I2CStart();				//i2c总线标准读模式
              I2CSendByte(Device|0x1); //读
              WaitAck();
              if (I2CERR ==0) 
              {
                  for (j=0;j<Num;j++)
                  {
                      *PData =I2CReceiveByte(); //读入数据
                      SendAck();		 //发送应答
											PData++;
                  }
                  SendNotAck();		 //发送非应答
                  I2CStop();
                  return;
              }
              
          }
      }
      I2CStop();
      nops(10);
  }
}
/************************************/
/**************RTC8025***************/
/************************************/



⌨️ 快捷键说明

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