以前習(xí)慣用SPI的器件,現(xiàn)在I2C的器件越來越多,不得不學(xué)習(xí)一下來充充電了。
寫了一個24C01的讀寫代碼,開發(fā)環(huán)境是IAR的EWARM,MCU是LPC2103,大家可以對照24C01的時序圖來寫程序。
本來想用LPC2000的I2C中斷的,不知道怎么回事,中斷老是開不起來,只好死等了。
/*
程序功能:24C01讀寫程序
晶振12M,I2C0,100K
*/
#include <iolpc2103.h>
#include <intrinsics.h>
#define MEMWRITE 0XA0 //寫命令
#define MEMREAD 0XA1 //讀命令
#define STA (1<<5) //起始位
#define I2CEN (1<<6) //允許位
#define STO (1<<4) //停止位
#define SI (1<<3) // 中斷標(biāo)志
#define AA (1<<2) // 響應(yīng)標(biāo)志
#define LASTBYTE 1 //最后字節(jié)標(biāo)志
//i2c_buf1為發(fā)送緩沖區(qū),i2c_buf2為接收緩沖區(qū)
unsigned char i2c_buf1[10]={1,2,3,4,5,6,7,8,9,10},i2c_buf2[10];
void i2cInit(void);//I2C初始化程序
void i2cStart(void);//I2C發(fā)送起始位
void i2cStop(void);//I2C發(fā)送停止位
void writeByte(unsigned char data);//寫一個字節(jié)的數(shù)據(jù)到總線上
void writeAddr(unsigned char mode);//寫 地址和方向標(biāo)志 到總線上
void writeData(unsigned char data);//完整的寫數(shù)據(jù),包括開始,清除標(biāo)志等操作
unsigned char readByte(unsigned char last);//讀字節(jié)數(shù)據(jù),返回讀到的值
void writeMem(int page_start,int count_byte,unsigned char *message_out);//寫存儲器的整體操作
void readMem(int page_start,int count_byte,unsigned char *message_in);//讀存儲器的整體操作
void delayMs(int dly);//延時
int main(void)
{
i2cInit();//I2C初始化
writeMem(0,8,i2c_buf1);//從存儲器的0地址開始寫8個字節(jié)的數(shù)據(jù)
delayMs(1000);
readMem(7,10,i2c_buf2);//讀存儲器的1地址開始寫5個字節(jié)的數(shù)據(jù)
while(1);
}
void i2cInit(void)
{
PINSEL0 = 0x50; //Switch GPIO to I2C pins
I2C0SCLH =15; //Set bit rate 12Mhz/VPBDIV+SCLH+SCLL = 12/4/(15+15) = 100Khz
I2C0SCLL =15;
I2C0CONCLR = 0XFF;
I2C0CONSET = I2CEN;
}
//I2C發(fā)送起始位
void i2cStart(void)
{
I2C0CONSET=STA;
do{}while(I2C0STAT!=0x08);//等待起始條件發(fā)送完成
I2C0CONCLR=STA;
}
//I2C發(fā)送停止位
void i2cStop(void)
{
I2C0CONSET=STO;//啟動發(fā)送stop位,STO位是自動清除的,不必判斷是否結(jié)束
I2C0CONCLR=SI; //只能清除SI,如果同時清除STO會導(dǎo)致返回到初始化狀態(tài)
}
//寫一個字節(jié)的數(shù)據(jù)到I2CDAT中
void writeByte(unsigned char data)
{
I2C0DAT=data;
I2C0CONCLR=SI;//啟動發(fā)送
}
//發(fā)送控制字,其中mode為 MEMWRITE 或 MEMREAD
void writeAddr(unsigned char mode)
{
writeByte(mode);
if(mode==MEMREAD)do{}while(I2C0STAT!=0x40);//如果發(fā)送的是讀控制字(地址),等待從機(jī)響應(yīng)
else
do{}while(I2C0STAT!=0x18);//如果發(fā)送的是寫控制字(地址),等待從機(jī)響應(yīng)
}
//寫數(shù)據(jù)
void writeData(unsigned char data)
{
writeByte(data);
do{}while(I2C0STAT!=0x28);//0x28——已發(fā)送I2CDAT中的字節(jié),已經(jīng)接受ACK
}
//讀數(shù)據(jù)
unsigned char readByte(unsigned char last)
{
if(last)//如果讀的是最后一個字節(jié),不需要發(fā)送應(yīng)答位
{
I2C0CONCLR=AA;
I2C0CONCLR=SI;
do{}while(I2C0STAT!=0x58);//等待接收數(shù)據(jù)直接和非ACK
}
else
{ I2C0CONSET=AA;//發(fā)送一個應(yīng)答位
I2C0CONCLR=SI;
do{}while(I2C0STAT!=0x50);//等待接收數(shù)據(jù)直接和ACK
}
return (I2C0DAT);
}
/*
寫24C01
入口: page_start——起始地址,count_byte——需要寫的字節(jié)數(shù),
message_out——需要寫入的數(shù)據(jù)緩沖區(qū)頭指針
*/
void writeMem(int page_start,int count_byte,unsigned char *message_out)
{
int i;
i2cStart();//發(fā)送起始位
writeAddr(MEMWRITE);//發(fā)送寫控制字
writeData(page_start);//發(fā)送寫的起始地址
for(i=0;i<count_byte;i++,message_out++)//寫數(shù)據(jù)
writeData(*message_out);
i2cStop();//發(fā)送停止位
}
/*
讀24C01,模式——順序讀(SEQUENTIAL READ)
入口:page_start——讀起始地址,count_byte——需要讀的字節(jié)數(shù),
message_in——讀緩沖區(qū)頭指針
出口:
*/
void readMem(int page_start,int count_byte,unsigned char *message_in)
{
int i;
//設(shè)置讀指針
i2cStart();//發(fā)送起始位
writeAddr(MEMWRITE);//發(fā)送寫控制字
writeData(page_start);//發(fā)送讀的起始地址
i2cStop();//發(fā)送停止位
//開始讀數(shù)據(jù)
i2cStart();//發(fā)送起始位
writeAddr(MEMREAD);//發(fā)送讀控制字
for(i=0;i<count_byte;i++,message_in++)//接收數(shù)據(jù)
*message_in=readByte(!LASTBYTE);
*message_in=readByte(LASTBYTE);
i2cStop();//發(fā)送停止位
}
void delayMs(int dly)
{
int i;
for(;dly>0;dly--)
for(i=0;i<1000;i++);
}