# 第三節:單片機最重要的一個特性
## 【3.1 單片機的 “一”】

圖 3.1 單片機工作的最小系統
“道生一,一生二,二生三,三生萬物。”《道德經》認為,世間萬物,繽紛多彩,都源自一個東西,這個 “一” 的東西就是 “道”。電子世界也存在 “一”,這個 “一” 繁衍出手機、電腦、電視機、機器人等豐富多彩的電子世界,這個 “一” 就是單片機最重要的一個特性:“程序下載進內存后,單片機既可以通過管腳識別外部輸入的高低電平信號,也可以通過管腳對外部輸出不同時間長度的高低電平。” 這句話有 5 個關鍵詞 “程序、內存、管腳、電平、時間。” 下面我詳細解讀每個關鍵詞的含義,涉及到某些專用名詞如果不理解也沒關系,主要是讓大家有個感性的認識就足矣。
## 【3.2 程序】
單片機程序有 3 種:C 程序、匯編程序、機器程序。能下載進單片機的只有機器程序,C 程序和匯編程序都不能直接下載進單片機,所以 C 程序和匯編程序都要經過編譯軟件翻譯成機器程序后,才能下載進單片機。程序是語言,語言是用來交流,交流就必須存在兩個對象,對象分別是程序員和單片機。程序員是人所以用 C 或者匯編語言,單片機是機器所以用機器語言,人和機是不同的世界,兩者交流就需要一個翻譯家,翻譯家就是編譯軟件,俗稱編譯器,它能把 C 語言或者匯編語言翻譯成單片機能識別的機器語言。機器語言就是 0101 的代碼,一般以十六進制的形式呈現。
理論上,程序員也可以拋開 C 和匯編語言,直接用機器語言做項目。我讀書時老師讓我們做實驗就是這么整。那時我還不知有燒錄器,老師讓我們先用匯編語言寫好程序,然后自己充當編譯器,對照匯編語言和機器語言的指令表,人工把匯編語言翻譯成十六進制的機器語言,最后把機器語言按字節一個一個的輸入到特定的實驗設備來觀察現象。現在回想起來,老師當時的初衷是讓我們了解編程語言的本質。
既然可以直接用機器語言做項目,為什么還要 C 語言或者匯編語言?在 C 語言或者匯編語言沒有誕生前,程序員就是通過在紙帶上打孔來代表 01 的機器語言,此時相當于結繩記事的原始階段。后來人類發明了匯編語言,通過英語單詞來表示 01 機器語言特定的指令語句,此時開始誕生了匯編語言的編譯器相當于進入象形文字的階段。再到后來人類又發明了 C 語言,通過數學符號和英語單詞來表達自己的邏輯,誕生了 C 語言的編譯器相當于進入了漢字白話文階段,從此程序員寫出來的 C 程序就非常方便移植,編輯,閱讀,傳播,繼承。現在單片機開發的主流是 C 語言,我本人出來工作后就沒有用過匯編做項目開發。C 語言是必修課,匯編語言是選修課;C 語言是白話文簡單易懂,匯編語言是文言文繁瑣難讀。當然匯編也有它的應用場合,匯編的翻譯效率高,往往是一句匯編語言對應一句機器語言,而一句 C 語言有可能對應幾句機器語言,這樣 C 程序的代碼效率在很大程度上取決于編譯器的水平,編譯器能不能幫你翻譯出高效的機器語言對于我們來說往往像黑盒子,不像匯編語言那么可控制。所以很多嵌入式系統某段要求簡潔高效的源代碼往往用匯編來寫,也有少數一些很便宜的單片機不提供 C 編譯器,只能用匯編語言開發。要不要學匯編,最好根據個人的工作需求來決定。
## 【3.3 內存】
單片機就像 MP3,程序代碼就像歌曲,把不同的歌曲下載到 MP3 里就可以聽到不同的音樂,把不同的程序下載到單片機里,單片機就能做不同的事。能裝程序的單片機必然有內存,內存由 ROM 和 RAM 組成,ROM 和 RAM 都能裝東西,但各有不同。
ROM 的優點是存儲的東西斷電后不會丟失,缺點是存儲的東西上電后不能更改,想要改變 ROM 的內容除非重新下載程序,而且下載次數有限制,FLASH 的 ROM 最大次數通常是 10 萬次,而 OTP 的 ROM 只能下載 1 次,所以平時上電工作時 ROM 存儲的東西是不能更改的,某些具有 IAP 功能的高級單片機不在此討論范圍內。而 RAM 恰好反過來,RAM 的優點是存儲的東西上電后可以隨時被單片機更改,更改次數沒有限制,缺點是存儲的東西斷電后會丟失,沒有記憶功能。
ROM 和 RAM 各有特點,單片機從中各取所長。ROM 用來存儲不可更改的指令代碼和常量數據,ROM 的容量往往相當于代碼的容量。RAM 用來存儲可以被更改的變量數據,RAM 的容量往往相當于全局變量和局部變量的容量。不管是用 C 語言還是匯編,所寫的程序代碼就自然包含了指令代碼、常量數據、全局變量、局部變量,那么誰在幕后幫我們進行分類存儲,誰把一個程序代碼的一分為二讓它們在 ROM 和 RAM 里各就各位?是編譯器軟件和下載器 (燒錄器),編譯器除了把 C 語言翻譯成機器語言之外,還幫我們分好了類,分配好了存儲的地址和位置,下載器 (燒錄器) 再根據這些信息把程序存儲到內存中,這些工作一般不用程序員干預,它們自動完成。
## 【3.4 管腳】
管腳是單片機與外部電路進行能量和信息交互的橋梁。有電源,復位,晶振和 IO 口這 4 類管腳。
第一類電源管腳。是給單片機內部電路供電的接口。單片機有兩種常用的供電電壓,一般是 3.3V 或者 5V,有的單片機兩種電壓都兼容。
第二類復位管腳。單片機上電后需要外部電路給它一個瞬間高電平或者低電平的復位信號,才能啟動工作。復位電路通常是由電容和電阻組成的充電電路來實現,也有一些系統是用專門的復位芯片來實現。
第三類晶振管腳。任何單片機想要工作必須要有晶振。單片機執行程序指令是按一個節拍一個節拍來執行的。這個節拍的時間就是由晶振產生,所以把晶振比喻成單片機的心臟是非常恰當的。現在也有很多單片機直接把晶振集成到內部,這類單片機不用外接晶振也可以。
第四類 IO 口管腳。這是跟我們編寫程序關聯最密切的管腳。前面提到的電源,復位,晶振這 3 種管腳是為了讓單片機能工作,俗稱單片機工作的三要素。而單片機工作的具體內容就是通過 IO 口管腳來體現的。比如,IO 口能識別按健的輸入,也能輸出驅動繼電器工作的開關信號,也能跟外圍器件進行通信。
## 【3.5 電平】
電平就是電壓的兩種狀態,低或者高,低相當于程序里的 0,高相當于程序里的 1。單片機 IO 口管腳檢測到的電壓低于或等于 0.8V 時是低電平,程序里讀取到的是 0 數字。單片機 IO 口管腳檢測到的電壓高于或等于 2.4V 時是高電平,程序里讀取到的是 1 數字。必須注意的是,IO 口輸入的最大電壓不能超過單片機的供電電壓。單片機輸出的低電平是 0V,單片機輸出的高電平等于它的供電電壓值,往往是 3.3V 或者 5V。
## 【3.6 時間】
時間是單片機程序必不可少的元素。跟外圍芯片通信的時序節拍需要時間,驅動發光二極管閃爍需要時間,工控自動化的某些延時需要時間。單片機的時間來源自兩方面。第一方面源自指令的周期時間。單片機是根據節拍來執行程序指令的,每執行一條指令都要消耗一點時間,只要讓程序執行的指令數量越多,產生的時間就越長,通過調整所執行指令的數量就可以得到所需的時間長度。第二方面源自單片機內部自帶的定時器。假如設置定時器每 20 毫秒產生一次中斷,現在要獲取 10 秒鐘的時間,只需在程序里統記 500 次定時中斷就可以了,因為 1 秒等于 1000 毫秒。指令和定時器這兩者的時間最后都來源于晶振。
- 首頁
- 第一節:我的價值觀
- 第二節:初學者的疑惑
- 第三節:單片機最重要的一個特性
- 第四節:平臺軟件和編譯器軟件的簡介
- 第五節:用Keil2軟件關閉,新建,打開一個工程的操作流程
- 第六節:把.c源代碼編譯成.hex機器碼的操作流程
- 第七節:本節預留
- 第八節:把.hex機器碼程序燒錄到單片機的操作流程
- 第九節:本節預留
- 第十節:程序從哪里開始,要到哪里去?
- 第十一節:一個在單片機上練習C語言的模板程序
- 第十二節:變量的定義和賦值
- 【TODO】第十三節:賦值語句的覆蓋性
- 【TODO】第十四節:二進制與字節單位,以及常用三種變量的取值范圍
- 【TODO】第十五節:二進制與十六進制
- 【TODO】第十六節:十進制與十六進制
- 【TODO】第十七節:加法運算的5種常用組合
- 【TODO】第十八節:連加、自加、自加簡寫、自加1
- 【TODO】第十九節:加法運算的溢出
- 【TODO】第二十節:隱藏中間變量為何物?
- 【TODO】第二十一節:減法運算的5種常用組合。
- 【TODO】第二十二節:連減、自減、自減簡寫、自減1
- 【TODO】第二十三節:減法溢出與假想借位
- 【TODO】第二十四節:借用unsigned long類型的中間變量可以減少溢出現象
- 【TODO】第二十五節:乘法運算中的5種常用組合
- 【TODO】第二十六節:連乘、自乘、自乘簡寫,溢出
- 【TODO】第二十七節:整除求商
- 【TODO】第二十八節:整除求余
- 【TODO】第二十九節:“先余后商”和“先商后余”提取數據某位,哪家強?
- 【TODO】第三十節:邏輯運算符的“與”運算
- 【TODO】第三十一節:邏輯運算符的“或”運算
- 【TODO】第三十二節:邏輯運算符的“異或”運算
- 【TODO】第三十三節:邏輯運算符的“按位取反”和“非”運算
- 【TODO】第三十四節:移位運算的左移
- 【TODO】第三十五節:移位運算的右移
- 【TODO】第三十六節:括號的強制功能---改變運算優先級
- 【TODO】第三十七節:單字節變量賦值給多字節變量的疑惑
- 【TODO】第三十八節:第二種解決“運算過程中意外溢出”的便捷方法
- 【TODO】第三十九節:if判斷語句以及常量變量的真假判斷
- 【TODO】第四十節:關系符的等于“==”和不等于“!=”
- 【TODO】第四十一節:關系符的大于“>”和大于等于“>=”
- 【TODO】第四十二節:關系符的小于“<”和小于等于“<=”
- 【TODO】第四十三節:關系符中的關系符:與“&&”,或“||”
- 【TODO】第四十四節:小括號改變判斷優先級
- 【TODO】第四十五節: 組合判斷if...else if...else
- 【TODO】第四十六節: 一維數組
- 【TODO】第四十七節: 二維數組
- 【TODO】第四十八節: while循環語句
- 【TODO】第四十九節: 循環語句do while和for
- 【TODO】第五十節: 循環體內的continue和break語句
- 【TODO】第五十一節: for和while的循環嵌套
- 【TODO】第五十二節: 支撐程序框架的switch語句
- 【TODO】第五十三節: 使用函數的三要素和執行順序
- 【TODO】第五十四節: 從全局變量和局部變量中感悟“棧”為何物
- 【TODO】第五十五節: 函數的作用和四種常見書寫類型
- 【TODO】第五十六節: return在函數中的作用以及四個容易被忽略的功能
- 【TODO】第五十七節: static的重要作用
- 【TODO】第五十八節: const(./book/或code)在定義數據時的作用
- 【TODO】第五十九節: 全局“一鍵替換”功能的#define
- 【TODO】第六十節: 指針在變量(./book/或常量)中的基礎知識
- 【TODO】第六十一節: 指針的中轉站作用,地址自加法,地址偏移法
- 【TODO】第六十二節: 指針,大小端,化整為零,化零為整
- 【TODO】第六十三節: 指針“化整為零”和“化零為整”的“靈活”應用
- 【TODO】第六十四節: 指針讓函數具備了多個相當于return的輸出口
- 【TODO】第六十五節: 指針作為數組在函數中的入口作用
- 【TODO】第六十六節: 指針作為數組在函數中的出口作用
- 【TODO】第六十七節: 指針作為數組在函數中既“入口”又“出口”的作用
- 【TODO】第六十八節: 為函數接口指針“定向”的const關鍵詞
- 【TODO】第六十九節: 宏函數sizeof(./book/)
- 【TODO】第七十節: “萬能數組”的結構體
- 【TODO】第七十一節: 結構體的內存和賦值
- 【TODO】第七十二節: 結構體的指針
- 【TODO】第七十三節: 結構體數據的傳輸存儲和還原
- 【TODO】第七十四節: 結構體指針在函數接口處的頻繁應用
- 【TODO】第七十五節: 指針的名義(例:一維指針操作二維數組)
- 【TODO】第七十六節: 二維數組的指針
- 【TODO】第七十七節: 指針唯一的“單向輸出”通道return
- 【TODO】第七十八節: typedef和#define和enum
- 【TODO】第七十九節: 各種變量常量的命名規范
- 【TODO】第八十節: 單片機IO口驅動LED
- 【TODO】第八十一節: 時間和速度的起源(指令周期和晶振頻率)
- 【TODO】第八十二節: Delay“阻塞”延時控制LED閃爍
- 【TODO】第八十三節: 累計主循環的“非阻塞”延時控制LED閃爍
- 【TODO】第八十四節: 中斷與中斷函數
- 【TODO】第八十五節: 定時中斷的寄存器配置
- 【TODO】第八十六節: 定時中斷的“非阻塞”延時控制LED閃爍
- 【TODO】第八十七節: 一個定時中斷產生N個軟件定時器
- 【TODO】第八十八節: 兩大核心框架理論(四區一線,switch外加定時中斷)
- 【TODO】第八十九節: 跑馬燈的三種境界
- 【TODO】第九十節: 多任務并行處理兩路跑馬燈
- 【TODO】第九十一節: 蜂鳴器的“非阻塞”驅動
- 【TODO】第九十二節: 獨立按鍵的四大要素(自鎖,消抖,非阻塞,清零式濾波)
- 【TODO】第九十三節: 獨立按鍵鼠標式的單擊與雙擊
- 【TODO】第九十四節: 兩個獨立按鍵構成的組合按鍵
- 【TODO】第九十五節: 兩個獨立按鍵的“電腦鍵盤式”組合按鍵
- 【TODO】第九十六節: 獨立按鍵“一鍵兩用”的短按與長按
- 【TODO】第九十七節: 獨立按鍵按住不松手的連續均勻觸發
- 【TODO】第九十八節: 獨立按鍵按住不松手的“先加速后勻速”的觸發
- 【TODO】第九十九節: “行列掃描式”矩陣按鍵的單個觸發(原始版)
- 【TODO】第一百節: “行列掃描式”矩陣按鍵的單個觸發(優化版)
- 【TODO】第一百零一節: 矩陣按鍵鼠標式的單擊與雙擊
- 【TODO】第一百零二節: 兩個“任意行輸入”矩陣按鍵的“有序”組合觸發
- 【TODO】第一百零三節: 兩個“任意行輸入”矩陣按鍵的“無序”組合觸發
- 【TODO】第一百零四節: 矩陣按鍵“一鍵兩用”的短按與長按
- 【TODO】第一百零五節: 矩陣按鍵按住不松手的連續均勻觸發
- 【TODO】第一百零六節: 矩陣按鍵按住不松手的“先加速后勻速”觸發
- 【TODO】第一百零七節: 開關感應器的識別與軟件濾波
- 【TODO】第一百零八節: 按鍵控制跑馬燈的啟動和暫停和停止
- 【TODO】第一百零九節: 按鍵控制跑馬燈的方向
- 【TODO】第一百一十節: 按鍵控制跑馬燈的速度
- 第一百一十一節: 工業自動化設備的開關信號的運動控制
- 【TODO】第一百一十二節: 數碼管顯示的基礎知識
- 【TODO】第一百一十三節: 動態掃描的數碼管顯示數字
- 【TODO】第一百一十四節: 動態掃描的數碼管顯示小數點
- 【TODO】第一百一十五節: 按鍵控制數碼管的秒表
- 【TODO】第一百一十六節: 按鍵控制數碼管的倒計時
- 【TODO】第一百一十七節: 按鍵切換數碼管窗口來設置參數
- 【TODO】第一百一十八節: 按鍵讓某位數碼管閃爍跳動來設置參數
- 【TODO】第一百一十九節: 一個完整的人機界面的程序框架的脈絡
- 【TODO】第一百二十節: 按鍵切換窗口切換局部來設置參數
- 【TODO】第一百二十一節: 可調參數的數碼管倒計時
- 【TODO】第一百二十二節: 利用定時中斷做的“時分秒”數顯時鐘
- 【TODO】第一百二十三節: 一種能省去一個lock自鎖變量的按鍵驅動程序
- 【TODO】第一百二十四節: 數顯儀表盤顯示“速度、方向、計數器”的跑馬燈
- 【TODO】第一百二十五節: “雙線”的肢體接觸通信
- 【TODO】第一百二十六節: “單線”的肢體接觸通信
- 【TODO】第一百二十七節: 單片機串口接收數據的機制
- 【TODO】第一百二十八節: 接收“固定協議”的串口程序框架
- 【TODO】第一百二十九節: 接收帶“動態密匙”與“累加和”校驗數據的串口程序框架
- 【TODO】第一百三十節: 接收帶“動態密匙”與“異或”校驗數據的串口程序框架
- 【TODO】第一百三十一節: 靈活切換各種不同大小“接收內存”的串口程序框架
- 【TODO】第一百三十二節:“轉發、透傳、多種協議并存”的雙緩存串口程序框架
- 【TODO】第一百三十三節:常用的三種串口發送函數
- 【TODO】第一百三十四節:“應用層半雙工”雙機串口通訊的程序框架