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

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

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

ARM Cortex-M學(xué)習(xí)筆記:初識GPIO流水燈

CHANBAEK ? 來源:嵌入式實(shí)驗(yàn)樓 ? 作者:BruceOu ? 2023-05-15 11:31 ? 次閱讀

1.1 GPIO工作原理

熟悉單片機(jī)的朋友都知道,學(xué)習(xí)的第一個(gè)例程就是流水燈,要想實(shí)現(xiàn)流水燈,首先必須了解GPIO的工作原理。GPIO的基本結(jié)構(gòu)如圖1所示。

圖片

STM32 的 IO 口可以由軟件配置成如下 8 種模式:

  • 輸入模式
  • 浮空輸入:浮空(floating)就是邏輯器件的輸入引腳即不接高電平,也不接低電平。由于邏輯器件的內(nèi)部結(jié)構(gòu),當(dāng)它輸入引腳懸空時(shí),相當(dāng)于該引腳接了高電平。一般實(shí)際運(yùn)用時(shí),引腳不建議懸空,易受干擾。 通俗講就是讓管腳什么都不接,浮空著。信號進(jìn)入芯片內(nèi)部后,既沒有接上拉電阻也沒有接下拉電阻,經(jīng)由觸發(fā)器輸入。配置成這個(gè)模式后,用電壓變量引腳電壓為1點(diǎn)幾伏,這是個(gè)不確定值。由于其輸入阻抗比較大,一般把這種模式用于標(biāo)準(zhǔn)的通訊協(xié)議,比如IIC、USART的等。該模式是STM32復(fù)位之后的默認(rèn)模式。

圖片

  • 上拉輸入:上拉就是把電位拉高,比如拉到Vcc。上拉就是將不確定的信號通過一個(gè)電阻嵌位在高電平,電阻同時(shí)起限流作用,弱強(qiáng)只是上拉電阻的阻值不同,沒有什么嚴(yán)格區(qū)分。上拉輸入就是信號進(jìn)入芯片后加了一個(gè)上拉電阻,再經(jīng)過施密特觸發(fā)器轉(zhuǎn)換成0、1信號,讀取此時(shí)的引腳電平為高電平;

圖片

  • 下拉輸入:就是把電壓拉低,拉到GND。與上拉原理相似。下拉輸入就是信號進(jìn)入芯片后加了一個(gè)下拉電阻,再經(jīng)過施密特觸發(fā)器轉(zhuǎn)換成0、1信號,讀取此時(shí)的引腳電平為低電平;

圖片

  • 模擬輸入:信號進(jìn)入后不經(jīng)過上拉電阻或者下拉電阻,關(guān)閉施密特觸發(fā)器,經(jīng)由另一線路把電壓信號傳送到片上外設(shè)模塊。模擬輸入是指傳統(tǒng)方式的輸入,數(shù)字輸入是輸入PCM數(shù)字信號,即0、1的二進(jìn)制數(shù)字信號,通過數(shù)模轉(zhuǎn)換,轉(zhuǎn)換成模擬信號,經(jīng)前級放大進(jìn)入功率放大器,功率放大器還是模擬的。比如傳送給ADC模塊,由ADC采集電壓信號。所以可以理解為模擬輸入的信號是未經(jīng)處理的信號,是原汁原味的信號。

圖片

  • 輸出模式
  • 開漏輸出:一般用在電平不匹配的場合,如需要輸出5V的高電平。輸出端相當(dāng)于三極管的集電極,要得到高電平狀態(tài)需要上拉電阻才行。適合于做電流型的驅(qū)動,其吸收電流的能力相對強(qiáng)(一般20mA以內(nèi))。

圖片

  • 復(fù)用開漏輸出:可以理解為GPIO口被用作第二功能時(shí)的配置情況(即并非作為通用IO口使用)。端口必須配置成復(fù)用開漏功能輸出模式。

圖片

  • 推挽式輸出:可以輸出高、低電平,連接數(shù)字器件;推挽結(jié)構(gòu)一般是指兩個(gè)三極管分別受兩個(gè)互補(bǔ)信號的控制,總是在一個(gè)三極管導(dǎo)通的時(shí)候另一個(gè)截止。高低電平由IC的電源決定。推挽電路是兩個(gè)參數(shù)相同的三極管或MOSFET,以推挽方式存在于電路中,各負(fù)責(zé)正負(fù)半周的波形放大任務(wù),電路工作時(shí),兩只對稱的功率開關(guān)管每次只有一個(gè)導(dǎo)通,所以導(dǎo)通損耗小、效率高。輸出既可以向負(fù)載灌電流,也可以從負(fù)載抽取電流。推拉式輸出級既提高電路的負(fù)載能力,又提高開關(guān)速度。

圖片

  • 推挽式復(fù)用輸出

圖片

1.2 I/O復(fù)用和重映射

1.2.1 I/O復(fù)用

STM32 有很多的內(nèi)置外設(shè),這些外設(shè)的外部引腳都是與 GPIO 復(fù)用的。也就是說,一個(gè) GPIO如果可以復(fù)用為內(nèi)置外設(shè)的功能引腳,那么當(dāng)這個(gè) GPIO 作為內(nèi)置外設(shè)使用的時(shí)候,就叫做復(fù)用。當(dāng)I/O端口被配置為復(fù)用功能時(shí):

●在開漏或推挽式配置中,輸出緩沖器被打開

●內(nèi)置外設(shè)的信號驅(qū)動輸出緩沖器(復(fù)用功能輸出)

●施密特觸發(fā)輸入被激活

●弱上拉和下拉電阻被禁止

●在每個(gè)APB2時(shí)鐘周期,出現(xiàn)在I/O腳上的數(shù)據(jù)被采樣到輸入數(shù)據(jù)寄存器

●開漏模式時(shí),讀輸入數(shù)據(jù)寄存器時(shí)可得到I/O口狀態(tài)

●在推挽模式時(shí),讀輸出數(shù)據(jù)寄存器時(shí)可得到最后一次寫的值

圖片

大家都知道, MCU 都有串口, STM32 有好幾個(gè)串口。比如說 STM32F103ZET6 有 5 個(gè)串口,我們可以查手冊知道,串口 1 的引腳對應(yīng)的 IO 為 PA9,PA10.PA9, PA10 默認(rèn)功能是 GPIO,所以當(dāng)PA9,PA10 引腳作為串口 1 的 TX,RX 引腳使用的時(shí)候,那就是端口復(fù)用。

USART1_TX PA9
USART1_RX PA10

復(fù)用端口初始化有幾個(gè)步驟:

1) GPIO 端口時(shí)鐘使能。要使用到端口復(fù)用,當(dāng)然要使能端口的時(shí)鐘了。RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

2)復(fù)用的外設(shè)時(shí)鐘使能。比如你要將端口 PA9,PA10 復(fù)用為串口,所以要使能串口時(shí)鐘。RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

3)端口模式配置。

關(guān)于串口的內(nèi)容后面的章節(jié)會詳細(xì)講解。

1.2.2 I/O重映射

為了使不同器件封裝的外設(shè) IO 功能數(shù)量達(dá)到最優(yōu),可以把一些復(fù)用功能重新映射到其他一些引腳上。 STM32 中有很多內(nèi)置外設(shè)的輸入輸出引腳都具有重映射(remap)的功能。我們知道每個(gè)內(nèi)置外設(shè)都有若干個(gè)輸入輸出引腳,一般這些引腳的輸出端口都是固定不變的,為了讓設(shè)計(jì)工程師可以更好地安排引腳的走向和功能,在 STM32 中引入了外設(shè)引腳重映射的概念,即一個(gè)外設(shè)的引腳除了具有默認(rèn)的端口外,還可以通過設(shè)置重映射寄存器的方式,把這個(gè)外設(shè)的引腳映射到其它的端口。

復(fù)用功能 USART1_REMAP = 0 USART1_REMAP = 1
USART1_TX PA9 PB6
USART1_RX PA10 PB7

從表中可以看出,默認(rèn)情況下,串口 1 復(fù)用的時(shí)候的引腳位 PA9、PA10,同時(shí)我們可以將 TX 和 RX 重新映射到管腳 PB6 和 PB7 上面去。所以重映射我們同樣要使能復(fù)用功能的時(shí)候講解的 2 個(gè)時(shí)鐘外,還要使能 AFIO 功能時(shí)鐘,然后要調(diào)用重映射函數(shù)。

詳細(xì)步驟為:

1)使能 GPIOB 時(shí)鐘:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

2)使能串口 1 時(shí)鐘:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

3)使能 AFIO 時(shí)鐘:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);

4)開啟重映射:

GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);

這樣就將串口的 TX 和 RX 重映射到管腳 PB6 和 PB7 上面了。

1.3 GPIO流水燈硬件電路分析

發(fā)光二極管是屬于二極管的一種,具有二級管單向?qū)щ娞匦裕粗挥性谡螂妷海ǘO管的正極接正,負(fù)極接負(fù))下才能導(dǎo)通發(fā)光。PB0引腳接發(fā)光二極管(LED1)的正極,所以PB0引腳輸出高電平LED1亮,PB0引腳輸出低電平LED1熄滅,,LED2,LED3同理。

圖片

值得注意的,不同的開發(fā)板,LED連接的GPIO一般是不同的,請注意修改。

1.4 GPIO流水燈寄存器分析

要想真正掌握一款單片機(jī),分析寄存器是必不可少,但是對于STM32來再說,ST已經(jīng)將寄存器操作封裝成庫函數(shù),開發(fā)者只需要調(diào)用庫函數(shù)即可,對于初學(xué)者來說,只需學(xué)會使用使用函數(shù)即可,筆者在《入門篇》也說了為何要來使用庫函數(shù)以及使用庫開發(fā)的好處,因此對于沒有基礎(chǔ)的讀者朋友就不必細(xì)究每個(gè)寄存器,當(dāng)學(xué)到一定程度,再來一探究竟吧,筆者再這里只是給出GPIO的寄存配置相關(guān)配置表,在后面的章節(jié)也是如此。好了,繼續(xù)進(jìn)入正題吧。

每個(gè)GPIO端口都有兩個(gè)32位配置寄存器(GPIOx_CRL ,GPIOx_CRH) ,兩個(gè)32位數(shù)據(jù)寄存器 (GPIOx_IDR和GPIOx_ODR),一個(gè)32位置位/ 復(fù)位寄存器(GPIOx_BSRR),一個(gè)16位復(fù)位寄存器(GPIOx_BRR),一個(gè)32位鎖定寄存器(GPIOx_LCKR)。每個(gè)I/O端口位可以自由編程,然而I/O端口寄存器必須按32位字被訪問(不允許半字或字節(jié)訪問) 。

點(diǎn)亮LED,基本步驟是:配置寄存器;控制寄存器。庫開發(fā)只是將傳統(tǒng)的配置方式編程函數(shù),是的單片機(jī)開發(fā)變得簡單方便快捷。

我們常用的 IO 端口寄存器只有 4 個(gè): CRL、 CRH、 IDR、 ODR。其中CRL 和 CRH 控制著每個(gè) IO 口的模式及輸出速率。

圖片

圖片

低配置寄存器 CRL 的描述,如下圖和下表所示。

CRL和CRH類似,在此就不在贅述了,讀者朋友可以參看《STM32F10XXX參考手冊》數(shù)據(jù)輸入輸出寄存器是將對應(yīng)的IO口置位,從而進(jìn)行數(shù)據(jù)的輸入與輸出。

圖片

圖片

1.5 GPIO 流水燈實(shí)現(xiàn)流程

筆者在上文已經(jīng)分析了GPIO的原理及操作步驟,現(xiàn)在我們就來寫代碼吧。本書是用庫來對STM32來開發(fā)的,這是本書的第一個(gè)實(shí)例,筆者為了讀者比較直接配置寄存和庫開發(fā)的區(qū)別,筆者在此用了兩種方式進(jìn)行開發(fā),希望讀者能自己體會兩種方式的優(yōu)劣。這里筆者會使用兩種庫:標(biāo)準(zhǔn)庫和HAL庫。

不管使用何種實(shí)現(xiàn)方式,其流程都是一樣的。

GPIO是開發(fā)STM32最基本的配置,所以掌握GPIO的配置顯得尤為重要。要實(shí)現(xiàn)流水燈,一般步驟可以總結(jié)為如下:

  1. GPIO 時(shí)鐘使能;
  2. GPIO 端口模式設(shè)置;
  3. 初始化IO口;
  4. 編寫處理函數(shù);

1.6GPIO 流水燈實(shí)現(xiàn)-直接操作寄存器方式

先看主函數(shù)。

/*Includes*********************************************************************/
#include"./LED/stm32f103_led.h"

/*延時(shí)函數(shù)*/
void Delay(u32 xms);

/**
 * @brief     主函數(shù)
 * @param     None
 * @retval    int
 */
int main(void)
{     
       /*LED 初始化 */
       LED_GPIO_Config();    

       while(1)
       {
              //ODR GPIOB
              //15 14 13 12     11 10 9 8    7 6 5 4   3 2 1 0
              //0  0 0  0      0 0  0 0    0 0 0 0   0 0 0 0 (復(fù)位值)
              //1  1 1  1      1 1  1 1    1 1 1 1   1 1 1 0
              GPIOB->ODR= 0XFFFE;           //低電平,GPIOB0(LED1)燈滅
              Delay(0x0FFFFF);
              GPIOB->ODR= 0XFFFF;            //高電平,GPIOB0(LED1)燈亮

              //ODR GPIOG
              //15 14 13 12     11 10 9 8    7 6 5 4   3 2 1 0
              //0  0 0  0      0 0  0 0    0 0 0 0   0 0 0 0 (復(fù)位值)
              //1  1 1  1      1 1  1 1    1 0 1 1   1 1 1 1
              GPIOG->ODR= 0XFFBF;          //低電平,GPIOG6(LED2)燈滅
              Delay(0x0FFFFF);

              GPIOG->ODR= 0XFFFF;            //高電平,GPIOG6(LED2)燈亮

              //ODR GPIOG
              //15 14 13 12     11 10 9 8    7 6 5 4   3 2 1 0
              //0  0 0  0      0 0  0 0    0 0 0 0   0 0 0 0 (復(fù)位值)
              //1  1 1  1      1 1  1 1    0 1 1 1   1 1 1 1      
              GPIOG->ODR= 0XFF7F;          //低電平,GPIOG7(LED3)燈滅
              Delay(0x0FFFFF);
              GPIOG->ODR= 0XFFFF;            //高電平,GPIOG7(LED3)燈亮
       }
}

/**
 * @brief  延時(shí)函數(shù)
 * @param 
            xms 延時(shí)長度
 * @retval None
 */
void Delay( u32 xms)
{
     //for(;nCount != 0; nCount--);(方法一)
     while(xms--);//(方法二)
}

首先是GPIO初始化,然后就是無限循環(huán),不斷設(shè)置GPIO的高低電平。

GPIO初始化代碼如下:

/**
 * @brief  初始化LED的GPIO
 * @param  None
 * @retval None
 */
void LED_GPIO_Config(void)
{
    /*開啟 GPIO 時(shí)鐘,使用外設(shè)時(shí)都要先開啟它的時(shí)鐘*/
    RCC->APB2ENR|= 1 << 3;    //使能PORTB時(shí)鐘       
    RCC->APB2ENR|= 1 <<8 ;    //使能PORTG時(shí)鐘 

    /* 配置GPIO為通用推挽輸出模式,速率為50M */
    GPIOB->CRL&= 0XFFFFFFF0;
    GPIOB->CRL|= 0X00000003;    //PB.0 推挽輸出      
    GPIOB->ODR|= 1 << 0;        //PB.0 輸出高

    GPIOG->CRL&= 0X00FFFFFF;
    GPIOG->CRL|= 0X33000000;    //PG.6, PG.7推挽輸出
    GPIOG->ODR|= 3 << 6;        //PG.6, PG.7輸出高 
}

控制LED的GPIO主要做了以下事情:

1.開啟GPIO時(shí)鐘

2.設(shè)置GPIO的輸出模式和速率,具體寄存器配置請參看CRL寄存器。

3.最后設(shè)置GPIO為高電平(非必須)。

最后在主函數(shù)不斷設(shè)置GPIO的高低電平即可實(shí)現(xiàn)流水燈。

1.7 GPIO 流水燈實(shí)現(xiàn)-標(biāo)準(zhǔn)庫

1.7.1 GPIO庫函數(shù)

GPIO庫函數(shù)相關(guān)的庫函數(shù)如下:

  • GPIO_DeInit 將外設(shè) GPIOx 寄存器重設(shè)為缺省值;
  • GPIO_AFIODeInit 將復(fù)用功能(重映射事件控制和 EXTI 設(shè)置)重設(shè)為缺省值;
  • GPIO_Init 根據(jù) GPIO_InitStruct 中指定的參數(shù)初始化外設(shè) GPIOx 寄存器;
  • GPIO_StructInit 把 GPIO_InitStruct 中的每一個(gè)參數(shù)按缺省值填入;
  • GPIO_ReadInputDataBit讀取指定端口管腳的輸入;
  • GPIO_ReadInputData讀取指定的 GPIO 端口輸入;
  • GPIO_ReadOutputDataBit讀取指定端口管腳的輸出;
  • GPIO_ReadOutputData讀取指定的 GPIO 端口輸出;
  • GPIO_SetBits 設(shè)置指定的數(shù)據(jù)端口位;
  • GPIO_ResetBits 清除指定的數(shù)據(jù)端口位;
  • GPIO_WriteBit 設(shè)置或者清除指定的數(shù)據(jù)端口位;
  • GPIO_Write 向指定 GPIO 數(shù)據(jù)端口寫入數(shù)據(jù);
  • GPIO_PinLockConfig鎖定 GPIO 管腳設(shè)置寄存器;
  • GPIO_EventOutputConfig選擇 GPIO 管腳用作事件輸出;
  • GPIO_EventOutputCmd使能或者失能事件輸出;
  • GPIO_PinRemapConfig改變指定管腳的映射;
  • GPIO_EXTILineConfig選擇 GPIO 管腳用作外部中斷線路;

1.7.2使用固件庫方式

核心代碼如下:

/*Includes*********************************************************************/
#include"./LED/stm32f103_led.h"

/*簡單延時(shí)函數(shù)*/
void Delay(u32 xms);

/**
 * @brief     主函數(shù)
 * @param     None
 * @retval   
 */
int main(void)
{     
       /*LED 初始化 */
       LED_GPIO_Config();    

       while(1)
       {
              LED1(ON );                  // 亮
              Delay(0xfFfff);
              LED1(OFF );          // 滅

              LED2(ON );                  // 亮
              Delay(0xfFfff);
              LED2(OFF );          // 滅

              LED3(ON );                  // 亮
              Delay(0xffFff);
              LED3(OFF );          // 滅
       }
}

/**
 * @brief  延時(shí)函數(shù)
 * @param 
            xms 延時(shí)長度
 * @retval None
 */
void Delay( u32 xms)
{
       //for(;nCount != 0; nCount--);(方法一)
       while(xms--);//(方法二)
}

使用庫函數(shù)的流程和寄存器版的一樣,唯一不同的是這里使用了庫函數(shù),而庫函數(shù)也是對寄存器的封裝與抽象。

1.8 GPIO 流水燈實(shí)現(xiàn)-HAL庫

1.8.1 STM32Cube新建工程

關(guān)于如何使用STM32Cube新建工程在前文已經(jīng)講解過了,這里直說配置GPIO部分內(nèi)容。本文要實(shí)現(xiàn)流水燈,其實(shí)輸出為初始化設(shè)置為高電平還是低電平都可以,因?yàn)榱魉疅粜枰粩喾崔D(zhuǎn)。

1.首先進(jìn)行系統(tǒng)配置,debug模式選擇可以選擇其他模式,默認(rèn)選擇No debug,Timebase Source選擇SysTick,關(guān)于Timebase Source在后文會詳細(xì)講解。

圖片

2.時(shí)鐘配置,外部高速時(shí)鐘。

圖片

配置系統(tǒng)時(shí)鐘配置72MHz,APB1總線配置36MHz。默認(rèn)高速時(shí)鐘是使用內(nèi)部(HSI),而且CPU時(shí)鐘配置的比較低。以我選擇的STM32F103,外部8M晶振為例(如下圖)。

圖片

3.GPIO初始化配置

我們將PB0、PG6、PG7配置輸出模式(高電平、低電平均可)、輸出速率、上/下拉等,默認(rèn)即可。

圖片

4.工程生成設(shè)置

圖片

其他默認(rèn)即可。最后點(diǎn)擊“生成代碼”即可生成代碼。

圖片

1.8.2 GPIO流水燈實(shí)現(xiàn)

我們要實(shí)現(xiàn)流水燈,需要在主函數(shù)添加一下代碼。

HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);

HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);

HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_7);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_7);

圖片

1.8.3流水燈代碼分析

在分析代碼前,先看看流水燈編程流程:

1>使能GPIO端口時(shí)鐘;

2>初始化GPIO引腳,即為GPIO初始化結(jié)構(gòu)體賦值,并調(diào)用相應(yīng)初始化函數(shù)完成初始化配置;

3>根據(jù)實(shí)際需求控制流水燈。

STM32采用固件庫開發(fā),代碼比較多,因此,我們在看一個(gè)實(shí)際工程時(shí),只需從主函數(shù)開始,好了,接下來,筆者就帶領(lǐng)大家一步一步看看流水燈是怎么實(shí)現(xiàn)的。筆者先貼出主函數(shù)代碼。

int main(void)
{
 /* USER CODE BEGIN 1 */

 /* USER CODE END 1 */

 /* MCUConfiguration--------------------------------------------------------*/

 /* Reset of all peripherals, Initializes the Flash interface and theSystick. */
 HAL_Init();

 /* USER CODE BEGIN Init */

 /* USER CODE END Init */

 /* Configure the system clock */
 SystemClock_Config();

 /* USER CODE BEGIN SysInit */

 /* USER CODE END SysInit */

 /* Initialize all configured peripherals */
 MX_GPIO_Init();
 /* USER CODE BEGIN 2 */

 /* USER CODE END 2 */

 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0);

    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_6);

    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOG, GPIO_PIN_7);
 }
 /* USER CODE END 3 */
}

注釋部分不用管,我們只看代碼。

1. 復(fù)位所有硬件

HAL_Init()函數(shù)為復(fù)位所有硬件,這個(gè)就不細(xì)說了。

HAL_StatusTypeDef HAL_Init(void)
{
 /* Configure Flash prefetch */
#if (PREFETCH_ENABLE != 0)
#if defined(STM32F101x6) ||defined(STM32F101xB) || defined(STM32F101xE) || defined(STM32F101xG) || \\
    defined(STM32F102x6) ||defined(STM32F102xB) || \\
    defined(STM32F103x6) ||defined(STM32F103xB) || defined(STM32F103xE) || defined(STM32F103xG) || \\
    defined(STM32F105xC) ||defined(STM32F107xC)

 /* Prefetch buffer is not available on value line devices */
 __HAL_FLASH_PREFETCH_BUFFER_ENABLE();
#endif
#endif /* PREFETCH_ENABLE */

 /* Set Interrupt Group Priority */
 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

 /* Use systick as time base source and configure 1ms tick (default clockafter Reset is HSI) */
 HAL_InitTick(TICK_INT_PRIORITY);

 /* Init the low level hardware */
 HAL_MspInit();

 /* Return function status */
 return HAL_OK;
}

2. 時(shí)鐘初始化函數(shù)

SystemClock_Config()函數(shù)用于時(shí)鐘初始化,也就是通過STM32Cube實(shí)現(xiàn)。

圖片

時(shí)鐘初始化函數(shù)如下:

void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 /** Initializes the RCC Oscillators according to the specifiedparameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
 RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
 RCC_OscInitStruct.HSIState = RCC_HSI_ON;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
    Error_Handler();
 }
 /** Initializes the CPU, AHB and APB buses clocks
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) !=HAL_OK)
 {
    Error_Handler();
 }
}

RCC_OscInitTypeDef結(jié)構(gòu)體類型定義時(shí)鐘來源和系統(tǒng)時(shí)鐘生成配置,就是圖9中的配置,本例程使用外部8MHz晶振,通過PLL鎖相環(huán)9倍頻后得到72M系統(tǒng)時(shí)鐘。

RCC_ClkInitTypeDef結(jié)構(gòu)體類型定義總線時(shí)鐘配置,一般選擇使能系統(tǒng)時(shí)鐘、AHB、APB1和APB2總線時(shí)鐘,其中只有APB1總線時(shí)鐘36MHz,其他都為72MHz。

HAL_RCC_ClockConfig函數(shù)就是HAL定義的一個(gè)系統(tǒng)滴答定時(shí)器初始化配置函數(shù),通過這個(gè)函數(shù)得到延時(shí)效果。

3. GPIO初始化函數(shù)

MX_GPIO_Init()函數(shù)用于LED的GPIO初始化,代碼如下:

static void MX_GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};

 /* GPIO Ports Clock Enable */
 __HAL_RCC_GPIOB_CLK_ENABLE();
 __HAL_RCC_GPIOG_CLK_ENABLE();

 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

 /*Configure GPIO pin Output Level */
 HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);

 /*Configure GPIO pin : PB0 */
 GPIO_InitStruct.Pin = GPIO_PIN_0;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

 /*Configure GPIO pins : PG6 PG7 */
 GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
 HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);

}

以上就是LED的初始化函數(shù),初始化GPIO有個(gè)重要的結(jié)構(gòu)體GPIO_InitTypeDef,先看看該結(jié)構(gòu)體。

typedef struct
{
 uint32_t Pin;       /*!
  • Pin:引腳編號選擇,一個(gè)GPIO有16個(gè)引腳可選,參數(shù)可選有:GPIO_PIN_0、….、GPIO_PIN_15和GPIO_PIN_ALL。很多時(shí)候我們可以使用或運(yùn)算進(jìn)行選擇:GPIO_PIN_0| GPIO_PIN_4。
  • Mode:引腳模式選擇,在前文筆者已經(jīng)介紹了引腳有8中工作模式,根據(jù)外設(shè)選擇相應(yīng)模式。

圖片

  • Pull:上下拉,用于輸入模式,可選:GPIO_NOPULL不上下拉;GPIO_PULLUP:使能下拉;GPIO_PULLDOWN使能下拉;
  • Speed:引腳速度,可選:GPIO_SPEED_FREQ_LOW:低速(2MHz);中速(10MHz);高速(50MHz)。

在初始化代碼中,還有一個(gè)重要的函數(shù)HAL_GPIO_WritePin()。HAL_GPIO_WritePin()函數(shù)為3個(gè)LED燈時(shí)鐘初始化狀態(tài),這里設(shè)置為低電平,所以初始化狀態(tài)3個(gè)LED都是暗的。

4. 流水燈實(shí)現(xiàn)

在前文已經(jīng)貼出了流水燈的相應(yīng)代碼。

while (1)
{
    /* USER CODE END WHILE */
    /* USER CODE BEGIN 3 */

    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_0);

    HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_6);

    HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_7);
    HAL_Delay(500);
    HAL_GPIO_TogglePin(GPIOG,GPIO_PIN_7);
}

HAL_GPIO_TogglePin函數(shù)用于GPIO電平反轉(zhuǎn),HAL_Delay用于延時(shí),單位是毫秒,以此不斷將LED1、LED2、LED3關(guān)滅,這就是實(shí)現(xiàn)流水燈的效果。

1.9實(shí)驗(yàn)現(xiàn)象

將編譯好的程序下載到板子中,可以看到三個(gè)LED燈不同地閃爍。

本章雖然用不同的方式實(shí)現(xiàn)了流水燈,也就是不斷控制GPIO的高低電平,我想大家會有很多疑問,寄存器、表混庫、HAL的區(qū)別是什么,流水燈是怎么一步步調(diào)用等等,后面的章節(jié)會一一解答,盡請期待!

小貼士:上拉電阻

1.當(dāng) TTL 電路驅(qū)動 CMOS 電路時(shí),如果 TTL 電路輸出的高電平低于 CMOS電路的最低高電平(一般為 3.5V),這時(shí)就需要在 TTL 的輸出端接上拉電阻,以提高輸出高電平的值。

2.OC(集電極開路)門電路必須加上拉電阻,才能使用。

3.為加大輸出引腳的驅(qū)動能力,有的單片機(jī)管腳上也常使用上拉電阻。

4.在 CMOS 芯片上,為了防止靜電造成損壞,不用的管腳不能懸空,一般接上拉電阻產(chǎn)生降低輸入阻抗,提供泄荷通路。

5.芯片的管腳加上拉電阻來提高輸出電平,從而提高芯片輸入信號的噪聲容限增強(qiáng)抗干擾能力。

6.提高總線的抗電磁干擾能力。管腳懸空就比較容易接受外界的電磁干擾。

7.長線傳輸中電阻不匹配容易引起反射波干擾,加上下拉電阻是電阻匹配,有效的抑制反射波干擾。

  • 上拉電阻阻值的選擇原則包括:
  • 從節(jié)約功耗及芯片的灌電流能力考慮應(yīng)當(dāng)足夠大;電阻大,電流小。
  • 從確保足夠的驅(qū)動電流考慮應(yīng)當(dāng)足夠小;電阻小,電流大。
  • 對于高速電路,過大的上拉電阻可能邊沿變平緩。綜合考慮

以上三點(diǎn),通常在 1k 到 10k 之間選取。對下拉電阻也有類似道理對上拉電阻和下拉電阻的選擇應(yīng)結(jié)合開關(guān)管特性和下級電路的輸入特性進(jìn)行設(shè)定,主要需要考慮以下幾個(gè)因素:

  • 驅(qū)動能力與功耗的平衡。以上拉電阻為例,一般地說,上拉電阻越小,驅(qū)動能力越強(qiáng),但功耗越大,設(shè)計(jì)是應(yīng)注意兩者之間的均衡。
  • 下級電路的驅(qū)動需求。同樣以上拉電阻為例,當(dāng)輸出高電平時(shí),開關(guān)管斷開,上拉電阻應(yīng)適當(dāng)選擇以能夠向下級電路提供足夠的電流。
  • 高低電平的設(shè)定。不同電路的高低電平的門檻電平會有不同,電阻應(yīng)適當(dāng)設(shè)定以確保能輸出正確的電平。以上拉電阻為例,當(dāng)輸出低電平時(shí),開關(guān)管導(dǎo)通,上拉電阻和開關(guān)管導(dǎo)通電阻分壓值應(yīng)確保在零電平門檻之下。
  • 頻率特性。以上拉電阻為例,上拉電阻和開關(guān)管漏源級之間的電容和下級電路之間的輸入電容會形成 RC 延遲,電阻越大,延遲越大。上拉電阻的設(shè)定應(yīng)考慮電路在這方面的需求。
  • 下拉電阻的設(shè)定的原則和上拉電阻是一樣的
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 單片機(jī)
    +關(guān)注

    關(guān)注

    6030

    文章

    44499

    瀏覽量

    632174
  • ARM
    ARM
    +關(guān)注

    關(guān)注

    134

    文章

    9030

    瀏覽量

    366539
  • STM32
    +關(guān)注

    關(guān)注

    2264

    文章

    10858

    瀏覽量

    354391
  • 流水燈
    +關(guān)注

    關(guān)注

    21

    文章

    432

    瀏覽量

    59612
  • GPIO
    +關(guān)注

    關(guān)注

    16

    文章

    1189

    瀏覽量

    51847
收藏 人收藏

    評論

    相關(guān)推薦

    ARM Cortex-M學(xué)習(xí)筆記GPIO流水燈的前世今生

    上一章通過控制GPIO的高低電平實(shí)現(xiàn)了流水燈,但只是告訴了大家怎么做,如何實(shí)現(xiàn)流水燈,本文將深入剖析的GPIO流水燈的前生今世,深入研究
    的頭像 發(fā)表于 05-15 14:44 ?2519次閱讀
    <b class='flag-5'>ARM</b> <b class='flag-5'>Cortex-M</b><b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>:<b class='flag-5'>GPIO</b><b class='flag-5'>流水燈</b>的前世今生

    ARM Cortex-M學(xué)習(xí)筆記初識Systick定時(shí)器

    Cortex-M的內(nèi)核中包含Systick定時(shí)器了,只要是Cortex-M系列的MCU就會有Systick,因此這是通用的,下面詳細(xì)分析。
    的頭像 發(fā)表于 05-15 15:01 ?2729次閱讀
    <b class='flag-5'>ARM</b> <b class='flag-5'>Cortex-M</b><b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>:<b class='flag-5'>初識</b>Systick定時(shí)器

    ARM Cortex-M堆棧機(jī)制介紹

      大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是ARM Cortex-M堆棧機(jī)制?! 〗裉旖o大家分享的這篇依舊是2016年之前痞子衡寫的技術(shù)文檔,花了點(diǎn)時(shí)間重新編排了一下
    發(fā)表于 12-16 06:26

    ARM Cortex-M內(nèi)核的相關(guān)資料推薦

      大家好,我是痞子衡,是正經(jīng)搞技術(shù)的痞子。今天痞子衡給大家介紹的是ARM Cortex-M功能模塊,不過側(cè)重點(diǎn)是三款安全特性處理器。  ARM Cortex-M處理器家族發(fā)展至今(2
    發(fā)表于 12-27 07:21

    ARM Cortex-M開發(fā)之初識GPIO流水燈

    1、GPIO工作原理熟悉單片機(jī)的朋友都知道,學(xué)習(xí)的第一個(gè)例程就是流水燈,要想實(shí)現(xiàn)流水燈,首先必須了解GPIO的工作原理。
    發(fā)表于 04-24 17:22

    Arm Cortex-M處理器—Cortex-M85介紹

    Arm發(fā)布了新一代的Cortex-M處理器,Cortex-M85。簡單粗暴的打個(gè)比方:Cortex-M85 ≈ Cortex-M7Trust
    發(fā)表于 07-15 14:59

    ARM Cortex-M 系列微控制器(ST)

    ARM Cortex-M 系列微控制器(ST) 意法半導(dǎo)體(ST)宣布在基于ARM Cortex-M系列處理器內(nèi)核的微控制器研發(fā)項(xiàng)目上取得突破,推出全球業(yè)內(nèi)首款采用90nm技術(shù)嵌入式
    發(fā)表于 11-02 09:29 ?943次閱讀

    ARM白皮書】ARM Cortex-M處理器入門

    ARM Cortex-M處理器家族現(xiàn)在有8款處理器成員。在本文中,會比較Cortex-M系列處理器之間的產(chǎn)品特性,重點(diǎn)講述如何根據(jù)產(chǎn)品應(yīng)用選擇正確的Cortex-M處理器。本文中會詳細(xì)
    發(fā)表于 04-20 15:34 ?39次下載

    Atmel Studio 6軟件中如何調(diào)試ARM Cortex-M

    Atmel Studio 6軟件中如何調(diào)試ARM Cortex-M
    的頭像 發(fā)表于 07-04 10:49 ?4205次閱讀

    基于STM32單片機(jī)流水燈控制中的GPIO_Init()函數(shù)解析

    學(xué)習(xí)STM32時(shí),首先要熟悉流水燈例程,在這里就來分析流水燈中的GPIO_Init()函數(shù) 例如:流水燈例程中使用的端口是macLED
    發(fā)表于 10-29 15:42 ?7058次閱讀

    米爾科技Cortex-M Prototyping System +介紹

    ARM? Cortex?-M原型系統(tǒng) MPS2+,為Cortex-M 系列微處理器設(shè)計(jì)的原型驗(yàn)證評估系統(tǒng),包含最新的Cortex-M7 及
    的頭像 發(fā)表于 11-14 10:45 ?1827次閱讀
    米爾科技<b class='flag-5'>Cortex-M</b> Prototyping System +介紹

    Cortex-MCortex-A認(rèn)識ARM處理器

    Cortex-MCortex-A認(rèn)識ARM處理器
    的頭像 發(fā)表于 03-08 11:34 ?3395次閱讀

    [STM32CubeMX]學(xué)習(xí)筆記1:GPIO輸出LED流水燈

    [STM32CubeMX]學(xué)習(xí)筆記1:GPIO輸出LED流水燈
    發(fā)表于 12-05 13:36 ?12次下載
    [STM32CubeMX]<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>1:<b class='flag-5'>GPIO</b>輸出LED<b class='flag-5'>流水燈</b>

    分析ARM Cortex-M內(nèi)核復(fù)位啟動過程

    ARM Cortex-M內(nèi)核的復(fù)位啟動過程也被稱為復(fù)位序列(Reset sequence),下面就來簡要總結(jié)分析下這一過程。
    的頭像 發(fā)表于 03-20 09:58 ?2222次閱讀

    敏矽微電子Cortex-M0學(xué)習(xí)筆記04——GPIO詳解及應(yīng)用實(shí)例

    敏矽微電子Cortex-M0學(xué)習(xí)筆記04——GPIO詳解及應(yīng)用實(shí)例
    的頭像 發(fā)表于 09-26 17:07 ?987次閱讀
    敏矽微電子<b class='flag-5'>Cortex-M</b>0<b class='flag-5'>學(xué)習(xí)</b><b class='flag-5'>筆記</b>04——<b class='flag-5'>GPIO</b>詳解及應(yīng)用實(shí)例