1、使用2440 iic 模块控制
#include "2440addr.h"
#include "uart.h"
volatile int ackFlag = 0;
void delay()
{
int i,j;
for(i = 0; i < 500;i++)
for(j = 0; j < 500; j++)
;
}
/***********************************************
Function name : Iic_ISR
Description : iic 中断处理函数
Input parameter : none
Return : none
Others :
*************************************************/
static void __irq Iic_ISR()
{
//清除中断
rSRCPND |= (1 << 27);
rINTPND |= (1 << 27);
ackFlag = 1;
}
/***********************************************
Function name : iic_init
Description : iic 通信初始化
Input parameter : none
Return : none
Others :
*************************************************/
void iic_init(void)
{
//配置GPE14\15 为 IICSCL 、IICSDA、不使能拉高电阻(GPE14\15没有对应的位)
rGPECON &= ~(0xf << 28);
rGPECON |= (0x2 << 30) | (0x2 << 28);
//清除中断
rSRCPND |= (1 << 27);
rINTPND |= (1 << 27);
//开启iic中断
rINTMSK &= ~(1 << 27);
//设置中断处理函数
pISR_IIC = (unsigned)Iic_ISR;
//配置IICCON寄存器:使能ACK,时钟源选择fPCLK /512
//(从eeprom手册看出,其最大的传输频率为100kHZ)
//使能中断,发送时钟值为0xf。
//Tx clock = IICCLK/(IICCON[3:0]+1)=50000000/512=97kHz
rIICCON = (1<<7)|(1<<6)|(1<<5);
//设置CPU的从设备地址(未使用)
rIICADD = 0x10;
//IIC-bus data output enable
rIICSTAT |= (1<<4);
}
/***********************************************
Function name : iic_Tx
Description : iic 发送数据
Input parameter : buffer 要发送的数据
size:数据大小
Return : none
Others :
*************************************************/
void iic_Tx(unsigned char devAddr,unsigned char wordAddr,char buffer[],int size)
{
int i = 0,j = 0;
ackFlag = 0;
//写从设备地址到IICDS寄存器
rIICDS = devAddr;
//配置为主发送模式
//写0XF0到IICSTAT(主发送模式,并开始)
rIICSTAT = 0xf0;
for(i = 0; i < 100; i++);
//清除挂起位
rIICCON &= ~(1<<4);
//等待ack中断响应
//while(!ackFlag);
//注意:这里等待挂起可以单独判断pending,但不能单独判断ack,防止数据丢失
while(!ackFlag)
delay();
ackFlag = 0;
//写起始地址到IICDS寄存器
rIICDS = wordAddr;
for(i = 0; i < 100; i++);
//清除挂起位
rIICCON &= ~(1<<4);
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
//向IICDS写入发送数据直到发送结束
for(j = 0; j < size; j++)
{
//写入新数据
rIICDS = buffer[j];
for(i = 0; i < 100; i++);
//清除挂起位
rIICCON &= ~(1<<4);
//等待ack中断
while(!ackFlag)
delay();
ackFlag = 0;
}
//发送结束,写0XD0到 IICSTAT
rIICSTAT = 0xd0;
rIICCON = 0xe0;
//等待停止条件生效
delay();
}
/***********************************************
Function name : iic_Rx
Description : iic 接收数据
Input parameter : buffer 接收buffer
Return : i: 接收到的数据大小
Others :
*************************************************/
int iic_Rx(unsigned char devAddr,unsigned char wordAddr,char * buffer,int size)
{
char ch;
int i = 0,j = 0;
ackFlag = 0;
//写从设备地址到IICDS寄存器
rIICDS = devAddr;
for(i = 0; i < 100; i++);
//配置为主发送模式
//写0XF0到IICSTAT(主发送模式,并开始)
rIICSTAT = 0xf0;
//清除挂起位
rIICCON &= ~0x10;
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
//写起始地址到IICDS寄存器
rIICDS = wordAddr;
for(i = 0; i < 100; i++);
//清除挂起位
rIICCON &= ~0x10;
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
//写从设备地址到IICDS寄存器
rIICDS = devAddr;
for(i = 0; i < 100; i++);
//写0XB0到IICSTAT(主接收模式,并开始)
rIICSTAT = 0xb0;
//清除挂起位
rIICCON &= ~0x10;
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
//从IICDS读取第一个字节舍弃
ch = rIICDS;
//清除挂起位
rIICCON &= ~0x10;
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
//从IICDS读取数据直到接收结束
for(j = 0; j < size; j++)
{
if(j == size-1)
{
rIICCON &= ~0x80;
}
//从IICDS读取数据
buffer[j] = rIICDS;
for(i=0;i<100;i++);
//清除挂起位
rIICCON &= ~0x10;
//等待ack中断响应
while(!ackFlag)
delay();
ackFlag = 0;
}
//接收结束,写0X90到 IICSTAT
rIICSTAT = 0x90;
rIICCON = 0xe0;
//等待停止条件生效
delay();
return j;
}
/***********************************************
Function name : iic_test
Description : iic 测试
Input parameter : none
Return : none
Others :
*************************************************/
int iic_test(void)
{
iic_init();
int i = 998;
int j = 0;
iic_Tx(0xa0,0,(char*)&i,4);
iic_Rx(0xa0,0,(char*)&j,4);
uart_printf("\nj = %d\n",j);
}
/******************
iic.h
*******************/
#ifndef _IIC_H_
#define _IIC_H_
#include "def.h"
void iic_init(void);
#define AT24C08_ADDRDRESS 0xa0
#define true 1
#define false 0
#define PAGE1 0xa0
#define PAGE2 0xa2
#define PAGE3 0xa4
#define PAGE4 0xa6
#define IIC_CLOCK_HIGH rGPEDAT |= (1<<14)
#define IIC_CLOCK_LOW rGPEDAT &= ~(1<<14)
#define IIC_DATA_HIGH rGPEDAT |= (1<<15)
#define IIC_DATA_LOW rGPEDAT &= ~(1<<15)
#define SET_IIC_DATA_INPUT rGPECON &= ~(3<<30)
#define SET_IIC_DATA_OUTPUT rGPECON |= (1<<30)
U8 i2c_write(U8 device_address, U8 memory_address , U8 data);
U8 i2c_read(U8 device_address, U8 memory_address, U8 *data);
U8 i2c_page_read(U8 device_address, U8 memory_address, U8 *destination,U32 size);
U8 i2c_page_write(U8 device_address, U8 memory_address , U8 *source,U32 size);
U8 i2c_largepage_write(U8 device_address, U8 memory_address , U8 *source,U32 size);
void i2c_test(void);
#endif
/*****************************
iic.c
*****************************/
#include "2440addr.h"
#include "def.h"
#include "uart.h"
#include "iic.h"
//#include "timer.h"
#define DELAY_DECIMUS_MS 100
extern void Delay_MS( unsigned int time);
void delayus( U32 time)
{
U32 i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<DELAY_DECIMUS_MS;j++)
{
}
}
}
void iic_init(void)
{
/* config GPE14, GPE15 as output*/
rGPECON &=(~((3<<30)|(3<<28)));
rGPECON |=(1<<30)|(1<<28);
/* SDA,SCL 默认为高电平 */
rGPEDAT |= ((1<<15)|(1<<14));
rGPEUP |= ((1<<15)|(1<<14));
delayus(1);
}
/* start */
void i2c_start(void)
{
IIC_DATA_HIGH;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
IIC_DATA_LOW;
delayus(1);
IIC_CLOCK_LOW;
}
void i2c_stop(void)
{
SET_IIC_DATA_OUTPUT;
delayus(1);
IIC_DATA_LOW;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
IIC_DATA_HIGH;
delayus(1);
}
U8 check_ack(void)
{
/* ack */
U8 ret;
U8 ucErrTime=0;
SET_IIC_DATA_INPUT;
delayus(1);
IIC_CLOCK_HIGH; //negative edge clock data out of each device
delayus(1);
while(rGPEDAT&(1<<15))
{
ucErrTime++; //时间累加
ret = false;
if(ucErrTime>250) //如果时间大于250
{
i2c_stop(); //调用IIC停止子函数
return ret; //程序返回值0
}
}
ret = true;
IIC_CLOCK_LOW;
delayus(1);
SET_IIC_DATA_OUTPUT;
delayus(1);
return ret;
}
void send_no_ack(void)
{
delayus(1);
IIC_CLOCK_LOW; //positive edge clock data into eachEEPROM
delayus(1);
SET_IIC_DATA_OUTPUT;//发送数据时与上升沿同步
IIC_DATA_HIGH; /* 发送高电平no ack */
delayus(2);
IIC_CLOCK_HIGH;
delayus(1);
IIC_CLOCK_LOW;
delayus(1);
}
void data_write(U8 data)
{
U8 i;
SET_IIC_DATA_OUTPUT;
delayus(1);
/* data transmit */
for (i = 0; i< 8; i++)
{
if(data&(1<<(7-i)))//发送数据时与上升沿同步
{
IIC_DATA_HIGH;
}
else
{
IIC_DATA_LOW;
}
delayus(1);
IIC_CLOCK_HIGH ;
delayus(1);
IIC_CLOCK_LOW ;
delayus(1);
}
IIC_DATA_HIGH;
delayus(1);
// UartPuts(" data write over!\n");
}
void data_read(U8 *data )
{
U8 i;
IIC_DATA_HIGH; // free
delayus(1);
SET_IIC_DATA_INPUT;
delayus(1);
/* data reas */
for (i = 0 ; i< 8; i++)
{
IIC_CLOCK_LOW;
delayus(1);
IIC_CLOCK_HIGH;
delayus(1);
if(rGPEDAT&(1<<15))//接收数据时与下降沿同步
{
(*data) |=(1<<(7-i)) ;
}
else
{
(*data) &=~(1<<(7-i)) ;
}
}
IIC_CLOCK_LOW;
delayus(1);
SET_IIC_DATA_OUTPUT;
// Uart_Printf("---- %4x \n",*data);
}
U8 i2c_write(U8 device_address, U8 memory_address , U8 data)
{
U8 write_addr;
U8 ack_flag;
U8 ret;
/* start */
i2c_start();
/* write address transmit */
data_write(device_address);
/* ack */
ack_flag = check_ack();
//ack_flag = 0;
if(!ack_flag)
{
ret = false;
UartPuts(" write i2c device address no ack!\n");
goto i2c_stop;
}
/* write address transmit */
data_write(memory_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" write memory address no ack!\n");
while(1);
goto i2c_stop;
}
/* write data transmit */
data_write(data);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" write data no ack!\n");
goto i2c_stop;
}
else
{
ret = true;
}
i2c_stop:
i2c_stop();
delayus(1000); //延时等待STOP信号生效(10ms)
return ret;
}
U8 i2c_dummy_write(U8 device_address, U8 memory_address )
{
U8 write_addr;
U8 ack_flag;
U8 ret;
/* start */
i2c_start();
/* write address transmit */
data_write(device_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" dummy write i2c device address no ack!\n");
goto i2c_stop;
}
/* write address transmit */
data_write(memory_address);
/* ack */
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" dummy write memory address no ack!\n");
goto i2c_stop;
}
/* write data transmit */
else
{
ret = true;
return ret;
}
i2c_stop:
i2c_stop();
return ret;
}
U8 i2c_read(U8 device_address, U8 memory_address, U8 *data)
{
U8 read_addr;
U8 ack_flag;
U8 ret;
ret = i2c_dummy_write( device_address , memory_address);
if(!ret)
{
ret = false;
return ret;
}
i2c_start();
read_addr = device_address |1;
data_write(read_addr);
ack_flag = check_ack();
if(!ack_flag)
{
ret = false;
UartPuts(" i2c_read write i2c device address no ack!\n");
goto i2c_read_stop;
}
data_read(data);
send_no_ack();
ret = true;
i2c_read_stop:
i2c_stop();
return ret;
}
U8 i2c_page_read(U8 device_address, U8 memory_address, U8 *destination,U32 size)
{
int i;
for(i=0;i<size;i++)
i2c_read(device_address,memory_address+i,destination+i);
}
U8 i2c_page_write(U8 device_address, U8 memory_address , U8 *source,U32 size)
{
int i;
for(i=0;i<size;i++)
{
i2c_write(device_address,memory_address+i,source[i]);
//Uart_Printf("write %d\n",i);
}
}
U8 i2c_largepage_write(U8 device_address, U8 memory_address , U8 *source,U32 size)
{
int i;
int n,m;
if(size>256)
Uart_Printf("Size illegal\n");
//assert(size<=256);//判断参数合法性
n=size/16; //写入的小页数
m=size%16; //写入小页后剩余的个数
for(i=0;i<n;i++)
i2c_page_write(device_address,(memory_address+16*i),(source+16*i),16);
for(i=0;i<m;i++)
i2c_write(device_address,(memory_address+16*n+i),*(source+16*n+i));
}
void i2c_test(void)
{
U8 flag;
U8 write_data;
U8 read_data;
U8 i,j;
i=1;
j=1;
UartPuts(" Begin to write!\n");
for(i=1;i<10;i++,j++)
{
flag = i2c_write(AT24C08_ADDRDRESS,i,j);
if(flag)
UartPuts(" write i2c ok!\n");
else
UartPuts(" write i2c failed!\n");
Delay_MS(1000);
flag = i2c_read(AT24C08_ADDRDRESS,i,&read_data);
if(flag)
{
Uart_Printf(" read i2c ok! %4x \n",read_data);
//UartPutch(0x30+read_data);
//UartPuts(" \n");
//Uart_Printf("%4x",read_data);
}
else
{
UartPuts(" read i2c failed!\n");
}
Delay_MS(500);
}
}