<delect id="sj01t"></delect>
  1. <em id="sj01t"><label id="sj01t"></label></em>
  2. <div id="sj01t"></div>
    1. <em id="sj01t"></em>

            <div id="sj01t"></div>
            C語言

            嵌入式C語言編程小知識

            時間:2025-04-20 19:24:41 志杰 C語言 我要投稿

            嵌入式C語言編程小知識

              嵌入式系統是用來控制或者監視機器、裝置、工廠等大規模設備的系統。下面為大家整理了一些嵌入式C語言編程小知識,一起來看看吧!

            嵌入式C語言編程小知識

              1. 流水線被指令填滿時才能發揮最大效能

              即每時鐘周期完成一條指令的執行(僅指單周期指令)。如果程序發生跳轉,流水線會被清空,這將需要幾個時鐘才能使流水線再次填滿。因此,盡量少的使用跳轉指令可以提高程序執行效率,解決發案就是盡量使用指令的“條件執行”功能。

              2. 在LPC2200系列中:

              可以通過過下面的程序延遲10毫秒:

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

              {

              for(j=0;j<200;j++);

              }

              3. 同過下面語句將一個16位的變量放在兩個8位的變量中。

              //IP數據報總長度高字節

              IpHeadUint8[10]=(IpHead.e_ip.Crc&0xff00)>>8;

              //IP數據報總長度低字節

              IpHeadUint8[11]=IpHead.e_ip.Crc&0x00ff;

              4. 在對全部數組元素賦初值時,可以不指定數組長度。

              eg;inta[]={1,2,3,4,5};

              但如果當輸出第a[5]以上的元素時,系統回輸出隨機數值,所以使用此方法時,不能使用超過初始值元素以上的元素。

              5.關鍵字register的用法:

              當對一個變量頻繁被讀寫時,需要反復訪問內存,從而花費大量的存取時間。為此,C語言提供了一種變量,即寄存器變量。這種變量存放在CPU的寄存器中,使用時,不需要訪問內存,而直接從寄存器中讀寫,從而提高效率。寄存器變量的說明符是register。對于循環次數較多的循環控制變量及循環體內反復使用的變量均可定義為寄存器變量,而循環計數是應用寄存器變量的最好候選者。

              (1) 只有局部自動變量和形參才可以定義為寄存器變量。因為寄存器變量屬于動態存儲方式,凡需要采用靜態存儲方式的量都不能定義為寄存器變量,包括:模塊間全局變量、模塊內全局變量、局部static變量;

              (2) register是一個"建議"型關鍵字,意指程序建議該變量放在寄存器中,但最終該變量可能因為條件不滿足并未成為寄存器變量,而是被放在了存儲器中,但編譯器中并不報錯(在C++語言中有另一個"建議"型關鍵字:inline)。

              6.對于程序代碼

              已經被燒錄在FLASH或ROM中,我們可以讓CPU直接從其中讀取代碼執行,但通常這不是一個好辦法,我們最好在系統啟動后將FLASH或ROM中的目標代碼拷貝入RAM中后再執行以提高取指令速度;

              CPU對各種存儲器的訪問速度,基本上是:

              CPU內部RAM > 外部同步RAM > 外部異步RAM > FLASH/ROM

              7. 函數指針

              1> C語言中函數名直接對應于函數生成的指令代碼在內存中的地址,因此函數名可以直接賦給指向函數的指針

              2> 調用函數實際上等同于“調用指令+參數傳遞處理+回歸位置入棧”,本質上最核心的操作是將函數生成的目標代碼的首地址賦給CPU的PC寄存器。

              3> 因為函數調用的本質是跳轉到某一個地址單元的code去執行,所以可以“調用一個根本就不存在在函數實體

              4> int (*p)();定義p是一個指向函數的指針變量,次函數返回帶回整型的返回值。*P兩側的括號不能省略,表示p先于*結合,是指針變量,然后再與后面的()結合,表示此指針指向函數。

              區別:int *p()表示這個函數的返回值是指向整型變量的指針。

              說明:

              (1) 指向函數的指針變量的一般定義形式為:

              數據類型 (*指針變量名)();

              1> 此處的“數據類型”是指函數返回值的類型

              (2) 返回指針值的函數:

              類型名 *函數名(參數表)

              eg: int * func(int x,int y)

              func是函數名,調用它以后能返回一個指向整型數據的指針。x,y是func的形參。

              區別方法:

              a.從右往左找第一個括號,括號里面的是函數的形參。

              b.括號外面的第一個標識符是函數的名字,函數前面的表示函數的返回數值。

              8. 數組指針

              1>int (*p)[4]

              表示*p有4個元素,每個元素為整型。也就是p所指的對象有4個整型元素的數組,既P是行指針。

              2> 指針數組

              一個數組,其元素均為指針類型數據,稱為指針數組;即指針數組中的每一個元素都相當于一個指針變量。

              一維指針數組的定義形式為:

              類型名 *數組名[數組長度]

              eg:int *p[4]:

              作用:它用于指向若干個字符串,使字符串處理更加方便靈活。適用于一個二維字符串數組,其中每一行的字符數組的長度各不相同

              eg:char * name[]={“Follow me”,”BASIC”,”GreatWall”};

              9. 結構體

              1> 可以用結構體變量做實參。但是用結構體變量作實參時,采取的是“值傳遞”的方式,將結構體變量所占的內存單元的內容全部順序遞給形參。形參也必須是同類型的結構體變量。

              eg:pint(su);//注在此處su為結構體

              注:這種傳遞方式在空間和時間上開銷較大,如果結構體的規模較大時,開銷是很可觀的。

              2> 用直向結構體變量(或數組)的指針作實參,將結構體變量(或數組)的地址傳給形參

              eg:print(&su);//注在此處su為結構體

              10. 共用體

              1> 共用體把幾種不同數據類型的變量存放在同一塊內存里。公用體中的變量共享同一塊內存。

              2> 定義公用體類型變量的一般形式為:

              union 共用體名

              {

              成員列表;

              }變量列表;

              3>在共用體中同一塊內存可以用來存放幾種不同類型的數據,但在某一時刻只能在其中存放一個成員變量。共用體變量中起作用的成員是最后一次存入的數據。

              eg: union data

              {

              int i;

              char c;

              double d;

              };

              union data a;

              共用體變量a中的成員i,c,d三個變量在內存中從同一個地址開始存儲。如進行如下賦值:

              a.i = 100;

              a.c = ‘A’;

              那么此時共用體變量a中的成員i已經沒有值了,因為存儲該值的內存現在已經被用來存儲成員c的值了。

              3> 共用體變量的長度取決于其成員的最大長度:

              說明:

              結構體變量所占內存的長度是各個成員的總和,每個成員分別占有自己的存儲空間。共用體變量所占內存的長度是其最長成員的長度。當然,編譯器出于提高訪問效率的目的,在編譯分配存儲空間時往往要進行對齊操作。

              對齊操作以最大基本類型為準。即以最大基本類型為基本單元。若按實際算下的長度不是基本單元的整數倍,則其實際長度應該是基本單元的整數倍。

              (在TurboC中不進行對齊,在Linux中進行對齊)

              11. CPU字長與存儲器位寬不一致處理

              例如:使用共用體來解決這一沖突:

              union send_temp{

              uint16 words;

              uint8 bytes[2];

              }send_buff;

              eg:send_buff.bytes[0]=a;//此處a 是8位

              send_buff.bytes[1]=b;//此處 b 是8位;

              此時就將8位字拼成了16位字存儲了。

              發送時send(send_buff.words)就可以每次發送一個16位的數據了。

              12. C語言符號優先級:

              1>復合賦值運算符號:

              a+=3*5;

              等價于a=a+(3*5);

              嵌入式C語言編程小知識

              1.使用位操作:嵌入式系統通常對內存和處理器資源有限,位操作可以用來優化代碼和節省內存。例如,使用位掩碼和位運算進行數據的打包和解包,以及對寄存器的位級操作。

              位操作示例:設置和清除位

              這個示例展示了如何使用位操作來設置和清除位標志,以及如何檢查位標志的狀態。

              2.使用宏定義:宏定義可以用來創建代碼片段的別名,增加代碼的可讀性和簡潔性。常見的用法包括定義常量、函數宏和條件編譯宏。

              宏定義示例:計算數組長度

              這個示例展示了如何使用宏定義來計算數組的長度,避免了在多個地方重復計算長度的代碼。

              3.內存管理:嵌入式系統對內存的使用非常關鍵。需要注意內存分配和釋放的方法,以避免內存泄漏和碎片化。可以使用靜態內存分配、動態內存分配(如malloc/free)或者內存池等方法。

              動態內存分配示例:使用malloc和free

              這個示例展示了如何使用動態內存分配函數malloc來分配一段內存,并使用free函數釋放該內存。

              4.中斷處理:中斷是嵌入式系統中常見的事件處理方式。需要編寫中斷服務函數(ISR)來響應中斷事件,并進行必要的處理。在編寫ISR時,要注意避免使用過多的計算和延時操作,以確保中斷的及時響應。

              中斷處理示例:定義中斷服務函數(ISR)

              這個示例展示了如何定義一個中斷服務函數(ISR)來處理中斷事件,然后在主循環中檢查中斷標志位并執行相應的操作。

              5.低功耗優化:嵌入式系統通常需要考慮功耗的優化。可以使用低功耗模式、定時器中斷等方法來降低系統功耗。此外,合理設計算法和數據結構,減少CPU的計算和存儲開銷,也能有效降低功耗。

              低功耗優化示例:休眠模式這個示例展示了如何通過進入休眠模式來實現低功耗優化。在主函數中,首先檢測系統是否處于空閑狀態(由is_idle()函數判斷),如果是空閑狀態,就調用enter_sleep_mode()函數將系統置于休眠模式。在休眠模式下,系統將關閉不必要的電路和外設,以減少功耗。通過合理地使用休眠模式,可以大大降低嵌入式系統的能耗。

              6.設備驅動編程:嵌入式系統通常需要與外設進行交互,編寫設備驅動程序來管理硬件資源。這涉及到對寄存器、時鐘、中斷等的操作,以及與設備進行通信和控制。

              設備驅動編程示例:讀取和寫入寄存器

              這個示例展示了如何通過讀取和寫入寄存器的方式與外設進行通信,通過讀取和寫入指定地址的方法來訪問寄存器的值。

              7.調試和日志:在嵌入式開發中,調試和日志記錄是非常重要的。可以使用調試器、串口打印、LED指示燈等方式來進行調試。另外,通過合理的日志記錄,可以幫助定位問題和系統優化。

              調試和日志示例:使用串口打印調試信息

              這個示例展示了如何通過串口打印函數來輸出調試信息。在關鍵位置插入調試打印語句,有助于調試程序并跟蹤程序的執行流程。

              8.防止整型溢出:在嵌入式系統中,經常需要處理計數、計時等操作。為了防止整型溢出,可以使用適當的數據類型和邊界檢查來確保數值的正確性。

              防止整型溢出示例:邊界檢查

              這個示例展示了如何使用邊界檢查來防止整型加法溢出。通過檢查相加操作后的結果是否超出整型的取值范圍,可以提前判斷是否會發生溢出。

              9.狀態機設計:嵌入式系統中,很多任務是基于狀態的。使用狀態機設計模式可以清晰地描述系統的各種狀態和狀態之間的轉換關系,提高代碼的可讀性和可維護性。

              狀態機設計示例:交通信號燈控制

              這個示例展示了一個簡單的交通信號燈控制狀態機。使用枚舉類型定義了紅燈、黃燈和綠燈三種狀態,并編寫了handle_traffic_light函數來根據當前狀態執行相應的操作。在主函數中,模擬了交通信號燈狀態的變化,并調用handle_traffic_light函數來處理每個狀態。

              10.優化編譯選項:編譯器的優化選項可以對代碼進行優化,提高執行效率。

              優化編譯選項示例:代碼執行速度優化

              在這個示例中,我們定義了一個簡單的函數sum_array,用于計算整型數組的和。在主函數中,我們初始化了一個包含5個元素的整型數組,并調用sum_array函數來計算數組的和,并將結果打印出來。

              代碼在默認編譯選項下進行編譯,這通常是沒有啟用任何優化級別的情況。為了體現代碼執行速度的優化效果,我們將使用GCC編譯器,并在編譯時啟用優化選項-O2,即優化級別2。

              編譯指令:

              gcc-O2example.c-oexample

              在啟用優化選項后,編譯器會對代碼進行各種優化,以提高代碼的執行速度和效率。優化的具體效果取決于編譯器和優化級別。

              具體的代碼差異在優化前后可能會有所不同,因為優化編譯選項的作用是對代碼進行改寫和重組,以使其更高效地執行。優化后的代碼可能會有以下改變:

              循環展開:編譯器可能會將循環展開,將多個迭代合并為一個,以減少循環開銷和分支預測。

              內聯函數:編譯器可能會將函數調用處直接替換為函數體,以減少函數調用的開銷。

              消除無用代碼:編譯器可能會識別和刪除沒有實際影響的代碼,以減少不必要的計算和內存訪問。

              寄存器分配:編譯器可能會優化寄存器的使用,以減少內存讀寫和提高數據訪問速度。

              常量折疊:編譯器可能會在編譯時計算常量表達式的值,并將結果直接替換為常量值。

              這些優化技術的具體應用取決于編譯器和優化級別。通過啟用適當的優化選項,編譯器可以對代碼進行優化。

            【嵌入式C語言編程小知識】相關文章:

            C語言嵌入式編程小知識01-08

            嵌入式C語言編程小知識總結08-12

            嵌入式C語言編程知識總結06-04

            C語言高效編程的小技巧06-03

            初學C語言編程基礎知識01-05

            C語言小知識匯總02-24

            C語言基礎小知識02-24

            嵌入式C語言優化小技巧04-12

            C語言編程基礎05-20

            <delect id="sj01t"></delect>
            1. <em id="sj01t"><label id="sj01t"></label></em>
            2. <div id="sj01t"></div>
              1. <em id="sj01t"></em>

                      <div id="sj01t"></div>
                      黄色视频在线观看