|
发表于 2010-8-2 13:45:38
|
显示全部楼层
/*在找资料的过程中无意发现了这强帖,就想问楼主一下有关I2C读写eeprom的问题,下列的代码只能写,读出的数据都是0xff,找了很久不知道是哪里出了问题,想问下呀。*/
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <avr/delay.h>
#define e2prom 8 // <---在此设定芯片型号, 1代表24C01; 16代表24C16; 512代表24C512
#if e2prom==1
#define PAGE_SIZE 8
#define SIZE 0x007f
#elif e2prom==2
#define PAGE_SIZE 8
#define SIZE 0x00ff
#elif e2prom==4
#define PAGE_SIZE 16
#define SIZE 0x01ff
#elif e2prom==8
#define PAGE_SIZE 16
#define SIZE 0x03ff
#elif e2prom==16
#define PAGE_SIZE 16
#define SIZE 0x07ff
#elif e2prom==32
#define PAGE_SIZE 32
#define SIZE 0x0fff
#elif e2prom==64
#define PAGE_SIZE 32
#define SIZE 0x1fff
#elif e2prom==128
#define PAGE_SIZE 64
#define SIZE 0x3fff
#elif e2prom==256
#define PAGE_SIZE 64
#define SIZE 0x7fff
#elif e2prom==512
#define PAGE_SIZE 128
#define SIZE 0xffff
#endif
#define W_ADD_COM 0xa0 //写字节命令及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 0
#define R_ADD_COM 0xa1 //读命令字节及器件地址(根据地址实际情况改变), 1010 A2 A1 A0 1
//-------------------------------
#define SLAW 0x18 //SLA_W 已正常发送代码,判断器件是否正常应答的常量.
#define ERR_SLAW 10 //写字节命令及器件地址错, 在此也就是读写器件错!!
uint8_t * wt24c_fc(uint8_t *p, uint16_t ad, uint8_t n); //向24Cxx写入数据wt24c_h()所要调用的函数
extern uint8_t mRxData[10];
extern uint8_t CompSeat;
extern uint8_t buffer[8];
uint8_t syserr;
uint8_t Clear_buffer[16]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
void Twi_init(void)
{
TWCR= 0X00; //disable twi
TWBR= 0x20; //set bit rate
TWSR= 0x00; //set prescale
TWAR= 0x00; //set slave address
TWCR= 0x04; //enable twi
}
//-------------------------------以下为其它I2总线器件可调用的函数--------------------------
/********************************************************************************************************
函数描述:总线上起动开始条件
输入参数:无
返回参数:无
*********************************************************************************************************/
void I2C_Start(void)
{
TWCR= (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
}
/********************************************************************************************************
函数描述:把一个字节数据输入器件, 返回TWI状态
输入参数:一个字节数值=a
返回参数:状态
*********************************************************************************************************/
uint8_t I2C_Wt(uint8_t a)
{
TWDR = a;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
return(TWSR&0b11111000);
}
/********************************************************************************************************
函数描述:从器件读出一个字节
输入参数:无
返回参数:读出数值
*********************************************************************************************************/
uint8_t I2C_Rd(void)
{
TWCR= (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
return(TWDR);
}
/********************************************************************************************************
函数描述:总线上起动停止条件
输入参数:无
返回参数:无
*********************************************************************************************************/
void I2C_Stop(void)
{
TWCR= (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}
/*********************************************************************************************
函数描述: 向24Cxx写入数据
参数: *p_rsc要输出数据的主机内存地址指针; ad_dst要写入数据的i2c的地址(双字节); num数据个数
参数条件: ad_dst: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
**********************************************************************************************/
void Write_24c08(uint8_t *p_rsc, uint16_t ad_dst, uint16_t num)
{ uint16_t n;
n=ad_dst/PAGE_SIZE; //确定地址与块地址的差
if(n)
{
n=(uint32_t)PAGE_SIZE*(n+1)-ad_dst;
}
else
{
n=PAGE_SIZE-ad_dst;
}
if(n>=num) //如果ad_dst所在的数据块的末尾地址 >= ad_dst + num, 就直接写入num个数据
{
wt24c_fc(p_rsc, ad_dst, num);
if(syserr!=0) return;
}
else //如果ad_dst所在的数据块末尾地址 < ad_dst + num, 就先写入ad_dst所在的数据块末尾地址与 ad_dst 之差个数据
{
p_rsc=wt24c_fc(p_rsc, ad_dst, n);
if(syserr!=0) return;
num-=n; //更新剩下数据个数
ad_dst+=n; //更新剩下数据的起始地址
//把剩下数据写入器件
while(num>=PAGE_SIZE) //先按PAGE_SIZE为长度一页一页的写入
{
p_rsc=wt24c_fc(p_rsc, ad_dst, PAGE_SIZE);
if(syserr!=0) return;
num-=PAGE_SIZE; //更新剩余数据个数
ad_dst+=PAGE_SIZE; //更新剩下数据的起始地址
}
if(num) //把最后剩下的小于一个PAGE_SIZE长度的数据写入器件
wt24c_fc(p_rsc, ad_dst, num);
}
}
/*****************************************************************************************************
函数描述: 从24cxx读出数据
参数: *p_dst要读入数据的主机内存地址指针; ad_rsc要输出数据的i2c的地址(整形); num数据个数(整形)
参数条件: ad_dst+(num-1)不能大于器件的最高地址; num必须>0;
*****************************************************************************************************/
void Read_24c08(uint8_t *p_dst, uint16_t ad_rsc, uint16_t num)
{ uint8_t t=0;
#if e2prom<32
t=ad_rsc>>8;
t<<=1;
#endif
I2C_Start(); //发送起始信号
if(I2C_Wt(W_ADD_COM+t)==SLAW) //发送SLA_W, 写字节命令及器件地址
{
#if e2prom>16
I2C_Wt(ad_rsc>>8); //ad_rsc的高位, 发送要读出数据的地址
#endif
I2C_Wt(ad_rsc); //ad_rsc的低位
I2C_Start(); //再发送起始信号
I2C_Wt(R_ADD_COM+t); //发送SLA_R, 读命令字节及器件地址
for(;num>0;num--)
{
*p_dst=I2C_Rd(); //从器件读出一个字节
p_dst++;
}
}
else syserr=ERR_SLAW; //写字节命令及器件地址错或对方无应答
I2C_Stop();
}
/*************************************************************************************************
函数描述: 向24Cxx写入数据wt24c_h()所要调用的函数
参数:
返回参数: 写入n个字节后的主机内存指针
**************************************************************************************************/
uint8_t * wt24c_fc(uint8_t *p, uint16_t ad, uint8_t n)
{ uint8_t t=0;
#if e2prom<32
t=ad>>8;
t<<=1;
#endif
I2C_Start(); //发送起始信号
if(I2C_Wt(W_ADD_COM+t)==SLAW)//发送SLA_W, 写字节命令及器件地址
{
#if e2prom>16
I2C_Wt(ad>>8); //ad_dst的高位到器件
#endif
I2C_Wt(ad); //ad_dst的低位到器件
for(;n>0;n--) //发送要写入的数据
{ I2C_Wt(*p);
p++;
}
}
else syserr=ERR_SLAW; //写字节命令及器件地址错
I2C_Stop();
_delay_ms(6); //延时6ms
return(p);
}
/*************************************************************************************************
函数描述: 清楚24c08
参数: 无
返回参数: 无
**************************************************************************************************/
void Clear_24c08(void)
{
uint16_t i;
for(i=0;i<100;i++)
{
Write_24c08(Clear_buffer, i*16, 16);
}
} |
|