STM32第一章-寄存器你懂嗎

1、什麼是嵌入式

嵌入式系統是小型計算機的一個分支系統。日常用的PC,就屬於功能比較專注的計算機,從核心的處理器來講,能夠分紅嵌入式微處理器和嵌入式微控制器,咱們傳統意義上的那種單片機,好比說像5一、AVR還有按裏面比較低配的一些,好比說像Cortex-M系列的這一類,咱們都把它劃分爲微控制器,微處理器呢,就相對來講處理能力,運算能力要強一些,好比ARM9以上的系列和 Cortex-A以及以上系列。STM32屬於一個微控制器,請你們緊緊記住微控制器這四個字。STM32自帶了各類經常使用通訊接口,好比USART、I2C、SPI等,可接很是多的傳感器,能夠控制不少的設備。現實生活中,咱們接觸到的不少電器產品都有STM32的身影,好比智能手環,微型四軸飛行器,平衡車、移動POST機,智能電飯鍋,3D打印機等等。編程

2、STM32長啥樣

以STM32F429IGT6爲例。芯片正面是絲印,ARM表示該芯片使用的是ARM的內核,STM32F429IGT6是芯片型號。芯片四周是引腳,左下角的小圓點表示1腳,而後從1腳起按照逆時針的順序排列(全部芯片的引腳順序都是逆時針排列的)。開發板中把芯片的引腳引出來,鏈接到各類傳感器上,而後在STM32上編程(實際就是經過程序控制這些引腳輸出高電平或者低電平)來控制各類傳感器工做,經過作實驗的方式來學習STM32芯片的各個資源。 在這裏插入圖片描述小程序

3、芯片裏面有什麼

咱們看到的STM32芯片已是已經封裝好的成品,主要由內核片上外設組成。若與電腦類比,內核與外設就如同電腦上的CPU與主板、內存、顯卡、硬盤的關係。 STM32F429採用的是Cortex-M4內核,內核即CPU,由ARM公司設計。ARM公司並不生產芯片,而是出售其芯片技術受權。芯片生產廠商(SOC)如ST、TI、Freescale,負責在內核以外設計部件並生產整個芯片,這些內核以外的部件被稱爲核外外設或片上外設。如GPIO、USART(串口)、I2C、SPI等都叫作片上外設。markdown

4、存儲器映射

請牢記住這一句話鏈接被控總線的是FLASH,RAM和片上外設,這些功能部件共同排列在一個4GB的地址空間內。咱們在編程的時候,操做的也正是這些功能部件。存儲器自己不具備地址信息,它的地址是由芯片廠商或用戶分配,給存儲器分配地址的過程就稱爲存儲器映射。若是給存儲器再分配一個地址就叫存儲器重映射寄存器映射 這個圖很是很是重要,初學者可能看不懂這個圖。接寫來我就詳細的將講解這一張圖,讓你真正的明白什麼是內存,什麼是寄存器,什麼是寄存器映射。學習

首先看這個圖最左邊的一豎排方格。咱們前面說到鏈接被控總線的是FLASH,RAM和片上外設,這些功能部件共同排列在一個4GB的地址空間內。這裏的4GB的地址空間就分佈在這個圖最左邊的一豎排方格中。從0x0000 0000到0xFFFF FFFF。一看到這個東西你們可能又不知道這是個啥,爲啥子地址要這樣寫。0x表明16進制,其實一看到F就知道這是十六進制了(0 1 2 3 4 5 6 7 8 9 A B C D E F16個數)。那0x0000 0000到0xFFFF FFFF是怎麼算成是4GB大小的呢?ui

  • 咱們首先把這些16進制化成2進制來看看,就是 從0000 0000 0000 0000 0000 0000 0000 0000 到 1111 1111 1111 1111 1111 1111 1111 1111 要清楚16進制的1位數在2進制中就要表示爲4位。例如16進制的F在二進制中2就表示爲1111。 從0000 0000 0000 0000 0000 0000 0000 0000 到 1111 1111 1111 1111 1111 1111 1111 1111 一共有2^(32)=4294967296個字節。 4294967296byte/1024=4194304KB, 4194304KB/1024=4096MB, 4096MB/1024=4GB.

額外的小知識 1TByte=1024GByte, 1GByte=1024MByte, 1MByte=1024KByte,(1MB=10241024個字節) 1KByte=1024Byte, (1KB=1024個字節) 1Byte=8bit(一個字節由8個二進制位組成) int i;int類型佔4個字節就是48=32個bit位(最大可表示的數爲2^31-1=2147483647) double i;double類型佔8個字節就是8*8=64個bit位(最大可表示的數爲2^63-1)spa

至此咱們就清楚了4GB的大小空間,在內存中有多少的個地址。 內存地址描述圖 在這4GB中,分爲8塊。每一塊的大小就是512MB字節。 存儲器功能分類其中第三塊,也就是Block2地址從0x4000 0000 到 0x5FFF FFFF分配給了咱們的片上外設用如GPIO、USART(串口)、I2C、SPI等。在這8個Block裏面,有3個塊很是重要,也是咱們最關心的三個塊。Boock0用來設計成內部FLASH,Block1用來設計成內部RAM,Block2用來設計成片上的外設。設計

4.一、存儲器Block0內部區域功能劃分

Block0主要用於設計片內的FLASH,F429系列片內部FLASH最大是2MB,咱們使用的STM32F429IGT6的FLASH是1MB。要在芯片內部集成更大的FLASH或者SRAM都意味着芯片成本的增長,每每片內集成的FLASH都不會太大,ST能在追求性價比的同時作到1MB以上,實乃良心之舉。Block內部區域的功能劃分具體見下圖。 存儲器Block0內部區域功能劃分3d

4.二、儲存器Block1內部區域功能劃分

Block1用於設計片內的SRAM。F429內部SRAM的大小爲256KB,其中64KB的CCM RAM位於Block0,剩下的192KB位於Block1,分SRAM1112KB,SRAM216KB,SRAM364KB,Block內部區域的功能劃分具體見下圖。 儲存器Block1內部區域功能劃分指針

4.三、儲存器Block2內部區域功能劃分

Block2用於設計片內的外設,根據外設的總線速度不一樣,Block被分紅了APB和AHB兩部分,其中APB又被分爲APB1和APB2,AHB分爲AHB1和AHB2,從小到大依次是APB一、APB二、AHB一、AHB1。具體見下圖。還有一個AHB3包含了Block3/4/5/6,這四個Block用於擴展外部存儲器,如SDRAM,NORFLASH和NANDFLASH等。 儲存器Block2內部區域功能劃分 在這裏我但願你們一看到地址就要知道它是在內存的哪個區域的,要會熟練地把地址和內存大小空間聯繫起來。若是你第一次不懂不要緊,在後面遇到了必定要回過頭來再看一遍,直到看懂爲止。code

5、寄存器映射

上面講的是存儲器映射,就是給存儲器劃分大小,分配地址,給存儲器編號。 下面講的是寄存器映射,就是給寄存器劃分大小,分配地址,給寄存器編號。

在存儲器 Block2 這塊區域,設計的是片上外設,它們以4個字節爲一個單元,共4*8=32bit,每個單元對應不一樣的功能,當咱們控制這些單元時就能夠驅動外設工做。咱們能夠找到每一個單元的起始地址,而後經過C語言指針的操做方式來訪問這些單元,若是每次都是經過這種地址的方式來訪問,不只很差記憶還容易出錯,這時咱們能夠根據每一個單元功能的不一樣,以功能爲名給這個內存單元取一個別名,這個別名就是咱們常常說的寄存器,這個給已經分配好地址的有特定功能的內存單元取別名的過程就叫寄存器映射。

好比,咱們找到 GPIOH 端口的輸出數據寄存器 ODR的地址是 0x40021C14(至於這個地址如何找到能夠先跳過,後面咱們會有詳細的講解),ODR 寄存器是 32bit,就是說ODR 寄存器在內存中佔據4個空位即四個地址(我以爲這樣說比較形象,比較好理解)低16bit(後面兩個格子能夠操做)有效,對應着 16個外部 IO,寫 0/1 對應的的 IO 則輸出低/高電平。如今咱們經過 C語言指針的操做方式,讓 GPIOH 的16個IO都輸出高電平。

// GPIOH 端口所有輸出 高電平
*(unsigned int*)(0x4002 1C14) = 0xFFFF;
複製代碼

有人會說咋不寫0x0000 FFFF 這樣看不是更直觀嗎?其實0x0000 FFFF和0xFFFF表示的意思同樣,就好比1和01都表示1,直接寫1不是更簡單嗎?對吧。可是你有這個想法很好,說明你在思考。

0x40021C14在咱們看來是 GPIOH端口 ODR的地址,可是在編譯器看來,這只是一個普通的變量,是一個當即數,要想讓編譯器也認爲是指針,咱們得進行強制類型轉換,把它轉換成指針,即(unsigned int*)0x40021C14,而後再對這個指針進行* 操做。剛剛咱們說了,經過絕對地址訪問內存單元很差記憶且容易出錯,咱們能夠經過寄存器的方式來操做.

// GPIOH 端口所有輸出 高電平
# define GPIOH_ODR *(unsigned int*)(GPIOH_BASE+0x14)
GPIOH_ODR = 0xFF;
複製代碼

5.1.STM32的外設地址映射

上面講的是存儲器映射,就是給存儲器劃分大小,分配地址,給存儲器編號。 寄存器映射,就是給寄存器劃分大小,分配地址,給寄存器編號。下面講STM32的外設地址映射,就是給外設地址劃分大小,從新分配地址,給外設地址編號。

片上外設區分爲四條總線,根據外設速度的不一樣,不一樣總線掛載着不一樣的外設,APB掛載低速外設,AHB掛載高速外設。相應總線的最低地址咱們稱爲該總線的基地址,總線基地址也是掛載在該總線上的首個外設的地址。其中 APB1總線的地址最低,片上外設從這裏開始,也叫外設基地址。

5.1.1總線基地址

總線基地址
總線基地址

5.1.2外設基地址

總線上掛載着各類外設,這些外設也有本身的地址範圍,特定外設的首個地址稱爲、「XX外設基地址」,也叫 XX外設的邊界地址。 外設基地址GPIOA的基址相對於 AHB1總線的地址偏移爲 0,咱們應該就能夠猜到,AHB1總線的第一個外設就是 GPIOA。

5.1.3外設寄存器

在 XX外設的地址範圍內,分佈着的就是該外設的寄存器。以 GPIO 外設爲例,GPIO是通用輸入輸出端口的簡稱,簡單來講就是 STM32可控制的引腳,基本功能是控制引腳輸出高電平或者低電平。最簡單的應用就是把 GPIO 的引腳鏈接到 LED 燈的陰極,LED 燈的陽極接電源,而後經過 STM32控制該引腳的電平,從而實現控制 LED 燈的亮滅。GPIO有不少個寄存器,每個都有特定的功能。每一個寄存器爲 32bit,佔四個字節,在該外設的基地址上按照順序排列,寄存器的位置都以相對該外設基地址的偏移地址來描述。這裏咱們以 GPIOH 端口爲例,來講明 GPIO 都有哪些寄存器 GPIOH 端口 這裏咱們以「GPIO 端口置位/復位寄存器」爲例,教你們如何理解寄存器的說明, GPIO 端口置位/復位寄存器說明)

  • 名稱 寄存器說明中首先列出了該寄存器中的名稱,「(GPIOx_BSRR)(x=A…I)」這段的意思是該寄存器名爲「GPIOx_BSRR」其中的「x」能夠爲 A-I,也就是說這個寄存器說明適用於 GPIOA、GPIOB 至 GPIOI,這些 GPIO 端口都有這樣的一個寄存器。
  • 偏移地址 偏移地址是指本寄存器相對於這個外設的基地址的偏移本寄存器的偏移地址是 0x18,從參考手冊中咱們能夠查到 GPIOA外設的基地址爲 0x4002 0000 ,就是AHB1這一塊內存的首地址,GPIO是掛載在咱們AHB1的總線上面的。咱們就能夠算出GPIOA的這個 GPIOA_BSRR 寄存器的地址爲:0x4002 0000+0x18 ;同理,因爲 GPIOB的外設基地址爲 0x4002 0400,可算出 GPIOB_BSRR 寄存器的地址爲:0x4002 0400+0x18 。其餘 GPIO端口以此類推便可。
  • 寄存器位表 緊接着的是本寄存器的位表,表中列出它的 0-31位的名稱及權限。表上方的數字爲位編號,中間爲位名稱,最下方爲讀寫權限,其中 w 表示只寫,r 表示只讀,rw 表示可讀寫。本寄存器中的位權限都是 w,因此只能寫,若是讀本寄存器,是沒法保證讀取到它真正內容的。而有的寄存器位只讀,通常是用於表示 STM32 外設的某種工做狀態的,由 STM32硬件自動更改,程序經過讀取那些寄存器位來判斷外設的工做狀態。
  • 位功能說明 位功能是寄存器說明中最重要的部分,它詳細介紹了寄存器每個位的功能。例如本寄存器中有兩種寄存器位,分別爲 BRy及 BSy,其中的 y數值能夠是 0-15,這裏的 0-15表示端口的引腳號,如 BR0、BS0用於控制 GPIOx的第 0 個引腳,若 x表示 GPIOA,那就是控制 GPIOA的第 0引腳,而 BR一、BS1 就是控制 GPIOA第 1個引腳。其中 BRy引腳的說明是「0:不會對相應的 ODRx 位執行任何操做;1:對相應 ODRx位進行復位」。這裏的**「復位」是將該位設置爲 0的意思**,而**「置位」表示將該位設置爲1**;說明中的 ODRx 是GPIO的另外一個寄存器的寄存器位,咱們只須要知道 ODRx位爲 1 的時候,對應的引腳 x輸出高電平,爲 0 的時候對應的引腳輸出低電平。因此,若是對 BR0 寫入「1」的話,那麼 GPIOx的第0 個引腳就會輸出「低電平」,可是對 BR0寫入「0」的話,卻不會影響 ODR0位,因此引腳電平不會改變。要想該引腳輸出「高電平」,就須要對「BS0」位寫入「1」,寄存器位BSy與 BRy是相反的操做。

這個功能說明建議多讀幾遍,反覆的去讀,直達完全理解爲止。

5.2.C語言對寄存器的封裝

5.2.1封裝總線和外設基地址

在編程上爲了方便理解和記憶,咱們把總線基地址和外設基地址都以相應的宏定義起來,總線或者外設都以他們的名字做爲宏名

/* 外設基地址 */
#define PERIPH_BASE ((uint32_t)0x40000000) // 0x40000000是APB1的首地址,請看最前面的的那張圖
#define APB1PERIPH_BASE PERIPH_BASE//使用宏定義 用APB1PERIPH_BASE代替PERIPH_BASE
//下面依次內推便可獲得GPIOA_BASE~GPIOK_BASE
/* 總線基地址 */
#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000)
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000)
/* GPIO 外設基地址 */
#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000)
#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400)
#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800)
#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00)
#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000)
#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400)
#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800)
#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00)
#define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000)
#define GPIOJ_BASE (AHB1PERIPH_BASE + 0x2400)
#define GPIOK_BASE (AHB1PERIPH_BASE + 0x2800)
/* 寄存器基地址,以 GPIOA 爲例 */
#define GPIOA_MODER (GPIOA_BASE+0x00)
#define GPIOA_OTYPER (GPIOA_BASE+0x04)
#define GPIOA_OSPEEDR (GPIOA_BASE+0x08)
#define GPIOA_PUPDR (GPIOA_BASE+0x0C)
#define GPIOA_IDR (GPIOA_BASE+0x10)
#define GPIOA_ODR (GPIOA_BASE+0x14)
#define GPIOA_BSRR (GPIOA_BASE+0x18)
#define GPIOA_LCKR (GPIOA_BASE+0x1C)
#define GPIOA_AFRL (GPIOA_BASE+0x20)
#define GPIOA_AFRH (GPIOA_BASE+0x24)
複製代碼

代碼首先定義了 「片上外設」基地址 PERIPH_BASE(0x40000000),接着在 PERIPH_BASE 上加入各個總線的地址偏移,獲得 APB一、APB2 等總線的地址 APB1PERIPH_BASE、APB2PERIPH_BASE,在其之上加入外設地址的偏移,獲得 GPIOA到GPIOK的外設地址,最後在外設地址上加入各寄存器的地址偏移,獲得特定寄存器的地址。一旦有了具體地址,就能夠用指針操做讀寫了,具體見代碼

/* 控制 GPIOA 引腳 10 輸出低電平(BSRR 寄存器的 BR10 置 1) */
*(unsigned int *)GPIOA_BSRR = (0x01<<(16+10));
/* 控制 GPIOA 引腳 10 輸出高電平(BSRR 寄存器的 BS10 置 1) */
*(unsigned int *)GPIOA_BSRR = 0x01<<10;
unsigned int temp;
/* 控制 GPIOH 端口全部引腳的電平(讀 IDR 寄存器) */
temp = *(unsigned int *)GPIOA_IDR;
複製代碼

該代碼使用 (unsigned int*) 把 GPIOA_BSRR宏的數值強制轉換成了地址,而後再用「*」號作取指針操做,對該地址的賦值,從而實現了寫寄存器的功能。一樣,讀寄存器也是用取指針操做,把寄存器中的數據取到變量裏,從而獲取 STM32外設的狀態。

5.2.2封裝寄存器列表

用上面的方法去定義地址,仍是稍顯繁瑣,例如 GPIOA-GPIOH 都各有一組功能相同的寄存器,如 PIOA_MODER和GPIOB_MODER和GPIOC_MODER 等等,它們只是地址不同,但卻要爲每一個寄存器都定義它的地址。爲了更方便地訪問寄存器,咱們引入 C語言中的結構體語法對寄存器進行封裝,具體見代碼

typedef unsigned int uint32_t;       /*無符號 32 位變量 佔4個字節*/
typedef unsigned short int uint16_t; /*無符號 16 位變量 佔2個字節*/
/* GPIO 寄存器列表 */
typedef struct
{

uint32_t MODER; /*GPIO 模式寄存器 地址偏移: 0x00 */
uint32_t OTYPER; /*GPIO 輸出類型寄存器 地址偏移: 0x04 */
uint32_t OSPEEDR; /*GPIO 輸出速度寄存器 地址偏移: 0x08 */
uint32_t PUPDR; /*GPIO 上拉/下拉寄存器 地址偏移: 0x0C */
uint32_t IDR; /*GPIO 輸入數據寄存器 地址偏移: 0x10 */
uint32_t ODR; /*GPIO 輸出數據寄存器 地址偏移: 0x14 */
uint16_t BSRRL; /*GPIO 置位/復位寄存器低 16 位部分 地址偏移: 0x18 */
uint16_t BSRRH; /*GPIO 置位/復位寄存器高 16 位部分 地址偏移: 0x1A */
uint32_t LCKR; /*GPIO 配置鎖定寄存器 地址偏移: 0x1C */
uint32_t AFR[2]; /*GPIO 複用功能配置寄存器 地址偏移: 0x20-0x24 */
} GPIO_TypeDef;
複製代碼

這段代碼用 typedef 關鍵字聲明瞭名爲 GPIO_TypeDef的結構體類型,結構體內有 8個成員變量,變量名正好對應寄存器的名字。C語言的語法規定,結構體內變量的存儲空間是連續的(這一點很是重要,否則就亂了套了),其中 32 位的變量佔用 4個字節,16位的變量佔用 2 個字節,具體見。 GPIO_TypeDef 結構體成員的地址偏移 也就是說,咱們定義的這個 GPIO_TypeDef ,假如這個結構體的首地址爲 0x40021C00(這也是第一個成員變量 MODER的地址), 那麼結構體中第二個成員變量OTYPER的地址即爲 0x4002 1C00 +0x04 ,加上的這個 0x04 ,正是表明 MODER所佔用的 4 個字節地址的偏移量,其它成員變量相對於結構體首地址的偏移,在上述代碼右側註釋已給出,其中的 BSRR寄存器分紅了低 16位 BSRRL和高 16位 BSRRH,BSRRL置 1 引腳輸出高電平,BSRRH 置 1引腳輸出低電平,這裏分開只是爲了方便操做。 這樣的地址偏移與 STM32 GPIO外設定義的寄存器地址偏移一一對應,只要給結構體設置好首地址,就能把結構體內成員的地址肯定下來,而後就能以結構體的形式訪問寄存器了,具體見代碼

GPIO_TypeDef * GPIOx;      //定義一個 GPIO_TypeDef 型結構體指針 GPIOx
GPIOx = GPIOH_BASE; //把指針地址設置爲宏 GPIOH_BASE 地址
GPIOx->BSRRL = 0xFFFF; //經過指針訪問並修改 GPIOH_BSRRL 寄存器
GPIOx->MODER = 0xFFFFFFFF; //修改 GPIOH_MODER 寄存器
GPIOx->OTYPER =0xFFFFFFFF; //修改 GPIOH_OTYPER 寄存器
uint32_t temp;
temp = GPIOx->IDR; //讀取 GPIOH_IDR 寄存器的值到變量 temp 中
複製代碼

這段代碼先用 GPIO_TypeDef類型定義一個結構體指針 GPIOx,並讓指針指向地址GPIOH_BASE(0x4002 1C00),使用地址肯定下來,而後根據 C語言訪問結構體的語法,用GPIOx->BSRRL、GPIOx->MODER及 GPIOx->IDR 等方式讀寫寄存器。最後,咱們更進一步,直接使用宏定義好 GPIO_TypeDef類型的指針,並且指針指向各個 GPIO端口的首地址,使用時咱們直接用該宏訪問寄存器便可.

/*使用 GPIO_TypeDef 把地址強制轉換成指針*/
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE)
#define GPIOI ((GPIO_TypeDef *) GPIOI_BASE)
#define GPIOJ ((GPIO_TypeDef *) GPIOJ_BASE)
#define GPIOK ((GPIO_TypeDef *) GPIOK_BASE)
複製代碼

這裏咱們僅是以 GPIO 這個外設爲例,給你們講解了 C 語言對寄存器的封裝。以此類推,其餘外設也一樣能夠用這種方法來封裝。好消息是,這部分工做都由固件庫幫咱們完成了,這裏咱們只是分析了下這個封裝的過程,讓你們知其然,也只其因此然。 下面寫一個小程序,其餘的都已經省略:

GPIO_InitTypeDef  GPIO_InitStructure;//GPIO_InitTypeDef是一個結構體,GPIO_InitStructure是定義的一個結構體變量,你能夠起名字爲阿貓阿狗均可以,只不過咱們習慣用GPIO_InitStructure,起到見明知意的效果,過有人都看得懂。
/* 第1步:打開GPIOA時鐘,必須的一步 */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
/* 第2步:配置全部的按鍵GPIO爲浮動輸入模式(實際上CPU復位後就是輸入狀態) */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; /* PA13 */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;/* 設爲輸入口 */
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;/* 設爲推輓模式 */
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;/* 無需上下拉電阻 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/* IO口最大速度 */
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 第1步:打開GPIOA的第13個引腳置位操做 */
GPIO_WritePin(GPIOA,GPIO_PIN_13,GPIO_PIN_SET); //引腳PA13拉高,置位1
GPIO_WritePin(GPIOA,GPIO_PIN_13,GPIO_PIN_RESET); //引腳PA13拉低,置位0
複製代碼
相關文章
相關標籤/搜索