搜索
bottom↓
回复: 14

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

[复制链接]

出0入0汤圆

发表于 2008-8-12 12:57:42 | 显示全部楼层 |阅读模式
向24C02写入100字节的0x08(自0x001地址起)。然后再从24C02读取,并送PC显示器显示(串口调试),结果只有前7个读出0x08,后面全是0XFF,似乎写入24C02只写入了7个字节
改过延时,改过写入起始地址都无用

阿莫论坛20周年了!感谢大家的支持与爱护!!

阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)

出0入0汤圆

 楼主| 发表于 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)

//状态字设置

#define  TW_START 0x08  
#define  REP_START 0x10
#define  MT_SLA_ACK 0x18
#define  MT_SLA_nACK 0x20
#define  MT_DAT_ACK  0x28
#define  MT_DAT_nACK 0x30
#define  LOST 0x38
#define  MR_SLA_ACK 0x40
#define  MR_SLA_nACK 0x48
#define  MR_DAT_ACK 0x50
#define  MR_DAT_nACK 0x58

//24C02 相关    内存空间为 000H~7ffH

#define  Page_size 8   //256 个 页面  每个页面8 个 字节
#define  Page_mask  Page_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;
}


void  I2C_stop(void)
{
TWCR=TWEN|TWSTO|TWINT;
}     

uchar I2C_write(uchar c)

  {
   uchar  ack=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[100];
   
    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){};
}

出0入0汤圆

 楼主| 发表于 2008-8-12 13:34:15 | 显示全部楼层
发现我用的24C02是后缀为N的 ,ATMEL公司的  我接法是    A0A1A2都接地,WP空

出0入0汤圆

 楼主| 发表于 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)写入正常

出0入0汤圆

 楼主| 发表于 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
这个结果, 不晓得发生了何事

出0入0汤圆

 楼主| 发表于 2008-8-13 18:10:24 | 显示全部楼层
有没有看过马潮老师的《AVR....>>一书的,帮忙指点明路

出0入0汤圆

 楼主| 发表于 2008-8-13 18:12:29 | 显示全部楼层
void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)
这个函数应该能实现自动换页写入

出0入0汤圆

 楼主| 发表于 2008-8-14 13:31:38 | 显示全部楼层
#define  Page_size 8   //256 个 页面  每个页面8 个 字节
改为        #define  Page_size 8   // 32 个页面  ,每个页面8 个字节

出0入0汤圆

 楼主| 发表于 2008-8-14 14:05:43 | 显示全部楼层
跨页有问题  ,超过8 字节写入,会冲掉前面已写的内容
void EEprom_Write(unsigned int Addr,unsigned char n, unsigned char* arr)  
这个函数应该能实现自动换页写入

出0入0汤圆

发表于 2008-8-15 12:57:06 | 显示全部楼层
(1)、跨页有问题  ,超过8 字节写入,会冲掉前面已写的内容
(2)、写完一页后,必须延时50毫秒才能写其它页(参见数据手册)

出0入0汤圆

 楼主| 发表于 2008-8-15 19:56:38 | 显示全部楼层
先谢谢ba_wang_mao。
问题我已经解决:
问题出在Addr

出0入0汤圆

发表于 2008-8-22 09:57:07 | 显示全部楼层
I2C_write(Addr>>8);                                 // 发存储单元地址高字节
很明显这里不对,24C02只要8位寻址就够了。

出0入0汤圆

发表于 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;
}

出0入0汤圆

发表于 2011-10-10 08:49:43 | 显示全部楼层
换页有问题

出0入0汤圆

发表于 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.
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-16 16:09

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表