盤盤-零死角玩轉(zhuǎn)stm32f429挑戰(zhàn)者_第1頁
盤盤-零死角玩轉(zhuǎn)stm32f429挑戰(zhàn)者_第2頁
盤盤-零死角玩轉(zhuǎn)stm32f429挑戰(zhàn)者_第3頁
盤盤-零死角玩轉(zhuǎn)stm32f429挑戰(zhàn)者_第4頁
盤盤-零死角玩轉(zhuǎn)stm32f429挑戰(zhàn)者_第5頁
已閱讀5頁,還剩1054頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第1 如何使用本本書的參考資本書參考資料為:《STM32F4xx中文參考手冊》和《Cortex?-M4內(nèi)核編程手冊》,這兩本是ST的手冊,屬于精華版,面面俱到,無所不包。限于篇幅問題,本書不可本書的編寫風F429的精髓所在,掌握了整個外設(shè)的框圖則可以熟練的使用該外設(shè),熟練的編本書的配套硬圖1-1秉火STM32—F429者硬件資本書的技術(shù)如果在學習過程中遇到問題,可以到: 更好,祝您學習愉快,M4的世界,秉火與您。第2 如何安裝溫馨提 KEIL5安裝文件,或者到KEIL的官網(wǎng):ht /download/product/,一大堆非常麻煩。我們這里面KEIL5的版本是MDK5.15,以后有新版本大家可使用更高版本。安裝STM32把下面彈出的界面關(guān)掉,我們直接去keil的官網(wǎng):h 在官網(wǎng)中找到STM32F1、STM32F4、STM32F7這3個系列的包到本地電腦,具體哪個系列的根據(jù)你使用的型號即可,這里我只需要使用的F1/4/7這三個系列的包,F(xiàn)1代表M3,F(xiàn)4代表M4,F(xiàn)7代表M7。把好的包雙擊安裝即可,安裝路徑選擇跟KEIL5一樣的安裝路徑,安裝成功之第3 如何用DAP仿真器程仿真器簡基于CortexM3、M4M73-1。Fire-Debugger支持和仿真程序,支持XP/WIN7/WIN8/WIN10這四個操作系統(tǒng),免驅(qū),不需要安裝驅(qū)動即可使用,支持KEIL和IAR直接,非常方便硬件連

圖3-1DAP器外KEILIAR給開發(fā)圖3-2仿真器與電腦和開發(fā)板連接方仿真器配Debug選項配選擇目標發(fā)板的配置是:F1選512K,F(xiàn)4選1M。這里面有個小技巧就是把ResetandRun也勾選上,這樣程序完之后就會自動運行,否則需要手動復位。擦除的FLASH大小選擇Sectors即可,不要選擇FullChip,不然會比較慢。圖3-6選擇目標程序不需要其他額外的軟件,直接點擊KEIL中的LOAD按鈕即可。圖3-7程程序后,BuildOutput選項卡如果打印出Applicationrunning…則表示程序成圖3-8程序運第4 初識什么是STM32,從字面上來理解,ST是意法半導體,MMicroelectronics的縮寫,32表示32位,合起來理解,STM32ST3232位控制器當中,STM32可以說是最璀璨的,它受寵若嬌,大受工程師和市場的青睞,無芯能出STM32誕生的背51是嵌入式學習中一款入門級的精典MCU,因其結(jié)構(gòu)簡單,易于教學,且可以通過51。51708位單片機,如今,久經(jīng)歲月的洗禮,既ARMARMv732Cortex-M3微控制器內(nèi)核。緊隨其后,ST(意法半導體)公司就推出了基于Cortex-M3內(nèi)核的MCU—STM32。STM32憑借其產(chǎn)品線的多樣化、極高的性價比、簡單易用的庫開發(fā)方式,迅速在眾多Cortex-M3MCU中脫穎而出,成為最閃亮的一顆。STM32一上市就迅速占領(lǐng)了中MCU市場,受到了市場和工程師的無比青睞,頗有星火燎原之勢。STM32的出現(xiàn)就是一種趨勢,一種潮流,我們STM32能做什STM32屬于一個微控制器,自帶了各種常用通口,比如USART、I2C、SPI等,有STM32的身影,比如智能手環(huán),微型四軸飛行器,平衡車、移動POST機,智能電飯鍋,3D等等。下面我們以最近最為火爆的兩個產(chǎn)品來講解下,一個是手環(huán),一個是智能手4-1三星GearFit智能橙圈:MacronixMX69V28F6416MB閃存,基于MCP封裝的器,是一種包含了NOR和SRAM的閃存,這在手環(huán)這種移動設(shè)備中經(jīng)常使用,優(yōu)點是體積小,可以減PCB的尺寸。這個閃存用的439FSMC接口驅(qū)動。用439的SDIO或者SPI接口驅(qū)動??隍?qū)動,OLED顯示部分用 C接口驅(qū)動。秉火STM32F429STM32F439ZIY6SWLCSP143裝STM32F429IGT6LQPF144裝NOR+SRAM16MB,F(xiàn)SMCSDRAM8MB,F(xiàn)MC1.84AMOLED,RGB5寸電容屏,RGB接口 藍牙:博通BCM4334,SDIOucosiiiemwin。如果功夫所至,學完之圖4-2ucosiii+emwin做的系統(tǒng)界面(429開發(fā)板的開機界面圖4-3微型四軸上面的是屬于產(chǎn)品,如果想自己DIY,可以在入門STM32之后,買一本飛行器DIY的書,邊做邊學。入門級的書籍推薦《四軸飛行器DIY—基于STM32微控制器》,見圖淘寶眾

圖4-5淘寶眾籌STM32怎么選STM32分F1F4,F(xiàn)1代表了基礎(chǔ)型,基于Cortex-M3內(nèi)核,主頻為72MHZ,F(xiàn)4代表了高性能,基于Cortex-M4內(nèi)核,主頻180M。CPU位CPU位8STM32—FIGT6429表示高性能且?guī)SPI—FIGT6429表示高性能且?guī)SPI176pinC48,R64,V100,ZT表示QFP6表示溫度等級為A:-4-6STM8STM32命名方法,摘自《STM8STM32MCU,普通應(yīng)用,不需要接大屏幕的一般選擇Cortex-M3內(nèi)核的F1系列,如果要追求高性能,需要大量的數(shù)據(jù)運算,且需要外接RGB大屏幕的則選擇Cortex-M4內(nèi)核的F429系列。FLASHMCUFLASH大小可供選擇,這個也是根據(jù)實用,更甚者連PCB的過孔的多少都有講究。項目中的元器件的選型的水深著啊,很多學如何分配原理圖體見表格4-4。表格4-4畫原理圖時的引腳分 BOOT 的總線,比如I2C,SPI,SDIO,F(xiàn)SMC,DCMI這些 的普通的元器件接到GPIO,比如蜂鳴器,LED如何尋找IO的功能說(英文叫Referencemanual),另外一個是(英文叫DataSheet)。兩者的具體區(qū)別見表格4-5。表格4-5參考手冊和的內(nèi)容區(qū)在中,有關(guān)引腳定義的部分在Pinoutsandpindescription這個小節(jié)中,具體表格4-6中對引腳定表格4-7對引①引腳序號②引腳名稱③引腳類型SI④I/OB⑤注意事項⑥復用功能⑦額外功能開始分配原理圖PCB哪里打設(shè)計好原理圖,畫好PCB之后,需要把板子做出來,進行軟硬件聯(lián)調(diào)。首先得PCB 。一塊10CM*10CM以內(nèi)的板子,三天做好,50塊就可以搞嘉立創(chuàng)還可以幫你把PCB樣板上的阻容貼好給你,打樣貼片一條龍。第5 什么是寄存學習本章時,配合《STM32F4xx中文參考手冊》“器和總線架構(gòu)”、“嵌入式什么是寄存STM32長啥接下來要學習的STM32,它講帶領(lǐng)我們進入嵌入式的殿堂。正面是絲印,ARM應(yīng)該是表示該使用的是ARM的內(nèi)核,STM32F429IGT6是型號,后面的字應(yīng)該是跟生產(chǎn)批次相關(guān),最下面的是ST的LOGO。傳感器上,然后在STM32上編程(實際就是通過程序控制這些引腳輸出高電平或者低電5-1STM32F429IGT6實物里面有什

電腦類比,內(nèi)核與外設(shè)就如腦上的CPU與主板、內(nèi)存、顯卡、硬盤的關(guān)系。STM32F429采用的是Cortex-M4內(nèi)核,內(nèi)核即CPUARM公司設(shè)計。ARM公司GPIO、USART(串口)、I2C、SPI5-3。圖5-3STM32架構(gòu)簡87圖54,總線矩陣用于主控總線之間的仲裁管理,仲裁采用循環(huán)調(diào)度算法。總線之間交叉的時候如果有個圓圈則表示可以通信,沒有圓圈則表示不可以通信。比如S0:I總線只有跟M0、M2和M6這三根被控總線交叉的時候才有圓圈,就表示S0只能跟這三根被控總線通信。從功能上來理解,I總線是指令總線,用來取指,指令指的是編譯好的程序指令。我們知道STM32有三種啟動方式,從FLASH啟動(包含系統(tǒng)器),從內(nèi)部SRAM啟動,從外部RM啟動,這三種器剛好對應(yīng)的就是M0、M2和M6這三條總線。圖5-4STM32F42xxx和STM32F43xxx器件的總線接口5.4器映在一個4GB的地址空間內(nèi)。我們在編程的時候,操作的也正是這些功能部件。5.4.1器映的過程就稱為器映射,具體見圖5-5。如果給器再分配一個地址就叫器重映圖5-5器映 器區(qū)域功能劃塊也都規(guī)定了用途,具體分類見表格5-1。每個塊的大小都有512MB,顯然這是非常大表格5-1器功能分Block0x00000000~0x1FFFBlock0x20000000~0x3FFFBlock0x40000000~0x5FFFBlockFMCbank1~0x60000000~0x7FFFBlockFMCbank3~0x80000000~0x9FFFBlock0xA0000000~0xCFFFBlock0xD0000000~0xDFFFBlock0xE0000000~0xFFFF8個Block3個塊非常重要,也是我們最關(guān)心的三個塊。Boock0用來設(shè)FLASH,Block1用來設(shè)計成內(nèi)部RAM,Block2用來設(shè)計成片上的外設(shè),下面我們簡單的介紹下這三個Block里面的具體區(qū)域的功能劃分。時做到1MB以上,實乃良心之舉。Block內(nèi)部區(qū)域的功能劃分具體見表格5-2。表格5-2器Block0內(nèi)部區(qū)域功能劃塊0x1FFFC008~0x1FFFOTP512個字節(jié)只能寫0x1FFFC000~0x1FFF0x1FFF7A10~0x1FFF器:里面寸的是ST0x1FFF0000~0x1FFF時燒寫好的isp0x1FFEC008~0x1FFE選項字節(jié):用于配置讀寫保護、BOR級別、軟件/硬件看門狗以及器RAM里面啟動來修改這部分相應(yīng)的0x1FFEC000~0x1FFE0x10010000~0x1FFECCMRAM:64K,CPU0x10000000~0x10000x08200000~0x000F0x08000000~0x081FFFFF0x00200000~0x07FF取決于BOOT引腳,為FLASH0x00000000~0x001FCCMRAMBlock0,剩下的192KB位于Block1SRAM1112KB,SRAM216KB,SRAM364KB,Block內(nèi)部區(qū)域的功能劃分具體見表格5-3。表格5-3器Block1內(nèi)部區(qū)域功能劃塊0x20030000~0x3FFFSRAM30x20020000~0x2002SRAM20x2001C000~0x2001SRAM10x20000000~0x2001Block2用于設(shè)計片內(nèi)的外設(shè),根據(jù)外設(shè)的總線速度不同,Block被分成了APB和兩部分,其中APBAPB1和APB2,AHB分為AHB1AHB2,具體見表格5-4。還有一個AHB3包含了Block3/4/5/6,這四個Block用于擴展外部器,如SDRAM,NORFLASH和NANDFLASH等。表格5-4器Block2內(nèi)部區(qū)域功能劃塊0x40000000~0x40000x40008000~0x40000x40010000~0x40010x40016C00~0x40010x40020000~0x40070x40080000~0x4FFF0x50000000~0x50060x50060C00~0x5FFF寄存器映在器Block2這塊區(qū)域,設(shè)計的是片上外設(shè),它們以節(jié)為一個單元,共以找到每個單元的起始地址,然后通過C語言指針的操作方式來這些單元,如果每次比如,我們找到GPIOHODR0x40021C14(至于這個地址如何找到可以先跳過,后面我們會有詳細的講解),ODR32bit16bit針的操作方式,讓GPIOH的16個IO都輸出高電平,具體見代碼5-1。代碼5-1通過絕對地址內(nèi)存單1GPIOH電2*(unsignedint*)(0x40021C14)=把它轉(zhuǎn)換成指針,即(unsignedint*)0x40021C14,然后再對這個指針進行*操作。器的方式來操作,具體見代碼5-2。代碼5-2通過寄存器別名方式內(nèi)存單1GPIOH電2#define (unsigned3*GPIOH_ODR=代碼5-3通過寄存器別名內(nèi)存單GPIOH電#define *(unsignedGPIOH_ODR=STM32的外設(shè)地址映掛載低速外設(shè),AHB掛載高速外設(shè)。相應(yīng)總線的最低地址我們稱為該總線的址,總線APB1總線的地址最低,片上外設(shè)從總線表格5-5總線總線相對外設(shè)址的偏0x40000x40010x00010x40020x00020x50000x10000x6000外設(shè)參考《STM32F4xx參考手冊》的2.3小節(jié)的器映射的表2:STM32F4xx寄存器邊界地外設(shè)名稱外 相對AHB1總線的地址偏移0x40020x40020x00000x40020x00000x40020x00000x40020x00000x40020x00000x40020x00000x40020x0000猜到,AHB1總線的第一個外設(shè)就是GPIOA。XXGPIO外設(shè)為例,GPIO出高電平或者低電平。最簡單的應(yīng)用就是把GPIOLED燈的陰極,LED燈的陽極接電源,然后通過STM32控制該引腳的電平,從而實現(xiàn)控制LED燈的亮滅。GPIO有很多個寄存器,每一個都有特定的功能。每個寄存器為32bit,占節(jié),在該外設(shè)的址上按照順序排列,寄存器的位置都以相對該外設(shè)址的偏移地址來描述。這里我們以GPIOH端口為例,來說明GPIO都有哪些寄存器,具體見表格5-7。5-7GPIOH寄存器名稱寄存器地址相對GPIOH基址的偏移0x40020x40020x40020x40020x40020x40020x40020x40020x40020x4002有關(guān)外設(shè)的寄存器說明可參考《STM32F4xx參考手冊》中具體章節(jié)的寄存器描述部這里我們以“GPIO端口置位/復位寄存器”為例,教大家如何理解寄存器的說明,具體見圖5-6。是該寄存器名為“GPIOx_BSRR”其中的“xA-I,也就是說這個寄存器說明適用于GPIOA、GPIOB至GPIOI,這些GPIO端口都有這樣的一個寄存器。偏移地址是指本寄存器相對于這個外設(shè)的址的偏移。本寄存器的偏移地址是0x18,從參考手冊中我們可以查到GPIOA外設(shè)的址為0x40020000,我們就可以算出GPIOAGPIOA_BSRR寄存器的地址為:0x40020000+0x18;同理,由于GPIOB的外設(shè)址為0x40020400,可算出GPIOB_BSRR寄存器的地址為:0x40020400+0x18。其他GPIO端口以此類推即可。編號,中間為位名稱,最下方為讀寫權(quán)限,其中w表示只寫,r表示只讀,rw表示可讀寫。本寄存器中的位權(quán)限都是w,所以只能寫,如果讀本寄存器,是無法保證到它真正內(nèi)容的。而有的寄存器位只讀,一般是用于表示STM32外設(shè)的某種工作狀態(tài)的,由STM32硬件自動更改,程序通過那些寄存器位來判斷外設(shè)的工作狀態(tài)。表示端口的引腳號,如BR0、BS0GPIOx0個引腳,若x表示GPIOA,那就是控制GPIOA的第0引腳,而BR1、BS1就是控制GPIOA1個引腳。其中BRy引腳的說明是“0:不會對相應(yīng)的ODRx位執(zhí)行任何操作;1ODRx位進行復位”。這里的“復位”是將該位設(shè)置為0的意思,而“置位”表示將該位設(shè)置為1;說明中的ODRx是另一個寄存器的寄存器位,我們只需要知道ODRx位為1的時候,對應(yīng)的引腳x輸出高電平,為0的時候?qū)?yīng)的引腳輸出低電平即可(感的讀者可以查詢該寄存器GPIOx_ODR的說明了解)。所以,如果對BR0寫入“1”的話,那么GPIOx的第0個引腳就會輸出“低電平”,但是對BR0寫入“0”的話,卻不會影響ODR0位,所以引BSy與BRy是相反的操作。C語言對寄存器的以上所有的關(guān)于器映射的內(nèi)容,最終都是為大家更好地理解如何用C語言控制讀封裝總線和外設(shè)來,總線或者外設(shè)都以他們的名字作為宏名,具體見代碼5-4。代碼5-4總線和外設(shè)基址宏定1/*外設(shè)址2#definePERIPH_BASE ((unsignedint)0x 4/*總線址#define #define (PERIPH_BASE+ #define (PERIPH_BASE+ #define (PERIPH_BASE+ 910/*GPIO外設(shè)址(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+(AHB1PERIPH_BASE+/*代碼5-4首先定義了“片上外設(shè)”址PERIPH_BASE,接著在PERIPH_BASE上加入各個總線的地址偏移,得到APB1、APB2等總線的地址APB1PERIPH_BASE、5-5使用指針控制BSRR1*GPIOH10輸出低電平(BSRRBR101)2*(unsignedint*)GPIOH_BSRR=34*GPIOH10輸出高電平(BSRRBS101)5*(unsignedint*)GPIOH_BSRR=0x01<<10;7unsignedint8/*GPIOH端口所有引腳的電平(IDR寄存器9temp=*(unsignedint該代碼使用(unsignedint*)把GPIOH_BSRR宏的數(shù)值強制轉(zhuǎn)換成了地址,然后再用是用取指針操作,把寄存器中的數(shù)據(jù)取到變量里,從而獲取STM32外設(shè)的狀態(tài)。用上面的方法去定義地址,還是稍顯繁瑣,例如GPIOA-GPIOH都各有一組功能相同的寄存器,如GPIOA_MODER/GPIOB_MODER/GPIOC_MODER等等,它們只是地址不一樣,但卻要為每個寄存器都定義它的地址。為了更方便地寄存器,我們引入C語言中的結(jié)構(gòu)體語法對寄存器進行封裝,具體見代碼5-6。代碼5-6使用結(jié)構(gòu)體對GPIO寄存typedef intuint32_t/*無符32位變量typedefunsignedshort intuint16_t*無符16位變量*/4/*GPIO寄存器列表5typedefstruct6uint32_t地址偏移7uint32_t輸出類地址偏移8uint32_t輸出速地址偏移9uint32_t上拉/下拉寄存地址偏移uint32_t輸入數(shù)uint32_t輸出數(shù)uint16_t/*GPIO置位/復位寄存器16偏移uint16_t/*GPIO置位/復位寄存器16偏移uint32_t/*GPIO配置鎖地址偏移16uint32_t/*GPIO復用功能配置寄存地址偏移0x20-這段代碼用typedef關(guān)鍵字了名為GPIO_TypeDef的結(jié)構(gòu)體類型,結(jié)構(gòu)體內(nèi)有8個成員變量,變量名正好對應(yīng)寄存器的名字。C語言的語定,結(jié)構(gòu)體內(nèi)變量的空間324個字節(jié),1625-7?!璒DR(32位IDR(32位PUPDR(32位OSPEEDR(32位OTYPER(32位MODER(32位圖5-7GPIO_TypeDef結(jié)構(gòu)體成員的地址偏也就是說,我們定義的這個GPIO_TypeDef,假如這個結(jié)構(gòu)體的首地址為0x40021C00(這也是第一個成員變量MODER的地址),那體中第二個成員變量4個字節(jié)地址的偏移量,其它成員變量相對于結(jié)構(gòu)體首地址的偏移,在上述代碼右側(cè)注釋已給出,其中的BSRR16BSRRL16BSRRH,BSRRL1引腳輸出高電平,BSRRH置1引腳輸出低電平,這里分開只是為了方便操作。這樣的地址偏移與STM32GPIO外設(shè)定義的寄存器地址偏移一一對應(yīng),只要給結(jié)構(gòu)體設(shè)置好首地址,就能把結(jié)構(gòu)體內(nèi)成員的地址確定下來,然后就能以結(jié)構(gòu)體的形式寄存器了,具體見代碼5-7。代碼5-7通過結(jié)構(gòu)體指針寄存GPIO_TypeDef* //定義一個GPIO_TypeDef型結(jié)構(gòu)體指針GPIOx //把指針地址設(shè)置為宏GPIOH_BASE地GPIOx->BSRRL= //通過指針并修改GPIOH_BSRRL寄存GPIOx->MODER //修改GPIOH_MODERGPIOx->OTYPER //修改GPIOH_OTYPER6uint32_ttempGPIOx GPIOH_IDR寄存temp這段代碼先用GPIO_TypeDef類型定義一個結(jié)構(gòu)體指針GPIOx,并讓指針指向地址GPIOx->BSRRL、GPIOx->MODER及GPIOx->IDR等方式讀寫寄存器。各個GPIO端口的首地址,使用時我們直接用該宏寄存器即可,具體代碼5-8。/*使用GPIO_TypeDef把地址強制轉(zhuǎn)換成指針#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)4#define((GPIO_TypeDef*)5#define((GPIO_TypeDef*)6#define((GPIO_TypeDef*)7#define((GPIO_TypeDef*)8#define((GPIO_TypeDef*)9#define((GPIO_TypeDef*)13/*使用定義好的宏直 14/*GPIOH端口的寄存器15GPIOH->BSRRL=//通過指 并修改GPIOH_BSRRL寄存16GPIOH->MODER=//修改GPIOH_MODER17GPIOH->OTYPER//修改GPIOH_OTYPER19uint32_t20temp=GPIOH-//GPIOH_IDR寄存器的值到變量temp22/*GPIOA端口的寄存器23GPIOA->BSRRL=//通過指 并修改GPIOA_BSRRL寄存24GPIOA->MODER=//修改GPIOA_MODER25GPIOA->OTYPER27uint32_t//修改GPIOA_OTYPER28temp=GPIOA-//GPIOA_IDR寄存器的值到變量temp這里我們僅是以GPIO這個外設(shè)為例,給大家講解了C語言對寄存器的封裝。以此類修改寄存器的位操作方使用C語言對寄存器賦值時,我們常常要求只修改該寄存器的某幾位的值,且其它的寄存器位不變,這個時候我們就需要用到C語言的位操作方法了。把變量的某位清代碼5-1對某位清1定義一個變a10011111b二進制數(shù)2unsignedchara=0x9f;4bit2清56a&=781左移兩位,(1<<2)得二進制數(shù):00000100//按位取反,~(1<<2)11111011//a中原來的值為二進制數(shù)a10011111//a作”位與&”運算,a10011111b)&(11111011//經(jīng)過運算后,a的值a=10011011//a的bit2位被被零,而其它位不變 把變量的某幾個連續(xù)位器的某幾個連續(xù)位清零,且其它位不變,方法見代碼5-2。代碼5-2對某幾個連續(xù)位清12//若把a中的23//bit0、bit1為第0組,bit2、bit3為第1組4//bit4、bit52組,bit6、bit735//要對第1組的bit2、bit3清67a&=893左移兩位,(3<<2*1)得二進制數(shù):0000110010//按位取反,~(3<<2*1)1111001111//a中原來的值為二進制數(shù)a1001111112//a作”位與&”運算,a10011111b)&(1111001113//經(jīng)過運算后,a的值a=1001001116//上述(~(3<<2*1))中的(1)即為組編號;如清零第3組bit6、bit7此處應(yīng)為17//括號中的(2)為每組的位數(shù),每組有2個二進制位;若分成4個一組,此處即為20//例如對第2bit4、bit5清21a&=對變量的某幾位進行賦且其它位不變,方法見代碼5-3,這時候?qū)懭氲臄?shù)值一般就是需要設(shè)置寄存器的位參代碼5-3對某幾位進行賦1//a=1000001122bit4、bit5設(shè)置成二進制數(shù)“01b34a|=5/a10010011b2對變量的某位取接用如下操作,其它位不變,見代碼5-4。代碼5-4對某位進行取反操1//a=1001001134a5//a=11010011每課一第6 新建工程—寄存器新建工新建本地工程文 下新建2個文件夾,具體如下:表格8工 文件夾圖6-1工程文件表格9工 文件夾內(nèi)容存放新建工在LED文件夾下。6-2KEIL5CPU型這個根據(jù)你開發(fā)板使用的CPU具體的型號來選擇,F(xiàn)429-“者”選STM32F429IGT型號。如果這里沒有出現(xiàn)你想要的CPU型號,或者一個型號都沒有,那么肯定是你的KEIL5device庫,KEIL5KEIL4MCU的型號,KEIL5需要自己添加,關(guān)于如何添加請參考《如何安裝KEIL5》這一章。圖6-4庫文件管添加文啟動文件,系統(tǒng)上電后第一個運行的程序,由匯編編寫,C編程用的比較少,可暫時 :F4固件庫圖6-5如何在工程配置魔術(shù)棒選項TargetUseMicroLib”,為的是在日后編寫串口驅(qū)動的時候可以使用printf函數(shù)。而且有些應(yīng)用中如果用了STM32的浮點運算單元FPU,一置選項下方的“UseSinglePrecision”中,默認是開的。6-6添加Output選項卡中把輸出文件夾定位到我們工程 下的output文件夾,如果想在編譯的過程中生成hex文件,那么那CreateHEXFile選項勾上。 DebugUtilities選擇目標板,具體選擇多大的FLASH要根據(jù)板子上的型號決定。F429-“圖6-12選擇目 程如果前面步驟都成功了,接下來就可以把編譯好的程序到開發(fā)板上運行。程序不需要其他額外的軟件,直接點擊KEIL中的LOAD按鈕即可。圖6-13程程序后,BuildOutput選項卡如果打印出Applicationrunning…則表示程序成第7 使用寄存器點亮LED學習本章時,配合《STM32F4xxI/O(GPIO)”章節(jié)一起閱讀,GPIO的GPIO引腳與外部設(shè)備連接起來,從而實現(xiàn)與外部通訊、控制以及的功能。片有GPIOA、GPIOB、GPIOC至GPIOI共9組GPIO,一共176個引腳,其中GPIO就占了一大部分,所有的GPIO引腳都有基本的輸入輸出功能。引腳接入到LEDLED燈的亮滅,引腳接入到繼電器或三極管,那就可GPIO框圖剖7-1GPIO式。該圖從最右端看起,最右端就是代表STM32引出的GPIO引腳,其余部件都位于基本結(jié)構(gòu)分保護二極管及上、下拉VDD_FT時,上方的二極管導通,當引腳電壓低于VSS時,下方的二極管導通,防止不正常大功率及電路驅(qū)動。具體電壓、電流范圍可查閱《STM32F4xx規(guī)格書》。器件不干擾該引腳電壓時,STM32的引腳都會有這個默認狀態(tài)。1點幾伏,這是個不確定值。所以一般來說我STM32的內(nèi)部上拉是“弱上拉”,即通過此上拉輸出的電流是很弱的,如要求大電流P-MOSN-MOSGPIO引腳線路經(jīng)過上、下拉電阻結(jié)構(gòu)后,向上流向“輸入模式”結(jié)構(gòu),向向“輸出模式”結(jié)構(gòu)。先看輸出模式部分,線路經(jīng)過一個由P-MOS和N-MOS管組成的單元電路。這個結(jié)構(gòu)使GPIO具有了“推挽輸出”和“開漏輸出”兩種模式。所謂的推挽輸出模式,是根據(jù)這兩個MOS管的工作方式來命名的。在該結(jié)構(gòu)中輸入高電平時,上方的P-MOS導通,下方的N-MOS關(guān)閉,對外輸出高電平;而在該結(jié)構(gòu)中輸入低電平時,N-MOS管導通,P-MOS關(guān)閉,對外輸出低電平。當引腳高低電平切換時,7-2而在開漏輸出模式時,上方的P-MOS管完全不工作。如果我們控制輸出為0,低電平,則P-MOS管關(guān)閉,N-MOS1它無法直接輸出高電平)時,則P-MOSN-MOS管都關(guān)閉,所以引腳既不輸出高電平,也不輸出低電平,線路就相當于短路接地,使得整條線路都為低電平,0伏。在STM32的應(yīng)用中,除了必須用開漏模式的場合,我們都習慣使用推挽輸出模式。I2C、SMBUS通訊等需要“線與”功能的總線電路中。除此之外,還用在電平不匹配的場合,如需要輸出5伏的高電平,就可以在外部接一個上拉電源向外輸出5伏的電平。前面提到的雙MOS管結(jié)構(gòu)電路的輸入信號,是由GPIO“輸出數(shù)據(jù)寄存器GPIOx_ODR”提供的,因此我們通過修改輸出數(shù)據(jù)寄存器的值就可以修改GPIO引腳的輸出電平。而“置位/復位寄存器GPIOx_BSRR”可以通過修改輸出數(shù)據(jù)寄存器的值從而影響復用功能輸此時GPIO引腳用作該外設(shè)功能的一部分,算是第二用途。從其它外設(shè)引出來的“復用功能輸出信號”與GPIOMOS管結(jié)構(gòu)的輸入中,通過圖中的例如我們使用USART串口通訊時,需要用到某個GPIO引腳作為通訊發(fā)送引腳,這個時候就可以把該GPIO引腳配置成USART串口復用功能,由串口外設(shè)控制該引腳,發(fā)送數(shù)GPIO結(jié)構(gòu)框圖的上半部分,它是GPIO引腳經(jīng)過上、下拉電阻后引入的,它連接入數(shù)據(jù)寄存器GPIOx_IDR”中,通過該寄存器就可以了解GPIO引腳的電平狀態(tài)。復用功能輸同樣,如我們使用USART串口通訊時,需要用到某個GPIO引腳作為通訊接收引腳,這個時候就可以把該GPIO引腳配置成USART串口復用功能,使USART可以通過該通訊模擬輸入輸0、1ADC外設(shè)要到原始的模擬信號,信號源輸入必須在施密特觸發(fā)器之前。類似地,當GPIO引腳用于DAC作為模擬電壓輸出通道時,此時作為“模擬輸出”功能,DAC的模擬信號輸同時,當GPIO用于模擬功能時(包括輸入輸出),引腳的上、下拉電阻是不起作用的,這個GPIO工作??偨Y(jié)一下,由GPIO的結(jié)構(gòu)決定了GPIO輸入模式(上拉/下拉/浮空在輸入模式時,施密特觸發(fā)器打開,輸出被。數(shù)據(jù)寄存器每隔1個AHB1時鐘周認配置一般為180MHz。輸出模式(推挽/開漏,上拉/下拉在輸出模式中,輸出使能,推挽模式時雙MOS管以方式工作,輸出數(shù)據(jù)寄存器I/O支持的高低電平狀態(tài)最高切換頻率,支持的頻率越高,功耗復用功能(推挽/開漏,上拉/下拉GPIOx_ODR無效;輸入可用,通過輸入數(shù)據(jù)寄存器可獲取I/O實際狀態(tài),但一般直接用外設(shè)的寄存器來獲取該數(shù)據(jù)信號。模擬輸入輸通過對GPIO寄存器寫入不同的參數(shù),就可以改變GPIO的應(yīng)用模式,再強調(diào)一下,要了解具體寄存器時一定要查閱《STM32F4xx參考手冊》中對應(yīng)外設(shè)的寄存器說明。在GPIOGPIOx_MODER”可配置GPIO的輸入/輸出/復用/模擬模式,“輸出類型寄存器GPIOx_OTYPER”配置推挽/開漏模式,配置“輸出速度寄存GPIOx_OSPEEDR2/25/50/100MHz輸出速度,“上/下拉寄存器GPIOx_PUPDR”可配置上拉/下拉/浮空模式,各寄存器的具體參數(shù)值見表7-1。MODER位OTYPER位OSPEEDRPUPDR位拉011011拉01實驗:使用寄存器點LED本小節(jié)中,我們以如何通過控制寄存器來點亮LED燈。此處側(cè)重于講解原理,請您直接用KEIL5軟件打開我們提供的實驗例程配合閱讀,先了解原理,學習完本小節(jié)后,再嘗試自己建立一個同樣的工程。本節(jié)配套例程名稱為“GPIO輸出—寄存器點亮LED燈”,在工程 下找到后綴為“.uvprojx”的文件,用KEIL5打開即可。若沒有安裝KEIL5軟件,請參考《如何安裝KEIL5》章節(jié)。圖7-3工程文硬件連7-4LED圖中3LED燈的陽3.3V電源,陰1個電阻引入STM323個GPIOPH10、PH11、PH12中,所以我們只要控制這三個引腳輸出高低電平,即可控制其所連接LEDSTM32LED燈的引腳或極性不一樣,只需要修改程序到對應(yīng)的GPIO引腳即可,工作原理都是一樣的。我們的目標是把GPIO的引腳設(shè)置成推挽輸出模式并且默認下拉,輸出低電平,這樣就能讓LED燈亮起來了。啟動文STM32上電啟動的時候,首先會執(zhí)行這里的匯編程序,從而建立起C語言的運行環(huán)指令,可從《Cortex-M4TechnicalReferenceManual》查到,也可參考《Cortex-M3指南中文》,M3跟M4大部分匯編指令相同。startup_stm32f429_439xx.s文件是由提供的,一般有需要也是在的基礎(chǔ)上修改,不會自己完全重寫。該文件可以從KEIL5安裝 設(shè)置C庫的分支“main”(最終用來調(diào)用main函數(shù)執(zhí)行的程序,代碼見代碼7-1。在實際工程中閱讀時,可使用編輯器的搜索(Ctrl+F)功代碼7-1復位后執(zhí)行的程;Reset EXPORT IMPORT6

R0, R0,= 第二行是定義了一個子程序:Reset_Handler。PROC是子程序定義偽指令。這里就相當于C語言里定義了一個函數(shù),函數(shù)名為Reset_Handler。EXPORTReset_Handler這個子程序可供其他模塊調(diào)用。相當于C語言的函數(shù)。關(guān)鍵字[WEAK]表示弱定義,如果編譯器發(fā)現(xiàn)在別處定義了同名的函數(shù),則在時用別處的地址進行,如果其它地方?jīng)]有定義,編譯器也不報錯,以此處地址進行,如果不理解WEAK,那就忽略它好了。第四行和第五行IMPORT說明SystemInit和main這兩個標號在其他文件,在的時候需要到其他文件去尋找。相當于C語言中,從其它文件引入函數(shù)。以便下面對外SystemInit需要由我們自己實現(xiàn),即我們要編寫一個具有該名稱的函數(shù),用來初始化STM32的時鐘,一般包括初始化AHB、APB等各總線的時鐘,需要經(jīng)過一系列的配置STM32才能達到穩(wěn)定運行的狀態(tài)。main其實不是我們定義的(不要與C語言中的main函數(shù)),當編譯器編譯時,只環(huán)境,準備好C語言并在最后跳轉(zhuǎn)到用戶自定義的main函數(shù),從此來到C的世界。第七行程序跳轉(zhuǎn)到R0SystemInit函數(shù)的內(nèi)容。第八行把main的地址加載到寄存器R0。第九行程序跳轉(zhuǎn)到R0中的地址執(zhí)行程序,即執(zhí)行main函數(shù),執(zhí)行完畢之后就去到我們熟知的C世界,進入main函數(shù)。SystemInitSTM32的時鐘;STM32SystemInit函數(shù),最后執(zhí)行我們C語言中的main函數(shù)。stm32f4xx.h文看完啟動文件,那我們立即寫SystemInit和main函數(shù)吧?別著急,定義好了SystemInitmain我們又能寫什么內(nèi)容?連接LED燈的GPIO引腳,是要通過讀寫寄好各個寄存器的地址,把這些地址定義都統(tǒng)一寫在stm32f4xx.h文件中,見代碼7-2。代碼7-2外設(shè)地址定義/*片上外設(shè)址#define ((unsigned /*總線址#define (PERIPH_BASE+ /*GPIO外設(shè)址#define (AHB1PERIPH_BASE+7/*GPIOH寄存器地址,強制轉(zhuǎn)換成指針#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#define *(unsigned#defineGPIOH_AFRH /*RCC外設(shè)址#define (AHB1PERIPH_BASE+/*RCC的AHB1時鐘使能寄存器地址,強制轉(zhuǎn)換成指針#define *(unsigned了指針,方便使用。代碼的最后兩段是RCC外設(shè)寄存器的地址定義,RCC外設(shè)是用來設(shè)置時鐘的,以后我們會詳細分析,本實驗中只要了解到使用GPIO外設(shè)必須開啟它的時鐘main文1intmain23“Error:L6218E:UndefinedsymbolSystemInit(referredfromSystemInit沒有定義。從分析啟動文件時我們知道,Reset_Handler調(diào)用了該函數(shù)用來初始化SMT32系統(tǒng)時鐘,為了簡單起見,我們在main文件里面定義一個SystemInit空函數(shù),什么也不做,為的是騙過編譯器,把這個錯誤去掉。關(guān)于配置系統(tǒng)時鐘我們在后面再寫。當我們不配置系統(tǒng)時鐘時,STM32會自動按系統(tǒng)內(nèi)部的默認時鐘運行,程序還是能跑的。我們在main中添加如下函數(shù):12void34代碼7-3注釋掉啟動文件中調(diào)用SystemInit的代1;Reset2 34567R0,89R0,=GPIO模首先我們把連接到LEDPH10引腳配置成輸出模式,即配置GPIOMODER寄器位設(shè)置成“01”時即為GPIO的輸出模式,見代碼7-4。代碼7-4配置輸出模/*GPIOHMODER10清空GPIOH_MODER&=~(0x03<</*PH10MODER1001b輸出模式GPIOH_MODER|=值“01”,從而使GPIOH10引腳設(shè)置成輸出模式。它位,因為寄存器不能按位讀寫,假如我們直接給MODER寄存器賦值:GPIOH_MODER= MODER10的兩個位被設(shè)置成“01”輸出模式,但其它GPIO引腳就有意見了,因為其它引腳的MODER位都已被設(shè)置成輸入模式。輸出類式,見代碼7-5。代碼7-5設(shè)置為推挽模GPIOH_OTYPER&=/*PH10OTYPER100b推挽模式GPIOH_OTYPER|= 輸出速GPIO引腳的輸出速度是引腳支持高低電平切換的最高頻率,本實驗可以隨便設(shè)置。此處我們配置OSPEEDR寄存器中的寄存器位OSPEEDR10PH10的輸出速度,見代碼7-6。代碼7-6設(shè)置輸出速度為GPIOH_OSPEEDR&=/*PH10OSPEEDR100bGPIOH_OSPEEDR|=上/下拉模GPIOODR寄存器影響,ODR寄存器對應(yīng)引腳位初始初始化后PUPDR寄存器的PUPDR10位,設(shè)置為二進制值“01”,見代碼7-7。代碼7-7設(shè)置為下拉模/*GPIOHPUPDR10清空GPIOH_PUPDR&=/*PH10PUPDR1001b下拉模式GPIOH_PUPDR|=控制引腳輸出電在輸出模式時,對BSRR寄存器和ODR寄存器寫入?yún)?shù)即可控制引腳的電平狀態(tài)。簡單起見,此處我們使用BSRR寄存器控制,對相應(yīng)的BR101PH10即為低電LED燈,對它的BS101PH10LED燈,見代碼清7-8。代碼7-8控制引腳輸出電/*PH10BSRR寄存器的BR101,使引腳輸出低電平GPIOH_BSRR|=3/*PH10BSRR寄存器的BS101,使引腳輸出高電平GPIOH_BSRR|=開啟外設(shè)時GPIO的引腳,控制電平輸出,以為現(xiàn)在總算可以點亮LED了吧,其實還差最在《STM32架構(gòu)》的外設(shè)章節(jié)中提到STM32外設(shè)很多,為了降低功耗,每個外設(shè)都對應(yīng)著一個時鐘,在剛上電的時候這些時鐘都是被關(guān)閉的,如果想要外設(shè)工作,STM32的所有外設(shè)的時鐘由一個專門的外設(shè)來管理,叫RCC(resetandclockcontrol),RCC在《STM32中文參考手冊》的第六章。GPIO都掛載到AHB1總線上,所以它們的時鐘由AHB1外設(shè)時鐘使能寄存器(RCC_AHB1ENR)來控制,其中GPIOH端口的時鐘由該寄存器的位7寫1使能,開啟GPIOH端口時鐘。以后我們還會詳細解釋STM32的時鐘系統(tǒng),此處我們了解到在GPIO的寄存器之前,要先使能它的時鐘即可,使用代碼7-9中的代碼可以開代碼7-9開啟端口時/*開啟GPIOH時鐘,使用外設(shè)時都要先開啟它的時鐘RCC_AHB1ENR|=水到渠開啟時鐘,配置引腳模式,控制電平,經(jīng)過這三步,我們總算可以控制一個LED了?,F(xiàn)在我們完整組織下用STM32控制一個LED的代碼,見代碼7-10。代碼7-10main文件中控制LED燈的代12 LED 5#include678 int{/*開啟GPIOH時鐘,使用外設(shè)時都要先開啟它的時鐘RCC_AHB1ENR|= /*LED端口初始化/*GPIOHMODER10清空GPIOH_MODER&=~(0x03<</*PH10MODER1001b輸出模式GPIOH_MODER|=GPIOH_OTYPER&=/*PH10OTYPER100b推挽模式GPIOH_OTYPER|=GPIOH_OSPEEDR&=/*PH10OSPEEDR100bGPIOH_OSPEEDR|=/*GPIOHPUPDR10清空GPIOH_PUPDR&=/*PH10PUPDR1001b上拉模式GPIOH_PUPDR|=/*PH10BSRR寄存BR101,使引腳輸出低電平GPIOH_BSRR|=/*PH10BSRR寄存BS101,使引腳輸出高電平//GPIOH_BSRR|=while}void{}驗每課一寄存器版本》、《如何安裝KEIL5》。第8 自己寫庫—構(gòu)建庫函數(shù)雛后就可以一直用寄存器開發(fā)。在用寄存器點亮LEDSTM32的寄存器32位的,每次配置的時候都要對照著《STM32F4xx參考手冊》中寄存器的說明,然代碼還很不好理解,不便于。所以學習STM32最好的方法是用軟件庫,然后在軟件什么STM32函數(shù)當我們調(diào)用庫API的時候不需要挖空心思去了解庫底層的寄存器操作,就像當年我們碼實現(xiàn),但需要深入研究的時候,經(jīng)過千錘百煉的庫API源碼就是最佳學習范例。庫函數(shù)圖8-1開發(fā)方式為什么采用庫來開發(fā)及學在以前8位機時代的程序開發(fā)中,一般直接配置的寄存器,控制的工作方STM32有充足的資源,權(quán)衡庫的優(yōu)勢與不足,絕大部分時候,我們愿意犧牲一點CPU資對于庫開發(fā)與直接配置寄存器的方式,就好比編程是用匯編好還是用C好一樣。在己的函數(shù)庫,但是它們大部分是兼容的,F(xiàn)1F4之間的程序移植,只需要小修改即可。陶醉,要想C語言,就從ST的庫開始吧。所以在以后的章節(jié)中,使用軟件庫是我們的重點,而且我們通過講解庫API去高效地學習STM32的寄存器,并不至于因為用庫學習,就不會用寄存器控制STM32。實驗:構(gòu)建庫函數(shù)雛GPIO函數(shù)庫,其他外設(shè)的我們直接參考ST標準庫學習即可,不必自己寫。修改寄存器地址存器都這樣操作,那將非常麻煩。我們考慮到外設(shè)寄存器的地址都是基于外設(shè)址的偏設(shè)的址,結(jié)構(gòu)體的成員等于寄存器,成員的排列順序跟寄存器的順序一樣。這樣我們操作寄存器的時候就不用每次都找到絕對地址,只要知道外設(shè)的址就可以操作外設(shè)的器,見代碼8-1。結(jié)構(gòu)體成員的順序按照寄存器的偏移地址從低到高排列,成員類型跟寄存器類型一樣。如不理解C語言對寄存器的封的語法原理,請參考《C語言對寄存器代碼8-1封裝寄存器列1//volatile表示2 3typedefunsignedint4typedefunsignedshortuint16_t;6/*GPIO寄存器列表7typedefstruct8/*GPIO模式寄存 地址偏移:9/*GPIO輸出類型寄存器地址偏移:/*GPIO輸出速度寄存器地址偏移:/*GPIO上拉/偏移/*GPIO輸入數(shù)據(jù)寄存器地址偏移:/*GPIO輸出數(shù)據(jù)寄存器地址偏移:BSRRL*GPIO置位/復位寄存器16位部分:0x18BSRRH*GPIO置位/復位寄存16位部分地址偏移:0x1A /*GPIO配置鎖定寄存器地址偏移: AFR[2];/*GPIO復用功能配置寄存器0x20-0x2418}20/*RCC寄存器列表21typedefstruct uint32_t /*RCC時鐘控制寄存器,地址偏移0x00PLLCFGR;*RCCPLL配置寄存器,地址偏移0x04CFGR;/*RCC時鐘配置寄存器,地址偏移0x08 /*RCC時鐘中斷寄存器,地址偏移0x0CAHB1RSTR;*RCCAHB1外設(shè)復位寄存器,地址偏移0x10AHB2RSTR;*RCCAHB2外設(shè)復位寄存器,地址偏移0x14AHB3RSTR;*RCCAHB3外設(shè)復位寄存器,地址偏移0x180*保留地址偏移:0x1CAPB1RSTR;*RCCAPB1外設(shè)復位寄存器,地址偏移0x20APB2RSTR;/*RCCAPB2外設(shè)復位寄存器,地址偏移1[2];/*保留,地址偏移:0x28-AHB1ENR;/*RCCAHB1外設(shè)時鐘寄存器,地址偏移0x30AHB2ENR;/*RCCAHB2外設(shè)時鐘寄存器,地址偏移0x34AHB3ENR*RCCAHB3外設(shè)時鐘寄存器,地址偏移0x38/*RCC后面還有很多寄存器,此處省略}這段代碼在每個結(jié)構(gòu)體成員前增加了一個“IO”前綴,它的原型在這段代碼的第一行,代表了C語言中的關(guān)鍵字“volatile”,在C語言中該關(guān)鍵字用于表示變量是易變的,設(shè)或STM32狀態(tài)修改的,也就是說即使CPU不執(zhí)行代碼修改這些變量,變量的值也就直接從CPU的某個緩存獲取該變量值,這時可以加快執(zhí)行速度,但該緩存中的是陳舊數(shù)定義外設(shè)的結(jié)構(gòu)體指體指針,見代碼8-2。代碼8-2指向外設(shè)首地址的結(jié)構(gòu)體指#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((GPIO_TypeDef*)#define ((RCC_TypeDef*)這些宏通過強制把外設(shè)的址轉(zhuǎn)換成GPIO_TypeDef類型的地址,從而得到GPIOA、GPIOB等直接指向?qū)?yīng)外設(shè)的指針,通過結(jié)構(gòu)體的指針操作,即可對應(yīng)外設(shè)代碼8-3使用結(jié)構(gòu)體指針方式控制LED1 4int56 RCC->AHB1ENR|=8 /*LED端口初始化/*GPIOHMODER10清空GPIOH->MODER&=~(0x03<</*PH10MODER1001b輸出模式GPIOH->MODER|=GPIOH->OTYPER&=/*PH10OTYPER100b推挽模式GPIOH->OTYPER|=GPIOH->OSPEEDR&=/*PH10OSPEEDR100bGPIOH->OSPEEDR|=/*GPIOHPUPDR10清空GPIOH->PUPDR&=/*PH10PUPDR1001b上拉模式GPIOH->PUPDR|=/*PH10BSRR寄存BR101,使引腳輸出低電平GPIOH->BSRRH|=/*PH10BSRR寄存BS101,使引腳輸出高電平//GPIOH->BSRRL|= while39 乍一看,除了最后一部分,把BSRR寄存器分成BSRRH和BSRRL兩段,其它部分跟打好了地基,下面我們就來建高樓。接下來使用函數(shù)來封裝GPIO的基本操作,方便針對GPIO外設(shè)操作的函數(shù)及其宏定義分別存放在“stm32f4xx_gpio.c”和電平,見代碼8-4。代碼8-4GPIO置位函數(shù)與復位函數(shù)的定1*參數(shù)說明:GPIOx:該參數(shù)為GPIO_TypeDef類型的指針,指向GPIO端口的地 GPIO_Pin:選擇要設(shè)置的GPIO端口引腳,可輸入宏GPIO_Pin_0- 表示GPIOx端口的0-15號引腳voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_t{/*設(shè)置GPIOx端口BSRRL寄存GPIO_Pin位,使其輸出高電平宏GPIO_Pin只是對應(yīng)位為1,其它位均為0,所以可以直接賦值 GPIOx->BSRRL=1416*參數(shù)說明:GPIOx:該參數(shù)為GPIO_TypeDef類型的指針,指向GPIO端口的地 GPIO_Pin:選擇要設(shè)置的GPIO端口引腳,可輸入宏GPIO_Pin_0- 表示GPIOx端口的0-15號引腳voidGPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_t{/*設(shè)置GPIOx端口BSRRH寄存器的第GPIO_Pin位,使其輸出低電平宏GPIO_Pin只是對應(yīng)位為1,其它位均為0,所以可以直接賦值 GPIOx->BSRRH=29這兩個函數(shù)體內(nèi)都是只有一個語句,對GPIOx的BSRRL或BSRRH寄存器賦值,從以修改它的值,如給它賦予GPIOA、GPIOB、GPIOH等結(jié)構(gòu)體指針值,這個函數(shù)就可以控制相應(yīng)的GPIOA、GPIOB、GPIOH等端口的輸出。對比我們前面對BSRR寄存器的賦值,都是用“|=”操作來防止對其它數(shù)據(jù)位產(chǎn)生干8-5。代碼8-5賦值方式對1*使用“|來賦值2GPIOH->BSRRH|=3/*直接使用號賦值4GPIOx->BSRRH=根據(jù)BSRR寄存器的特性,對它的數(shù)據(jù)位寫“0”,是不會影響輸出的,只有對它的數(shù)00000001b”,它會控制GPIO的引腳0輸出低電平,賦二進制值“0000000000010000b”,它會控制GPIO40,所以不會受到干擾。同代碼8-6BSRR寄存器賦值等效代1*使用“|來賦值2GPIOH->BSRRH|=3/*直接使用來賦值,二進制數(shù)(0000010000004GPIOH->BSRRH=利用這兩個位操作函數(shù),就可以方便地操作各種GPIO的引腳電平了,控制各種端口引腳的范例見代碼8-7。代碼8-7位操作函數(shù)使用范12/*控制GPIOH的引腳10輸出高電平34/*控制GPIOH的引腳10輸出低電平56/*控制GPIOH的引腳10、引腳11輸出高電平,使用“|”同時控制多個引腳/*控制GPIOH的引腳10、引腳11輸出低電平/*控制GPIOA的引腳8輸出高電平/*控制GPIOB的引腳9輸出低電平操作數(shù)都定義成宏,見代碼8-8。代碼8-8選擇引腳參數(shù)的/*GPIO引腳號定義2/*Pin01<<0)3/*Pin14/*Pin25/*Pin36/*Pin47/*Pin58/*Pin69/*Pin710/*Pin811/*Pin912/*Pin1013/*Pin1114/*Pin1215/*Pin1316/*Pin1417/*Pin1518/*!<選擇全部引腳所有引腳。利用這些宏,GPIO的控制代碼可改為代碼8-9。代碼8-9使用位操作函數(shù)及宏控制1/*控制GPIOH的引腳10輸出高電平/*控制GPIOH的引腳10輸出低電平6/*控制GPIOH的引腳10、引腳11輸出高電平,使用“|”,同時控制多個引腳/*控制GPIOH的引腳10、引腳11輸出低電平/*控制GPIOH的所有輸出低電平/*控制GPIOA的引腳8輸出高電平/*控制GPIOB的引腳9輸出低電平定義初始化結(jié)構(gòu)體定義位操作函數(shù)后,控制GPIO輸出電平的代碼得到了簡化,但在控制GPIO輸出電平前還需要初始化GPIO引腳的各種模式,這部分代碼涉及的寄存器有很多,我們希望初始化GPIO也能以如此簡單的方法去實現(xiàn)。為此,我們先根據(jù)GPIO初始化時涉及到的初始化參數(shù)以結(jié)構(gòu)體的形式封裝起來,一個名為GPIO_InitTypeDef的結(jié)構(gòu)體類型,見代碼8-10。typedefuint8_tunsigned*GPIOtypedefstructuint32_t 可輸入GPIO_Pin_定義的宏8uint8_t 可輸入二進制值00、01、10、表示輸入/輸出/復用/模擬uint8_t 可輸入二進制值00、01、10、uint8_t 可輸入二進制值0、表示推挽/開漏uint8_t /*!<選擇GPIO引腳的上/下拉??奢斎攵M制值00、01、}這個結(jié)構(gòu)體中包含了初始化GPIO所需要的信息,包括引腳號、工作模式、輸出速這樣的結(jié)構(gòu)體變量,根據(jù)需要配置GPIO的模式,對這個結(jié)構(gòu)體的各個成員進行賦值,然后把這個變量作為“GPIO初始化函數(shù)”的輸入?yún)?shù),該函數(shù)能根據(jù)這個變量值中的內(nèi)容去定義引腳模式的枚舉類“00、011011”,我們不希望每次用到都要去查找這些索引值,所以使用C語言中的枚舉語法定義這些參數(shù),見代碼8-11。代碼8-11GPIO配置參數(shù)的枚舉定1*GPIOtypedefenum =0x00,*輸入模式GPIO_Mode_OUT0x01,*輸出模式 =0x02,*復用模式 0x03/*模擬模式}11*GPIOtypedefenumGPIO_OType_PP /*推挽模式GPIO_OType_OD /*開漏模式}19*GPIOtypedefenum =0x00,/*!< GPIO_Speed_25MHz=0x01,/*!<25MHzGPIO_Speed_50MHz=0x02,/*!<50MHzGPIO_Speed_100MHz=0x03/*!<100MHz}29*GPIO上/下拉配置枚舉定typedefenumGPIO_PuPd_NOPULL0x00,/*浮空 0x01*上拉 0x02/*下拉} 了,代碼8-13。代碼8-12使用枚舉類型定義的GPIO_InitTypeDef結(jié)構(gòu)體成12*GPIO34typedefstruct5uint32_t6可輸入GPIO_Pin_定義的宏789可輸入GPIOMode_TypeDef定義的枚舉值可輸入GPIOSpeed_TypeDef定義的枚舉值可輸入GPIOOType_TypeDef定義的枚舉值 /*!<選擇GPIO引腳的上/可輸入GPIOPuPd_TypeDef定義的枚舉值}利用這些枚舉定義,給GPIO_InitTypeDef結(jié)構(gòu)體類型賦值配置就非常直觀了,范例見代碼8-13。代碼8-13給GPIO_InitTypeDef初始化結(jié)構(gòu)體賦值范2/*LED端口初始化/*選擇要GPIO引腳InitStruct.GPIO_Pin=InitStruct.GPIO_Mode=InitStruct.GPIO_OType=InitStruct.GPIO_PuPd=InitStruct.GPIO_Speed=GPIO接著前面的思路,對初始化結(jié)構(gòu)體賦值后,把它輸入到GPIO初始化函數(shù),由它來實現(xiàn)寄存器配置。我們的GPIO初始化函數(shù)實現(xiàn)見代碼8-14,代碼8-14GPIO初始化函1*參數(shù)說明:GPIOx,該參數(shù)為GPIO_TypeDef類型的指針,指向GPIO端口的地 voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*{uint32_tpinpos=0x00,pos=0x00,currentpin=0x00;/*--GPIOModeConfiguration--for(pinpos=0x00;pinpos<16;pinpos++)/*經(jīng)過運pospinpos位為10GPIO_Pin_x宏對應(yīng)pinpos變量每次循環(huán)加pos=((uint32_t)0x01)<<pinpos;/*posGPIO_InitStruct->GPIO_Pin&若運算結(jié)currentpin則表示GPIO_InitStruct->GPIO_Pin的pinpos位也為從而可知pinpos就是GPIO_InitStruct->GPIO_Pin對應(yīng)的引腳號:0-currentpin=(GPIO_InitStruct->GPIO_Pin)&pos;/*currentpinpos時執(zhí)行初始化if(currentpin==pos)/*GPIOx端口,MODER寄存器的GPIO_InitStruct->GPIO_Pin對應(yīng)MODER位清空GPIOx->MODER&=~(3<<(2/*GPIOx端口,MODER寄存器的GPIO_PinMODER位設(shè)置"輸入/輸出/復用輸出/模擬"模式GPIOx->MODER|=(((uint32_t)GPIO_InitStruct->GPIO_Mode)<</*GPIOx端口,PUPDR寄存器的GPIO_PinPUPDR位清空GPIOx->PUPDR&=~(3<<((2/*GPIOx端口,PUPDR寄存器的GPIO_PinPUPDR位設(shè)置"上/下拉"模式GPIOx->PUPDR|=(((uint32_t)GPIO_InitStruct->GPIO_PuPd)<<if((GPIO_InitStruct->GPIO_Mode==GPIO_Mode_OUT)/*GPIOx端口,OSPEEDRGPIO_Pin引腳OSPEEDR位清空GPIOx->OSPEEDR&=~(3<<(2/*GPIOx端口,OSPEEDRGPIO_Pin引腳OSPEEDR位設(shè)置輸出速度/*GPIOx端口,OTYPERGPIO_Pin引腳OTYPER位清空GPIOx->OTYPER&=~(1<<(pinpos))/*GPIOx端口,OTYPER位寄GPIO_PinOTYPER位設(shè)置"推挽/開漏"輸出類型 62forGPIO_InitStructGPIO_Pin計算出要初始化的引的參數(shù)計算出x值(宏的參數(shù)值是第x數(shù)據(jù)位為1,其余為0,參考代碼8-8),計算得的引腳號結(jié)果在pinpos變量中。得到引腳號pinpos后,利用初始化結(jié)構(gòu)體各個成員的值,對相應(yīng)寄存器進行配置,這部分與我們前面直接配置寄存器的操作是類似的,先對引腳號pinpos相應(yīng)的配置位清空,后根據(jù)結(jié)構(gòu)體成員對配置位賦值(GPIO_Mode成員對應(yīng)MODER寄存器的配置,GPIO_PuPd成員對應(yīng)PUPDR寄存器的配置等)。區(qū)別是這里的寄存器配 全新面貌,使用函數(shù)點亮LED代碼8-15使用函數(shù)點亮LED12 LED 5#include67voidDelay(uint32_tnCount);9 主函數(shù),使用封裝好的函數(shù)來控制LEDint{/*開啟GPIOH時鐘,使用外設(shè)時都要先開啟它的時鐘RCC->AHB1ENR|= /*LED端口初始化/*初始化PH10引腳/*選擇要GPIO引腳InitStruct.GPIO_Pin=InitStruct.GPIO_Mode=InitStruct.GPIO_OType=InitStruct.GPIO_PuPd=InitStruct.GPIO_Speed=/*調(diào)用庫函數(shù),使用上面配置的GPIO_InitStructure初始化/*使引腳輸出低電平,點亮/*使引腳輸出高電平,關(guān)閉/*初始化PH11引腳InitStruct.GPIO_Pin= /*使引腳輸出低電平,點亮 while5357voidDelay(uint32_t58 for(;nCount!=0;nCount--6062函數(shù)為空,目的是為了騙過編譯器不報63void6465LED燈與之前直接控制寄存器已經(jīng)有了很大的區(qū)別:main函數(shù)中先定義了一個初始化結(jié)構(gòu)體變量InitStruct,然后對該變量的各個成員按點亮LED燈所需要的GPIOGPIO_Init函數(shù),讓它根據(jù)結(jié)構(gòu)體成員值對GPIOGPIO引腳初始化??刂齐娖綍r,直接使用GPIO_SetBits和GPIO_Resetbits函數(shù)控制輸出。如若對其它引腳進行不同模式的初始化,代碼中新增的eay(),它的實現(xiàn)原理是讓U要它時,個輸數(shù),到板,太就STM32驗總LED,再把寄存器操作封裝成一個個函數(shù)。一步一步走來,我們實現(xiàn)了庫最簡單的雛本章中的GPIOST標準庫搬過來的。這樣分是很有好處的,順便感受一下ST庫設(shè)計的嚴謹性,我認為這樣的代碼不僅嚴謹且華麗優(yōu)也消耗一些時間(如GPIO中運算求出引腳號時)。而其它的宏、枚舉等解釋操作是作編譯過STM32控制器;配置外設(shè)狀態(tài)時,不需要再糾結(jié)要向寄存器寫入什么數(shù)值;交流方便,查現(xiàn)在的處理器的主頻是越來越高,我們不需要擔心CPU耗費那么多時間來干活會不會我們還是擔心一下如果都用寄存器操作,每行代碼都要查《STM32F4xx規(guī)格書》中的說ST的庫函數(shù)的實現(xiàn)了。因為外設(shè)的庫函數(shù)是每課一裝USART的寄存器成一個USART_TypeDef類型,并定義USART1、USART2、USART3外設(shè)的結(jié)構(gòu)體指針。參考GPIO_SetBits的函數(shù)實現(xiàn),定義一個能GPIO引腳狀態(tài)的函數(shù),函數(shù):“uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin)”,要GPIOx端口的GPIO_Pin1,低電平返回0。第9 初識STM32固件本章參考資料:《STM32F4xx參考手冊》、《STM32F4xx規(guī)格書》、《Cortex-M3權(quán)威指南》,STM32標準庫幫助文檔:《stm32f4xx_dsp_stdperiph_lib_um. 在上一章中,我們構(gòu)建了幾個控制GPIO外設(shè)的函數(shù),算是實現(xiàn)了函數(shù)庫的雛形,但GPIO還有很多功能函數(shù)我們沒有實現(xiàn),而且STM32不僅僅只有GPIO這一個外設(shè)。含了STM32所有寄存器的控制操作,我們直接學習如何使用ST標準庫,會極大地方便控制STM32。 標準及庫層次關(guān)因為基于Cortex系列采用的內(nèi)核都是相同的,區(qū)別主要為核外的片上外設(shè)的差MicroControllerSoftwareInterfaceStandard)。層層層Cortex-其它外STM32驅(qū)動函數(shù)庫CMSISCMSIS-DSP用戶代9-1CMSIS內(nèi)核函數(shù)層:其中包含用于內(nèi)核寄存器的名稱、地址定義,主要由ARM公司提可見CMSIS層位于硬件層與操作系統(tǒng)或用戶層之間,提供了與生產(chǎn)商無關(guān)的硬件這對軟件的移植是有極大的好處的。STM32的庫,就是按照CMSIS標準建立的。 、文件簡STM32標準庫可以從官網(wǎng)獲得,也可以直接從本書的配套資料得到。本書講解的例程全部采用1.5.1庫文件。以下內(nèi)容請大家打開STM32標準庫文件配合閱讀。 圖9-2ST標準 Utilities:包含了基于ST實驗板的例程,以及第軟件庫,如emwin圖形軟件庫、fatfs文件系統(tǒng)。stm32f4xx_dsp_stdperiph…HTML文件,主要HTML就是告訴我們:ST公司已經(jīng)為你寫好了每個外設(shè)的驅(qū)動了,想知道如何運用這些例子就來向我求的。但這里要告訴大家,英文僅僅是一種工具,絕對不能讓它成為我們學習的障在使用庫開發(fā)時,我們需要把libraries 幫助文檔來了解ST提供的庫函數(shù),這個文檔說明了每一個庫函數(shù)的使用方法。先看看CMSIS文件夾。文件夾下內(nèi)容見圖圖9-3CMSIS文件夾內(nèi) 其中DeviceIncludeInclude文件夾中包含了的是位于CMSIS標準的核內(nèi)設(shè)備函數(shù)層的Cortex-M核通用的頭文件,它們的作用是為那些采用Cortex-M核設(shè)計SOC的商設(shè)計的外設(shè)提供一個進入內(nèi)核的接口,定義了一些內(nèi)核相關(guān)的寄存器(類似我們前面寫的stm32f4xx.h文件,但定義的是內(nèi)核部分的寄存器)。這些文件在其它公司的Cortex-M系列也是相同《cortex_m4_TechnicalReferenceManual》及《Cortex?-M4內(nèi)核參考手冊》文檔,《STM32我們寫STM32F4的工程,必須用到其中的四個文件:core_cm4.h、core_cmFunc.h、core_cm4.c文件有一些與編譯器相關(guān)條件編譯語句,用于不同編譯器的差異。里面包含了一些跟編譯器相關(guān)的信息,如:“CC_ARM”(本書采用的RVMDK、KEIL),“GNUC”(GNU編譯器)、“ICCCompiler(IAR編譯器)。這些不同的編譯器對于C嵌入?yún)R編或內(nèi)聯(lián)函數(shù)關(guān)鍵字的語法不一樣,這段代碼統(tǒng)一使用“ASM、INLINE”宏代 9-1:core_cm3.c文件中對編譯器差異 defined(CC_ARM

使用RVMDK編譯器時#define asm /*!<asmkey的關(guān)鍵字形 er inline/*

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論