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
流程图如下:
主机发送流程图
3.主机接收,流程如下:
接收时需要先将AT24C08从机地址以及要读的地址发送给从机,所以读操作开始是两个字节的写操作,具体方法见主机写操作。
然后是读操作:
IICSTAT = 0xb0;//1010 0000 主机接收,启动
IICCON = 0xaf; //恢复IIC操作
然后等待接收中断,注意第一次中断是发送完地址产生的中断,读到的数据为0,无效。以后每来一次中断,读一次IICDS,读完恢复IIIC传输IICCON = 0xaf,依次循环,直到最后一个字节,发送IICCON = 0x2f;//恢复IIC传输,接收下一数据时无ACK,等到接收下一数据时,IICSTAT = 0x90;//发送P 停止信号,以此结束IIC读操作。
主机接收流程图
具体程序如下:排版可能有问题,把程序添加到附件,需要的同学可以下载下来,有问题的地方,请指出来,共同进步。
#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--);
}