Stm32單片機開發KEIL啟動文件彙編語言詳解

2020-12-20 單片機嵌入式愛好者

文章目錄

簡介啟動文件彙編代碼相關指令堆棧空間的定義初始化中斷向量表復位中斷函數中斷函數的弱(WEAK)聲明用戶棧和堆初始化簡介

我們在做單片機編程的時候,大部分都是用KEIL自帶的啟動文件來使程序進入C語言main函數,然後進行C語言編程開發的工作。那麼這個啟動文件到底做了什麼呢?相信朋友們肯定和我一樣好奇,想弄明白啟動文件到底都幹了些什麼。那麼本文就來介紹下,本文介紹stm32啟動文件彙編代碼,對應文件名startup_stm32f10x_hd.s。其他Cortex-M3內核的單片機都是大同小異的。

其實啟動文件存在的目的就是構建可以供C語言代碼運行的工作環境,比如傳遞參數時需要的棧空間初始化,動態分配內存時的堆初始化,一些初始化為0的變量空間的初始化等等。如果這些沒有配置好,無法達到C語言代碼運行的工作環境,那麼後面的C語言代碼執行的結果就是不對的,也會導致總個系統無法工作。所以啟動文件很重要,也正是因為我們覺得它重要,所以才想搞懂它。

startup_stm32f10x_hd.s啟動文件中的彙編代碼主要做了下面5個工作。

1.堆棧空間的定義;

2.初始化中斷向量表;

3.復位中斷函數(Reset_Handler){系統初始化,然後進入main函數};

4.中斷函數的弱(WEAK)聲明

5.用戶棧和堆初始化

再介紹這5個部分的詳細代碼前,這裡已經先總結了啟動文件中用到的彙編代碼與編譯器相關的指令,下面就先來介紹下這些指令。

啟動文件彙編代碼相關指令

啟動文件代碼主要由ARM指令代碼和與編譯器相關的彙編指令組成,下表羅列了啟動文件中用到的相關彙編指令。

上面只是對指令做了簡要的說明,後面代碼用到時我們再一一講解。我們也可以通過在代碼中選中指令,按F1按鍵調出幫助說明,查看具體指令的相關介紹。

接下來我們就對代碼做詳細分析吧。

一、堆棧空間的定義

首先這裡使用指令EQU定義了一個數值常量符號Stack_Size指明棧大小為0x00000400即1K,這個值可以根據實際需求更改。使用QEU定義常數,類似與C語言的#define定義常數。

然後這裡又使用指令AREA定義了一個未初始化,可以讀寫並要求8位元組邊界對齊的段,段名,為STACK。這裡可以為段選擇任何段名。但是,以一個數字開始的名稱必須包含在豎槓號內,否則會產生一個缺失段名錯誤。例如, |1_DataArea|。有些名稱是習慣性的名稱。例如,|.text| 用於表示由 C 編譯程序產生的代碼段,或用於以某種方式與 C 庫關聯的代碼段。這裡的NOINIT表示數據段是未初始化的或初始化為零。其只包含零初始化的空間保留命令 SPACE 或 DCB, DCD, DCDU, DCQ, DCQU, DCW 或 DCWU 。可以決定在連結時 AREA 是未初始化的,還是零初始化的,後面一條指令是SPACE,所以這裡要初始化為0,READWRITE指明段可以讀寫,ALIGN=3指明段要在2^3=8位元組邊界上對齊。

再然後使用SPACE定義了一個初始化為0的存儲塊Stack_Mem,可以理解為存儲塊是別歸別到段裡的。標號__initial_sp緊挨著SPACE語句放置,表示棧的結束地址,即棧頂地址,棧是由高向低生長的。

同樣的堆也是這樣定義的,只是這裡先是指明了堆開始__heap_base(堆起始地址),再指明堆存儲塊,最後指明__heap_limit(堆終止地址)。堆是由低向高生長的,跟棧的生長方向相反。堆主要用來動態內存的分配,像malloc()函數申請的內存就在堆上面。這裡堆默認大小為0x00000200即512位元組,一般的程序中我們很少用到malloc函數,所以這裡也就不做過多更改,如果要使用malloc函數,需要將此處堆大小定義的值根據需求改大。

後面的PRESERVE8,指明當前文件的堆棧按照8位元組對齊。

二、初始化中斷向量表

THUMB指示彙編器將隨後的指令解釋為16位的Thumb指令。Cortex-M3使用的是Thumb-2指令集,是一種介於Thumb指令集和ARM指令集。ARM指令集全部是32位的,Thumb指令集全部是16位的,Thumb-2指令集是即有部分16位Thumb指令的也有部分32位的ARM指令。

後面定義一個只讀數據段RESET,用於保存中斷向量表,和三個標號__Vectors(向量表開始)、__Vectors_End(向量表結束)和__Vectors_Size(向量表大小)並使用EXPORT指明其具有全局性。這樣可以使在其他文件中訪問此文件中的這三標號。

DCD 命令分配一個或多個字的存儲器,在四個字節的邊界上對齊,並定義存儲器的運行時初值。

__Vectors DCD __initial_sp ; Top of Stack

這裡就指示了段的開始為向量表的開始,標號__Vectors(向量表開始)編譯器會根據不同單片機為其指定值,比如stm32單片機就是0x08000000,然後我們定義的RESET段就被分在了0x08000000開始的地址處,其結束位置就是從0x08000000開始依次加4個字節,因為這裡每個DCD命令佔存儲器4個字節,這樣一直到__Vectors_End(向量表結束),__Vectors_Size(向量表大小)就是這個RESET段所佔大小。比如復位的時候,復位中斷來了,就從這個段的第二個存儲地址0x08000004處對應的值0x08000144作為復位函數Reset_Handler的地址。

三、復位中斷函數

這裡先使用AREA定義了一個只讀代碼段。這裡的標號Reset_Handler就代表了復位函數的入口地址(函數名),使用PROC標記函數入口,使用ENDP標記函數結束。

EXPORT Reset_Handler [WEAK]

這裡EXPORT聲明Reset_Handler是一個全局性的。WEAK表示其他地方沒有定義Reset_Handler函數時,就將此處作為Reset_Handler函數的實例。IMPORT用於指示如果在當前彙編代碼中未找到其引用,則不導入該名稱,很顯然,下面有用到__main和SystemInit。

從上那些代碼我就就知道,程序上電後,從0x08000000地址處加載SP,上電復位從0x08000004處加載PC,0x08000004處的地址就是復位函數的地址,然後復位函數裡面先調用SystemInit函數來初始化系統的各種時鐘,再調用__main函數(由編譯器實現)。

復位函數中用到的Thumb-2指令介紹如下:

LDR從存儲器中加載字到一個寄存器中

BL跳轉到由寄存器/標號給出的地址,並把跳轉前的下條指令地址保存到LR

BLX跳轉到由寄存器給出的地址,並根據寄存器的LSE確定處理器的狀態,還要把跳轉前的下條指令地址保存到LR

BX跳轉到由寄存器/標號給出的地址,不用返回

四、中斷函數的弱(WEAK)聲明

這裡定義了各種中斷函數,使用PROC表示函數開始,ENDP表示函數結束,EXPORT說明函數的全局性,WEAK說明如果其他地方沒有定義這個函數,那麼就把此處作為函數的實例。這裡函數的代碼都是B . 。這裡的B表示跳轉到一個標號,這裡跳轉到一個'.',即表示無限循環,所以我們在寫C語言程序時如果沒有寫中斷函數,那麼對應的中斷來了會運行這裡到中斷函數,即B .那麼將無限循環在此。

ALIGN命令通過用零或空指令NOP填充,來使當前位置與一個指定的邊界對齊。使用ALIGN來確保數據和代碼對齊到適當的邊界上。這裡使用了默認為字對齊方式。

五、用戶棧和堆初始化

棧和堆初始化部分,這裡IF、ELSE、ENDIF是條件編譯。

先判斷是否定義了__MICROLIB ,如果定義了則賦予標號__initial_sp(棧頂地址)、__heap_base(堆起始地址)、__heap_limit(堆結束地址)全局屬性,可供外部文件調用,這樣我們使用到molloc函數申請的空間就是從這裡有關堆的兩個標號之間的內存中申請的。如果沒有定義(實際的默認情況就是我們沒定義__MICROLIB)則通過 IMPORT __use_two_region_memory 表明使用雙段模式,即一部分儲存區用於棧空間,其他的存儲區用於堆空間,堆區空間可以為0,但是,這樣就不能調用malloc()內存分配函數。然後使用__user_initial_stackheap標號處的代碼用於初始化用戶堆棧,這部分由編譯器提供的__main來調用。

END 命令指示彙編器,已到達一個源文件的末尾。

關於STM32單片機的Keil啟動文件彙編代碼就講解完了,大家有沒有看明白呢,歡迎評論交流,如果覺得我這篇文章寫到很好到話,就轉發出去分享給更多到朋友吧。最後歡迎大家點讚評論轉發收藏,跟多好文章歡迎關注我——單片機嵌入式愛好者。

相關焦點

  • 51,AVR,PIC,MSP430,STM32單片機比較
    IDE環境推薦 keil。編程器自己自製ISP下載線就行,好做,成本5元左右。STC12系列宏晶沒給出keil驅動。工具支持沒有自己的,要用keil的,在深層應用上會出現隱患。IDE:keil頭文件:宏晶網站上有,或者用at89x52.h,新的寄存器自己定義一下就行或者自己寫一個頭文件(推薦)。
  • 單片機編程軟體大佬:明確單片機編程軟體編寫單片機程序步驟
    單片機用什麼軟體編程?單片機開發中除必要的硬體外,同樣離不開軟體,我們寫的彙編語言源程序要變為CPU可以執行的機器碼有兩種方法,一種是手工彙編,另一種是機器彙編,目前已極少使用手工彙編的方法了。機器彙編是通過彙編軟體將源程序變為機器碼,用於MCS-51單片機的彙編軟體有早期的A51,隨著單片機開發技術的不斷發展,從普遍使用彙編語言到逐漸使用高級語言開發,單片機的開發軟體也在不斷發展,Keil軟體是目前最流行開發MCS-51系列單片機的軟體,這從近年來各仿真機廠商紛紛宣布全面支持Keil即可看出。
  • Keil中C語言與彙編語言混合編程需要注意的幾個地方
    在keil C語言與彙編語言的混合編程中曾經遇到過的一些問題,寫下來留作以後參考。#pragma endasmC語言代碼……}其中紅色為C語言部分,綠色為嵌入的彙編語言部分。首先右鍵單擊包含有彙編部分的c語言文件名,然後在如上圖所示的菜單中選擇帶有紅色方框的選項
  • stm32用什麼語言編程
    例如移動、自增,因此彙編源程序一般比較冗長、複雜、容易出錯,而且使用彙編語言編程需要有更多的計算機專業知識,但彙編語言的優點也是顯而易見的,用彙編語言所能完成的操作不是一般高級語言所能夠實現的,而且源程序經彙編生成的可執行文件不僅比較小,而且執行速度很快。   高級語言是大多數編程者的選擇。
  • avr單片機和stm32區別與優缺點分析
    摘要:avr單片機和stm32單片機是目前使用較廣泛的單片機,那麼avr單片機和stm32單片機有什麼區別呢?有什麼優劣勢呢?   avr單片機缺點:   1. 是沒有位操作,都是以字節形式來控制和判斷相關寄存器位的   2. C語言與51的C語言在寫法上存在很大的差異,這讓從開始學習51單片機的朋友很不習慣   3. 通用寄存器一共32個(R0~R31),前16個寄存器(R0~R15)都不能直接與立即數打交道,因而通用性有所下降。
  • STM32開發環境(工具)之Keil MDK 介紹
    5.1 Keil MDK介紹Keil是德國知名軟體公司Keil(現已併入ARM 公司)開發的微控制器軟體開發平臺,是目前ARM內核單片機開發的主流工具。Keil提供了包括C編譯器、宏彙編、連接器、庫管理和一個功能強大的仿真調試器在內的完整開發方案,通過一個集成開發環境(uVision)將這些功能組合在一起。
  • keil5.24創建uCOSIII工程實現stm32實時作業系統(環境配置)
    自從ARM keil升級到keil5系列版本後,Keil工具對作業系統,以及各種庫文件的移植大大簡化了只需要動動手指,勾選一些庫文件就能實現移植工作了。1:假設你安裝了keil 5.24(稍早點版本支持的os偏少),並且下載了你需要的支持包。
  • 【編程基礎學習教程】Keil(MDK-ARM)介紹、下載、安裝與註冊
    一、前言Keil C51是美國Keil Software公司出品的51系列兼容單片機C語言軟體開發系統,與彙編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。用過彙編語言後再使用C來開發,體會更加深刻。Keil C51軟體提供豐富的庫函數和功能強大的集成開發調試工具,全Windows界面。另外重要的一點,只要看一下編譯後生成的彙編代碼,就能體會到Keil C51生成的目標代碼效率非常之高,多數語句生成的彙編代碼很緊湊,容易理解。在開發大型軟體時更能體現高級語言的優勢。下面詳細介紹Keil C51開發系統各部分功能和使用。
  • 51單片機彙編指令的記憶方法
    想讓單片機按你的意思(想法)完成一項任務,必須先編寫供其使用的程序,編寫單片機的程序應使用該單片機可以識別的「語言」,否則你將是對「石」彈琴。目前較流行的有彙編和C語言;彙編語言可以精確的控制單片機工作的每一步,而C語言則注重結果,不必關心單片機具體的每一步。習慣上宜先學彙編語言後學C語言,這樣可以對單片機有一個更深的了解,再說,就是用C語言編程,在需要精確控制時還需要嵌入彙編語句。
  • 基於STM32的 USB設計 --單片機程序篇
    下面具體從usb的中斷輸入輸出來講述基於keil C mdk開發環境的stm32的USB接口單片機程序設計。值得一提的是,st或相關公司給我們提供許多封裝函數和相關例子,我們可以根據其中的例子並進行修改即可實現我們自己需要的usb通訊程序。
  • Keil uvision C51----51系列兼容單片機C語言軟體開發系統
    軟體簡介:       Keil C51是美國Keil Software公司(ARM公司之一)出品的51系列兼容單片機C語言軟體開發系統。與彙編相比,C語言在功能上、結構性、可讀性、可維護性上有明顯的優勢,因而易學易用。
  • printf()函數重定向到STM32串口輸出
    輸出數字的問題,而STM32的串口輸出的是字符型,最先想到的方法是將整型數據轉換為字符型輸出,C庫函數中提供了相關的函數參考:http://www.cnblogs.com/processakai/archive/2011/06/24/2089348.htmlhttp://c.biancheng.net/cpp/html/1573.htmlC語言中使用
  • STM32編程與51編程一樣嗎?區別是什麼?
    而傳統的8位單片機的性能也得到了飛速提高,處理能力比起80年代提高了數百倍。目前,高端的32位單片機主頻已經超過300MHz,性能直追90年代中期的專用處理器,而普通的型號出廠價格跌落至1美元,最高端的型號也只有10美元。 當代單片機系統已經不再只在裸機環境下開發和使用,大量專用的嵌入式作業系統被廣泛應用在全系列的單片機上。
  • PIC單片機C語言程序實例
    編者按:為了幫助具有PIC單片機彙編語言知識的技術人員或工程師,快速掌握利用C語言編寫PIC單片機程序的方法,本刊特推出《PIC單片機C語言程序設計》系列連載文章。丈中給出的C語言程序實例,均是可執行的,讀者可以放心引用。      一、彙編語言與C語言      早期的單片機程序多採用彙編語言編寫。
  • Keil編譯警告:function "assert_param" declared implicitly的...
    Keil C51的使用(C語言) 實驗目的:初步掌握Keil(C51語言)和SUN ES59PA實驗儀的操作和使用,能夠輸入和運行簡單的程序。這個軟體既可以與硬體(SUN ES59PA實驗儀)連接,在硬體(單片機)上運行程序;也可以不與硬體連接,僅在計算機上以虛擬仿真的方法運行程序。如果程序有對硬體的驅動,就需要與硬體連接;如果沒有硬體動作,僅有軟體操作,就可以使用虛擬仿真。2.
  • 大哥,STM32單片機啟動代碼你不會不知道吧!
    想要深入學習STM32單片機,就必須要去研究STM32單片機的啟動代碼,否則你就無法從整體框架上去了解它,所以STM32啟動代碼早晚都是要研究學習的,避不掉的坑。啟動代碼裡主要是由彙編和偽指令構成的,下面我們從頭到尾來理一遍這些神秘的代碼究竟是什麼含義。
  • 單片機:明明是一門動手實踐課程,卻硬生生學成了理論課
    學習單片機的現狀是:明明是一門動手實踐的課程,卻硬生生學成了理論課。還記得大學學習單片機的時候,老師在講臺上熱情激昂的講著51單片機的彙編指令,卻隻字不提單片機的編程環境,整個學期結束唯一記住的就是110條彙編指令。你肯定理解錯了,這裡記住的其實是數字110,那些指令一條也沒有記住。
  • 回憶當年硬體開發夢:就TM倆字——青澀
    偉福的軟體我認為不怎麼好,只支持彙編,比起大名鼎鼎的keil c51遜了一大截,但除非你想等到自己有問題不會的時候周邊竟沒有人幫助你,不然在前期還是選擇偉福的軟體方便溝通。再後來,經過自己的摸索和向身邊的工程師們請教,偉福用很熟悉了,彙編也有了自己的一套,這時候我開始在偉福裡邊嵌入keil,用c語言來寫程序,但調試的時候用偉福軟體還是有缺陷,比如不能夠單步執行等。
  • 解析單片機中的keil常見問題
    關於reentrant的使用keil的官方論壇上有詳細的討論。  Andy Neil(官方工程師)建議  "Are you sure that you really need to make everything reentrant?...
  • 單片機使用printf函數的兩種辦法
    ①C語言函數:vsprintf,本文引用地址:http://www.eepw.com.cn/article/201611/321829.htm其原型為int vsprintf(char *string, char *format, va_list param);,作用為將param按格式format寫入字符串string中,因此他可以用於將任何格式數據轉化為字符串數據,比如把整數