Ilove51andAVR 发表于 2011-11-20 16:31:11

!!!痛苦,AVR内部EEPROM读写失败,已经严格按照官方手册规定的步骤来写,极其精简仍然不成功,

代码极其简单的EEPROM读写程序,调试良久,仍不成功,已经无语了。求助各位高手,指点一二!

硬件电路连接:(很简单的,就不贴电路图出来了)
1、使用4位共阳数码管显示数值。
2、使用外部晶振8MHz。
3、+5V外部电源供电。
4、使用标准的ISP下载口下载程序。(本人有并行打印口和USB下载器,两者都能正常下载程序)

软件和程序设置:
1、使用AVR Studio 4.12编程软件,下载到单片机的软件是:ProgISP V1.66版。
2、AVR Studio 4.12设置频率为8MHz,优化程度选:00(即没有优化)。
3、单纯为了测试EEPROM有没有成功,除了显示函数外,其它函数和功能一概没有。
4、严格按照官方手册规定的步骤来写。

http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_697168YS8UFL.jpg
(原文件名:GCC中的频率设置.jpg)


下载软件ProgISP V1.66的设置:
1、勾选:外部晶振(3.0--MHz)起动时间16K CK+64ms[...省略N字...]
2、不勾选:使能JTAG接口。 JTAGEN
3、勾选:使能ISP编程。SPIEN
4、勾选:执行芯片擦除时保留EEPROM的内容。EESAVE
5、其它选项使用默认值。
6、时钟校正框选择:1.0MHz。(1.0MHz-8.0MHz都试过了不成功)
7、编程框选择:“芯片擦除”、“编程FLASH”、“校验FLASH”、“编程熔丝”、“数据自动重载”,其它不选。

熔丝低位:(1=未被编程,0=被编程)
1 BODLEVEL: BOD触发电平,默认值:1
1 BODEN:      BOD使能,默认值:1
1 SUT1:      选择启动时间,默认值:1
1 SUT0:      选择启动时间,默认值:0
1 CKSEL3:   选择时钟源,默认值:0
1 CKSEL2:   选择时钟源,默认值:0
1 CKSEL1:   选择时钟源,默认值:0
1 CKSEL0:   选择时钟源,默认值:1

熔丝高位:
1 OCDEN:   使能OCD,默认值:1
1 JTAGEN:    JTAG仿真调试接口,默认值:0
0 SPIEN:       SPI下载允许,使能串行程序和数据下载,默认值:0
1 CKOPT:      振荡器选项,默认值:1
0 EESAVE:    执行芯片擦除时EEPROM的内容保留,默认值:1(1:不保留;0:保留)
0 BOOTSZ1:选择BOOT区大小,默认值:0
0 BOOTSZ0:选择BOOT区大小,默认值:0
1 BOOTRST:选择复位向量,默认值:1

http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_697333HY9354.jpg
(原文件名:下载器抓图01.jpg)

http://cache.amobbs.com/bbs_upload782111/files_47/ourdev_697334RR5IGH.jpg
(原文件名:下载器抓图02.jpg)


下面是程序源码:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>

//*************************************************************************
//   定义LED数码管的位选端和小数点位置
//*************************************************************************
...省略N字...(地球人都知道数码管的管脚定义方法,在此就不贴出来了)

#ifndefFREQ
#defineFREQ    (8)// 单片机主频为8MHz,用于延时子程序,括号(8)里面的“8”表示单片机的主频为8MHz。
#endif

//*************************************************************************
//   精确延时定义
//*************************************************************************
#define delay_1us(x)\
_delay_loop_2((uint)((x)*FREQ/4))//_delay_loop_2(xxx)的意思是等于=xxx*4(个cpu时钟周期)/8(M时钟)
//#define delay_1us(x)中的括号(x)里面的“x”表示延时x uS。例如:x为1表示延时1uS,x为550表示延时550uS。

#define ucharunsigned char
#define uint   unsigned int
uchar scandata[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0xfe,0xf7,0xbf};//共阳极数码管段码,为0-9,10:空白和11:上标-,12:下标_,13:中间-

//*************************************************************************
//   显示函数
//*************************************************************************
void Display(uint i)
{
...省略N字...(很简单的显示程序,地球人都知道,在此就不贴出来了)
}

//*************************************************************************
//   AVR内部EEPROM写函数
//*************************************************************************
void EEPROM_write(uint addr,uint adata) //写EEPROM函数
{
        while(EECR & (1<<EEWE));//等待上一次写操作结束
        EEAR=addr; //配置地址
        EEDR=adata;//配置数据
        EECR |= (1<<EEMWE);//置位EEMWE
        EECR |= (1<<EEWE);//置位EEWE以启动写操作
}

//*************************************************************************
//   AVR内部EEPROM读函数
//*************************************************************************
uchar EEPROM_read(uint addr) //读EEPROM函数
{
        while(EECR & (1<<EEWE)); //等待上一次写操作结束
        EEAR=addr; //配置地址
        EECR |= (1<<EERE);//设置EERE以启动读操作
        return EEDR; //直接从数据寄存器返回数据,不需要另外定义变量了。
}

//*************************************************************************
//   主程序
//*************************************************************************
int main(void)
{
        DDRA=0b11111111; //设置PA端口为输出口,1为输出,0为输入。(段码)
        DDRC|=0b00001111; //设置PC端口的第1~4个端口为输出口。(位选端)
        uint i=99;
        uint j=57;

        EEPROM_write(2,j); //在地址2的位置上,写入数据j。(把57这个数存入EEPROM,然后再读出来,以此验证读写是否成功)
        delay_1us(10); //延时10us,让写和读之间有个空隙。
        i=EEPROM_read(2); //从第2个地址读取数据。

        while(1)
        {
                Display(i); //显示EEPROM中存储的数值
        }
}

cock 发表于 2011-11-20 17:10:50

先用库函数解决,再用自己的程序对比。
如果库函数也出错,换芯片。
换芯片仍错,换厂家或使用外置EEPROM。
还错,换工作!

Ilove51andAVR 发表于 2011-11-20 17:27:00

回复【1楼】cock
先用库函数解决,再用自己的程序对比。
......
-----------------------------------------------------------------------

什么是“库函数”??

lsy5110 发表于 2011-11-20 17:43:48

我用m8的eeprom很好用,cvavr下很方便。

avrstm32 发表于 2011-11-20 18:00:16

我用的M64内部EEPROM,就照抄手册上的那段汇编程序。现在稳如磐石。操作EEPROM,最好关中断。另外还要记得打开BOD哦。

huayuliang 发表于 2011-11-20 18:21:47

回复【楼主位】Ilove51andAVR
-----------------------------------------------------------------------

#include <avr/eeprom.h>.....都已经引用了却不用,好好看看手册。

jason1927 发表于 2011-11-20 20:01:40

做这种无用功!为何不直接用库函数,而且具有通用性,多好啊

dzng11 发表于 2011-11-20 20:46:13

参考一下iar的自带的

写数据
#define __EEPUT(ADR,VAL){while (EECR & 0x02); \
EEAR = (ADR); EEDR = (VAL); EECR = 0x04; EECR = 0x02;}

读数据
#define __EEGET(VAR, ADR) {while (EECR & 0x02); \
      EEAR = (ADR); EECR = 0x01; (VAR) = EEDR;}

Ilove51andAVR 发表于 2011-11-20 22:09:49

回复【5楼】huayuliang 花生
回复【楼主位】ilove51andavr   
-----------------------------------------------------------------------
#include &lt;avr/eeprom.h&gt;.....都已经引用了却不用,好好看看手册。
-----------------------------------------------------------------------

回复【6楼】jason1927
做这种无用功!为何不直接用库函数,而且具有通用性,多好啊
-----------------------------------------------------------------------


我汗啊,原来AVR Studio 4.12(GCC)编程软件已经自带了读写语句,只需要三句就搞定了:
i=eeprom_read_byte((uchar *)0x02); //从EEPROM读取0x02地址处的数据赋给i。
eeprom_busy_wait();//等待EEPROM读写空闲
eeprom_write_byte((uchar *)0x02,j); //把j的值写入EEPROM地址0x02处。

以上三句就搞定了一切,根本用不着按ATMega16的官方手册来编写EEPROM的程序。看来对GCC编程软件自带的库函数还不熟悉。

已经调试成功,谢谢大家!

eblc1388 发表于 2011-11-20 22:53:44

回复【楼主位】ilove51andavr   

按ATMega16的官方手册来编写EEPROM的程序,
-----------------------------------------------------------------------
因为手册写EEPROM的程序时序有误。

问题出现在最後两句, ECR |= (1<<EEMWE);//置位EEMWE
及 EECR |= (1<<EEWE);//置位EEWE以启动写操作。ASM 程序没问题, C 程序超过了容许时限(四个周期)。

cock 发表于 2011-11-20 22:59:21

超容许时限(四个周期)是因为优化级最低时,把SFR当RAM操作,才超时的。优化到0级之外的其它级,就可以了。

oldbreadman 发表于 2011-11-21 00:24:21

都是高手

taojie 发表于 2011-11-21 10:43:00

库自带的函数,好方便的

BILLCHIA 发表于 2012-3-24 12:29:30

mark。。。。

Gorgon_Meducer 发表于 2012-3-24 15:22:51

winavr中,有些芯片对时序有要求的寄存器设置需要将优化等级设置为-O0以上,比较推荐-Os

longfeix86 发表于 2012-3-24 21:01:50

不是有内部的读写函数吗?

MiniCat 发表于 2012-3-24 22:54:07

这个。。。其实真的用内部函数就好了嘛、、

FLYMOUSE 发表于 2012-3-27 19:52:49

学习了,刚要用

chengtina 发表于 2012-3-28 09:15:31

本来内部有的,我以前也出过问题,那个DATASHEET里的要改一下也可以用的

zhengyiqun 发表于 2013-8-16 08:52:13

chengtina 发表于 2012-3-28 09:15 static/image/common/back.gif
本来内部有的,我以前也出过问题,那个DATASHEET里的要改一下也可以用的

datasheet里面的函数需要修改什么?

chengtina 发表于 2013-8-16 17:00:17

zhengyiqun 发表于 2013-8-16 08:52 static/image/common/back.gif
datasheet里面的函数需要修改什么?

void EEPROM_write(uint uiAddress, uchar ucData)
{
        while(EECR & (1<<EEWE))         /* 等待上一次写操作结束 */
        ;
        EEAR = uiAddress;         /* 设置地址和数据寄存器*/
        EEDR = ucData;
        EECR |= (1<<EEMWE);         /* 置位EEMWE */
//        EECR |= (1<<EEWE);
        EECR = (1<<EEWE) | (1<<EEMWE); //修改这里         /* 置位EEWE 以启动写操作*/
}

logsoft 发表于 2013-8-17 19:01:51

chengtina 发表于 2013-8-16 17:00
void EEPROM_write(uint uiAddress, uchar ucData)
{
        while(EECR & (1

置位EEMWE前加上一句cli();写完成以后加上,sei();

zhengyiqun 发表于 2013-9-12 11:03:18

chengtina 发表于 2013-8-16 17:00 static/image/common/back.gif
void EEPROM_write(uint uiAddress, uchar ucData)
{
        while(EECR & (1

读取EEPROM的内容函数是否有这样的情况?我现在是ATMEGA328P在用datasheet中的的读取EEROM函数出现有问题!!读取一个变量的内容变成oxff;等下次上电可能就OK了~~EEPROM内存的数据没变,只是读上来有问题~~

huangxiaolpbany 发表于 2014-9-5 10:30:23

chengtina 发表于 2013-8-16 17:00
void EEPROM_write(uint uiAddress, uchar ucData)
{
        while(EECR & (1

找到您去年的回复,解决了我的问题,谢谢!

zhwm3064 发表于 2014-9-5 10:38:46

用CVAVR是最方便的,直接使用就行。eeprom unsigned char a;a=

tgl3721 发表于 2015-10-31 10:41:34

搞了一个早上,看到这个帖子一下就搞好了,谢谢{:lol:}

lujan1 发表于 2015-10-31 11:19:17

M64 M128 内置eeprom有掉数据,不知道程序哪里的问题{:mad:}

rundream 发表于 2015-10-31 15:08:56

这种情况,我一般先看官方汇编程序。
页: [1]
查看完整版本: !!!痛苦,AVR内部EEPROM读写失败,已经严格按照官方手册规定的步骤来写,极其精简仍然不成功,