huhucao 发表于 2008-8-12 12:57:42

读写24C02遇到的问题(在马老师24C256例子基础上稍作改动)

向24C02写入100字节的0x08(自0x001地址起)。然后再从24C02读取,并送PC显示器显示(串口调试),结果只有前7个读出0x08,后面全是0XFF,似乎写入24C02只写入了7个字节
改过延时,改过写入起始地址都无用

huhucao 发表于 2008-8-12 12:59:32

附程序如下

//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){};
}

huhucao 发表于 2008-8-12 13:34:15

发现我用的24C02是后缀为N的 ,ATMEL公司的我接法是    A0A1A2都接地,WP空

huhucao 发表于 2008-8-13 18:02:02

发现初始化程序 所设置的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)写入正常

huhucao 发表于 2008-8-13 18:08:29

部分实验结果:
若自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
这个结果, 不晓得发生了何事

huhucao 发表于 2008-8-13 18:10:24

有没有看过马潮老师的《AVR....>>一书的,帮忙指点明路

huhucao 发表于 2008-8-13 18:12:29

void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
这个函数应该能实现自动换页写入

huhucao 发表于 2008-8-14 13:31:38

#definePage_size 8   //256 个 页面每个页面8 个 字节
改为      #definePage_size 8   // 32 个页面,每个页面8 个字节

huhucao 发表于 2008-8-14 14:05:43

跨页有问题,超过8 字节写入,会冲掉前面已写的内容
void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
这个函数应该能实现自动换页写入

ba_wang_mao 发表于 2008-8-15 12:57:06

(1)、跨页有问题,超过8 字节写入,会冲掉前面已写的内容
(2)、写完一页后,必须延时50毫秒才能写其它页(参见数据手册)

huhucao 发表于 2008-8-15 19:56:38

先谢谢ba_wang_mao。
问题我已经解决:
问题出在Addr

zlh390 发表于 2008-8-22 09:57:07

I2C_write(Addr>>8);                                 // 发存储单元地址高字节
很明显这里不对,24C02只要8位寻址就够了。

xiuqi410 发表于 2009-6-5 15:41:25

我用的与你一样的程序,为什么我的程序走到下面这个子函数里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;
}

wangyj173 发表于 2011-10-10 08:49:43

换页有问题

millwood0 发表于 2011-10-10 09:28:01

" 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]
查看完整版本: 读写24C02遇到的问题(在马老师24C256例子基础上稍作改动)