色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深度:單片機(jī)到底是如何軟硬件結(jié)合的

單片機(jī)與嵌入式 ? 來源:單片機(jī)與嵌入式 ? 2023-07-19 16:26 ? 次閱讀

我們通過IO和串口的軟件開發(fā),已經(jīng)體驗了嵌入式軟件開發(fā)。不知道大家有沒有疑惑,為什么軟件能控制硬件?反正當(dāng)年我學(xué)習(xí)51的時候,有這個疑惑。今天我們就暫停軟件開發(fā),分析單片機(jī)到底是如何軟硬件結(jié)合的。并通過一個基本的程序,分析單片機(jī)程序的編譯,運(yùn)行。

軟硬件結(jié)合

初學(xué)者,通常有一個困惑,就是為什么軟件能控制硬件?就像當(dāng)年的51,為什么只要寫P1=0X55,就可以在IO口輸出高低電平?要理清這個問題,先要認(rèn)識一個概念:地址空間

尋址空間

什么是地址空間呢?所謂的地址空間,就是PC指針的尋址范圍,因此也叫尋址空間。

大家應(yīng)該都知道,我們的電腦有32位系統(tǒng)和64位系統(tǒng)之分,為什么呢?因為32位系統(tǒng),PC指針就是一個32位的二進(jìn)制數(shù),也就是0xffffffff,范圍只有4G尋址空間。現(xiàn)在內(nèi)存越來越大,4G根本不夠,所以需要擴(kuò)展,為了能訪問超出4G范圍的內(nèi)存,就有了64位系統(tǒng)。STM32是多少位的?是32位的,因此PC指針也是32位,尋址空間也就是4G。

我們來看看STM32的尋址空間是怎么樣的。在數(shù)據(jù)手冊《STM32F407_數(shù)據(jù)手冊.pdf》中有一個圖,這個圖,就是STM32的尋址空間分配。所有的芯片,都會有這個圖,名字基本上都是叫Memory map,用一個新芯片,就先看這個圖。

41338c6a-260b-11ee-962d-dac502259ad0.png

  • 最左邊,8個block,每個block 512M,總共就是4G,也就是芯片的尋址空間。

  • block 0 里面有一段叫做FLASH,也就是內(nèi)部FLASH,我們的程序就是下載到這個地方,起始地址是0X800 0000,大家注意,這個只有1M空間。現(xiàn)在STM32已經(jīng)有2M flash的芯片了,超出1M的FLASH放在哪里呢?請自行查看對應(yīng)的芯片手冊。

  • 3 在block 1 內(nèi),有兩段SRAM,總共128K,這個空間,也就是我們前面說的內(nèi)存,存放程序使用的變量。如果需要,也可以把程序放到SRAM中運(yùn)行。407不是有196K嗎?

  • 其實407有196K內(nèi)存,但是有64k并不是普通的SRAM,而是放在block 0 內(nèi)的CCM。這兩段區(qū)域不連續(xù),而且,CCM只能內(nèi)核使用,外設(shè)不能使用,例如DMA就不能用CCM內(nèi)存,否則就死機(jī)。

  • block 2,是Peripherals,也就是外設(shè)空間。我們看右邊,主要就是APB1/APB2、AHB1/AHB2,什么東西呢?回頭再說。

  • block 3、block4、block5,是FSMC的空間,F(xiàn)SMC可以外擴(kuò)SRAM,NAND FALSH,LCD等外設(shè)。

好的,我們分析了尋址空間,我們回過頭看看,軟件是如何控制硬件的。在IO口輸出的例程中,我們配置IO口是調(diào)用庫函數(shù),我們看看庫函數(shù)是怎么做的。

例如:

GPIO_SetBits(GPIOG,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);

這個函數(shù)其實就是對一個變量賦值,對GPIOx這個結(jié)構(gòu)體的成員BSRRL賦值。

voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin)
{
/*Checktheparameters*/
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));

GPIOx->BSRRL=GPIO_Pin;
}

assert_param:這個是斷言,用于判斷輸入參數(shù)是否符合要求GPIOx是一個輸入?yún)?shù),是一個GPIO_TypeDef結(jié)構(gòu)體指針,所以,要用->獲取其成員

GPIOx是我們傳入的參數(shù)GPIOG,具體是啥?在stm32f4xx.h中有定義。

#defineGPIOG((GPIO_TypeDef*)GPIOG_BASE)

GPIOG_BASE同樣在文件中有定義,如下:

#defineGPIOG_BASE(AHB1PERIPH_BASE+0x1800)
AHB1PERIPH_BASE,AHB1地址,有點(diǎn)眉目了吧?在進(jìn)一步看看

/*!#defineAPB1PERIPH_BASEPERIPH_BASE
#defineAPB2PERIPH_BASE(PERIPH_BASE+0x00010000)
#defineAHB1PERIPH_BASE(PERIPH_BASE+0x00020000)
#defineAHB2PERIPH_BASE(PERIPH_BASE+0x10000000)

再找找PERIPH_BASE的定義

#definePERIPH_BASE((uint32_t)0x40000000)

到這里,我們可以看出,操作IO口G,其實就是操作0X40000000+0X1800這個地址上的一個結(jié)構(gòu)體里面的成員。說白了,就是操作了這個地方的寄存器。實質(zhì)跟我們操作普通變量一樣,就像下面的兩句代碼,區(qū)別就是變量i是SRAM空間地址,0X40000000+0X1800是外設(shè)空間地址。

u32i;
i=0x55aa55aa;

這個外設(shè)空間地址的寄存器是IO口硬件的一部分。如下圖,左邊的輸出數(shù)據(jù)寄存器,就是我們操作的寄存器(內(nèi)存、變量),它的地址就是0X40000000+0X1800+0x14.

41967294-260b-11ee-962d-dac502259ad0.png

控制其他外設(shè)也類似,就是將數(shù)據(jù)寫到外設(shè)寄存器上,跟操作內(nèi)存一樣,就可控制外設(shè)了。

寄存器,其實應(yīng)該是內(nèi)存的統(tǒng)稱,外設(shè)寄存器應(yīng)該叫做特殊寄存器。慢慢的,所有人都把外設(shè)的叫做寄存器,其他的統(tǒng)稱內(nèi)存或RAM。寄存器為什么能控制硬件外設(shè)呢?因為,初略的說,一個寄存器的一個BIT,就是一個開關(guān),開就是1,關(guān)就是0。通過這個電子開關(guān)去控制電路,從而控制外設(shè)硬件。

純軟件-包羅萬象的小程序

我們已經(jīng)完成了串口和IO口的控制,但是我們僅僅知道了怎么用,對其他一無所知。程序怎么跑的?代碼到底放在那里?內(nèi)存又是怎么保存的?下面,我們通過一個簡單的程序,學(xué)習(xí)嵌入式軟件的基本要素。

分析啟動代碼

  • 函數(shù)從哪里開始運(yùn)行?

每個芯片都有復(fù)位功能,復(fù)位后,芯片的PC指針(一個寄存器,指示程序運(yùn)行位置,對于多級流水線的芯片,PC可能跟真正執(zhí)行的指令位置不一致,這里暫且認(rèn)為一致)會復(fù)位到固定值,一般是0x00000000,在STM32中,復(fù)位到0X08000004。因此復(fù)位后運(yùn)行的第一條代碼就是0X08000004。前面我們不是拷貝了一個啟動代碼文件到工程嗎?startup_stm32f40_41xxx.s,這個匯編文件為什么叫啟動代碼?因為里面的匯編程序,就是復(fù)位之后執(zhí)行的程序。在文件中,有一段數(shù)據(jù)表,稱為中斷向量,里面保存了各個中斷的執(zhí)行地址復(fù)位,也是一個中斷。

芯片復(fù)位時,芯片從中斷表中將Reset_Handler這個值(函數(shù)指針)加載到PC指針,芯片就會執(zhí)行Reset_Handler函數(shù)了。(一個函數(shù)入口就是一個指針

;VectorTableMappedtoAddress0atReset
AREARESET,DATA,READONLY
EXPORT__Vectors
EXPORT__Vectors_End
EXPORT__Vectors_Size

__VectorsDCD__initial_sp;TopofStack
DCDReset_Handler;ResetHandler
DCDNMI_Handler;NMIHandler
DCDHardFault_Handler;HardFaultHandler
DCDMemManage_Handler;MPUFaultHandler
DCDBusFault_Handler;BusFaultHandler
DCDUsageFault_Handler;UsageFaultHandler

Reset_Handler函數(shù),先執(zhí)行SystemInit函數(shù),這個函數(shù)在標(biāo)準(zhǔn)庫內(nèi),主要是初始芯片時鐘。然后跳到__main執(zhí)行,__main函數(shù)是什么函數(shù)?

是我們在main.c中定義的main函數(shù)嗎?后面我們再說這個問題。

;Resethandler
Reset_HandlerPROC
EXPORTReset_Handler[WEAK]
IMPORTSystemInit
IMPORT__main

LDRR0,=SystemInit
BLXR0
LDRR0,=__main
BXR0
ENDP

芯片是怎么知道開始就執(zhí)行啟動代碼的呢?或者說,我們?nèi)绾伟堰@個啟動代碼放到復(fù)位的位置?這就牽涉到一個一般情況下不關(guān)注的文件wujique.sct,這個文件在wujiqueprjObjects目錄下,通常把這個文件叫做分散加載文件,編譯工具在鏈接時,根據(jù)這個文件放置各個代碼段和變量。

在MDK軟件Options菜單Linker下有關(guān)于這個菜單的設(shè)置。

4211315a-260b-11ee-962d-dac502259ad0.png

把Use Memory Layout from Target Dialog前面的勾去掉,之前不可設(shè)置的框都可以設(shè)置了。點(diǎn)擊Edit進(jìn)行編輯。

425fd8dc-260b-11ee-962d-dac502259ad0.png

在代碼編輯框出現(xiàn)了分散加載文件內(nèi)容,當(dāng)前文件只有基本的內(nèi)容。

其實這個文件功能很強(qiáng)大,通過修改這個文件可以配置程序的很多功能,例如:1 指定FLASH跟RAM的大小于起始位置,當(dāng)我們把程序分成BOOT、CORE、APP,甚至進(jìn)行驅(qū)動分離的時候,就可以用上了。2 指定函數(shù)與變量的位置,例如把函數(shù)加載到RAM中運(yùn)行。

429c38e0-260b-11ee-962d-dac502259ad0.png

從這個基本的分散加載文件我們可以看出:

  • 第6行 ER_IROM1 0x08000000 0x00080000定義了ER_IROM1,也就是我們說的內(nèi)部FLASH,從0x08000000開始,大小0x00080000。

  • 第7行.o (RESET, +First)從0x08000000開始,先放置一個.o文件, 并且用(RESET, +First)指定RESET塊優(yōu)先放置,RESET塊是什么?請查看啟動代碼,中斷向量就是一個AREA,名字叫RESET,屬于READONLY。這樣編譯后,RESET塊將放在0x08000000位置,也就是說,中斷向量就放在這個地方。DCD是分配空間,4字節(jié),第一個就是__initial_sp,第二個就是Reset_Handler函數(shù)指針。也就是說,最后編譯后的程序,將Reset_Handler這個函數(shù)的指針(地址),放在0x800000+4的地方。所以芯片在復(fù)位的時候,就能找到復(fù)位函數(shù)Reset_Handler。

  • 第8行 *(InRoot$$Sections)什么鬼?GOOGLE啊!回頭再說。

  • 第9行 .ANY (+RO)意思就是其他的所有RO,順序往后放。就是說,其他代碼,跟著啟動代碼后面。

  • 第11行 RW_IRAM1 0x20000000 0x00020000定義了RAM大小。

  • 第12行 .ANY (+RW +ZI)所有的RW ZI,全部放到RAM里面。RW,ZI,也就是變量,這一行指定了變量保存到什么地址。

分析用戶代碼

到此,基本啟動過程已經(jīng)分析完。下一步開始分析用戶代碼,就從main函數(shù)開始。1 程序跳轉(zhuǎn)到main函數(shù)后:RCC_GetClocksFreq獲取RCC時鐘頻率;SysTick_Config配置SysTick,在這里打開了SysTick中斷,10毫秒一次。

Delay(5);延時50毫秒。

intmain(void)
{
GPIO_InitTypeDefGPIO_InitStructure;

/*!

/*SysTickendofcounteventeach10ms*/
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency/100);

/*Addyourapplicationcodehere*/
/*Insert50msdelay*/
Delay(5);

2 初始化IO就不說了,進(jìn)入while(1),也就是一個死循環(huán),嵌入式程序,都是一個死循環(huán),否則就跑飛了。

/*初始化LEDIO口*/
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE);

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_Init(GPIOG,&GPIO_InitStructure);

/*Infiniteloop*/
mcu_uart_open(3);
while(1)
{
GPIO_ResetBits(GPIOG,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
Delay(100);
GPIO_SetBits(GPIOG,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
Delay(100);
mcu_uart_test();

TestFun(TestTmp2);
}

3 在while(1)中調(diào)用TestFun函數(shù),這個函數(shù)使用兩個全局變量,兩個局部變量。

/*Privatefunctions---------------------------------------------------------*/
u32TestTmp1=5;//全局變量,初始化為5
u32TestTmp2;//全局變量,未初始化

constu32TestTmp3[10]={6,7,8,9,10,11,12,13,12,13};

u8TestFun(u32x)//函數(shù),帶一個參數(shù),并返回一個u8值
{
u8test_tmp1=4;//局部變量,初始化
u8test_tmp2;//局部變量,未初始化

staticu8test_tmp3=0;//靜態(tài)局部變量

test_tmp3++;

test_tmp2=x;

if(test_tmp2>TestTmp1)
test_tmp1=10;
else
test_tmp1=5;

TestTmp2+=TestTmp3[test_tmp1];

returntest_tmp1;
}

然后程序就一直在main函數(shù)的while循環(huán)里面執(zhí)行。中斷呢?對,還有中斷。中斷中斷,就是中斷正常的程序執(zhí)行流程。我們查看Delay函數(shù),uwTimingDelay不等于0就死等?誰會將uwTimingDelay改為0?

/**
*@briefInsertsadelaytime.
*@paramnTime:specifiesthedelaytimelength,inmilliseconds.
*@retvalNone
*/
voidDelay(__IOuint32_tnTime)
{
uwTimingDelay=nTime;

while(uwTimingDelay!=0);
}

搜索uwTimingDelay變量,函數(shù)TimingDelay_Decrement會將變量一直減到0。

/**
*@briefDecrementstheTimingDelayvariable.
*@paramNone
*@retvalNone
*/
voidTimingDelay_Decrement(void)
{
if(uwTimingDelay!=0x00)
{
uwTimingDelay--;
}
}

這個函數(shù)在哪里執(zhí)行?經(jīng)查找,在SysTick_Handler函數(shù)中運(yùn)行。誰用這個函數(shù)?

/**
*@briefThisfunctionhandlesSysTickHandler.
*@paramNone
*@retvalNone
*/
voidSysTick_Handler(void)
{
TimingDelay_Decrement();
}

經(jīng)查找,在中斷向量表中有這個函數(shù),也即是說這個函數(shù)指針保存在中斷向量表內(nèi)。當(dāng)發(fā)生中斷時,就會執(zhí)行這個函數(shù)。當(dāng)然,在進(jìn)出中斷會有保存和恢復(fù)現(xiàn)場的操作。這個主要涉及到匯編,暫時不進(jìn)行分析了。有興趣自己研究研究。通常,現(xiàn)在我們開發(fā)程序不用關(guān)心上下文切換了。

__VectorsDCD__initial_sp;TopofStack
DCDReset_Handler;ResetHandler
DCDNMI_Handler;NMIHandler
DCDHardFault_Handler;HardFaultHandler
DCDMemManage_Handler;MPUFaultHandler
DCDBusFault_Handler;BusFaultHandler
DCDUsageFault_Handler;UsageFaultHandler
DCD0;Reserved
DCD0;Reserved
DCD0;Reserved
DCD0;Reserved
DCDSVC_Handler;SVCallHandler
DCDDebugMon_Handler;DebugMonitorHandler
DCD0;Reserved
DCDPendSV_Handler;PendSVHandler
DCDSysTick_Handler;SysTickHandler

余下問題

1 __main函數(shù)是什么函數(shù)?是我們在main.c中定義的main函數(shù)嗎?2 分散加載文件中*(InRoot$$Sections)是什么?3 ZI段,也就是初始化為0的數(shù)據(jù)段,什么時候初始化?誰初始化?

為什么這幾個問題前面留著不說?因為這是同一個問題。順藤摸瓜!

通過MAP文件了解代碼構(gòu)成

編譯結(jié)果

程序編譯后,在下方的Build Output窗口會輸出信息

***UsingCompiler'V5.06update5(build528)',folder:'C:Keil_v5ARMARMCCBin'
Buildtarget'wujique'
compilingstm32f4xx_it.c...
...
assemblingstartup_stm32f40_41xxx.s...
compilingmisc.c...
...
compilingmcu_uart.c...
linking...
ProgramSize:Code=9038RO-data=990RW-data=40ZI-data=6000
FromELF:creatinghexfile...
".Objectswujique.axf"-0Error(s),0Warning(s).
BuildTimeElapsed:00:00:32
  • 編譯目標(biāo)是wujique
  • C文件compiling,匯編文件assembling,這個過程叫編譯
  • 編譯結(jié)束后,就進(jìn)行l(wèi)ink,鏈接。
  • 最后得到一個編譯結(jié)果,9038字節(jié)code,RO 990,RW 40,ZI 6000。CODE,是代碼,很好理解,那RO、RW、ZI都是什么?
  • FromELF,創(chuàng)建hex文件,F(xiàn)romELF是一個好工具,需要自己添加到option中才能用

map文件配置

更多編譯具體信息在map文件中,在MDK Options中我們可以看到,所有信息都放在Listingswujique.map

默認(rèn)很多編譯信息可能沒鉤,鉤上所有信息會增加編譯時間。

42d5b688-260b-11ee-962d-dac502259ad0.png

map文件

打開map文件,好亂?習(xí)慣就好。我們抓重點(diǎn)就行了。

43373c32-260b-11ee-962d-dac502259ad0.png

  • map 總信息

從最后看起,看到?jīng)]?最后的這一段map內(nèi)容,說明了整個程序的基本概況。

有多少RO?RO到底是什么?

有多少RW?RW又是什么?

ROM為什么不包括ZI Data?為什么包含RW Data?

437d001e-260b-11ee-962d-dac502259ad0.png

  • Image component sizes

往上,看看Image component sizes,這個就比剛剛的總體統(tǒng)計更細(xì)了。

這部分內(nèi)容,說明了每個源文件的概況

首先,是我們自己的源碼,這個程序我們的代碼不多,只有main.o,wujique_log.o,和其他一些STM32的庫文件。

43a226b4-260b-11ee-962d-dac502259ad0.png

第2部分是庫里面的文件,看到?jīng)]?里面有一個main.o。main函數(shù)是不是我們寫的main函數(shù)?明顯不是,我們的main函數(shù)是放在main.o文件。這么小的一個工程,用了這么多庫,你以前關(guān)注過嗎?估計沒有,除非你曾經(jīng)將一個原本在1M flash上的程序壓縮到能在512K上運(yùn)行。

43cc0de4-260b-11ee-962d-dac502259ad0.png

第3部分也是庫,暫時沒去分析這兩個是什么東西。

43f17ebc-260b-11ee-962d-dac502259ad0.png

庫文件是什么?庫文件就是別人已經(jīng)別寫好的代碼庫。在代碼中,我們經(jīng)常會包含一些頭文件,例如:

#include 
#include 
#include  

這些就是庫的頭文件。這些頭文件保存在MDK開發(fā)工具的安裝目錄下。我們經(jīng)常用的庫函數(shù)有:memcpy、memcmp、strcmp等。只要代碼中包含了這些函數(shù),就會鏈接庫文件。

  • 文件map

再往上,就是文件MAP了,也就時每個文件中的代碼段(函數(shù))跟變量在ROM跟RAM中的位置首先是ROM在0x08000000確實放的是startup_stm32f40_41xxx.o中的RESET

庫文件是什么?

庫文件就是別人已經(jīng)別寫好的代碼庫。

在代碼中,我們經(jīng)常會包含一些頭文件,例如:

#include
#include
#include

這些就是庫的頭文件。這些頭文件保存在MDK開發(fā)工具的安裝目錄下。

我們經(jīng)常用的庫函數(shù)有:

memcpy、memcmp、strcmp等。

只要代碼中包含了這些函數(shù),就會鏈接庫文件。

  • 文件map

再往上,就是文件MAP了,也就時每個文件中的代碼段(函數(shù))跟變量在ROM跟RAM中的位置。首先是ROM在0x08000000確實放的是startup_stm32f40_41xxx.o中的RESET

441f7f56-260b-11ee-962d-dac502259ad0.png

每個文件有有多行,例如串口,4個函數(shù)。

444920b8-260b-11ee-962d-dac502259ad0.png

然后是RAM的,main.o中的變量,放在0x20000000,總共有0x0000000c,類型是Data、RW。串口有兩種變量,data和bss,什么是bss?這兩個名稱,是section name,也就是段的意思。看前面type和Attr,

RW Data,放在.data段;RW Zero放在.bss段,RW Zero,其實就是ZI到底哪些變量是RW,哪些是ZI?

44733308-260b-11ee-962d-dac502259ad0.png

  • Image Symbol Table

再往上就是Image Symbol Table,就更進(jìn)一步到每個函數(shù)或者變量的信息了

44a12650-260b-11ee-962d-dac502259ad0.png

例如,全局變量TestTmp1,是Data,4字節(jié),分配的位置是0x20000004。

44d24078-260b-11ee-962d-dac502259ad0.png

TestTmp3數(shù)組放在哪里?放在0X080024E0這個地方,這可是代碼區(qū)額。因為我們用const修飾了這個全局變量數(shù)組,告訴編譯器,這個數(shù)組是不可以改變的,編譯器就將這個數(shù)組保存到代碼中了。程序中我們經(jīng)常會使用一些大數(shù)組數(shù)據(jù),例如字符點(diǎn)陣,通常有幾K幾十K大,不可能也沒必要放到RAM區(qū),整個程序運(yùn)行過程這些數(shù)據(jù)都不改變,因此通過const修飾,將其存放到代碼區(qū)。

const的用處比較多,可以修飾變量,也可以修飾函數(shù)。更多用法自行學(xué)習(xí)

44ebef8c-260b-11ee-962d-dac502259ad0.png

那局部變量存放在哪里呢?我們找到了test_tmp3,

451635f8-260b-11ee-962d-dac502259ad0.png

沒找到test_tmp1/test_tmp2,為什么呢?在定義時,test_tmp3增加了static定義,意思就是靜態(tài)局部變量,功能上,相當(dāng)于全局變量,定義在函數(shù)內(nèi),限制了這個全局變量只能在這個函數(shù)內(nèi)使用。哪test_tmp1、test_tmp2放在哪里呢?局部變量,在編譯鏈接時,并沒有分配空間,只有在運(yùn)行時,才從棧分配空間。

u8TestFun(u32x)//函數(shù),帶一個參數(shù),并返回一個u8值
{
u8test_tmp1=4;//局部變量,初始化
u8test_tmp2;//局部變量,未初始化

staticu8test_tmp3=0;//靜態(tài)局部變量

上一部分,我們留了一個問題,哪些變量是RW,哪些是ZI?我們看看串口變量的情況,UartBuf3放在bss段,其他變量放在.data段。為什么數(shù)組就放在bss?bss是英文Block Started by Symbol的簡稱。

453c1714-260b-11ee-962d-dac502259ad0.png

到這里,我們可解釋下面幾個概念了:

Code就是代碼,函數(shù)。

RO Data,就是只讀變量,例如用const修飾的數(shù)組。

RW Data,就是讀寫變量,例如全局變量跟static修飾的局部變量。

ZI Data,就是系統(tǒng)自動初始化為0的讀寫變量,大部分是數(shù)組,放在bss段。

RO Size等于代碼加只讀變量。

RW Size等于讀寫變量(包括自動初始化為0的),這個也就是RAM的大小。

ROM Size,也就是我們編譯之后的目標(biāo)文件大小,也就是FLASH的大小。但是?為什么會包含RW Data呢?因為所有全局變量都需要一個初始化的值(就算沒有真正初始化,系統(tǒng)也會分配一個初始化空間),例如我們定義一個變量u8 i = 8;這樣的全局變量,8,這個值,就需要保存在FALSH區(qū)。

45656d3a-260b-11ee-962d-dac502259ad0.png

我們看看函數(shù)的情況,前面我們不是有一個問題嗎?__main和main是一個函數(shù)嗎?查找main后發(fā)現(xiàn),main是main,放在0x08000579

45912ea2-260b-11ee-962d-dac502259ad0.png

main是main,放在0x08000189

45ba1772-260b-11ee-962d-dac502259ad0.png

__main到main之間發(fā)生了什么?還記得分散加載文件中的這句嗎?

*(InRoot$$Sections)

__main就在這個段內(nèi)。下圖是__main的地址,在0x08000189。__Vectors就是中斷向量,放在最開始。

45fc2676-260b-11ee-962d-dac502259ad0.png

在分散加載文件中,緊跟RESET的就是*(InRoot$$Sections)。

4621707a-260b-11ee-962d-dac502259ad0.png

而且,RESET段正好大小0x00000188。

46665a0a-260b-11ee-962d-dac502259ad0.png

巧合?參考PPT文檔《ARM嵌入式軟件開發(fā).ppt》,或自行GOOGLE。

46b98e5a-260b-11ee-962d-dac502259ad0.png

這一段代碼都完成什么功能呢?主要完成ZI代碼的初始化,也就是將一部分RAM初始化為0。其他環(huán)境初始化,通常,我們不用管這一部分。

  • 其他再往上,就是其他信息了,例如優(yōu)化了哪些東西,移除了哪些函數(shù)。

最后

到這里,一個程序,是怎么組成的,程序是如何運(yùn)行的,基本有一個總體印象了。不過,對于中斷,后面還會進(jìn)行詳細(xì)說明。


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6040

    文章

    44604

    瀏覽量

    637100
  • 二進(jìn)制
    +關(guān)注

    關(guān)注

    2

    文章

    795

    瀏覽量

    41707
  • STM32
    +關(guān)注

    關(guān)注

    2270

    文章

    10918

    瀏覽量

    356843

原文標(biāo)題:深度:單片機(jī)到底是如何軟硬件結(jié)合的

文章出處:【微信號:單片機(jī)與嵌入式,微信公眾號:單片機(jī)與嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    兆芯CPU近期軟硬件適配動態(tài)

    近期,兆芯攜手多家軟硬件合作伙伴,基于開先KX-7000、開勝KH-40000等自主CPU和信創(chuàng)操作系統(tǒng)環(huán)境,持續(xù)推進(jìn)應(yīng)用生態(tài)建設(shè)工作,順利完成醫(yī)療自主終端、商用收款機(jī)、服務(wù)器操作系統(tǒng)、數(shù)據(jù)庫管理
    的頭像 發(fā)表于 01-15 15:33 ?112次閱讀

    恩智浦電機(jī)控制軟硬件解決方案

    。因此,設(shè)計一套結(jié)合軟硬件的高效電機(jī)控制解決方案,不僅能降低能耗,還能實現(xiàn)精準(zhǔn)控制,滿足多樣化應(yīng)用需求。本文將介紹電機(jī)控制技術(shù)的發(fā)展趨勢,以及NXP(恩智浦)與艾睿電子在電機(jī)控制技術(shù)上的優(yōu)勢與解決方案。
    的頭像 發(fā)表于 01-15 10:12 ?428次閱讀
    恩智浦電機(jī)控制<b class='flag-5'>軟硬件</b>解決方案

    用LDC1000EVM接單片機(jī)單片機(jī)PWM輸出6MHZ的方波給LDCLK,為什么寄存器讀不到數(shù)據(jù)?

    你們好,我用LDC1000EVM的芯片和線圈那部分接飛思卡爾的單片機(jī)單片機(jī)PWM輸出6MHZ的方波給LDCLK,SPI給的SCK是4M及100K都嘗試過,寫寄存器SDI線上可以量到正確的波形
    發(fā)表于 12-11 07:59

    星融元與焱融科技AI分布式存儲軟硬件完成兼容性互認(rèn)證

    星融元與焱融科技AI分布式存儲軟硬件完成兼容性互認(rèn)證
    的頭像 發(fā)表于 11-20 16:36 ?196次閱讀
    星融元與焱融科技AI分布式存儲<b class='flag-5'>軟硬件</b>完成兼容性互認(rèn)證

    研華產(chǎn)品通過統(tǒng)信及兆芯通用軟硬件適配互認(rèn)測試

    近日,研華自主研發(fā)的iEMS智慧能源、iMachine設(shè)備云智聯(lián)以及InsightAPM軟件通過了統(tǒng)信及兆芯通用軟硬件適配互認(rèn)測試,順利取得了“通用軟硬件適配認(rèn)證中心”聯(lián)合認(rèn)證證書。這不僅對研華產(chǎn)品性能與兼容性給與認(rèn)可,更是對其在國產(chǎn)化道路上給與了重要肯定。
    的頭像 發(fā)表于 09-14 17:58 ?1189次閱讀

    國產(chǎn)精密信號鏈產(chǎn)品完整解決方案,軟硬件兼容TI和ADI

    國產(chǎn)精密信號鏈產(chǎn)品完整解決方案,軟硬件兼容TI和ADI
    的頭像 發(fā)表于 08-19 09:58 ?544次閱讀
    國產(chǎn)精密信號鏈產(chǎn)品完整解決方案,<b class='flag-5'>軟硬件</b>兼容TI和ADI

    用于多路信號采集的國產(chǎn)模數(shù)轉(zhuǎn)換器,軟硬件兼容ADS1220

    用于多路信號采集的國產(chǎn)模數(shù)轉(zhuǎn)換器,軟硬件兼容ADS1220
    的頭像 發(fā)表于 06-24 09:58 ?490次閱讀
    用于多路信號采集的國產(chǎn)模數(shù)轉(zhuǎn)換器,<b class='flag-5'>軟硬件</b>兼容ADS1220

    機(jī)器視覺系統(tǒng)讀取二維碼-軟硬件配置方案

    機(jī)器視覺系統(tǒng)讀取二維碼-軟硬件配置方案
    的頭像 發(fā)表于 05-24 00:56 ?666次閱讀
    機(jī)器視覺系統(tǒng)讀取二維碼-<b class='flag-5'>軟硬件</b>配置方案

    嵌入式系統(tǒng)軟硬件基礎(chǔ)知識大全

    制約的,只有硬件和軟件協(xié)同工作,才能使嵌入式系統(tǒng)正常運(yùn)行。本文將從嵌入式系統(tǒng)的定義和特點(diǎn)出發(fā),詳細(xì)介紹其硬件和軟件的組成,并通過實例分析,深入剖析嵌入式系統(tǒng)的工作原理和應(yīng)用場景。通過對嵌入式系統(tǒng)軟硬件
    發(fā)表于 05-09 14:12

    mpu6050芯片的INT中斷信號引腳和單片機(jī)之間需要接電阻嗎?

    mpu6050芯片的INT中斷信號引腳和單片機(jī)之間需要接電阻嗎? 我見有的電路圖里面沒有接,有的卻說需要接,到底是怎樣的?
    發(fā)表于 05-07 07:21

    磐啟XNS1042軟硬件資料

    電子發(fā)燒友網(wǎng)站提供《磐啟XNS1042軟硬件資料.zip》資料免費(fèi)下載
    發(fā)表于 05-06 10:35 ?6次下載

    上線啦!深蕾半導(dǎo)體開發(fā)者中心:VS680 SoC芯片軟硬件資料、演示方案# #人工智能 #智慧能源

    人工智能軟硬件
    深蕾半導(dǎo)體
    發(fā)布于 :2024年04月17日 12:05:18

    共享單車到底是什么通信原理

    我們經(jīng)常騎的共享單車到底是什么通信原理,有人了解過嗎? 一、智能車鎖 共享單車最核心的硬件是智能車鎖,主要用于實現(xiàn)控制和定位功能。
    發(fā)表于 04-09 10:33 ?889次閱讀
    共享單車<b class='flag-5'>到底是</b>什么通信原理

    電池管理系統(tǒng)(BMS)軟硬件介紹

    電子發(fā)燒友網(wǎng)站提供《電池管理系統(tǒng)(BMS)軟硬件介紹.pdf》資料免費(fèi)下載
    發(fā)表于 03-27 09:20 ?9次下載
    主站蜘蛛池模板: 欧洲video60| 亚洲qingse中文字幕久久| 男人J桶进男人屁股过程| 蜜桃视频一区二区| 免费无码国产欧美久久18| 免费鲁丝片一级在线观看| 欧洲电影巜肉欲丛林| 少妇内射兰兰久久| 国产AV电影区二区三区曰曰骚网| 出轨的妻子在线观看| 国产高清视频免费在线观看| 国产午夜精品理论片免费观看 | 欧美色妞AV重囗味视频| 日日干夜夜啪蕉视频| 新版孕妇bbwbbwbbw| 亚洲一区自拍高清亚洲精品| 色小姐.com| 亚洲精品国产拍在线观看| 中文在线观看永久免费| a视频在线看| 国产白浆视频在线播放| 狠狠撸亚洲视频| 男人到天堂a在538线| 伦理在线影院伦理电影 | h片下载地址| 国产精品一国产AV麻豆| 久久草这里全是精品香蕉频线观| 暖暖 免费 高清 日本 在线| 特级淫片大乳女子高清视频| 一本道手机无码在线看| couo福利姬图库| 国产香蕉视频在线播放| 曼谷av女郎| 挺进老师的紧窄小肉六电影完整版 | 综合色中色| 动漫美女喷水| 九九免费高清在线观看视频| 青青娱乐网| 野花日本免费完整版高清版动漫| jizzjizz丝袜| 簧片在线观看|