📄 i2c0.c
字号:
/*----------------------------------------------------------------------------------
文件描述
文件名: I2C0.c
功能描述:I2C的驱动程序
编译环境:KEIL C FOR ARM - ARTX
目标CPU: LPC2XXX
作者:卢业亮
创建时间:2006.04.03
建议编辑环境:UltraEdit 11.00a+ 制表符宽度为三个字符,程序可读性更好。
----------------------------------------------------------------------------------*/
#include "RTOS.h"
#define IIC0_GLOBALS 1
#include "I2C0.h"
#include <string.h>
#define I2C_FREQUENCY 172800
#if (I2C_FREQUENCY >= 400000)
#error "Out of IIC MAX Frequency"
#endif
unsigned char saa_iic_mark=0;
/* -------------------------------------------------------------------------------------------
函数名称:IIC_Read
功能描述:按指定的从机地址的当前存储地址和长度读取数据
入口参数:SlaveAddr-从机地址,Comm-IIC总线号,Length-为要读取的长度,pBuffer-读取数据缓冲区
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/
//-------------------以上原形声明的函数供本函数调用-------------------------
uchar IIC_Read(uchar SlaveAddr,uchar Comm,uint Length,uchar *pBuffer)
{
NOP(); NOP();
if(IIC.Busy)
return ERROR;
IIC.Busy = TRUE;
IIC.SlaverAddress = SlaveAddr;
IIC.Command = Comm;
IIC.RLen = Length;
IIC.ReadWrite = TW_READ;
IIC.RW_Type = IIC_READ_COMM;
IIC.pReadBuffer = pBuffer;
TW_Start();
saa_iic_mark=1;
return OK;
} // End of <IIC_Read> function
/* -------------------------------------------------------------------------------------------
函数名称:IIC_Write
功能描述:写数据到从机
1-可以用于向指定的从机的指定地址写入数据,此时pBuffer指向的是子地址+要写入数据
入口参数:Addr-从机地址,Comm-IIC总线号,Length-为要写数据的长度,pBuffer-要写数据的头指针
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/
//-------------------以上原形声明的函数供本函数调用-------------------------
uchar IIC_Write(uchar SlaveAddr,uchar Comm,uint Length,uchar *pBuffer)
{
NOP(); NOP();
if(IIC.Busy)
return ERROR;
IIC.Busy = TRUE;
IIC.SlaverAddress = SlaveAddr;
IIC.Command = Comm;
IIC.WLen = Length;
IIC.ReadWrite = TW_WRITE;
IIC.RW_Type = IIC_WRITE_COMM;
IIC.pWriteBuffer = pBuffer;
TW_Start();
saa_iic_mark=1;
return OK;
} // End of <IIC_Write> function
/* -------------------------------------------------------------------------------------------
函数名称:IIC_WriteRead
功能描述:按指定的从机地址的随机存储地址读取数据
1-可以用于从指定的从机的指定地址读取数据,此时pW指向要读取的地址,Wlen为要地址的长度
入口参数:Addr-从机地址,Comm-IIC总线号,Wlen-写数据或地址长度,pW-地址或数据缓冲指针
RLen-读数据长度,pR-读取数据的缓冲区
出口参数:OK=发送成功,ERROR=发送失败
全局变量: 结构体IIC
创建时间:2006.03.31 15:00
修改时间:2006.03.31 15:00
---------------------------------------------------------------------------------------------*/
//-------------------以上原形声明的函数供本函数调用-------------------------
uchar IIC_WriteRead(uchar Addr,uchar Comm,uint16 WLen,uchar *pW,uint16 RLen,uchar *pR)
{
NOP(); NOP();
if(IIC.Busy) //忙则返回错误标志以便等待
return ERROR;
IIC.Busy = TRUE; //I2C忙
IIC.SlaverAddress = Addr; //I2C的从机地址
IIC.Command = Comm; //I2C的标即,使用I2C1还是I2C0口
IIC.WLen = WLen; //写长度
IIC.ReadWrite = TW_WRITE; //I2C的读写状态为写
IIC.RW_Type = IIC_RW_COMM; //IIC写读(需重复开始信号)
IIC.pWriteBuffer = pW; //写缓冲
IIC.RLen = RLen; //读长度
IIC.pReadBuffer = pR; //读缓冲
TW_Start(); //启动IIC
saa_iic_mark=1;
return OK;
} // End of <IIC_WriteRead> function
/* --------------------------------------------------------------------------------
函数名称:ReadEEPROM
功能描述:读EEPROM
入口参数:DAddr-器件地址,RAddr-要读数据的头地址,RLen-要读长度,pData-读取存储指针
出口参数:无
全局变量: 无
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
--------------------------------------------------------------------------------*/
//-------------------以上原形声明的函数供本函数调用-------------------------
void ReadEEPROM(uchar DAddr,uint16 RAddr,uint16 RLen,uchar *pData)
{
uchar sAddr[2];
NOP(); NOP();
sAddr[0] = RAddr>>8;
sAddr[1] = RAddr;
while(IIC_WriteRead(DAddr,0,2,sAddr,RLen,pData));
while(saa_iic_mark);
//os_dly_wait(1);
NOP(); NOP();
} // End of <ReadEEPROM> function
/* --------------------------------------------------------------------------------
函数名称:EEPROM_Write
功能描述:写EEPROM
入口参数:DAddr-器件地址,PageLen-器件页长度,WAddr-数据要写入从机的子地址头
WLen-要写入数据长度,pData-指向要写入的数据头地址
出口参数:输入成功与否(只判断输入EEPROM,不判断是否写成功),返回0表示成功
全局变量: 无
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
---------------------------------------------------------------------------------*/
//-------------------以上原形声明的函数供本函数调用-------------------------
uchar WriteEEPROM(uchar DAddr,uchar PageLen,uint16 WAddr,uint16 WLen,uchar *pData)
{
uchar PageBuffer[68];
uchar owLen; // One time Write Len
NOP(); NOP();
if(PageLen%8) return ERROR; // 页长度必须为8的位数
//写首址
PageBuffer[0] = WAddr>>8;
PageBuffer[1] = WAddr;
//写入的地址%页长度=页地址偏移+要写入长度
if((WLen+(WAddr%PageLen))<=PageLen) //要写入数据所需空间小于当前要写入页的剩余空间,则无须翻页,直接写入
{
memmove(&PageBuffer[2],pData,WLen); //把要写入的地址头插入到要发送的数据头的前面组合在缓冲区里
while(IIC_Write(DAddr,0,(WLen+2),PageBuffer));
//IIC_Write(DAddr,0,(WLen+2),PageBuffer); //调用I2C写函数,将数据写入指定器件
while(saa_iic_mark);
//os_dly_wait(1); //任务休眠等待10MS后唤醒
}
else //要写入数据所需空间超过当前要写入页的剩余空间,也就是说须翻页,则先写当前页的剩余空间,再进入翻页写数据循环,直到写完
{
if(WAddr%PageLen) //要写入地址不是从整页首地址开始写
{
owLen = PageLen-WAddr%PageLen; // 第一轮写的长度为当前页的剩余空间
memmove(&PageBuffer[2],pData,owLen); // 把要写入的头地址插入第一轮写的数据的前面
while(IIC_Write(DAddr,0,(owLen+2),PageBuffer)); //把地址和数据写入EEPROM,先写头地址后写数据
while(saa_iic_mark);
//os_dly_wait(1); //任务挂起10MS后唤醒
WAddr += owLen; //计算出要写入的下一页地址
pData += owLen; //计算下次要发送数据指针的头地址
WLen -= owLen; //计算剩余要发送数据的长度
}
while(WLen) //要写入地址是从整页首地址开始写
{
PageBuffer[0] = WAddr>>8; //便于处理多页写,把新的写地址再次写入
PageBuffer[1] = WAddr;
if(WLen>=PageLen) //剩余要写入数据长度大于页长度则,一次写入一页
owLen = PageLen;
else //否则写入最后剩余的数据
owLen = WLen;
memmove(&PageBuffer[2],pData,owLen); //把要写入的地址头插入到要发送的数据头的前面组合在缓冲区里
while(IIC_Write(DAddr,0,(owLen+2),PageBuffer)); //把地址和数据写入EEPROM,先写头地址后写数据
while(saa_iic_mark);
//os_dly_wait(1); //任务挂起10MS后唤醒
WAddr += owLen; //计算出要写入的下一页地址
pData += owLen; //计算下次要发送数据指针的头地址
WLen -= owLen; //计算剩余要发送数据的长度
}
}
return OK;
}
/* ----------------------------------------------------------------
函数名称:I2C0_INT
功能描述:IIC0中断报务函数
入口参数:无
出口参数:无
全局变量: 结构体IIC
创建时间:2006.03.31 15:30
修改时间:2006.03.31 15:30
------------------------------------------------------------------*/
void I2C0_INT(void) __irq // IIC0 interrupt function
{
uchar s;
NOP(); NOP();
s = IIC.Status = I20STAT;
NOP(); NOP();
switch(s)
{
/// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
/// Start or repeat Start bit has been Transmitted
case TW_MS_START: //0x08:发送起始条件成功;
case TW_MS_REP_START: //0x10:重复发送起始条件成功
I20DAT = (IIC.SlaverAddress)|IIC.ReadWrite; //装入从机地址和读写位
break;
///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//主模式I2C的发送
case TW_MT_SLA_ACK: //0x18:成功发送从机地址和写控制位(SLA+W)成功并接收到应答ACK后
I20DAT = *IIC.pWriteBuffer++;//若有从机子地址,写则发送地址+数据,写读则发送地址,若无则发送单写1字节数据
break;
case TW_MT_DATA_ACK: //0x28:已经发送I2DAT中的数据字节并接手到ACK
IIC.WLen--; //结构体IIC.WLEN即要向从机写的数据或地址的长度
if(IIC.WLen) //写的数据或子地址未发送完,则继续发送
{
I20DAT = *IIC.pWriteBuffer++;
}
else
{
if(IIC.RW_Type==IIC_RW_COMM) //如果读写类型为:IIC写读,则需重复开始信号即为有子地址的I2C操作,则
{
IIC.ReadWrite = TW_READ; //更改当前I2C的当前的读写状态为读
IIC.RW_Type = IIC_READ_COMM; //更改当前读写类型为读写IIC读命令(没有重复开始信号)
I20CONCLR = (TW_INT_FLAG); //清除IIC中断标志
VICVectAddr = 0; //清除总中断标志
TW_Start(); //再次启动IIC为主模式I2C数据接收
return;
}
else //当无子地址写时为单写完成,用于向从机写入1字节数据
{ //当有子地址写时为连续写数据完成
UserEvtFlag.IIC = IIC_WRITE_EVT_OK;
TW_Stop(); // 结束总线
IIC.Busy = FALSE;
saa_iic_mark=0;
}
}
break;
///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
// 主模式I2C的数据接收
case TW_MR_SLA_ACK: //0x40:成功发送从机地址和写控制位(SLA+R)成功并返回应答ACK后
if(IIC.RLen>1) //如果要接收的数据长度大于1则
TW_Ack(); //设置AA=1,控制下次接收到数据后发送应答信号
else
TW_NoAck(); //设置AA=0,控制下次接收到数据后发送非应答信号
break;
case TW_MR_DATA_ACK: //已经接收到数据并接收到应答ACK,则
*IIC.pReadBuffer++ = I20DAT; //接收数据到缓冲区
IIC.RLen--;
if(IIC.RLen==1) //如果下次接收到最后一字节,则
TW_NoAck(); //设置AA=0,控制下次接收到数据后发送非应答信号
break;
case TW_MR_DATA_NACK: //0x40:成功发送从机地址和写控制位(SLA+R)成功并返回到非应答NACK后
*IIC.pReadBuffer++ = I20DAT; //接收最后一字节数据到缓冲区
NOP();
TW_Stop(); //结束总线
IIC.Busy = FALSE; //释放IIC
saa_iic_mark=0;
break;
///&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
// 主模式异常处理 //////////////////////////////////////////////////
case TW_MR_SLA_NACK: // 发送了SLA+R,接收到非ACK
case TW_MT_SLA_NACK: // 发送了SLA+W,接收到非ACK
case TW_MT_DATA_NACK: // 发送了数据,接收到非ACK
case TW_MT_ARB_LOST: // 丢失仲裁
default:
TW_Stop();
IIC.Busy = FALSE;
saa_iic_mark=0;
break;
}
I20CONCLR = (TW_INT_FLAG); // 清除中断标志(清除STA和SI位)
NOP(); NOP();
VICVectAddr = 0;
}
/* ----------------------------------------------------------------
函数名称:I2cInit
功能描述:I2c初始化函数
入口参数:无
出口参数:无
全局变量: 结构体IIC
创建时间:2006.03.30 16:30
修改时间:2006.03.30 16:30
------------------------------------------------------------------*/
void I2C0_Init(void)
{
I20CONCLR = 0x6C; /* 清除控制寄存器I20CONSET中的各位*/
VICIntEnClr = (1<<IIC0_INT_VECT); /* 禁止能I2c中断 */
PINSEL0 = (PINSEL0 & 0xffffff0f) | 0x50; /* 选择管脚为I2c */
I20SCLH = (Fpclk / I2C_FREQUENCY + 1) / 2; /* 设置高电平时间 */
I20SCLL = (Fpclk / I2C_FREQUENCY) / 2; /* 设置低电平时间 */
I20CONSET = 1<<TW_ENABLE; //设置为I2C主模式
/////////////////////////////////////////////
VICVectAddr6 = (uint32)I2C0_INT; //将I2C0的中断的向量地址设置在IRQ通道6位置
VICVectCntl6 = (IRQ_ENABLE|IIC0_INT_VECT); //将I2C0向量IRQ使能,其优先级为6。从而产生唯一的ISR号,并将UART0的中断编号设置为9
VICIntEnable |= (1<<IIC0_INT_VECT); //使能中断编号为9的中断请求
IIC.Busy = IIC.WLen = IIC.RLen = IIC.RW_Type = 0;//清除I2C的各类标志
IIC.Command = 0;
IIC.SlaverAddress = 0;
} //End of <I2C0_Init> Function
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -