最近迫于找工作的壓力,我不得不加快嵌入式學(xué)習(xí)的步伐,不再和AVR、PIC8位機(jī)糾纏了,開始學(xué)習(xí)32位單片機(jī)。開發(fā)環(huán)境如下:STM32F103RBT6+MDK+JLINK。今天打開了第一個(gè)程序:流水燈。程序內(nèi)容很簡(jiǎn)單,只是這個(gè)工程的結(jié)構(gòu)看上去很是復(fù)雜,不像之前一個(gè)工程里就那么幾個(gè)C源程序和頭文件。因此,今天很有必要討論一下這個(gè)工程的結(jié)構(gòu),相當(dāng)于一個(gè)程序的骨架。 其實(shí)認(rèn)真研究一下,會(huì)發(fā)現(xiàn)例程工程和之前我們使用編寫51單片機(jī)程序用的工程大同小異。至于剛開始感覺這個(gè)結(jié)構(gòu)很復(fù)雜,我的原因是之前編寫51程序是將所有的代碼幾乎都寫進(jìn)主源程序里,頭文件和多個(gè)源程序的使用很少。開發(fā)STM32時(shí),因?yàn)橛辛斯俜降姆庋b的外圍器件驅(qū)動(dòng)代碼庫(kù),這樣我就不得不使用頭文件和多個(gè)源程序,感覺不適應(yīng),只能說是少見多怪。其實(shí)想想,開發(fā)STM32的這種編程方式才是科學(xué)的。STM32的外圍器件驅(qū)動(dòng)庫(kù)的作用其實(shí)就是將面向寄存器的操作封裝成為函數(shù),這樣我們?cè)诰帉懢唧w的應(yīng)用程序的時(shí)候就可以直接調(diào)用這些函數(shù),這樣,一方面降低編寫程序的難度,提高了編程的準(zhǔn)確性,另一方面,也提高了程序的可讀性。在編程之前,我們必須將我們的要用到的外圍器件的驅(qū)動(dòng)程序的頭文件(各種宏定義和寄存器操作函數(shù)的聲明)和源程序(宏定義和各種寄存器操作函數(shù)的實(shí)現(xiàn))從頭到尾看一遍,這樣我們?cè)诰帉懗绦虻臅r(shí)候心里才有數(shù),知道用哪些宏定義的變量和函數(shù)。 說了這么多,回到工程結(jié)構(gòu)上來。STM32的例程工程通常包含幾個(gè)組User,RVMDK,CMSIS,StdPeriph_Driver,DOC。在3.0.0版本的外圍器件驅(qū)動(dòng)庫(kù)的例程工程中只有這些,在3.3.0和3.5.0的版本中,還有一個(gè)STM32_EVAL組,這個(gè)組的源程序和頭文件定義了一些與STM32自己的開發(fā)板相關(guān)一些變量,如果你用的不是這幾款開發(fā)板,這個(gè)組就可以刪去。 User組里放的是我們自己的編寫的源代碼和頭文件。 RVMDK組通常存放的是匯編啟動(dòng)代碼。 CMSIS(Cortex Microcontroler Software InterfaceStandard)組放的時(shí)與Cortex-M3相關(guān)的文件,如core_cm3.c和system_stmf10x.c。 StdPeriph_Driver組里放的是外圍器件驅(qū)動(dòng)代碼。用什么就向這個(gè)組里加入什么。例程中所有的驅(qū)動(dòng)都加上了,這在我們實(shí)際使用時(shí)是沒有必要的。 DOC組放一些說明文本,這從側(cè)面說明說明一個(gè)問題,工程這種文件組織形式一方面有利于多個(gè)程序文件的編譯,另一方面則方便文件瀏覽。參與編譯的是工程里的啟動(dòng)代碼(.s),源程序(.c)和頭文件(.h)。這些代碼經(jīng)compiler編譯生成目標(biāo)文件(.obj),然后linker再將這些目標(biāo)文件鏈接成可執(zhí)行文件(.hex)(在PC環(huán)境下則是.exe)。 有一點(diǎn)需要明確,工程結(jié)構(gòu)僅僅是一個(gè)映射。它只是使程序看起來有條理。 這么多組只是浮云,在電腦里并不一定要有User,RVMDK,CMSIS,StdPeriph_Driver,DOC這些文件夾。這些組包含的文件都存放在外圍器件驅(qū)動(dòng)壓縮包解壓出得到Library文件夾里。咱們只要把這些文件映射到工程中,并且在工程設(shè)置中將這些文件的路徑指明,這樣編譯器在編譯的時(shí)候遇到文件包含時(shí)就到這個(gè)指定路徑里找頭文件。另外,例程模板文件夾里還有兩個(gè)文件夾(List和Obj),它們兩個(gè)負(fù)責(zé)存放編譯鏈接過程中產(chǎn)生的中間文件。 我的第一個(gè)工程是這樣建立的: 1、建立一個(gè)文件夾,并命名為GPIO。 2、在這個(gè)文件夾下,新建文件夾,命名為RVMDK,然后在RVMDK文件夾下建立兩個(gè)文件夾,分別命名為Obj和List。 3、將例程STM32F10x_StdPeriph_Lib_V3.0.0\Project\Examples\GPIO\IOToggle中的所有文件復(fù)制到GPIO文件夾下,我們的程序就以其中的main.c為基礎(chǔ)。 4、接下來就該建立工程了,這和之前建立51工程一樣,我將工程建立在RVMDK文件夾下。 5、將之前提到那些工作組(User,RVMDK,CMSIS,StdPeriph_Driver,DOC)添加到工程中,我只添加了User,Startup,Driver這幾個(gè)工作組。然后把從STM32F10x_StdPeriph_Lib_V3.0.0\Project\Examples\GPIO\IOToggle復(fù)制的源程序添加到User工作組,把STM32F10x_StdPeriph_Lib_V3.0.0\Libraries\STM32F10x_StdPeriph_Driver\src中的源程序添加到Driver工作組,把STM32F10x_StdPeriph_Lib_V3.0.0\Libraries\CMSIS\Core\CM3下的源程序(.c)和STM32F10x_StdPeriph_Lib_V3.0.0\Libraries\CMSIS\Core\CM3\startup\arm的啟動(dòng)文件(.s)添加到Startup工作組。這樣工程就搭建好了。 6、之前建立51工程時(shí),工程的設(shè)置很簡(jiǎn)單。不過在建立STM32工程時(shí),工程的設(shè)置很重要。設(shè)置的主要內(nèi)容是指明文件包含路徑。就是指示編譯器在編譯時(shí)遇到文件包含是應(yīng)該到哪兒去尋找被包含的頭文件。如果路徑設(shè)置不對(duì)或者有遺漏,編譯器一旦找不到要找的頭文件,就會(huì)到keil自己的頭文件庫(kù)去尋找,由于頭文件庫(kù)的版本不配,就會(huì)編譯失敗,出現(xiàn)一堆令人頭疼的error。 7、 指示include路徑有 ..\ ..\..\..\Libraries\STM32F10x_StdPeriph_Driver\inc ..\..\..\Libraries\CMSIS\Core\CM3 注:..\ 的意思是工程文件所在路徑的上一層 .\ 則是工程文件的當(dāng)前路徑,即工程文件所在的文件夾里。 我的工程文件夾GPIO位于與模板(template)相同的路徑(STM32F10x_StdPeriph_Lib_V3.0.0\Project)。 另外還要將USE_STDPERIPH_DRIVER,STM32F10X_MD寫入工程配置面板的C/C++選項(xiàng)面板的define欄里。 現(xiàn)在基本上大功告成了,保存后,按下F7,就 Build target 'GPIO'
compiling main.c...
compiling core_cm3.c...
compiling system_stm32f10x.c...
compiling misc.c...
compiling stm32f10x_gpio.c...
compiling stm32f10x_rcc.c...
linking...
Program Size: Code=2588 RO-data=268 RW-data=24ZI-data=608
FromELF: creating hex file...
".\Obj\GPIO.axf" - 0 Error(s), 0 Warning(s).
|