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