<kbd id="sapis"><rt id="sapis"><var id="sapis"></var></rt></kbd>
    <tbody id="sapis"><noscript id="sapis"></noscript></tbody>
    1. <button id="sapis"><object id="sapis"></object></button>
      1. <rp id="sapis"></rp>

        0
        • 聊天消息
        • 系統消息
        • 評論與回復
        登錄后你可以
        • 下載海量資料
        • 學習在線課程
        • 觀看技術視頻
        • 寫文章/發帖/加入社區
        創作中心

        完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

        3天內不再提示

        單片機是怎么做到軟硬件結合的

        云腦智庫 ? 來源:嵌入式學習站 ? 作者:嵌入式學習站 ? 2023-01-17 15:25 ? 次閱讀

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

        軟硬件結合

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

        尋址空間

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

        大家應該都知道,我們的電腦有32位系統和64位系統之分,為什么呢?因為32位系統,PC指針就是一個32位的二進制數,也就是0xffffffff,范圍只有4G尋址空間?,F在內存越來越大,4G根本不夠,所以需要擴展,為了能訪問超出4G范圍的內存,就有了64位系統。STM32是多少位的?是32位的,因此PC指針也是32位,尋址空間也就是4G。

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

        f2bd54fe-8de3-11ed-bfe3-dac502259ad0.png

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

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

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

        其實407有196K內存,但是有64k并不是普通的SRAM,而是放在block 0 內的CCM。這兩段區域不連續,而且,CCM只能內核使用,外設不能使用,例如DMA就不能用CCM內存,否則就死機。

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

        block 3、block4、block5,是FSMC的空間,FSMC可以外擴SRAM,NAND FALSH,LCD等外設。

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

        例如:

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

        這個函數其實就是對一個變量賦值,對GPIOx這個結構體的成員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:這個是斷言,用于判斷輸入參數是否符合要求GPIOx是一個輸入參數,是一個GPIO_TypeDef結構體指針,所以,要用->獲取其成員

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

        #defineGPIOG((GPIO_TypeDef*)GPIOG_BASE)
        

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

        #defineGPIOG_BASE(AHB1PERIPH_BASE+0x1800)
        AHB1PERIPH_BASE,AHB1地址,有點眉目了吧?在進一步看看
        
        /*!
        

        再找找PERIPH_BASE的定義

        #definePERIPH_BASE((uint32_t)0x40000000)

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

        u32i;
        i=0x55aa55aa;

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

        f2ef1ee4-8de3-11ed-bfe3-dac502259ad0.png

        控制其他外設也類似,就是將數據寫到外設寄存器上,跟操作內存一樣,就可控制外設了。

        寄存器,其實應該是內存的統稱,外設寄存器應該叫做特殊寄存器。慢慢的,所有人都把外設的叫做寄存器,其他的統稱內存或RAM。寄存器為什么能控制硬件外設呢?因為,粗略的說,一個寄存器的一個BIT,就是一個開關,開就是1,關就是0。通過這個電子開關去控制電路,從而控制外設硬件。

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

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

        分析啟動代碼

        函數從哪里開始運行?

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

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

        ;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函數,先執行SystemInit函數,這個函數在標準庫內,主要是初始芯片時鐘。然后跳到__main執行,__main函數是什么函數?

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

        ;Resethandler
        Reset_HandlerPROC
        EXPORTReset_Handler[WEAK]
        IMPORTSystemInit
        IMPORT__main
        
        LDRR0,=SystemInit
        BLXR0
        LDRR0,=__main
        BXR0
        ENDP
        

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

        在MDK軟件Options菜單Linker下有關于這個菜單的設置。

        f30c9eb0-8de3-11ed-bfe3-dac502259ad0.png

        把Use Memory Layout from Target Dialog前面的勾去掉,之前不可設置的框都可以設置了。點擊Edit進行編輯。

        f32d09c0-8de3-11ed-bfe3-dac502259ad0.png

        在代碼編輯框出現了分散加載文件內容,當前文件只有基本的內容。

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

        f33eb706-8de3-11ed-bfe3-dac502259ad0.png

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

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

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

        分析用戶代碼

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

        Delay(5);延時50毫秒。

        intmain(void)
        {
        GPIO_InitTypeDefGPIO_InitStructure;
        
        /*!
        

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

        /*初始化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)中調用TestFun函數,這個函數使用兩個全局變量,兩個局部變量。

        /*Privatefunctions---------------------------------------------------------*/
        u32TestTmp1=5;//全局變量,初始化為5
        u32TestTmp2;//全局變量,未初始化
        
        constu32TestTmp3[10]={6,7,8,9,10,11,12,13,12,13};
        
        u8TestFun(u32x)//函數,帶一個參數,并返回一個u8值
        {
        u8test_tmp1=4;//局部變量,初始化
        u8test_tmp2;//局部變量,未初始化
        
        staticu8test_tmp3=0;//靜態局部變量
        
        test_tmp3++;
        
        test_tmp2=x;
        
        if(test_tmp2>TestTmp1)
        test_tmp1=10;
        else
        test_tmp1=5;
        
        TestTmp2+=TestTmp3[test_tmp1];
        
        returntest_tmp1;
        }
        
        

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

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

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

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

        這個函數在哪里執行?經查找,在SysTick_Handler函數中運行。誰用這個函數?

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

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

        __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函數是什么函數?是我們在main.c中定義的main函數嗎?2 分散加載文件中*(InRoot$$Sections)是什么?3 ZI段,也就是初始化為0的數據段,什么時候初始化?誰初始化?

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

        通過MAP文件了解代碼構成

        編譯結果

        程序編譯后,在下方的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
        

        編譯目標是wujique

        C文件compiling,匯編文件assembling,這個過程叫編譯

        編譯結束后,就進行link,鏈接。

        最后得到一個編譯結果,9038字節code,RO 990,RW 40,ZI 6000。CODE,是代碼,很好理解,那RO、RW、ZI都是什么?

        FromELF,創建hex文件,FromELF是一個好工具,需要自己添加到option中才能用

        map文件配置

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

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

        f35ff376-8de3-11ed-bfe3-dac502259ad0.png

        map文件

        打開map文件,好亂?習慣就好。我們抓重點就行了。

        f3841c88-8de3-11ed-bfe3-dac502259ad0.png

        map 總信息

        從最后看起,看到沒?最后的這一段map內容,說明了整個程序的基本概況。

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

        有多少RW?RW又是什么?

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

        f3a1efd8-8de3-11ed-bfe3-dac502259ad0.png

        Image component sizes

        往上,看看Image component sizes,這個就比剛剛的總體統計更細了。

        這部分內容,說明了每個源文件的概況

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

        f3b394d6-8de3-11ed-bfe3-dac502259ad0.png

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

        f3bed8dc-8de3-11ed-bfe3-dac502259ad0.png

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

        f3d37a6c-8de3-11ed-bfe3-dac502259ad0.png

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

        #include 
        #include 
        #include  

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

        文件map

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

        庫文件是什么?

        庫文件就是別人已經別寫好的代碼庫。

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

        #include
        #include
        #include
        

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

        我們經常用的庫函數有:

        memcpy、memcmp、strcmp等。
        

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

        文件map

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

        f3e2463c-8de3-11ed-bfe3-dac502259ad0.png

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

        f3f14e0c-8de3-11ed-bfe3-dac502259ad0.png

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

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

        f3fe79ec-8de3-11ed-bfe3-dac502259ad0.png

        Image Symbol Table

        再往上就是Image Symbol Table,就更進一步到每個函數或者變量的信息了

        f40a4682-8de3-11ed-bfe3-dac502259ad0.png

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

        f41caa8e-8de3-11ed-bfe3-dac502259ad0.png

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

        const的用處比較多,可以修飾變量,也可以修飾函數。更多用法自行學習

        f43c0f82-8de3-11ed-bfe3-dac502259ad0.png

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

        f44c4104-8de3-11ed-bfe3-dac502259ad0.png

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

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

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

        f461d9a6-8de3-11ed-bfe3-dac502259ad0.png

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

        Code就是代碼,函數。

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

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

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

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

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

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

        f4737aee-8de3-11ed-bfe3-dac502259ad0.png

        我們看看函數的情況,前面我們不是有一個問題嗎?__main和main是一個函數嗎?查找main后發現,main是main,放在0x08000579

        f480abd8-8de3-11ed-bfe3-dac502259ad0.png

        main是main,放在0x08000189

        f4910b9a-8de3-11ed-bfe3-dac502259ad0.png

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

        *(InRoot$$Sections)
        

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

        f4a3be70-8de3-11ed-bfe3-dac502259ad0.png

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

        f4afa870-8de3-11ed-bfe3-dac502259ad0.png

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

        f4d19264-8de3-11ed-bfe3-dac502259ad0.png

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

        f4e26e4a-8de3-11ed-bfe3-dac502259ad0.png

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

        其他再往上,就是其他信息了,例如優化了哪些東西,移除了哪些函數。

        最后

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

        編輯:何安

        聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
        • 單片機
          +關注

          關注

          5945

          文章

          42596

          瀏覽量

          614837
        • 軟件
          +關注

          關注

          65

          文章

          4058

          瀏覽量

          84247
        • 程序
          +關注

          關注

          112

          文章

          3342

          瀏覽量

          78684
        • 代碼
          +關注

          關注

          29

          文章

          4074

          瀏覽量

          65681
        • 編譯
          +關注

          關注

          0

          文章

          547

          瀏覽量

          31750
        收藏 人收藏

          評論

          相關推薦

          AVR單片機軟硬件設計教程入門篇

          單片機軟硬件設計教程入門篇單片機就是一臺微型電腦。麻雀雖小,五臟俱全,單片機將微型電腦的所有基本部分都集成在一片硅片上。構成單片機的基本要素:CPU核,ROM,RAM,片上外設,總線&nbsp;[hide]AVR單片機軟硬件設計教程.rar[/hi
          發表于 12-09 15:22

          承接單片機軟硬件開發

          單片機軟硬件方案,主營無線產品開發(GPRS,315-433M,2.4G發射接收,WIFI,ZIGBEE,藍牙),臺燈和吸頂燈燈控,工控,汽車電子,智能家居??商峁?b>硬件設計和軟件開發。歡迎大家咨詢,有需要的請聯系,范先生QQ1054467185,在深圳
          發表于 09-10 11:55

          承接各種單片機系統的軟硬件開發項目,以及單片機反匯編項目

          單片機軟硬件開發經驗,精通C/C++和匯編。熟悉串口,USB,CAN等各種通信技術。承接各種單片機系統的軟硬件開發及反匯編項目(深圳和周邊地區),email:sxtyqx08@163.com
          發表于 11-28 10:56

          單片機按鍵軟硬件設計技巧有哪些

          單片機按鍵軟硬件設計技巧!
          發表于 04-22 14:37

          為什么軟件能控制硬件?單片機到底是如何軟硬件結合

          硬件?反正當年我學習51的時候,有這個疑惑。今天我們就暫停軟件開發,分析單片機到底是如何軟硬件...
          發表于 02-14 06:22

          單片機測控系統的軟硬件平臺技術

          單片機軟硬件綜合設計方法——軟硬件平臺技術,重點闡述了其基本原理、設計思想、實現方法,并給出了一個單片機測控系統軟硬件開發平臺
          發表于 08-13 09:38 ?12次下載

          AVR單片機軟硬件學習教程

          單片機軟硬件學習教程 o第一講:單片機及其開發工具簡介 o第二講:AVR硬件電路設計教程 o第三講:AVR開發環境的建立,數字邏輯與C語言程序設計基礎知識 o第四講:流水燈、蜂鳴器
          發表于 11-30 15:36 ?523次下載
          AVR<b>單片機</b><b>軟硬件</b>學習教程

          單片機系統軟硬件調試及維修技術

          單片機系統軟硬件調試及維修技術,快來下載吧
          發表于 09-01 18:17 ?71次下載

          深度:單片機到底是如何軟硬件結合的?

          硬件?反正當年我學習51的時候,有這個疑惑。今天我們就暫停軟件開發,分析單片機到底是如何軟硬件...
          發表于 12-09 10:51 ?0次下載
          深度:<b>單片機</b>到底是如何<b>軟硬件</b><b>結合</b>的?

          AVR單片機十日通:介紹AVR單片機軟硬件配置(1)

          單片機系列視頻教程之《AVR單片機十日通》,這是第一日:AVR單片機軟硬件配置入門,配套硬件平臺DMAVR-M16,軟件AVR GCC
          的頭像 發表于 07-06 04:03 ?3622次閱讀

          深度解剖單片機是如何軟硬件結合的并分析單片機程序的編譯,運行

          硬件?反正當年我學習51的時候,有這個疑惑。今天我們就暫停軟件開發,分析單片機到底是如何軟硬件結合的。
          的頭像 發表于 04-03 11:46 ?1345次閱讀
          深度解剖<b>單片機</b>是如何<b>軟硬件</b><b>結合</b>的并分析<b>單片機</b>程序的編譯,運行

          STM32單片機到底是如何實現軟硬件結合?

          單片機到底是如何實現軟硬件結合的,接著分析單片機程序如何編譯、運行。
          發表于 05-16 09:54 ?285次閱讀
          STM32<b>單片機</b>到底是如何實現<b>軟硬件</b><b>結合</b>?

          單片機到底是如何軟硬件結合

          硬件?反正當年我學習51的時候,有這個疑惑。今天我們就暫停軟件開發,分析單片機到底是如何 軟硬件結合 的。并通過一個基本的程序,分析單片機程序的編譯,運行
          的頭像 發表于 08-08 09:31 ?585次閱讀
          <b>單片機</b>到底是如何<b>軟硬件</b><b>結合</b>的
          亚洲啪啪啪免费福利视频,美女裸体淫荡自慰三极色,国产无码资源在线,在线看色毛片网址你懂的
          <kbd id="sapis"><rt id="sapis"><var id="sapis"></var></rt></kbd>
            <tbody id="sapis"><noscript id="sapis"></noscript></tbody>
            1. <button id="sapis"><object id="sapis"></object></button>
              1. <rp id="sapis"></rp>