读写24C02遇到的问题(在马老师24C256例子基础上稍作改动)
向24C02写入100字节的0x08(自0x001地址起)。然后再从24C02读取,并送PC显示器显示(串口调试),结果只有前7个读出0x08,后面全是0XFF,似乎写入24C02只写入了7个字节改过延时,改过写入起始地址都无用 附程序如下
//ATmega16L
//基于CVAVR
//8MHZ晶振
//基于16L硬件I2C实现
//利用PC显示器做调试用窗口
//PC1--SDA
//PC0--SCL
#include <mega16.h>
#include <stdio.h>//通用串行异步总线 要用到
#include <delay.h>
#define uchar unsigned char
#define BUS_ADDR 0xa0 //24c02 所在地址
//TWI 状态寄存器TWSR设置项
//预分频率设置
#define TWPS0 (1<<0)
#define TWPS1 (1<<1)
//控制寄存器TWCR设置项
#define TWEN (1<<2)
#define TWIE (1<<0)
#define TWEA (1<<6)
#define TWINT (1<<7)
#define TWSTA (1<<5)
#define TWSTO (1<<4)
//状态字设置
#defineTW_START 0x08
#defineREP_START 0x10
#defineMT_SLA_ACK 0x18
#defineMT_SLA_nACK 0x20
#defineMT_DAT_ACK0x28
#defineMT_DAT_nACK 0x30
#defineLOST 0x38
#defineMR_SLA_ACK 0x40
#defineMR_SLA_nACK 0x48
#defineMR_DAT_ACK 0x50
#defineMR_DAT_nACK 0x58
//24C02 相关 内存空间为 000H~7ffH
#definePage_size 8 //256 个 页面每个页面8 个 字节
#definePage_maskPage_size-1 //页内
void I2C_init(void)
{
TWSR=0x00; //清状态
TWBR=0x00; //复位值
TWAR=0x00; //
TWCR=TWIE|TWEA;//ACK Enable and TWI ENABLE
}
uchar I2C_start(void)
{
TWCR=TWEN|TWSTA|TWINT;//先清出INT 标志位
while(!(TWCR&TWINT));//当TWINT be set to"1",marked finished the current job
return 1;
}
voidI2C_stop(void)
{
TWCR=TWEN|TWSTO|TWINT;
}
uchar I2C_write(uchar c)
{
ucharack=1;
TWDR = c;
TWCR = TWINT|TWEN;
while (!(TWCR & TWINT));
if((TWSR & 0xF8) != MT_SLA_ACK)
ack = 0;
return ack;
}
uchar I2C_read(unsigned char ack) //读一字节 ack: 1时应答,0时不应答
{
if (ack)
TWCR = TWINT|TWEN|TWEA;
else
TWCR = TWINT|TWEN;
while (!(TWCR & TWINT));
return(TWDR);
}
void EEprom_Page_write(unsigned int Addr,unsigned char n, unsigned char* arr)
{
unsigned char i;
I2C_start(); // 发起始信号
I2C_write(BUS_ADDR); // 发写从机写寻址字节
I2C_write(Addr>>8); // 发存储单元地址高字节
I2C_write(Addr); // 发存储单元地址低字节
for (i=1;i<=n;i++)
{
I2C_write(*arr); // 写一个字节数据到24C02
arr++;
}
I2C_stop(); // 发停止信号
delay_ms(10); // 等待10ms,保证24C02内部写操作完成再进行新操作
}
void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
{
unsigned char n_tmp;
n_tmp=Page_size-(unsigned char)(Addr&Page_mask);//页内剩余字节数
if ((n>n_tmp)&&(n_tmp!=0)) //还剩空间, 但不够写完
{
EEprom_Page_write(Addr,n_tmp,arr);//先写完剩余空间
Addr += n_tmp;
n -= n_tmp;
arr += n_tmp;
}
while (n >= Page_size) //未写完的数据超过一页的,
{
EEprom_Page_write(Addr,Page_size, arr);
Addr += Page_size;
n -= Page_size;
arr += Page_size;
}
if (n!=0) //还剩的未写完的数据,不足一页的
EEprom_Page_write(Addr,n,arr);
}
void EEprom_read(unsigned int Addr,unsigned char n, unsigned char* arr)
{
unsigned char i;
I2C_start(); // 发起始信号
I2C_write(BUS_ADDR); // 发写从机写寻址字节
I2C_write(Addr>>8); // 发存储单元地址高字节
I2C_write(Addr); // 发存储单元地址低字节
I2C_start(); // 发起始信号
I2C_write(BUS_ADDR+ 1); // 发从机读寻址字节
for (i=1;i<=n-1;i++)
{
*arr = I2C_read(1); // 读一个字节数据,返回ACK
arr++;
}
*arr=I2C_read(0); // 读最后一个字节数据,返回NO ACK
I2C_stop(); // 发停止信号
}
void main(void)
{
unsigned char i,data;
UCSRA=0x00; // USART initialization
UCSRB=0x18; // Communication Parameters: 8 Data, 1 Stop, No Parity
UCSRC=0x86; // USART Receiver: On,USART Transmitter: On
UBRRH=0x00; // USART Mode: Asynchronous ,USART Baud Rate: 9600
UBRRL=0x33;
// ================================================
I2C_init(); // initialize the I2C bus
for (i=0;i<100;i++) {data=8;} // 数组赋值
EEprom_Write(0x001,100,data);
for (i=0;i<100;i++) {data=0;} // 数组清零
EEprom_read(0x001,100,data);
for (i=0;i<100;i++) {putchar(data);} // 送PC检验
while (1){};
} 发现我用的24C02是后缀为N的 ,ATMEL公司的我接法是 A0A1A2都接地,WP空 发现初始化程序 所设置的SCLK频率为500kHZ ,
又修改成250KHZ: TWBR=2 TWPS=1
即TWBR=0x02 TWPS【1:0】=00
TWCR=TWIE|TWEA;//ACK Enable and TWI ENABLE
改为 TWCR=TWEN|TWEA
结果没改善
后来不知怎弄的,又好了些 ,超过一页的有问题 ,但小于或等于一页的(8Bytes)写入正常 部分实验结果:
若自225页开始写:
for (i=0;i<8;i++) data=i+1 ;
EEprom_Write(0x7f8, 8,data);
for (i=0;i<8;i++) {data=0;} // 数组清零
EEprom_read(0x7f8,8,data);
for (i=0;i<8;i++) putchar(data);// 送PC检验
while (1){};
}
串口调试结果: 01 02 03 04 05 06 07 08
若自第一页开始写
for (i=0;i<8;i++) data=i+1 ;
EEprom_Write(0x000, 8,data);
for (i=0;i<8;i++) {data=0;} // 数组清零
EEprom_read(0x000,8,data);
for (i=0;i<8;i++) putchar(data);// 送PC检验
串口调试结果:01 02 03 04 05 06 07 08
若自第二页写
for (i=0;i<8;i++) data=i+1 ;
EEprom_Write(0x008, 8,data);
for (i=0;i<8;i++) {data=0;} // 数组清零
EEprom_read(0x008,8,data);
for (i=0;i<8;i++) putchar(data);// 送PC检验
while (1){};
串口调试结果:01 02 03 04 05 06 07 08
若超过8字节写入
for (i=0;i<16;i++) data=i+1 ;
EEprom_Write(0x008, 16,data);
for (i=0;i<18;i++) {data=0;} // 数组清零
EEprom_read(0x008,16,data);
for (i=0;i<16;i++) putchar(data);// 送PC检验
while (1){};
串口调试结果:09 0A 0B 0C 0D 0E 0F 08 11 12 0B 0C 0D 0E 0F FF
这个结果, 不晓得发生了何事 有没有看过马潮老师的《AVR....>>一书的,帮忙指点明路 void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
这个函数应该能实现自动换页写入 #definePage_size 8 //256 个 页面每个页面8 个 字节
改为 #definePage_size 8 // 32 个页面,每个页面8 个字节 跨页有问题,超过8 字节写入,会冲掉前面已写的内容
void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
这个函数应该能实现自动换页写入 (1)、跨页有问题,超过8 字节写入,会冲掉前面已写的内容
(2)、写完一页后,必须延时50毫秒才能写其它页(参见数据手册) 先谢谢ba_wang_mao。
问题我已经解决:
问题出在Addr I2C_write(Addr>>8); // 发存储单元地址高字节
很明显这里不对,24C02只要8位寻址就够了。 我用的与你一样的程序,为什么我的程序走到下面这个子函数里while语句就不走了,死到这里了,有谁知道什么原因吗?
uchar I2C_start(void)
{
TWCR=TWEN|TWSTA|TWINT;//先清出INT 标志位
while(!(TWCR&TWINT));//当TWINT be set to"1",marked finished the current job
return 1;
} 换页有问题 " I2C_write(Addr>>8); // 发存储单元地址高字节 "
for your eeprom, you don't need to send 16-bit address.
alternatively, you can keep the code and use conditional compilation.
" delay_ms(10); // 等待10ms,保证24C02内部写操作完成再进行新操作 "
look for "acknowledge polling" in the datasheet.
页:
[1]