新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > AVR 單片機與GCC 編程----之二

        AVR 單片機與GCC 編程----之二

        作者: 時間:2016-12-02 來源:網絡 收藏
        2.5 EEPROM 數據存儲器操作
        #include EEPROM.h>
        頭文件聲明了avr-libc 提供的操作EEPROM 存儲器的API 函數。
        這些函數有:
        EEPROM_is_ready() //EEPROM 忙檢測(返回EEWE 位)
        EEPROM_busy_wait() //查詢等待EEPROM 準備就緒
        uint8_t EEPROM_read_byte (const uint8_t *addr) //從指定地址讀一字節
        uint16_t EEPROM_read_word (const uint16_t *addr) //從指定地址一字
        void EEPROM_read_block (void *buf, const void *addr, size_t n) //讀塊
        void EEPROM_write_byte (uint8_t *addr, uint8_t val) //寫一字節至指定地址
        void EEPROM_write_word (uint16_t *addr, uint16_t val) //寫一字到指定地址
        void EEPROM_write_block (const void *buf, void *addr, size_t n)//寫塊
        在程序中對EEPROM 操作有兩種方式
        方式一:直接指定EERPOM 地址
        示例:
        /*此程序將0xaa 寫入到EEPROM 存儲器 0 地址處,
        再從0 地址處讀一字節賦給RAM 變量val */
        #include
        #include EEPROM.h>
        int main(void)
        {
        unsigned char val;
        EEPROM_busy_wait(); //等待EEPROM 讀寫就緒
        EEPROM_write_byte(0,0xaa); //將0xaa 寫入到EEPORM 0 地址處
        EEPROM_busy_wait();
        val=EEPROM_read_byte(0); //從EEPROM 0 地址處讀取一字節賦給RAM 變量val
        while(1);
        }
        方式二:先定義EEPROM 區變量法
        示例:
        #include
        #include EEPROM.h>
        unsigned char val1 __attribute__((section(".EEPROM")));//EEPROM 變量定義方式
        int main(void)
        {
        unsigned char val2;
        EEPROM_busy_wait();
        EEPROM_write_byte (&val1, 0xAA); /* 寫 val1 */
        EEPROM_busy_wait();
        val2 = EEPROM_read_byte(&val1); /* 讀 val1 */
        while(1);
        }
        在這種方式下變量在EEPROM 存儲器內的具體地址由編譯器自動分配。相對方式一,數據在EEPROM 中的具體位置是不透明的。
        為EEPROM 變量賦的初始值,編譯時被分配到.EEPROM 段中,可用avr-objcopy 工具從.elf文件中提取并產生ihex 或binary 等格式的文件。
        2.6 avr-gcc 段(section)與再定位(relocation)
        粗略的講,一個段代表一無縫隙的數據塊(地址范圍),一個段里存儲的數據都為同一性質,如“只讀”數據。as (匯編器)在編譯局部程序時總假設從0 地址開始,并生成目標文件。最后ld(鏈接器)在連接多個目標文件時為每一個段分配運行時(run-time)統一地址。這雖然是個簡單的解釋,卻足以說明我門為為什么用段.
        ld 將這些數據塊正確移動到它們運行時的地址。 此過程非常嚴格,數據的內部順序與長度均不能發生變化.這樣的數據單元叫做段,為段分配運行時地址叫再定位,此任務根據目標文件內的參考地址將段數據調整到運行時地址。
        Avr-gcc 中匯編器生成的目標文件(object-file)至少包含四個段,分別為: .text 段、.data段 、 .bss 段和.EEPROM 段,它們包括了程序存儲器(FLASH)代碼,內部RAM 數據,和EEPROM 存儲器內的數據。這些段的大小決定了程序存儲器(FLASH)、數據存儲器(RAM)、EEPROM 存儲器的使用量,關系如下:
        程序存儲器(FLASH)使用量 = .text + .data
        數據存儲器(RAM)使用量 = .data + .bss [+ .noinit] + stack [+ heap]
        EEPROM 存儲器使用量 = .EEPROM
        一..text 段
        .text 段包含程序實際執行代碼。另外,此段還包含.initN 和.finiN 兩種段,下面詳細討論。
        段.initN 和段.finiN 是個程序塊,它不會象函數那樣返回,所以匯編或C 程序不能調用。
        .initN、.finN 和絕對段(absolute section 提供中斷向量)構成avr-libc 應用程序運行框架,用戶編寫的應用程序在此框架中運行。
        .initN 段
        此類段包含從復位到main()函數開始執行之間的啟動(startup)代碼。
        此類段共定義10 個分別是.init0 到.init9。執行順序是從.init0 到.init9。
        .init0:
        此段綁定到函數__init()。用戶可重載__init(),復位后立即跳到該函數。
        .init1:
        未用,用戶可定義
        .init2:
        初始化堆棧的代碼分配到此段
        .init3:
        未用,用戶可定義
        .init4:
        初始化.data 段(從FLASH 復制全局或靜態變量初始值到.data),清零.bss 段。
        像UNIX 一樣.data 段直接從可執行文件中裝入。Avr-gcc 將.data 段的初始值存儲到flash
        rom 里.text 段后,.init4 代碼則負責將這些數據復制SRAM 內.data 段。
        .init5:
        未用,用戶可定義
        .init6:
        C 代碼未用,C++程序的構造代碼
        .init7:
        未用,用戶可定義
        .init8:
        未用,用戶可定義
        .init9:
        跳到main()
        avr-libc 包含一個啟動模塊(startup module),用于應用程序執行前的環境設置,鏈接時它被分配到init2 和init4 中,負責提供缺省中斷程序和向量、初始化堆棧、初始化.data 段和清零.bss 段等任務,最后startup 跳轉到main 函數執行用戶程序。
        .finiN 段
        此類段包含main()函數退出后執行的代碼。
        此類段可有0 到9 個, 執行次序是從fini9 到 fini1。
        .fini9
        此段綁定到函數exit()。用戶可重載exit(),main 函數一旦退出exit 就會被執行。
        .fini8:
        未用,用戶可定義
        .fini7:
        未用,用戶可定義
        .fini6:
        C 代碼未用, C++程序的析構代碼
        .fini5:
        未用,用戶可定義
        .fini4:
        未用,用戶可定義
        .fini3:
        未用,用戶可定義
        .fini2:
        未用,用戶可定義
        .fini1:
        未用,用戶可定義
        .fini0:
        進入一個無限循環。
        用戶代碼插入到.initN 或.finiN
        示例如下:
        void my_init_portb (void) __attribute__ ((naked))
        __attribute__ ((section (".init1")));
        void my_init_portb (void)
        {
        outb (PORTB, 0xff);
        outb (DDRB, 0xff);
        }
        由于屬性section(“.init1”)的指定,編譯后函數my_init_portb 生成的代碼自動插入到.init1段中,在main 函數前就得到執行。naked 屬性確保編譯后該函數不生成返回指令,使下一個初始化段得以順序的執行。
        二..data 段
        .data 段包含程序中被初始化的RAM 區全局或靜態變量。而對于FLASH 存儲器此段包含在程序中定義變量的初始化數據。類似如下的代碼將生成.data 段數據。
        char err_str[]=”Your program has died a horrible death!”;
        struct point pt={1,1};
        可以將.data 在SRAM 內的開始地址指定給連接器,這是通過給avr-gcc 命令行添加
        -Wl,-Tdata,addr 選項來實現的,其中addr 必須是0X800000 加SRAM 實際地址。例如 要將.data 段從0x1100 開始,則addr 要給出0X801100。
        三..bss 段
        沒有被初始化的RAM 區全局或靜態變量被分配到此段,在應用程序被執行前的startup過程中這些變量被清零。
        另外,.bss 段有一個子段 .noinit , 若變量被指定到.noinit 段中則在startup 過程中不會被清零。將變量指定到.noinit 段的方法如下:
        int foo __attribute__ ((section (“.noinit”)));
        由于指定到了.noinit 段中,所以不能賦初值,如同以下代碼在編譯時產生錯誤:
        int fol __attribute__((section(“.noinit”)))=0x00ff;
        四..EEPROM 段
        此段存儲EEPROM 變量。
        Static unsigned char eep_buffer[3] __attribute__((section(“.EEPROM”)))={1,2,3};
        在鏈接選項中可指定段的開始地址,如下的選項將.noinit 段指定位到RAM 存儲器
        0X2000 地址處。
        avr-gcc ... -Wl,--section-start=.noinit=0x802000
        要注意的是,在編譯時Avr-gcc 將FLASH、RAM 和EEPROM 內的段在一個統一的地址空間內處理,flash 存儲器被定位到0 地址開始處,RAM 存儲器被定位到0x800000 開始處,EEPROM 存儲器被定位到0X810000 處。所以在指定段開始地址時若是RAM 內的段或EEPROM 內的段時要在實際存儲器地址前分別加上0x800000 和0X810000。
        除上述四個段外,自定義段因需要而可被定義。由于編譯器不知道這類段的開始地址,又稱它們為未定義段。必需在鏈接選項中指定自定義段的開始地址。如下例:
        void MySection(void) __attribute__((section(".mysection")));
        void MySection(void)
        {
        printf("hello avr!");
        }
        鏈接選項:
        avr-gcc ... -Wl,--section-start=.mysection=0x001c00
        這樣函數MySection 被定位到了FLASH 存儲器0X1C00 處。
        上一頁 1 2 下一頁

        關鍵詞: AVR單片機GCC編

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 建昌县| 鹤岗市| 德保县| 桃园县| 精河县| 锡林郭勒盟| 沙雅县| 浦城县| 夹江县| 榆社县| 金乡县| 伊吾县| 同仁县| 普兰店市| 西华县| 信阳市| 小金县| 浦县| 永胜县| 米易县| 昌乐县| 射阳县| 阿拉善盟| 东乌| 太白县| 海阳市| 阜城县| 衡南县| 通辽市| 象州县| 长子县| 晋宁县| 肥西县| 聂荣县| 右玉县| 乳山市| 珠海市| 达日县| 新乐市| 勃利县| 南乐县|