最近在看以前同事编写的关于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的读者有所帮助,有不对的地方也请各位指正。 |