原创 AVR学习日志(四十八)—学习使用单片机自带的EEPROM

2010-11-3 10:25 5682 6 10 分类: MCU/ 嵌入式

源程序与电路图在附件中:



     EEPROM (Electrically Erasable Programmable Read-Only Memory),即电可擦可编程只读存储器,它是一种掉电后数据不丢失的存储器。ATmega8515单片机内部包含512字节的EEPROM数据存储器。它是作为一个独立的数据空间而存在的,可以按字节读写。EEPROM的访问由地址寄存器(EEARH/EEARL)、数据寄存器(EEDR)和控制寄存器(EECR)决定。EEPROM地址寄存器-EEARH与EEARL指定了512字节的EEPROM空间。EEPROM地址是线性的,从0到511。EEAR的初值没有定义。在请问EEPROM之前必须为其赋予正确的数据,懒猫建议从地址0X0001开始。对于EEPROM数据寄存器-EEDR主要作用是把要写入的数据赋值给EEDR,把要从地址单元中读出的值,要从EEAR中读取出来,就相当于一个人事中介。EEPROM控制寄存器-EECR,顾名思义当然是控制EEPROM的读写操作的了。注意在CPU写FLASH存储器的时候不能对EEPROM进行编程。


    今天就学习使用8515内部的EEPROM写的小程序试一下。测试的电路主要有两部分组成按键与数码显示。按键部分包括三个按键,K1主要负责向EEPROM中写入1-20这20个数,K2是负责向EEPROM中写入随机的20个数,K3主要负责是把写入的数据读出来,并在数码管上显示。另外还加了一个小小的蜂鸣器,在操作成功后都会叫一下。其整体电路如下所示:参看附件(图1-1 硬件电路图)


    好了硬件介绍完了,说说软件吧,软件也不是太难,主要就是数码显示,按键处理,至于今天主要做的EEPROM读写操作,我用的是GCC自己的库函数,它是在avr/eeprom.h这个头文件中有定义,其实很多就是宏定义,如果你想了解最好自己看看这个头文件。如果你想好好运用GCC,懒猫建议最好把avr-lib-manual数据手册读一下,虽然是英文的,但慢慢啃它还是能啃动的。关于avr/eeprom.h这个文件也在手册中有介绍,大概在242-244页,如果你看avr/eeprom.h,不太理解的可以到这个手册中看一下。


好了,下面贴上懒猫的程序:


/**************************************************************************


//文件名称:EEPROM_TEST.c


//功    能:学习使用单片机内部EEPROM


//作    者:懒猫爱飞


//建立日期:2010.11.02


//备    注:MCU-ATmega8515 开发环境-winavr100110  Crystal-8MHz


**************************************************************************/


#include <avr/io.h>


#include <inttypes.h> //关于数据类型的一些定义


#include <stdint.h>    //同样是一些数据类型的定义


//#include <avr/interrupt.h> //---这个程序用不上---


#include <util/delay.h>


#include <avr/eeprom.h>


#include <stdlib.h>


 


#define KEY_W    (PIND & _BV(PB0))    //第一个按键向EEPROM中写入1-20个数据


#define KEY_WS   (PIND & _BV(PB1))    //第二个按键向EEPROM中写入随机数组


#define KEY_D    (PIND & _BV(PB2))    //第三个按键让数码管循环显示


 


#define Display_Data    PORTA                     //A口发送数据


#define On_Dis(N)       PORTC &= ~_BV(N)          //显示第的位数


#define Show_Off()      PORTC |= _BV(0) | _BV(1)  //关闭所有的数码管


 


#define Beep_Ring()          PORTC ^= _BV(PC7) //Buzzer 连接在C端口的第七脚


 


int8_t Current_Data = 0;   //当前读出的数据


int8_t Loop_Show_Flag = 0; //循环显示标志


int16_t Current_Read_Addr = 0x0001; //当前读取的地址


 


 //将字节变量eepromx分配在EEPROM存储器(地址不透明)


int8_t eepromx __attribute__((section("eeprom")));


 


uint8_t EEMEM eeprom_array[] =


{


    0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,


    0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f


};


 


//共阴极数码管显示码0-9黑屏


const uint8_t Dis_Code[] =


{


    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00


};


 


//显示缓存


uint8_t Dis_Buf[]={0,0};


 


/**************************************************************************


//函数名称:void port_init(void)


//功    能:端口初始化


//入口参数:NULL


//出口参数:NULL


//备    注:NULL


**************************************************************************/


void port_init(void)


{


    DDRA  = 0xff; //端口A用于向数码管中发送数据


    PORTA = 0x00; //初始化时把数码管关掉


 


    DDRC  |= (_BV(PC0))|(_BV(PC1))|(_BV(PC7));  //PC0-数码管1、PC1-数码管2、PC7-Buzzer


    PORTC = 0x00;


   


    DDRD  = 0x00;  //D口接三个按键


    PORTD = 0x07; 


}


 


/**************************************************************************


//函数名称:void Beep_Play(void)


//功    能:蜂鸣器蜂鸣程序


//入口参数:NULL


//出口参数:NULL


//备    注:NULL


**************************************************************************/


void Beep_Play(void)


{


    int8_t cunt = 0;


    for(cunt=0; cunt<100; cunt++)


    {


        Beep_Ring();      //连续响20次


        _delay_ms(1);


    }


}


 


/**************************************************************************


//函数名称:void Show_Display(void)


//功    能:显示函数


//入口参数:NULL


//出口参数:NULL


//备    注:NULL


**************************************************************************/


void Show_Display(void)


{


    Show_Off();//消隐一下


   


    Display_Data = Dis_Code[Dis_Buf[1]]; //显示十位


    On_Dis(0);


    _delay_ms(5);


 


    Show_Off();//消隐一下


                             


    Display_Data = Dis_Code[Dis_Buf[0]]; //显示个位


    On_Dis(1);


    _delay_ms(5);


       


}


 


/**************************************************************************


//函数名称:void Key_Ctrl(void)


//功    能:按键处理程序


//入口参数:NULL


//出口参数:NULL


//备    注:NULL


**************************************************************************/


void Key_Ctrl(void)


{


    int8_t i;  //做一些临时循环变量用


    //start:


    //------------KEY_D:显示按键------------------//


    if(!KEY_D) //KEY_D:显示按键,所有按键都是采用上升沿有效


    {


        while(!KEY_D);


        Current_Read_Addr = 0x0001; //从地址0x0001开始读取数据


 


        eeprom_busy_wait();  //宏定义在stdlib.h这个头文件中


        Current_Data = eeprom_read_byte((int8_t*)Current_Read_Addr); //读取当前地址数据


 


        /*


          因为写入的数据都是不超过100,如果读0x0001时出现0xff,说明未写入新数据,这时循


          环标志Loop_Show_Flag为关闭,否则要打开显示标志。


        */


        if(Current_Data != 0xff)


        {


            Loop_Show_Flag = 1;


        }


 


 


        Beep_Play(); //读取完毕响铃


 


    }      


 


    //------------KEY_W:写入1-20数据------------------//


    if(!KEY_W)


    {


        while(!KEY_W);


        Loop_Show_Flag = 0; //当要写数据时,关闭显示


        for(i=0; i<=20; i++) //前20个地址写入1-20这20个数


        {


            eeprom_busy_wait();


            eeprom_write_byte((int8_t*)i,(int8_t)i);


        }


 


        //再向EEPROM中写一个数据21,地址不确定


        eeprom_busy_wait();


        eeprom_write_byte(&eepromx,0x15);


 


        Beep_Play(); //操作完毕响铃


    }


 


    //------------KEY_WS:写入21个随机数据------------------//


    if(!KEY_WS)


    {


        while(!KEY_WS);


 


        Loop_Show_Flag = 0; //当要写数据时,关闭显示


        for(i=0; i<=20; i++) //前20个地址写入20个随机数据


        {


            eeprom_busy_wait();


            eeprom_write_byte((int8_t*)i,rand()%100);


        }


 


        //再向EEPROM中写一个随机数据,地址也不确定


        eeprom_busy_wait();


        eeprom_write_byte(&eepromx,rand()%100);


 


        Beep_Play(); //操作完毕响铃


    }


 


    //------------调度显示------------------//


    if(Loop_Show_Flag)


    {


        eeprom_busy_wait();


        if(Current_Read_Addr != 21) //前20个数是从0x0001-0x0020中读出


        {


            Current_Data = eeprom_read_byte((int8_t*)Current_Read_Addr);


        }


        else                       //第二十一个数从eepromx这介地址中读取


        {


            Current_Data = eeprom_read_byte(&eepromx);


        }


 


        Dis_Buf[1] = Current_Data/10;


        Dis_Buf[0] = Current_Data%10;


       


        for(i=0; i<30; i++)


        {


            Show_Display();


 


            if((!KEY_W) || (!KEY_WS)) //如果此时有新有数据写入,关闭数码码管


            {


                Loop_Show_Flag = 0;


                Show_Off(); //关闭数码码管,等待数据更新后重新显示


                break;


                //goto start; //最好不要作用跳转语句


            }


        }


 


        Current_Read_Addr = Current_Read_Addr%21 + 1; //地址循环递增   


 


    }


}


 


/**************************************************************************


//函数名称:int main(void)


//功    能:主程序


//入口参数:NULL


//出口参数:0


//备    注:NULL


**************************************************************************/


int main(void)


{


 


    /*


    Dis_Buf[0] = 2; //用于测试显示函数


    Dis_Buf[1] = 5;


    */


    port_init();


    srand(200); //设置随机种子,此函数在stdlib.h中有定义


    //Beep_Play(); //用于测试蜂鸣函数,调试时使用


    while(1)


    {


        Key_Ctrl();


        /*这之间的函数用于测试eeprom的操作函数


        eeprom_busy_wait();


        eeprom_write_byte((int8_t* )0x02,89);


        eeprom_busy_wait();


        Dis_Buf[1] = eeprom_read_byte((int8_t* )0x02)/10;


        Dis_Buf[0] = eeprom_read_byte((int8_t* )0x02)%10;


        */


 


        //Show_Display(); //用于测试显示函数,调试时使用


       


    }


 


    return 0;


}    


程序可能稍微有点长,不过不是太复杂,可以一块一块的看,应该很容易理解的哦^_^


 


 


 


再喊一下口号,鼓励一下自己:


 


每天进步一点点,开心多一点^_^

PARTNER CONTENT

文章评论4条评论)

登录后参与讨论

用户1824753 2014-12-30 09:14

感谢楼主,帮了大忙

用户1588142 2011-4-27 18:51

mark!!

用户1530930 2010-11-8 10:40

哈哈 谢谢楼主去我那溜达 我也来学习下

huotingtu_505472073 2010-11-3 23:35

学习了
相关推荐阅读
xucun915_925777961 2013-04-28 11:31
毕业后的五年拉开大家差距的原因在哪里?【转】
  有人工作,有人继续上学,大家千万不要错过这篇文章,能看到这篇文章也是一种幸运,真的受益匪浅,对我有很大启迪,这篇文章将会改变我的一生,真的太好了,希望与有缘人分享,也希望对有缘人有所帮助!...
xucun915_925777961 2013-03-31 20:28
职场大牛精彩总结:职场上,如何做人做事做管理【转】(文/张子阳)
      大道至简,越是根源和基本的问题,道理实际上越简单。关于如何做人、做事、做管理的书很多,我看得不多,但是我觉得这些书更多是侧重技术和实现细节上的,而很少从人的思想和观念去讲。实际...
xucun915_925777961 2013-03-28 14:03
介绍几种优秀的UML工具
统一建模语言(UML是 Unified Modeling Language的缩写)是用来对软件密集系统进行可视化建模的一种语言。UML为面向对象开发系统的产品进行说明、可视化、和编制文档的一种标准语言...
xucun915_925777961 2013-03-27 18:05
IAR EW FOR 8051 修改工程名称的方法
        近段时间一直在搞蓝牙4.0的开发任务,所以用到了IAR编译器,话说IAR编译器用途蛮广,可以编译MSP430,ARM,还有TI的51核芯片,当然,这要不同的版本,我现在用的是for...
xucun915_925777961 2013-03-26 16:40
Cortex-M3学习日志(八)-- TFT实验Part(a)
    自己用的LPC1768的开板带有一块2.4寸的TFT彩色液晶屏,虽然自己工作中还用不过显示屏,但是晚上闲着也是闲着,于是继续玩咱的LPC1768吧。 我的开发板上的液晶屏的用的是SPI接口,当...
xucun915_925777961 2013-03-25 20:48
说说那几款查看源代码的工具
说说那几款查看代码的工具 今天给大家介绍几款单片机工程师所喜欢的几款查看源代码的工具,这几款工具在懒猫的日常工作中可是帮了不少忙。 一、 Source Insight     Source Insig...
EE直播间
更多
我要评论
4
6
关闭 站长推荐上一条 /1 下一条