📄 i2c.c
字号:
#define I2C_GLOBALS
#include "configLPC.h"
BYTE ack;
#define SCL (0x04)//(0x01 << 2)
#define SDA (0x08)//(0x01 << 3)
BYTE InitI2C()
{
PINSEL0 &= 0xFFFFFF0F;
IO0DIR |= 0x0000000C;
//IO0CLR |= 0x10000000;
return 1;
}
//****************************************************************************
// DelayInuSec
//****************************************************************************
// Delay a certain number of microseconds.
//
//
//
void DelayInuSec(DWORD uS)
{
DWORD passed;
DWORD i;
//startTime= *TIM_DEBUGVALUELOW;
passed=0;
//
// Get stuck in this loop until
//
while ( passed < uS)
{
i = 5;
while (i--);
passed++;
}
}
/*******************************************************************
起动总线函数
函数原型: void Start_I2c();
功能: 启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
ack=0;
IO0SET = (SCL | SDA);//0x0000000C;
DelayInuSec(5); //起始条件建立时间大于4.7us,延时
IO0CLR = SDA; //发送起始信号
DelayInuSec(5); // 起始条件锁定时间大于4μs
IO0CLR = SCL;
DelayInuSec(5);
}
/*******************************************************************
结束总线函数
函数原型: void Stop_I2c();
功能: 结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{
IO0CLR = SDA; //发送结束条件的数据信号
DelayInuSec(1); //发送结束条件的时钟信号
IO0SET = SCL; //结束条件建立时间大于4μs
DelayInuSec(5);
IO0SET = SDA | SCL; //发送I2C总线结束信号
DelayInuSec(5);
}
/*******************************************************************
字节数据传送函数
函数原型: void SendByte(BYTE c);
功能: 将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0 假)
发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void SendByte(BYTE c)
{
BYTE BitCnt;
for (BitCnt = 0; BitCnt < 8; BitCnt++) /*要传送的数据长度为8位*/
{
if ((c << BitCnt) & 0x80)
{
IO0SET = SDA; /*判断发送位*/
}else
{
IO0CLR = SDA;
}
DelayInuSec(5);
IO0SET = SCL; /*置时钟线为高,通知被控器开始接收数据位*/
DelayInuSec(5); /*保证时钟高电平周期大于4μs*/
IO0CLR = SCL;
}
//DelayInuSec(2);
IO0SET = SDA; /*8位发送完后释放数据线,准备接收应答位*/
IO0DIR &= ~SDA; //SDA输入
DelayInuSec(5);
IO0SET = SCL;
DelayInuSec(2);
if (IO0PIN & SDA)
{
ack = 0;
}else
{
ack=1; /*判断是否接收到应答信号*/
}
DelayInuSec(3);
IO0DIR |= SDA;
IO0CLR = SCL;
}
/*******************************************************************
字节数据接收函数
函数原型: BYTE RcvByte();
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
BYTE RcvByte()
{
BYTE retc;
BYTE BitCnt;
retc = 0;
IO0DIR &= ~SDA; //SDA 输入
IO0SET = SDA; /*置数据线为输入方式*/
for (BitCnt = 0; BitCnt < 8; BitCnt++)
{
DelayInuSec(1);
IO0CLR = SCL; /*置时钟线为低,准备接收数据位*/
DelayInuSec(5); /*时钟低电平周期大于4.7μs*/
IO0SET = SCL; /*置时钟线为高使数据线上数据有效*/
DelayInuSec(2);
retc = retc << 1;
if (IO0PIN & SDA)
{
retc = retc + 1; /*读数据位,接收的数据位放入retc中 */
}
DelayInuSec(2);
}
IO0CLR = SCL;
DelayInuSec(2);
IO0DIR |= SDA;
return (retc);
}
/********************************************************************
应答子函数
原型: void Ack_I2c(BYTE a);
功能:主控器进行应答信号,(可以是应答或非应答信号)
********************************************************************/
void Ack_I2c(BYTE a)
{
if (a == 0)
{
IO0CLR = SDA; /*在此发出应答或非应答信号 */
}else
{
IO0SET = SDA;
}
DelayInuSec(3);
IO0SET = SCL;
DelayInuSec(5); /*时钟低电平周期大于4μs*/
IO0CLR = SCL; /*清时钟线,钳住I2C总线以便继续接收*/
DelayInuSec(2);
}
/*******************************************************************
向无子地址器件发送字节数据函数
函数原型: BYTE ISendByte(BYTE sla,ucahr c);
功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
BYTE ISendByte(BYTE sla,BYTE c)
{
Start_I2c(); /*启动总线*/
SendByte(sla); /*发送器件地址*/
if (ack == 0)
return(0);
SendByte(c); /*发送数据*/
if (ack == 0)
return(0);
Stop_I2c(); /*结束总线*/
return(1);
}
/*******************************************************************
向有子地址器件发送多字节数据函数
函数原型: BYTE ISendStr(BYTE sla,BYTE suba,ucahr *s,BYTE no);
功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
BYTE ISendStr(BYTE sla,BYTE suba,BYTE *s,BYTE no)
{
BYTE i;
BYTE bRet = 0;
OS_ENTER_CRITICAL();
for (i = 0; i < no; i++)
{
Start_I2c(); ///启动总线
SendByte(sla); //*发送器件地址
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
SendByte(0); //*发送器件地址0
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
SendByte(suba + i); //*发送器件子地址
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
SendByte(*(s + i)); //*发送数据
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
Stop_I2c(); //*结束总线
DelayInuSec(3000);
}
bRet = 1;
LEAVE:
OS_EXIT_CRITICAL();
return bRet;
}
/*******************************************************************
向无子地址器件读字节数据函数
函数原型: BYTE IRcvByte(BYTE sla,ucahr *c);
功能: 从启动总线到发送地址,读数据,结束总线的全过程,从器件地
址sla,返回值在c.
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
BYTE IRcvByte(BYTE sla,BYTE *c)
{
Start_I2c(); /*启动总线*/
SendByte(sla+1); /*发送器件地址*/
if(ack==0)return(0);
*c=RcvByte(); /*读取数据*/
Ack_I2c(1); /*发送非就答位*/
Stop_I2c(); /*结束总线*/
return(1);
}
/*******************************************************************
向有子地址器件读取多字节数据函数
函数原型: BYTE ISendStr(BYTE sla,BYTE suba,ucahr *s,BYTE no);
功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
BYTE IRcvStr(BYTE sla,BYTE suba,BYTE *s,BYTE no)
{
BYTE i;
BYTE bRet = 0;
OS_ENTER_CRITICAL();
Start_I2c(); /*启动总线*/
SendByte(sla); /*发送器件地址*/
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
SendByte(0); //*发送器件地址0
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
SendByte(suba); /*发送器件子地址*/
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
Start_I2c();
SendByte(sla+1);
if (ack == 0)
{
bRet = 0;
goto LEAVE;
}
for (i = 0; i < no-1; i++)
{
*s = RcvByte();
Ack_I2c(0);
s++;
}
*s=RcvByte();
Ack_I2c(1); //发送非应位
Stop_I2c(); //结束总线
bRet = 1;
LEAVE:
OS_EXIT_CRITICAL();
return bRet;
}
//*******************************
//
// 调用实例
//
//*******************************
BYTE TestI2C()
{
BYTE dat[64];
int i;
BYTE status;
BYTE tmp;
/*
while(1)
{
IO0SET = SDA;
DelayInuSec(100);
IO0CLR = SDA;
}
*/
OS_ENTER_CRITICAL();
status = 0x02;
ISendStr(0xde,0x3f,&status,1);//printf("send CCR status 02. ret=%d\n",ISendStr(0xde,0x3f,&status,1));
status = 0x06;
ISendStr(0xde,0x3f,&status,1);//printf("send CCR status 06. ret=%d\n",ISendStr(0xde,0x3f,&status,1));
//read write eeprom
for (i = 0; i < 64; i++)
{
dat[i] = 64;
}
ISendStr(0xae,0,dat,64);//printf("send ret=%d\n",ISendStr(0xae,0,dat,64));
memset(dat, 0, 64);
IRcvStr(0xae,0,dat,64);//printf("recv ret=%d\n",IRcvStr(0xae,0,dat,64));
//for(i = 0; i < 64; i++) //printf(" dat%02x=%02x\n",i,dat[i]);
//read datetime
IRcvStr(0xde,0x37,&tmp,1);//printf("year2K:%02x\n",tmp);
IRcvStr(0xde,0x36,&tmp,1);//printf("dayofweek:%02x\n",tmp);
IRcvStr(0xde,0x35,&tmp,1);//printf("year:%02x\n",tmp);
IRcvStr(0xde,0x34,&tmp,1);//printf("month:%02x\n",tmp);
IRcvStr(0xde,0x33,&tmp,1);//printf("day:%02x\n",tmp);
IRcvStr(0xde,0x32,&tmp,1);//printf("hour:%02x\n",tmp);
IRcvStr(0xde,0x31,&tmp,1);//printf("minute:%02x\n",tmp);
IRcvStr(0xde,0x30,&tmp,1);//printf("second:%02x\n",tmp);
OS_EXIT_CRITICAL();
return 1;
}
BYTE MyGetLocalTime(LPSYSTEMTIME lpst)
{
BYTE status;
BYTE y2k,wk,yy,mm,dd,hh,mi,ss;
BYTE bRet = 0;
OS_ENTER_CRITICAL();
status=0x02;ISendStr(0xde,0x3f,&status,1);
status=0x06;ISendStr(0xde,0x3f,&status,1);
if(IRcvStr(0xde,0x37,&y2k,1) &&
IRcvStr(0xde,0x36,&wk,1) &&
IRcvStr(0xde,0x35,&yy,1) &&
IRcvStr(0xde,0x34,&mm,1) &&
IRcvStr(0xde,0x33,&dd,1) &&
IRcvStr(0xde,0x32,&hh,1) &&
IRcvStr(0xde,0x31,&mi,1) &&
IRcvStr(0xde,0x30,&ss,1))
{
lpst->wYear=(((y2k&0xf0)>>4)*1000 + (y2k&0x0f)*100 + ((yy&0xf0)>>4)*10 + (yy&0x0f) );
lpst->wMonth=(((mm&0xf0)>>4)*10 + (mm&0x0f) );
lpst->wDayOfWeek=wk;
lpst->wDay=(((dd&0xf0)>>4)*10 + (dd&0x0f) );
lpst->wHour=(((hh&0x70)>>4)*10 + (hh&0x0f) );
lpst->wMinute=(((mi&0xf0)>>4)*10 + (mi&0x0f) );
lpst->wSecond=(((ss&0xf0)>>4)*10 + (ss&0x0f) );
lpst->wMilliseconds=0;
bRet = 1;
}
else
bRet = 0;
OS_EXIT_CRITICAL();
return bRet;
}
BYTE MySetLocalTime(LPSYSTEMTIME lpst)
{
BYTE status;
BYTE y2k,wk,yy,mm,dd,hh,mi,ss;
BYTE bRet = 0;
OS_ENTER_CRITICAL();
status=0x02;ISendStr(0xde,0x3f,&status,1);
status=0x06;ISendStr(0xde,0x3f,&status,1);
status=(BYTE)(lpst->wYear/100);
y2k=( ((status/10)<<4) | ((status%10)&0x0f) );
status=(BYTE)(lpst->wYear%100);
yy=( ((status/10)<<4) | ((status%10)&0x0f) );
wk=(BYTE)(lpst->wDayOfWeek);
status=(BYTE)(lpst->wMonth);
mm=( ((status/10)<<4) | ((status%10)&0x0f) );
status=(BYTE)(lpst->wDay);
dd=( ((status/10)<<4) | ((status%10)&0x0f) );
status=(BYTE)(lpst->wHour);
hh=( ((status/10)<<4) | ((status%10)&0x0f) );
hh=(hh|0x80);
status=(BYTE)(lpst->wMinute);
mi=( ((status/10)<<4) | ((status%10)&0x0f) );
status=(BYTE)(lpst->wSecond);
ss=( ((status/10)<<4) | ((status%10)&0x0f) );
if(ISendStr(0xde,0x37,&y2k,1) &&
ISendStr(0xde,0x36,&wk,1) &&
ISendStr(0xde,0x35,&yy,1) &&
ISendStr(0xde,0x34,&mm,1) &&
ISendStr(0xde,0x33,&dd,1) &&
ISendStr(0xde,0x32,&hh,1) &&
ISendStr(0xde,0x31,&mi,1) &&
ISendStr(0xde,0x30,&ss,1))
bRet = 1;
else
bRet = 0;
OS_EXIT_CRITICAL();
return bRet;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -