專業嵌入式軟體開發——全面走向高質高效編程

專業嵌入式軟體開發——全面走向高質高效編程

本書適合嵌入式軟體開發領域的新手和在工作中碰到瓶頸的老手閱讀。 學習嵌入式軟體開發的另一大困難是實踐問題,本書必須幫助讀者解決這一問題。 掌握開發所需的工具是學習嵌入式軟體開發的又一大挑戰,本書在這方面也花費了大量筆墨。

出版信息

專業嵌入式軟體開發——全面走向高質高效編程

李雲 著
ISBN 978-7-121-14783-8
2012年1月出版
定價:108.00元(含DVD光碟1張)
16開
640頁

內容簡介

本書分為6篇。硬體篇就嵌入式軟體開發所需掌握的處理器概念進行了介紹。工具篇對make、gcc編譯器、bintuils工具集、ld連結器和gdb調試器進行了講解,其中對make這一嵌入式開發環境的全能管家進行了精闢的介紹,致力於幫助讀者成為Makefile方面的專家。程式語言篇致力於讓讀者更深入地理解C程式語言。作業系統篇通過循序漸進的方式介紹ClearRTOS的設計與實現,使得讀者能透徹地理解作業系統的關鍵概念和實現原理。設計篇和質量保證篇通過實踐的方式逐步展開講解,以幫助讀者獲得一些實用的設計原則、最佳實踐和一套有效的質量保證方法論。
本書適合嵌入式軟體開發領域的新手和在工作中碰到瓶頸的老手閱讀。閱讀本書要求讀者已掌握C程式語言和基本的UML知識。

前 言

我於2000年第一次接觸嵌入式軟體開發工作,那時和很多入門者一樣,因為找不到全面、易懂、深入的讀物,也沒有人指導,因而遭遇了極大的自學痛苦。即使在今天,學習嵌入式軟體開發似乎仍困難重重,這從我的部落格空間不時有網友發私信詢問如何學習可以看出。
我也曾被網友要求推薦學習嵌入式軟體開發的好書。但當我以“嵌入式”關鍵字在網上書店進行搜尋時,所獲得的書大部分與Linux、Windows CE、Android和ARM有關。在我看來,網友並不是讓我幫助他選擇Linux還是Windows CE,ARM還是x86,而認為他希望獲得一本學習通用原理和方法的書,因此不敢貿然推薦。基於這種現狀,我萌發了寫一本既能指導新手入門,又能幫助老手獲得突破的書。讀者手上拿的正是這本書!本書的創作始於2009年6月,歷時2年後於2011年下半年面市。
在本書的創作之初,我問自己:這本書應當包含哪些內容呢?或許可以根據自己過去十多年所經歷並克服的成長痛苦進行編排!
嵌入式軟體開發是一種軟硬體結合非常緊密的職業,對工程師的能力要求自然也就高了。剛開始學習嵌入式軟體開發時,最困難的莫過於學習作業系統原理和處理器方面的知識,所以本書必須包含這兩方面的內容。講解作業系統原理如果以Linux、Windows CE等成熟的作業系統為素材並不好,因為它們太大,很容易讓人“只見森林不見樹木”,也容易讓人望而生畏而失去學習的興趣和信心。從軟體開發的角度來看,作業系統的概念和實現原理一旦掌握,不論基於哪一個作業系統做開發都只是調用不同的函式而已。為了讓讀者獲得最好的學習體驗,我為本書設計了一個實現簡潔、完整的“實時” 作業系統——ClearRTOS,通過漸進式的方式細緻地講解作業系統的概念和實現原理。至於處理器方面的知識,本書沒有針對某一具體處理器,而是就編程方面所需的通用知識進行了介紹。對這些通用知識的掌握,將使得處理器對於讀者不再那么神秘。
學習嵌入式軟體開發的另一大困難是實踐問題,本書必須幫助讀者解決這一問題。對於很多初學者來說,為了實踐而購買一塊開發板的學習成本偏高。值得欣喜的是,讀者學習本書並不需要購買開發板,而只需要有一台安裝於x86或x86-64(包括Intel 64 和AMD 64)處理器上的Windows或Linux作業系統的計算機,對於大多數讀者來說這樣的學習環境就在身邊。另外,軟體開發工程師有一個特點,對於自己能修改和調試的代碼更具學習興趣,通過這種方式學習的效果也更佳。本書的所有代碼(包括ClearRTOS)都被設計成能在Cygwin環境 和Linux作業系統上編譯、調試和運行,所以本書完全迎合工程師的這一學習偏好。總的說來,實踐性強是本書很突出的一個特色。
掌握開發所需的工具是學習嵌入式軟體開發的又一大挑戰,本書在這方面也花費了大量筆墨。與非嵌入式軟體開發採用集成開發環境不同,嵌入式軟體開發大多是基於命令行的。軟體開發工程師除了進行編碼工作,還需要能駕馭自己的編譯環境並運用其他的開發工具輔助開發工作。本書的工具篇以來自GNU的工具為例幫助讀者戰勝這一挑戰。值得強調的是,其中花了很大的篇幅幫助讀者成為Makefile方面的專家。
如果讀者只想入門,那么掌握作業系統、處理器和必要的工具就足夠了。但如果想獲得突破,以實現高質高效地從事軟體開發工作顯然不夠,還必須理解軟體設計的重要性,並藉助一定的質量保證方法論來提高工作質量和效率。軟體設計和質量保證方法論是業內比較抽象和高級的話題,為此本書在設計篇和質量保證篇通過實踐的方式逐步展開講解,以幫助讀者獲得一些實用的設計原則、最佳實踐和一套有效的質量保證方法論。
總而言之,本書從知識、工具、方法和思想這四大方面全面講解如何專業地從事嵌入式軟體開發,致力於幫助讀者全面走向高質高效編程。
讀者閱讀本書之前,需要掌握C程式語言和基本的UML知識 。如果有使用Linux作業系統的基礎經驗,對學習本書也會有小小的幫助 。儘管本書是針對嵌入式領域的,但書中的很多思想和方法適用於整個軟體行業。
本書結構
全書分為6大篇共33章,讀者可以通過瀏覽書的目錄以進一步了解各篇所涵蓋的內容。
硬體篇就嵌入式軟體開發所需掌握的處理器概念進行了介紹,並通過介紹電路信號的完整性問題告訴讀者,嵌入式產品的質量不是軟體質量單方面能保證的。
工具篇介紹了提高嵌入式軟體開發效率所需掌握的工具。make作為嵌入式開發環境的全能管家,在本篇中花了較大的篇幅對其進行精闢的介紹。此外,gcc編譯器、binutils工具集、ld連結器和gdb調試器都在本篇中涵蓋了。對於工具的介紹是基於實用的角度展開的,而不是“大全”。
程式語言篇致力於讓讀者更深入地理解C程式語言。其中對程式的結構、ABI/EABI、volatile關鍵字進行了講解,這幾方面的知識在非嵌入式軟體開發中並不需要深入了解,但在嵌入式軟體開發中卻是必須掌握的。本篇還通過分析一個因混淆指針和數組所導致的問題,指出開發活動中容易忽視的一個認識盲點,並提出了預防這類問題的終極方法。
設計篇解釋了為什麼設計是軟體產品的質量之本,還介紹了作者常用的設計原則及所倡導的軟體設計思想和一些最佳實踐。設計思想包括:平台與框架開發、可查錯性設計、可開發性設計;最佳實踐則覆蓋模組管理和錯誤管理。
作業系統篇通過循序漸進的方式介紹ClearRTOS的設計與實現,使得讀者能透徹地理解作業系統的關鍵概念和實現原理。讀者掌握這篇的內容,有助於輕鬆地在實時Linux、VxWorks、Windows CE等各種實時作業系統上從事軟體開發工作。
質量保證篇關注於如何通過質量保證方法論來獲得高質量的軟體產品,也探討了工程師的編程習慣對軟體質量的影響。本篇中強調了單元測試這一被忽視的質量保證方法的價值,並通過設計實用的單元測試框架展示如何在項目中實施它。本篇中還展示了如何將代碼覆蓋、靜態分析、動態分析和性能分析無縫地整合到開發環境中,以及闡述了“以單元測試為中心”和“要素有形化”質量保證方法論設計思想的具體含義。
致謝
本書是我的處女作,能與讀者見面離不開很多人的支持和幫助。首先,感謝我的妻子和女兒。正是在妻子的提議下,我從寫部落格開始揚起了本書的寫作之帆。女兒則是我的開心果,給我的寫作之路帶來了很多的樂趣,讓我得到更多的放鬆機會。
感謝我的朋友及職業生涯中的上司和同事,正是他們給我機會,或鼓勵,或幫助,讓我一路積累,才有可能完成本書的創作。他們包括但不限於:龐惠民、章佳歡、劉偉民、夏青、於善成、范鵬、羅延庭。
感謝51CTO部落格的同仁,他們的幕後支持讓我堅持了下來。廣大51CTO博友的期待也激勵著我努力地寫好本書。
感謝電子工業出版社的策劃編輯張春雨,他的出現加速了本書的面市,也給我吃了一顆將書寫到底的“定心丸”。與他交流寫作方面的話題讓我感受到了什麼是隔行如隔山,他對出版行業的專家意見和追求滿分的精神讓本書增色不少。
最後,再一次感謝我的妻子和好友於善成,兩位預讀了本書並提出了自己的真知灼見,使得本書更簡練、嚴謹和更具可讀性。
附書光碟內容介紹
******************************************************************************************
書中如果出現錯誤,請先接受作者的致歉,如能來信告知那將不勝感激。錯誤一旦發現會通過我的部落格第一時間通知其他讀者。讀者在學習中如需幫助,可以通過技術圈發帖討論。
李 雲
2011-07-04

目 錄

硬 件 篇
第1章 處理器的基本概念 2
1.1 區分微處理器與微控制器 2
1.2 暫存器 2
1.3 處理器是如何啟動的 4
1.4 輸入與輸出 4
1.5 指令與數據 5
1.6 中斷 6
1.7 位元組序 8
1.8 邊界對齊 10
1.9 程式斷點和數據斷點 15
1.10 記憶體管理單元 16
1.11 快取 17
1.12 小結 18
第2章 開發活動中的硬體問題 19
2.1 兩個案例 19
2.2 案例的背後——信號完整性 19
2.3 應對方法 21
2.4 小結 21
工 具 篇
第3章 make,開發環境全能管家 24
3.1 從最簡單的Makefile中了解規則 24
3.2 創建基本的編譯環境 29
3.2.1 將規則運用於程式編譯 30
3.2.2 讓Makefile更專業 34
3.3 提高編譯環境的實用性 48
3.3.1 讓編譯環境更加有序 48
3.3.2 提升依賴關係管理 51
3.4 打造更專業的編譯環境 67
3.4.1 規劃項目目錄結構 68
3.4.2 增進復用性 72
3.4.3 支持頭檔案目錄的指定 75
3.4.4 實現庫連結 77
3.4.5 增強可使用性 82
3.4.6 管理對庫的依賴關係 84
3.4.7 改善編譯效率 87
3.4.8 恰當地書寫注釋 89
3.5 理解make的解析行為 90
3.6 Makefile的調試 91
3.7 make的常用選項 92
3.8 活用make 92
3.9 小結 94
第4章 gcc,c語言編譯器 96
4.1 什麼是交叉編譯器 96
4.2 gcc幕後工作揭示 97
4.3 實用的gcc選項 99
4.3.1 解決宏錯誤的好幫手 99
4.3.2 輔助編寫彙編程式的好方法 100
4.3.3 獲取系統頭檔案路徑 101
4.3.4 產生映射檔案 102
4.3.5 通過選項定義宏 102
4.3.6 生成依賴關係 103
4.3.7 指定程式庫 104
第5章 binutils工具集,軟體開發利器 107
5.1 addr2line,指令地址翻譯器 108
5.2 ar,靜態庫生成器 111
5.3 nm,符號顯示器 113
5.4 Objdump,信息查看器 115
5.5 objcopy,段剪輯器 119
5.6 ranlib,庫索引生成器 120
5.7 size,段大小觀察器 121
5.8 strings,字元串窺視器 122
5.9 strip,程式檔案瘦身器 124
第6章 ld,連結器 125
6.1 重定位的概念 125
6.2 連結腳本 126
6.2.1 段 128
6.2.2 符號 129
6.2.3 存儲區域 130
6.2.4 常用命令 131
6.3 常用選項 137
6.3.1 指定程式的入口點 137
6.3.2 生成可重定位的中間檔案 137
6.3.3 指定連結腳本 138
練習與思考 138
第7章 gdb,程式調試助手 139
7.1 啟動和退出gdb 139
7.2 獲取幫助 140
7.3 調試程式 142
7.3.1 斷點設定 142
7.3.2 控制程式運行 144
7.3.3 檢查程式 147
7.3.4 提高調試效率 151
7.4 查看符號表 152
7.5 控制gdb的行為 153
程式語言篇
第8章 掌握必要的彙編知識 156
8.1 as的語法 156
8.1.1 宏 157
8.1.2 彙編命令 157
8.1.3 符號和標籤 157
8.1.4 彙編指令 158
8.2 嵌入彙編的語法 158
第9章 深入理解程式的結構 161
9.1 段 161
9.1.1 指令段 161
9.1.2 數據段 162
9.2 棧 166
9.3 堆 168
9.4 小結 169
第10章 ABI/EABI規範,締造程式兼容契約 170
10.1 定義基本數據類型 171
10.2 規範位元組對齊處理 171
10.3 分配暫存器的功能 173
10.4 規定棧幀結構 174
10.4.1 棧幀的含義和作用 175
10.4.2 函式參數的傳遞方法 182
10.4.3 函式返回值的返回方法 184
10.5 小結 187
練習與思考 187
第11章 混淆指針與數組所導致的問題 188
11.1 問題示例 188
11.2 問題分析 189
11.2.1 數組的記憶體模型 189
11.2.2 指針的記憶體模型 190
11.3 問題成因 191
11.4 預防措施 193
11.5 小結 194
第12章 volatile,讓我保持原樣 195
設 計 篇
第13章 設計,軟體質量之本 200
13.1 軟體設計是什麼 200
13.2 軟體質量的概念 201
13.3 阻礙改善設計的常見觀念 203
13.3.1 測試是替罪羊或救命稻草 203
13.3.2 資源永遠不足 204
13.3.3 不改變就可以規避風險 204
13.4 如何提高設計能力 205
13.5 設計模式、設計原則和設計思想 206
13.6 放之四海皆適用的設計原則 207
13.6.1 以人為本 207
13.6.2 追求簡單性 210
13.6.3 讓模組善始善終 211
13.6.4 重視收集統計信息 212
13.6.5 藉助命名傳達設計意圖 213
13.6.6 消除“審美告警” 215
13.6.7 通過機制解決問題 215
13.6.8 防止他人犯錯 218
13.6.9 考慮可查錯性 220
13.7 小結 221
第14章 模組管理,保障系統有序運行 222
14.1 管理參照系 222
14.2 設計思路 224
14.3 程式實現 226
14.3.1 引入模組標識 226
14.3.2 實現層與級的表達 226
14.3.3 系統狀態和回調函式原型定義 228
14.3.4 模組註冊 228
14.3.5 系統啟動 230
14.3.6 系統關閉 232
14.4 module示例程式 233
14.5 模組管理的一些思考 235
14.6 小結 235
練習與思考 235
第15章 錯誤管理,不可或缺的用戶需求 236
15.1 表達錯誤的通用方法 236
15.1.1 錯誤碼格式 237
15.1.2 定義方法 238
15.1.3 使用示例 239
15.1.4 提高可使用性 240
15.1.5 定義和使用錯誤碼的準則 246
15.2 最佳化錯誤日誌的輸出 246
15.2.1 傳統方法 246
15.2.2 更有效的方法 249
15.3 平台和框架層的錯誤處理 251
15.4 小結 251
第16章 目錄結構管理,使項目進展更順利 252
16.1 規劃目錄結構的意義 252
16.1.1 書架功能 252
16.1.2 意識引導 252
16.1.3 加速新手上手 253
16.2 出色目錄結構的特點 253
16.3 一個示例 253
16.4 小結 254
第17章 平台與框架開發,高質量軟體打造之路 255
17.1 區分系統庫、平台和框架 255
17.1.1 系統庫 255
17.1.2 平台 256
17.1.3 框架 256
17.2 本質和優點 257
17.3 確立架構模型 258
17.4 小結 259
第18章 可開發性設計,一種高效且經濟的開發模式 260
18.1 可開發性問題一瞥 260
18.2 可開發性設計的內涵 261
18.3 引入設備抽象層 261
18.4 更複雜的設備抽象層 263
18.5 圖形界面的可開發性設計 264
18.5.1 增強設備抽象層 264
18.5.2 提供可視化編輯環境 264
18.6 其他可開發性設計 264
18.7 小結 265
作業系統篇
第19章 引導載入器,系統啟航者 268
19.1 功能 268
19.2 檔案存儲布局 269
19.3 程式載入原理 270
19.4 優點 274
19.5 小結 274
練習與思考 275
第20章 任務,軟體基本調度單元 276
20.1 任務情景 278
20.1.1 情景內容 278
20.1.2 情景保存 279
20.1.3 情景恢復 281
20.1.4 情景切換 282
20.2 任務調度 286
20.2.1 調度算法 286
20.2.2 調度器 290
20.3 任務的生命周期 293
20.4 任務控制 295
20.4.1 任務創建 297
20.4.2 任務啟動 306
20.4.3 任務刪除 307
20.4.4 任務掛起 309
20.4.5 任務恢復 310
20.4.6 任務睡眠 311
20.5 競爭問題與中斷控制 313
20.5.1 競爭問題的產生 314
20.5.2 通過中斷控制解決競爭問題 315
20.5.3 中斷控制的嵌套問題 316
20.6 任務與中斷狀態 317
20.7 任務棧溢出檢測 318
20.8 滴答與空閒任務 320
20.9 多任務環境控制 323
20.10 任務模組管理 324
20.11 taskv1示例程式 326
20.12 任務鉤子函式 330
20.13 任務變數 334
20.13.1 taskv2示例程式 334
20.13.2 原理 336
20.13.3 實現 337
20.14 其他概念與思考 340
20.14.1 搶占式任務與實時系統的關係 340
20.14.2 影響任務切換效率的因素 341
20.14.3 避免直接刪除任務 341
20.14.4 小心多任務設計被濫用 342
20.15 小結 343
練習與思考 343
第21章 任務同步與通信,實現協同工作 345
21.1 信號量 345
21.1.1 套用場合 345
21.1.2 程式實現 347
21.1.3 semaphore示例程式 358
21.2 互斥鎖 360
21.2.1 套用場合 361
21.2.2 程式實現 361
21.2.3 mutex示例程式 365
21.2.4 優先權反轉與繼承 367
21.2.5 遞歸鎖 375
21.3 事件 379
21.3.1 套用場合 379
21.3.2 程式實現 379
21.3.3 event示例程式 384
21.4 訊息佇列 386
21.4.1 套用場合 386
21.4.2 程式實現 387
21.4.3 實現訊息佇列 390
21.4.4 queue示例程式 396
21.4.5 使用指南 398
21.5 死鎖及預防 399
21.6 小結 399
練習與思考 400
第22章 記憶體管理,協調動態記憶體的使用 401
22.1 堆管理 401
22.1.1 heapv1示例程式 401
22.1.2 程式實現 406
22.1.3 設計改進 416
22.1.4 支持記憶體泄漏檢測 421
22.1.5 實現記憶體溢出檢測 431
22.1.6 記憶體碎片問題 431
22.2 記憶體池管理 432
22.2.1 mpool示例程式 432
22.2.2 程式實現 436
22.2.3 緩衝區泄漏檢測 444
22.3 小結 444
練習與思考 444
第23章 設備管理,方便與外設互動 445
23.1 字元設備管理 445
23.2 中斷管理 447
23.2.1 中斷向量表 447
23.2.2 中斷控制 448
23.2.3 中斷狀態管理 450
23.2.4 設備與中斷 451
23.2.5 模組管理 451
23.3 實現設備管理 452
23.3.1 安裝驅動程式 454
23.3.2 註冊設備 455
23.3.3 打開設備 456
23.3.4 關閉設備 458
23.3.5 設備讀寫與控制 458
23.4 設備驅動程式實現 459
23.4.1 “滴答”設備 460
23.4.2 控制台設備 462
23.4.3 終止程式運行設備 464
23.5 驅動安裝與設備註冊 466
23.6 小結 468
練習與思考 468
第24章 定時器,程式鬧鐘 469
24.1 軟體定時器分類 469
24.2 設計思路 469
24.3 中斷回調定時器 470
24.3.1 程式實現 470
24.3.2 timerv1示例程式 481
24.4 定時誤差 484
24.5 提高遍歷效率 484
24.6 改善實時性 489
24.6.1 實時性分析 490
24.6.2 改進實時性 491
24.7 任務回調定時器 494
24.7.1 程式實現 494
24.7.2 timerv3示例程式 497
24.8 小結 498
練習與思考 498
第25章 ClearRTOS“實時”作業系統 499
25.1 設計原則 499
25.2 源程式目錄管理 499
25.3 讓Makefile體現概念 502
25.4 實現集中配置 503
25.5 改進與移植 504
質量保證篇
第26章 質量保證導言 508
26.1 軟體開發的特點 508
26.1.1 腦力密集型工作 508
26.1.2 實現不具唯一性 508
26.1.3 隱性成本高 509
26.1.4 忽視的細節很容易被放大 509
26.1.5 質量難以評估 509
26.2 保證質量的關鍵要素 509
26.2.1 完備的需求分析 510
26.2.2 高質量的設計 510
26.2.3 編程好習慣 510
26.2.4 充分的驗證 510
26.2.5 必要的流程 511
26.2.6 合適的工具 512
26.2.7 言簡意賅的文檔 512
26.3 質量保證需要系統性的方法論 512
26.3.1 方法論 = 流程 + 工具 513
26.3.2 構建有效方法論的核心手段 516
26.4 走出質量困境的指導性思想 518
26.4.1 從管理者的角度 518
26.4.2 從工程師的角度 519
26.4.3 從組織的角度 519
26.5 小結 520
第27章 編程好習慣,質量保證的基本條件 521
27.1 終生受用的編程好習慣 521
27.1.1 判斷失敗而非成功 521
27.1.2 採用sizeof減少記憶體操作失誤 522
27.1.3 禁止程式語言特性 524
27.1.4 恰當使用goto語句 527
27.1.5 合理運用數組 529
27.1.6 以逆序方式釋放資源 530
27.1.7 在模組對外接口中防範錯誤 531
27.1.8 避免出現魔數 532
27.1.9 利用程式語言特性提高效率 533
27.1.10 復用代碼提高維護性 534
27.1.11 藉助隱式初始化簡化程式邏輯 536
27.1.12 青睞小粒度鎖 538
27.1.13 精確包含頭檔案 539
27.1.14 讓模組的對外頭檔案保持簡潔 541
27.1.15 只暴露必要的變數和函式 542
27.1.16 清除編譯器報告的所有警告 542
27.2 小結 543
第28章 單元測試,被忽視的質量保證方法 544
28.1 警惕單元測試無用論 544
28.2 一個簡單但不完善的單元測試例子 545
28.3 構建單元測試框架 548
28.4 無縫整合單元測試 555
28.4.1 維護規則 557
28.4.2 目錄規劃 557
28.4.3 更改Makefile 559
28.4.4 檢查整合效果 566
28.5 幾個實施問題 569
28.6 樁函式和打樁 570
28.7 錯誤注入,一種可測試性設計 571
28.8 平台開發與單元測試 576
28.9 被測行為的確定性 576
28.10 測試用例的有效性 577
28.11 小結 578
第29章 代碼覆蓋,單元測試效果的衡量指標 579
29.1 了解代碼覆蓋工具 580
29.2 無縫整合代碼覆蓋 584
29.2.1 更改Makefile 584
29.2.2 檢查整合效果 586
29.3 三個代碼覆蓋程度指標 587
29.4 小結 588
第30章 靜態分析,防止將失誤帶給用戶 589
30.1 認識靜態分析工具 589
30.2 無縫整合靜態分析 596
30.2.1 更改Makefile 596
30.2.2 檢查整合效果 601
30.3 小結 602
第31章 動態分析,使程式更健壯 603
31.1 結識動態分析工具 604
31.2 無縫整合動態分析 607
31.2.1 更改Makefile 607
31.2.2 檢查整合效果 609
31.3 小結 609
第32章 性能分析,讓最佳化程式有的放矢 610
32.1 初探性能分析工具 610
32.2 無縫整合性能分析 612
32.2.1 更改Makefile 613
32.2.2 檢查整合效果 614
32.3 小結 615
第33章 qBench,一個開發高質軟體的工作檯 616
參考資料 618

相關詞條

熱門詞條

聯絡我們