zoukankan      html  css  js  c++  java
  • 淺談C51記憶體優化(data idata xdata)

    對 51 微控制器記憶體的認識,很多人有誤解,最常見的是以下兩種

    ① 超過變數128後必須使用compact模式編譯
       實際的情況是隻要記憶體佔用量不超過 256.0 就可以用 small 模式編譯
    ② 128以上的某些地址為特殊暫存器使用,不能給程式用
       與 PC 機不同,51 微控制器不使用線性編址,特殊暫存器與 RAM 使用重複的重複的地址。但訪問時採用不同的指令,所以並不會佔用 RAM 空間。

        由於記憶體比較小,一般要進行記憶體優化,儘量提高記憶體的使用效率。

        以 Keil C 編譯器為例,small 模式下未指儲存型別的變數預設為data型,即直接定址,只能訪問低 128 個位元組,但這 128 個位元組也不是全為我們的程式所用,暫存器 R0-R7必須對映到低RAM,要佔去 8 個位元組,如果使用寄存組切換,佔用的更多。

        所以可以使用 data 區最大為 120 位元組,超出 120 個位元組則必須用 idata 顯式的指定為間接定址,另外堆疊至少要佔用一個位元組,所以極限情況下可以定義的變數可佔 247 個位元組。當然,實際應用中堆疊為一個位元組肯定是不夠用的,但如果巢狀呼叫層數不深,有十幾個位元組也夠有了。


    為了驗上面的觀點,寫了個例子

    #define LEN 120
    data UCHAR tt1[LEN];
    idata UCHAR tt2[127];

    void main()
    {
        UCHAR i,j;

        for(i = 0;  i < LEN; ++i )
        {
            j = i;
            tt1[j] = 0x55;
        }
    }

    可以計算 R0-7(8) + tt1(120) + tt2(127) + SP(1) 總共 256 個位元組

    keil 編譯的結果如下:
    Program Size: data=256.0 xdata=0 code=30
    creating hex file from "./Debug/Test"...
    "./Debug/Test" - 0 Error(s), 0 Warning(s).
    (測試環境為 XP + Keil C 7.5)

        這段程式碼已經達到了記憶體分配的極限,再定義任何全域性變數或將陣列加大,編譯都會報錯 107

        這裡要引出一個問題:為什麼變數 i、j 不計算在內?
        這是因為 i、j 是區域性變數,編譯器會試著將其優化到暫存器 Rx 或棧。問題也就在這了,如果區域性變數過多或定義了局部陣列,編譯器無法將其優化,就必須使用 RAM 空間,雖然全域性變數的分配經過精心計算沒有超出使用範圍,仍會產生記憶體溢位的錯誤!

        而編譯器是否能成功的優化變數是根據程式碼來的
        上面的程式碼中,迴圈是臃腫的,變數 j 完全不必要,那麼將程式碼改成

    UCHAR i;
    UCHAR j;

    for(i = 0;  i < LEN; ++i )
    {
        tt1[i] = 0x55;
    }

    再編譯看看,出錯了吧!
    因為編譯器不知道該如何使用 j,所以沒能優化,j 須佔 RAM 空間,RAM 就溢位了。
    (智慧一點的編譯器會自動將這個無用的變數去掉,但這個不在討論之列了)

    另外,對 idata 的定義的變數最好放在 data 變數之後

    對於這一種定義


    uchar c1;
    idata uchar c2;
    uchar c3;
    變數 c2 肯定會以間接定址,但它有可能落在 data 區域,就浪費了一個可直接定址的空間


    變數優化一般要注意幾點:

        ①讓儘可能多的變數使用直接定址,提高速度
          假如有兩個單位元組的變數,一個長119的字元型陣列
          因為總長超過 120 位元組,不可能都定義在 data 區
          按這條原則,定義的方式如下:


          data UCHAR tab[119];
          data UCAHR c1;
          idata UCHaR c2;
          但也不是絕的,如果 c1, c2 需要以極高的頻率訪問,而 tab 訪問不那麼頻繁
          則應該讓訪問量大的變數使用直接定址:

          data UCAHR c1;
          data UCHaR c2;
          idata UCHAR tab[119];
          這個是要根據具體專案需求來確定的

        ②提高記憶體的重複利用率
          就是儘可能的利用區域性變數,區域性變數還有個好處是訪問速度比較快
          由前面的例子可以看出,區域性變數 i, j 是沒有單獨佔用記憶體的
          子程式中使用記憶體數目不大的變數儘量定義為區域性變數

        ③對於指標陣列的定義,儘可能指明儲存型別
           儘量使用無符號型別變數

          一般指標需要一個位元組額外的位元組指明儲存型別
         8051 系列本身不支援符號數,需要外加庫來處理符號數,一是大大降低程式執行效率,二是需要額外的記憶體


        ④避免出現記憶體空洞

          可以通過檢視編譯器輸出符號表檔案(.M51)檢視
          對前面的程式碼,M51檔案中關於記憶體一節如下:


    * * * * * * *   D A T A   M E M O R Y   * * * * * * *
    REG     0000H     0008H     ABSOLUTE     "REG BANK 0"
    DATA    0008H     0078H     UNIT         ?DT?TEST
    IDATA   0080H     007FH     UNIT         ?ID?TEST
    IDATA   00FFH     0001H     UNIT         ?STACK 


    第一行顯示暫存器組0從地址0000H開始,佔用0008H個位元組
    第二行顯示DATA區變數從0008H開始,佔用0078H個位元組
    第三行顯示IDATA區變數從0080H開始,佔用007F個位元組
    第四行顯示堆疊從00FFH開始,佔0001H個位元組

    由於前面程式碼中變數定義比較簡單,且連續用完了所有空間,所以這裡顯示比較簡單
    變數定義較多時,這裡會有很多行

    如果全域性變數與區域性變數分配不合理,就有可能出現類似下面的行

    0010H     0012H                  *** GAP ***
          該行表示從0010H開始連續0012H個位元組未充分利用或根本未用到
    出現這種情況最常見的原因是局變數太多、多個子程式中的區域性變數數目差異太大、使用了暫存器切換但未充分利用

    from: https://www.itread01.com/content/1549179365.html

  • 相关阅读:
    Access, SQL Server, and Oracle数据类型的对应关系
    [转]SQL Server 2005 从差异备份还原数据库
    疲惫
    关于在cmd命令里的路径包含空格的问题
    导Excel时的科学计数法问题
    [转]SQL SERVER 2005 备份与恢复简介
    [转]用C#创建Windows Service
    [转] vb.net option
    [转]sql server profiler only TrueType fonts are supported. this is not a truetype font
    进程、线程、协程之概念理解[转帖]
  • 原文地址:https://www.cnblogs.com/aspirs/p/13594883.html
Copyright © 2011-2022 走看看