打印
[AVR单片机]

关于读写EEPROM的若干体会(转)

[复制链接]
6197|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
huamunv|  楼主 | 2010-1-15 23:09 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
最近在看以前同事编写的关于PKE项目(汽车防盗器)的程式,其中便用到了读写EEPROM,于是便想深入了解下如何读写EEPROM,看完ATMEGA128关于如何读写EEPROM的手册后,于是便想自己动手操作一下。接着开始编写了以下程式。
//---------------------------------------------------------------------------------------------------------------------
// MCU:   ATMEGA128
// 开发软件:Winavr + AvrStudio
// 开发工具: AVR JTAG ISP V2.5
//---------------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#include<avr/eeprom.h>
void main(void)
{
    while(EECR & _BV(EEWE));
    while(SPMCSR & _BV(SPMEN));
    EEAR=0x10;
    EEDR=0x0C;
    EECR =_BV(EEMWE);
    EECR|=_BV(EEWE);
    while(1);
}
程序编写完毕并进行编译后,用仿真器进行调试,通过MEMORY窗口发现EEPROM地址为0x10的数据为0xFF;这说明数据0x0C没有写入EEPROM,于是便开始找原因,首先核对语法问题,例如:&被写成了!等等,发现没有语法错误,接着便开始想是否是写EEPROM时序有问题,在与ATMEGA128手册核对了几遍都发现我写EEPROM时序上没有任何错误,接着便纳闷了,到底哪里出问题了,于是又开始看数据书册,发现这样一个问题,在置位EEMWE 的4 个周期内,须置位EEWE,否则无法写EEPROM,我想我在写完EECR =_BV(EEMWE)即置位EEMWE后立即写了 EECR|=_B(EEWE)即置位EEWE,不应该是置位EEMWE 的4 个周期内,没有置位EEWE造成的啊,但是却实在想不出别的问题,于是变半信半疑的用AVR Simulator看看EECR|=_BV(EEWE)这条语句所消耗的时间,一看发现其用了5个时钟周期,这时我便豁然开朗了,但是我还是想不通为什么EECR|=_BV(EEWE)这条语句会要5个时钟周期这么长,于是便看了这条语句的反汇编,发现Winavr读写I/O寄存器(包括EECR)全是用的LDI,STD指令,即把I/O寄存器当做SRAM处理,而没有用OUT指令,导致其需要花费5个时钟周期,这里要提醒大家注意,Winavr把所有的I/O寄存器都当做SRAM来处理,其花费的时钟周期较长。至此问题已经找出,于是便开始想解决办法,我想到的是在C里面嵌入汇编来做,因为之前全部都是用C,所以开始找C中如何嵌入汇编的资料,找到相关资料后便开始写了如下程序:
//---------------------------------------------------------------------------------------------------------------------
// MCU:   ATMEGA128
// 开发软件:Winavr + AvrStudio
// 开发工具: AVR JTAG ISP V2.5
// I/O address   EEAR 0x1E   EEDR 0x1D   EECR 0x1C
//---------------------------------------------------------------------------------------------------------------------
#include <avr/io.h>
#include<avr/eeprom.h>
void main(void)
{
    while(EECR & _BV(EEWE));
    while(SPMCSR & _BV(SPMEN));
  __asm__ __volatile__ ( "LDI R16,0x10" CR_TAB
                            "LDI R17,0x00" CR_TAB
                            "OUT 0x1E,R16" CR_TAB
                            "OUT 0x1F,R17" CR_TAB
                            "LDI R16,0x0C" CR_TAB
                            "OUT 0x1D,R16" CR_TAB
                            "LDI R16,0x04" CR_TAB
                            "OUT 0x1C,R16" CR_TAB
                            "LDI R16,0x06" CR_TAB
                            "OUT 0x1C,R16");
    while(1);
}

通过MEMORY窗口发现EEPROM地址为0x10已经为0x0C,止此问题解决。Winavr里面有自带的关于读写EEPROM的库函数,本人写以上程序纯粹个人爱好。本以为一切问题都解决了,却又发现另外一个问题,我向ATMEGA128的EEPROM写数据,用JTAG调试的时候通过MEMORY窗口可以看到有正确的数据被写入,然后我Stop Debugging,接着我又Start Debugging,却发现之前写的数据被擦除为0xFF,于是便看ATMEGA128数据手册,刚开始以为是上电后VCC没有达到足够电压后便开始写EEPROM,导致写入EEPROM的数据错误,回过头又看了下硬件,发现RESET端有加外部复位电路,看来原因不是这个,于是又开始查找原因,在AVRVI里面看到这个帖子:

标题:AVR STUDIO里是不是有个可以测试EEPROM是否正常?
http://bbs.avrvi.com/read-htm-tid-446-keyword-EEPROM.html
依照楼主的做法,将问题解决。

此时我并没有太多的兴奋,只是觉得花了两天时间在EEPROM上,需要总结点什么,却又不知道该总结什么。可能觉得找问题的过程其实就是一个学习与成长的过程吧。于是便花了点时间写了一个流水帐样的总结,希望对各位初学读写EEPROM的读者有所帮助,有不对的地方也请各位指正。

相关帖子

沙发
928315| | 2010-1-16 09:11 | 只看该作者
一般在写这个的时候好像要关中断吧。。。

使用特权

评论回复
板凳
lovelyegle| | 2010-1-17 21:15 | 只看该作者
学习加上总结是很好的习惯!:)

使用特权

评论回复
地板
zhuhan| | 2010-5-16 16:16 | 只看该作者
谢谢您的分享!!!

使用特权

评论回复
5
love_life| | 2010-5-16 21:53 | 只看该作者
写的不错,谢谢分享

使用特权

评论回复
6
yidou| | 2010-5-16 22:08 | 只看该作者
如何读写EEPROM,细致

使用特权

评论回复
7
qfengbj| | 2010-5-16 22:45 | 只看该作者
EEPROM地址为0x10的数据为0xFF;这说明数据0x0C没有写入EEPROM
这个是怎么看出来的?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

88

主题

730

帖子

1

粉丝