单片机c语言必背代码_【典藏】深度剖析单片机程序的运行(C程序版)
1、日常聊一聊
? ? 今天為大家帶來一篇對于單片機學習的小伙伴非常重量級的一篇文章《深度剖析單片機程序的運行(C語言版本)》,該文章會比較全面的為大家解析我們的用C語言編譯出來的程序是如何在單片機中運行,包括程序的結構、變量的存儲模型、內核運行程序流程等等內容,幫助大家能夠更好的理解單片機運行程序的機制,便于我們在平時的開發過程中定位并解決相關bug,從而寫出更加優質且符合單片機運行的代碼。
2、兩大體系結構
? ? 計算機界的兩大體系結構分別是:馮洛伊曼體系結構和哈佛體系結構,對于一款芯片到底屬于其中哪一種體系結構大家也是爭論不休,根據我的了解其實并不是這兩種體系結構有多難區分,而是因為為了提高運行程序的高效等衍生出了很多變體的結構導致難以評判,不過對于一般應用小伙伴并不會說一定要對這兩種體系結構進行區分,這里作者就個人認識來說上幾句:馮氏結構的觀點認為程序也是一種數據,所以兩者可以混合存儲,并且數據總線和地址總線都是共用的,而哈佛結構則是把程序和數據分開存儲,并且分別有獨立的數據總線進行訪問,從而大大提高了數據的吞吐量。
????目前大部分intel的計算機處理器大多是馮氏結構,而單片機、ARM等微型計算機大多采用的是哈佛結構。
3、單片機內部結構簡介
????為了便于后面內容更好的理解,這里簡單補充一下單片機內部的一些單元,下圖是我為大家簡單畫的一個示意圖:
????這里我們簡單解析一下該圖:該圖描述了大部分單片機的結構簡圖,左邊主要是用于計算和數據處理,右邊主要是用于數據存儲和對外輸入輸出結構。CPU的工作原理就幾個字:取指令->譯碼-->執行指令;為了加快數據處理等會與數據處理單元合作進行相關運算和處理,如果把CPU看做"皇帝",那么寄存器就像是一些"小太監"配合CPU完成相關工作,而我們的CPU所取的指令來自于哪里呢?當然是我們的存儲設備了,在上電前程序位于我們的ROM中,上電以后對于部分單片機等等會把ROM中的程序指令加載到RAM中從而提高程序運行速度,這樣我們的程序就固化在了ROM中,而我們的RAM掉電便會丟失數據,但是在單片機正常運行過程中用于訪問數據會提高運行效率,所以訪問比較頻繁數據都會放在RAM里面來進行訪問,而我們外設也就是我們平時使用的GPIO、UART、ADC等等與外部進行交互的接口了。
????從單片機的整體內部結構看來,單片機所有的運作都依賴于我們編寫的程序,換一種說法,我們所編寫的程序指導著單片機的運作,所以我們不僅僅要了解如何制作該程序,還需要了解程序是如何指導我們單片機運作的。在前面的《嵌入式編程“進階有道”之C程序(1)》中我為大家詳細描述了一個C程序如何生成機器碼,在《Jlink調試的那些事》中也告訴大家大部分JTAG接口的芯片是如何把固件燒錄到我們的芯片內部FLASH中,大家如果不理解可以回頭看一下相對應的文章。
4、C程序數據存儲
????我們通過C程序編譯生成了對應的機器碼,一般單片機的程序都分為不同的段,下面我畫了一張簡圖便于大家理解:
?? ?詳細分析一下每個段:
????1).bss段:該段主要是用于存儲C語言中未初始化或者初始化為0的全局變量、靜態變量等;
??? 2).data段:該段主要保存C語言中對應的已經被初始化的全局變量或者靜態變變量等;
??? 3).rodata段:只讀數據段,該段主要用于存儲對應的常量等;
??? 4).text段:也叫代碼段,我們的程序運行邏輯基本上就是存儲在該區域,該區域一般都只讀不寫;
??? 5)其他段:該部分對于一些單片機存儲著對應的boot代碼、相關算法等等。
????看了上面的每個段的分析,有些小伙伴們可能就問了?局部變量屬于哪個區域呀?動態內存分配的區域又在哪里?答案是他們分別在棧上和堆上。
“堆”和“?!?/p>
????堆:屬于動態內存分配區域,我們平時在C語言中調用的malloc所獲得的內存就是來自于這塊區域,同時我們使用完后需要進行釋放,如調用對應的free函數。
????棧:該概念類似于一種先進后出的數據結構,在調用函數的時候函數的參數及函數內部的局部變量都會存儲在區域,函數結束以后該區域也就自動釋放了。
????注意:堆棧都屬于程序的RAM區域。對于堆的實現,我們大部分都是通過模擬的方式進行管理,同時大家還要注意單片機的系統棧和RTOS的棧的區別。(后續的文章我都會為大家講解這塊的內容)
5、在單片機如何運行程序
????好了,有了前面的準備知識,這里我就可以放開講解單片機的運行了,如果簡單說單片機的運行,那么可以說就是CPU的運行,取指令-->譯碼-->執行指令;那么這里我就以提問的方式為大家更加詳細的說明:
1)CPU在哪里取指令??
????我們都知道對于PC機,都是從硬盤中加載對應的應用程序到內存中進行執行,那么CPU所取的指令都來自于內存,那么我們的單片機是不是這樣的呢?我們大部分玩單片機的小伙伴都知道,單片機的RAM都是在K級別,而我們生成的Bin文件可能比這大得多,那這樣看來單片機的取指令還不是從RAM中來的,那就只有對應的flash了,是的,單片機CPU取指令是通過總線直接訪問Flash,不過該Flash并不是我們平時使用的串行flash,一般為NorFlash,CPU可以直接訪問,且讀的速度對于單片機的速度相比RAM相差不大。
????不過Flash存在擦寫次數的問題,并且向Flash寫入需要特殊的命令,所以單片機的程序對于代碼段和只讀數據段等只讀段會繼續存放在Flash中(如果你需要加快部分算法,可以加載到RAM中進行);而對于.data段和.bss段都會最終啟動加載放到RAM中進行訪問。
2)單片機程序從什么地方開始執行??
? ? 在之前的連載的《用"庫"來學習嵌入式驅動編程》文章中,我詳細的解析了stm32的啟動文件,在文章中分析了該單片機的啟動過程,所以我們要明確一點的是我們的單片機程序并不是從main函數開始執行的,在單片機執行main函數執行進行了一系列的初始化工作,我們可以大體認為一方面是初始化單片機的基礎硬件配置,另一方面是為調用我們的C函數構造環境。如下圖所示:
3)單片機如何調用函數??
? ? 我們都知道函數是我們程序的重要組成部分,那我們的C函數在單片機里面是如何執行的呢?首先我們應該知道PC(程序計數器),該寄存器中存儲著下一條CPU需要執行的指令,當順序執行到函數調用入口處會進行壓棧push進行保存現場,比如當前調用函數的返回地址,當前棧指針以及相關寄存器等等。那么當函數即將返回,就會從對應的堆棧中pop出相關數據來進行現場的恢復。在這過程中函數中的局部變量都是在棧中分配的,函數運行完對應的局部變量內存也就自動回收。下面為大家簡單的畫了個過程示意圖方便大家理解:
6、最后小結一下
? ? 上面為大家基本上把C語言程序與大多數單片機的運行進行了一一對應,大家如果遇到了一款自己不太熟悉的單片機,可以按照上面的思路進行理解和查閱對應的數據手冊文檔,只有你充分了解了一款單片機的運行機制才能編寫出符合目標單片機上的優秀代碼,同時也便于一些可移植框架的移植,比如RTOS,GUI等等。同時對于一些比較復雜的程序bug也能夠更加詳細的分析和解決。
本文來源:最后一個bug
EDN
推薦閱讀:
你眼里的嵌入式工程師是這樣的嗎?
模塊化編程到底有多重要?
硬件工程師日常崩潰圖鑒
33歲入行嵌入式軟件開發晚不晚啊?
干貨||稀里煳涂學習STM32完整版
【視頻】教你DC-DC及做一個開關電源,不信你學不會!
什么是PWM“死區”?
這2個單片機編程的思想,請你掌握
長文:嵌入式程序員的編程修養
485通信自動收發電路 歷史上最詳細的解釋
多個單片機的通信方式【詳細】
10個單片機電路設計中的難點,你都解決了嗎?
總結
以上是生活随笔為你收集整理的单片机c语言必背代码_【典藏】深度剖析单片机程序的运行(C程序版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 智能进入系统是什么(人工智能是什么)
- 下一篇: date类before()方法的主要作用