s3c2440 IIC AT24C08

S3C2440 裸机IIC程序代码(基于AT24C08测试):

因为不能上传附件:源代码放在了资源页。点击下载

包括两种读写方式:中断非中断(其实原理相通,非中断也是通过检测IICCON bit4 以此来判断是否有中断产生,后面的中断、非中断处理函数一样)。

然后AT24C08读写方式又分两种:按页读写和单字节读写。

本节介绍中断方式读写:

S3C2440手册上主机收发方式:

1.Master/Transmitter Mode(主机发送模式)按照以下步骤初始化:

GPEUP  |= 0xc000;  //1100 0000 0000 0000  使用内部上拉
GPECON |= 0xa0000000; //关闭内部上拉,注意要有外部上拉电阻

INTMSK &=~ (BIT_IIC); //使能IIC中断
IICCON |= ((1<<7)|(0<<6)|(1<<5)|(0xf));//0xaf (0<<4)|(1<<0)); // 

//使能ACK  ,IICCLK=fPCLK/16,使能IIC收发中断,   Tx Clock =  IICCLK/8

//例:PCLK 50.7MHz, IICCLK=PCLK/16=3.17MHz, Tx Clock(发送时钟)=IICCLK/16=0.198MHz
IICADD |= 0x10; //10100**0 //2440 slave address=[7:1]=0x10 从机地址
IICSTAT = 0x10; //1101 0000  //IIC bus data output enable(Rx/Tx) IIC数据输出使能

2.主机发送数据,流程如下图:

         与IO模拟IIC总线操作有差别的地方在于,从机地址最后一字节不需要实现读写操作,直接将bit[7:1]从机地址,bit0=0即可。

IICDS = slvAddr ;   //从机地址末字节不需要自己添加
IICSTAT = 0xf0;//主机发送,启动

发送过程关键是检测是否有从机ACK中断产生,产生中断后,进入中断函数,然后清中断,将要发送数据写入IICDS,然后IICCON  = 0xaf恢复IIC操作,依次循环,实现一个字节一个字节的发送数据。到最后一个字节时,发送停止信号:IICSTAT = 0xd0

流程图如下:

s3c2440 IIC AT24C08_第1张图片

主机发送流程图

3.主机接收,流程如下:

接收时需要先将AT24C08从机地址以及要读的地址发送给从机,所以读操作开始是两个字节的写操作,具体方法见主机写操作。

        然后是读操作:

IICSTAT = 0xb0;//1010 0000 主机接收,启动
IICCON = 0xaf;  //恢复IIC操作

然后等待接收中断,注意第一次中断是发送完地址产生的中断,读到的数据为0,无效。以后每来一次中断,读一次IICDS,读完恢复IIIC传输IICCON = 0xaf,依次循环,直到最后一个字节,发送IICCON = 0x2f;//恢复IIC传输,接收下一数据时无ACK,等到接收下一数据时,IICSTAT = 0x90;//发送P 停止信号,以此结束IIC读操作。


s3c2440 IIC AT24C08_第2张图片

主机接收流程图


具体程序如下:排版可能有问题,把程序添加到附件,需要的同学可以下载下来,有问题的地方,请指出来,共同进步。

#include "s3c24xx.h"
#include "i2c.h"
#include "serial.h"
#include

//#define BIT_IIC (1<<27)

#define WRDATA 1
#define RDDATA 2
#define SETADDR 3
#define POLLACK 4

typedef struct tI2C {
    unsigned char pData[18];   //pData[2];   // 数据缓冲区
      //******* 不可以直接定义成指针
    volatile int DataCount; /* 等待传输的数据长度 */
    volatile int Status;    /* 状态 */
    volatile int Mode;      /* 模式:读/写 */
    volatile int Pt;        /* pData中待传输数据的位置 */
}tS3C24xx_I2C, *ptS3C24xx_I2C;


tS3C24xx_I2C g_tS3C24xx_I2C;


void Test_Iic_Page(void){
static unsigned char data_write[256];
static unsigned char data[256];
static int i,j;


i2c_init();


printf("\r\nClean data in AT24C08!!!\n\r");
for(i=0;i<16;i++){
Wr24C08(0xa0,(unsigned char)(16*i),0);
}

printf("Write data to AT24C08!!!\n\r");
for(i=0;i<16;i++){
for(j=0;j<16;j++){
data_write[i*16+j] = i*16+j;
if((data_write[i*16+j])<10)
printf("%s%s%d、"," "," ",data_write[i*16+j]);
else if((10<=data_write[i*16+j])&&(data_write[i*16+j]<100))
printf("%s%d、"," ",data_write[i*16+j]);
else if(data_write[i*16+j]>=100)
printf("%d、",data_write[i*16+j]);
}
Wr24C08_Page(0xa0,(unsigned char)(i*16),&data_write[i*16]);
printf("\n\r");
}

printf("\r\nRead data from AT24C08 to data!!!\n\r");
for(i = 0;i<16;i++){
Rd24C08_Page(0xa0, 16*i, &data[16*i]);
}
for(i=0;i<16;i++){
for(j=0;j<16;j++){
if((data[i*16+j])<10)
printf("%s%s%d、"," "," ",data[i*16+j]);
else if((10<=(data[i*16+j]))&&(data[i*16+j]<100))
printf("%s%d、"," ",data[i*16+j]);
else if(data[i*16+j]>=100)
printf("%d、",data[i*16+j]);
else printf("\r\n out of range!!\n\r");
}
printf("\n\r");
}
//INTMSK |= (BIT_IIC); //禁止IIC 中断
}






void Test_Iic_Byte(void){
static unsigned char data[256];
static int i,j;


i2c_init();


printf("\r\nClean data in AT24C08!!!\n\r");
for(i=0;i<256;i++){
Wr24C08(0xa0,(unsigned char)i,0);
}
printf("Write data to AT24C08!!!\n\r");
for(i=0;i<16;i++){
for(j=0;j<16;j++){
Wr24C08(0xa0,(unsigned char)(i*16+j),i*16+j);
if((i*16+j)<10)
printf("%s%s%d、"," "," ",(i*16+j));
else if((10<=(i*16+j))&&((i*16+j)<100))
printf("%s%d、"," ",(i*16+j));
else if((i*16+j)>=100)
printf("%d、",(i*16+j));
}
printf("\n\r");
}

for(i=0;i<256;i++){
data[i] = 0;
}
printf("Read data from AT24C08 to data!!!");
for(i=0;i<256;i++){
Rd24C08(0xa0,(unsigned char)i,&(data[i]));
}
printf("Read data from AT24C08!!!\n\r");
for(i=0;i<16;i++){
for(j=0;j<16;j++){
//printf("%d",data[i*16+j]);
if((data[i*16+j])<10)
printf("%s%s%d、"," "," ",data[i*16+j]);
else if((10<=(data[i*16+j]))&&(data[i*16+j]<100))
printf("%s%d、"," ",data[i*16+j]);
else if(data[i*16+j]>=100)
printf("%d、",data[i*16+j]);
else printf("\r\n out of range!!\n\r");
}
printf("\n\r");
}
}




/*I2C SDA:GPE15 SCL:GPE14*/
void i2c_init(void){
printf("I2C Init!\n\r");

GPEUP  |= 0xc000;  //1100 0000 0000 0000  使用内部上拉
GPECON |= 0xa0000000; //1010  

INTMSK &=~ (BIT_IIC); //使能中断
IICCON |= ((1<<7)|(0<<6)|(1<<5)|(0xf));//0xaf (0<<4)|(1<<0)); 
IICADD |= 0x10; //10100**0
IICSTAT = 0x10; //1101 0000  0x10??
}


void Wr24C08(unsigned int slvAddr , unsigned int addr,unsigned char data){
g_tS3C24xx_I2C.Mode = WRDATA;//写操作
g_tS3C24xx_I2C.Pt   = 0;//??
g_tS3C24xx_I2C.pData[0]= (unsigned char)addr;//保存缓冲区地址
g_tS3C24xx_I2C.pData[1]= data;//保存缓冲区地址
g_tS3C24xx_I2C.DataCount = 2; //传输长度


IICDS = slvAddr ;  //从机地址末字节不需要自己添加
IICSTAT = 0xf0;//主机发送,启动


//等待直至数据传输完毕
while(g_tS3C24xx_I2C.DataCount != -1);



//判断有无ACK信号
g_tS3C24xx_I2C.Mode = POLLACK;//等待ACK信号应答模式,有应答表示从设备已经收到


while(1){
IICDS = slvAddr ;
g_tS3C24xx_I2C.Status = 0x100;
IICSTAT = 0xf0;
IICCON  = 0xaf;


while(g_tS3C24xx_I2C.Status == 0x100);


if(!(g_tS3C24xx_I2C.Status & 0x01))
break;
}
IICSTAT = 0xd0;
IICCON = 0xaf;
Delay(10000);
}


/*
* 按页写一次16  字节
*/
void Wr24C08_Page(unsigned int slvAddr , unsigned int addr,unsigned char * data){
g_tS3C24xx_I2C.Mode = WRDATA;//写操作
g_tS3C24xx_I2C.Pt   = 0;//??
g_tS3C24xx_I2C.pData[0]= (unsigned char)addr;//保存缓冲区地址
g_tS3C24xx_I2C.DataCount = 17; //传输长度 Count = len + 1  byte:2  page:17


int i ;

for(i = 0;i<16;i++)
g_tS3C24xx_I2C.pData[i+1]= *data++;//保存缓冲区地址


IICDS = slvAddr ;   //从机地址末字节不需要自己添加
IICSTAT = 0xf0;//主机发送,启动


//等待直至数据传输完毕
while(g_tS3C24xx_I2C.DataCount != -1);



//判断有无ACK信号
g_tS3C24xx_I2C.Mode = POLLACK;//等待ACK信号应答模式,有应答表示从设备已经收到


while(1){
IICDS = slvAddr ;
g_tS3C24xx_I2C.Status = 0x100;
IICSTAT = 0xf0;
IICCON  = 0xaf;


while(g_tS3C24xx_I2C.Status == 0x100);


if(!(g_tS3C24xx_I2C.Status & 0x01))
break;
}
IICSTAT = 0xd0;
IICCON = 0xaf;
Delay(10000);
}


void Rd24C08(unsigned int slvAddr , unsigned int addr,unsigned char *data){
//putString("I2C Start Read!",15);

g_tS3C24xx_I2C.Mode = SETADDR;//读操作
g_tS3C24xx_I2C.Pt   = 0;//?? 索引值初始化为-1,表示第一个中断时钟不接受数据
g_tS3C24xx_I2C.pData[0] = (unsigned char)addr;//保存缓冲区地址
g_tS3C24xx_I2C.DataCount = 1; //传输长度


IICDS = slvAddr;//slvAddr ;//从机地址末字节不需要自己添加
IICSTAT = 0xf0;//1010 0000 主机接收,启动


while(g_tS3C24xx_I2C.DataCount != -1);  //写2次数据后DataCount != -1




g_tS3C24xx_I2C.Mode  = RDDATA;//读操作
g_tS3C24xx_I2C.Pt    = 0;//?? 索引值初始化为-1,表示第一个中断时钟不接受数据
g_tS3C24xx_I2C.DataCount = 1; //传输长度




IICDS = slvAddr ;//| 0x01;  //读 1
IICSTAT = 0xb0;//1010 0000 主机接收,启动
IICCON = 0xaf; 
//等待直至数据传输完毕
while(g_tS3C24xx_I2C.DataCount != -1);


*data = g_tS3C24xx_I2C.pData[1];

}


void Rd24C08_Page(unsigned int slvAddr , unsigned int addr,unsigned char *data){
//putString("I2C Start Read!",15);
/* 先将要读取的地址写入AT24C08*/
g_tS3C24xx_I2C.Mode = SETADDR;//读操作
g_tS3C24xx_I2C.Pt   = 0;//?? 索引值初始化为-1,表示第一个中断时钟不接受数据
g_tS3C24xx_I2C.pData[0] = (unsigned char)addr;//保存缓冲区地址
g_tS3C24xx_I2C.DataCount = 1; //传输长度


int i;


IICDS = slvAddr;//slvAddr ;//从机地址末字节不需要自己添加
IICSTAT = 0xf0;//1010 0000 主机接收,启动


while(g_tS3C24xx_I2C.DataCount != -1);  //写2次数据后DataCount != -1


/* 读取AT24C08中数据 */
g_tS3C24xx_I2C.Mode  = RDDATA;//读操作
g_tS3C24xx_I2C.Pt    = 0;//?? 索引值初始化为-1,表示第一个中断时钟不接受数据
g_tS3C24xx_I2C.DataCount = 16; //传输长度 


IICDS = slvAddr ;//| 0x01;  //读 1
IICSTAT = 0xb0;//1010 0000 主机接收,启动
IICCON = 0xaf; 
//等待直至数据传输完毕
while(g_tS3C24xx_I2C.DataCount != -1);
for(i=0;i<16;i++){
*data++ = g_tS3C24xx_I2C.pData[i+1];
}
}

/*
* I2C中断服务程序
*/
void I2CIntHandle(void){
unsigned int iicSt,i;

//清中断
SRCPND = BIT_IIC;
INTPND = BIT_IIC;

iicSt  = IICSTAT;
if(iicSt & 0x08){
putString("Bus arbitration failed\n\r",30);
}
switch(g_tS3C24xx_I2C.Mode){
case POLLACK:
g_tS3C24xx_I2C.Status = IICSTAT;
break;
case WRDATA:
if(g_tS3C24xx_I2C.DataCount-- == 0){//如果
//下面两行用来恢复I2C 操作,发出P信号
IICSTAT = 0xd0;
IICCON  = 0xaf;
Delay(10000);//等待一段时间以便P信号已经发出
break;
}
IICDS = g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++];


//将数据写入IICDS 后需要一大UN时间爱你才能出现在SDA线上
for(i = 0; i<10; i++);


IICCON = 0xaf;

break;

case RDDATA:
if(g_tS3C24xx_I2C.DataCount-- == 0){//最后一个字节数据
g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;
//下面两行恢复IIC操作
IICSTAT = 0x90;//发送P 停止信号
IICCON  = 0xaf;//最后一字节,无ACK
Delay(10000);  //等待一段时间以便P 信号已经发出
break;
}

g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS;
//接收最后一个数据时,不要发出ACK 信号
if(g_tS3C24xx_I2C.DataCount == 0){
IICCON = 0x2f;//恢复IIC传输,接收下一数据时无ACK
}else{
IICCON = 0xaf;//恢复IIC传输,接收下一数据时有ACK
}


break;


case SETADDR:
if(g_tS3C24xx_I2C.DataCount-- ==0)
break;
IICDS = g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++];
Delay(10000);  //等待一段时间
IICCON = 0xaf;

break;

default :
break;
}
}


/* * 延时函数 */
void Delay(int time){ 
for (; time > 0; time--);
}



具体程序如下:

你可能感兴趣的:(ARM)