成大资工GPIO相关wiki

本文详细介绍了 STM32 GPIO 的输入输出、配置、功能描述及应用示例,包括浮动、拉高、拉低、推挽、开漏、模拟等模式的实现,通过示波器验证了 GPIO 的实际操作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

General-purpose Input/Output (GPIO)

    Introduction

    General Purpose Input/Output (GPIO) is a generic pin on a chip whose behavior (including whether it is an input or output pin) can be controlled (programmed) by the user at run time.

    通常我們program使用的data都是放在memory比較多,而GPIO也提供類似的操作方法給programmer(讓我們去更改記憶體內容就可以去控制pin,並影響周遭設備的運行),但真正的設備的位置並非真正落在記憶體上(如:LED、Button、…等),故GPIO的核心是記憶體操作與設備之間的一些電路特性。

    Main Feature

    GPIO雖然建立起記憶體與設備之間的橋梁,但也並非我們就可以隨意使用,我們必須要經過設定之後才能讓我們想要的設備正常工作。

    一個pin通常可被設定成input、output、alternate function或analog,input會有兩種狀態表現(floating, pull-up/down),output也有兩種狀態表現(push-pull with pull-up/pull-down or open drain with pull-up/down)。

    • input/output方向解說 : input是指記憶體方接收來自設備的訊號源,output是指記憶體傳送訊號給設備。

    當pin被設定成input時,非analog的設定下,我們可以利用GPIO的input data register(GPIOx_IDR) 或是memory中提供給目標設備的data register (當設成alternate function的時候)去接收data。

    當pin被設定成output時,非analog的設定下,GPIO本身有提供output data register (GPIOx_ODR)來對目標設備做控制,但要是pin不是使用原本預先定義好的功能時(非預先定義的功能都算是alternate function的類別),此時要用memory中,另外規劃給目標設備用的register。

    如果pin被設成analog的話,無論input or output都會由adc那邊做處理。

    Functional Description

    input

    • floating vs. pull-up/pull-down

    當input pin被處在高阻抗的模式下,若沒有外部訊號源進來的話,此時是無法確定pin的狀態(不能確定現在處在高電位或低電位),除非有外部訊號來驅動電路。換句話說,input floating,這個input電位狀態完全是由外部訊號來決定,沒有訊號驅動的話,就會呈現高阻抗狀態。

    剛剛提到floating在沒有外部訊號驅動的情況下是呈現高阻抗狀態(無法確定電位狀態=>不能明確表示現在值是0或1),如果我們需要這個pin有一個明確的預設狀態時,必須借助pull-up(pull-down)resistor來做調整,在pull-up resistor(pull-up外接高電壓,pull-down通常會接地)加入之下,讓pin的維持在明確的高電壓狀態(pull-down則是讓pin維持在低電壓狀態)。舉例來說,如果我們定電壓在3-4 V之間是1的狀態,0-1之間是0的狀態,高阻抗的時候,電壓是不明確的,有可能電壓值會落在1-3之間的不明確地帶,甚至是沒有在任何一個狀態維持一段時間,此時的狀態是未定的,但如果我們加入pull-up resistor的話,這個pin接受來自pull-up另一端的電壓供應,讓pin至少維持在3v以上時,我們就可以確定在沒有外部訊號驅動時,pin是維持在高電位狀態。

    output

    • push-pull with pull-up/pull-down
    • open-drain with pull-up/pull-down

    analog

    前面所述的input/output跟現在要談的類比模式是不一樣的類型,前者的資料型態主要是高低電位的數位型態(0/1的分別),而類比訊號是普遍自然界的訊號型態,故當我們設定成類比輸入的模式時,進來GPIO pin的原始訊號源在還沒經過施密特觸發器(Schmitt trigger)會有另一個線路將訊號做導向(通常是要導到ADC去),另一方面,當我們用了類比輸出模式後,GPIO的內部將會有一條線路接收DAC處理完的類比訊號,在經過此pin傳遞到外部去。

    • 施密特觸發器(Schmitt trigger) : 將類比訊號的波形整成數位電路所能處理的方波波形(處理完只能分辨出高低電位的差別)。
    image

    (施密特觸發器具有整流效果)

    basic structure (P.137, Figure 13. Basic structure of a five-volt tolerant I/O port bit in Reference manual)

    image
    • VDD:芯片內部的工作電壓
    • VSS:接地點

    Configuration

    Input configuration (P.143, 6.3.9 Input configuration in Reference manual)

    image

    When the I/O port is programmed as Input:

    • the output buffer is disabled
    • the Schmitt trigger input is activated
      • 這種模式處理的數位訊號只在意高低電位的差別(開關控制)。
    • the pull-up and pull-down resistors are activated depending on the value in the GPIOx_PUPDR register
      • 想要讓pin的state變成一個確定的狀態,可以設定pull-up/pull-down的使用。
    • The data present on the I/O pin are sampled into the input data register every AHB1 clock cycle
      • input data的更新主要就是以AHB1本身的更新週期做決定,每一個cycle抵達時,data register就會根據當時Schmitt trigger整流完的狀態做更新。
    • A read access to the input data register provides the I/O State
      • 對data register的理解,我覺得用’狀態’比’數值’的敘述來的更好(大部分都是開關,就是外部訊號源是否有狀態改變,如 : button的按下與放開),而此處寫I/O state的意思是,即使我們現在是設成output(如 : LED控制),但我們仍然可用input data register來檢查LED現在的狀態。

    Output configuration (P.144, 6.3.10 Output configuration in Reference manual)

    image

    When the I/O port is programmed as output:

    • The output buffer is enabled:
      • Open drain mode: A “0” in the Output register activates the N-MOS whereas a “1” in the Output register leaves the port in Hi-Z (the P-MOS is never activated)
      • Push-pull mode: A “0” in the Output register activates the N-MOS whereas a “1” in the Output register activates the P-MOS
    • The Schmitt trigger input is activated
    • The weak pull-up and pull-down resistors are activated or not depending on the value in the GPIOx_PUPDR register
    • The data present on the I/O pin are sampled into the input data register every AHB1 clock cycle
    • A read access to the input data register gets the I/O state
    • A read access to the output data register gets the last written value

    Alternate function configuration (P.144, 6.3.11 Alternate function configuration in Reference manual)

    image

    When the I/O port is programmed as alternate function:

    • The output buffer can be configured as open-drain or push-pull
    • The output buffer is driven by the signal coming from the peripheral (transmitter enable and data)
    • The Schmitt trigger input is activated
    • The weak pull-up and pull-down resistors are activated or not depending on the value in the GPIOx_PUPDR register
    • The data present on the I/O pin are sampled into the input data register every AHB1 clock cycle
    • A read access to the input data register gets the I/O state

    Remark:

    GPIOx_AFRL[31:0] and GPIOx_AFRH[31:0] provide ways to select alternation functions. However, different alternate functions maps to different bits of ports. Table below is part of alternate function mapping, which is mainly about USART2/3.

    For more information, please refer to Table 9. Alternate function mapping from P.60-68 in STM32F407xx Datasheet.

    image

    Analog configuration (P.145, 6.3.12 Analog configuration in Reference manual)

    image

    When the I/O port is programmed as analog configuration:

    • The output buffer is disabled
    • The Schmitt trigger input is deactivated, providing zero consumption for every analog value of the I/O pin. The output of the Schmitt trigger is forced to a constant value (0).
    • The weak pull-up and pull-down resistors are disabled
    • Read access to the input data register gets the value “0”

    Note: In the analog configuration, the I/O pins cannot be 5 Volt tolerant.

    Demo

    工具介紹

    image
    • BNC對鱷魚夾線
    image
    • 示波器(oscilloscope) 畫面很差…

    示波器驗證

    image
    • 示波器我們調整的scale是1 volt為單位。
    • 我們接線是使用BNC對鱷魚夾線,黑接Groud,紅接要觀察的Pin。此圖為我們還沒做任何操作呈現的狀態。
    image
    • 以button做為觀察GPIO input的部份
    • USER button對應的腳位為PA0
    • 按下button馬上放開後會產生一個小方波,由此可知,按下button是產生高電位訊號。(看’按下’多久高電位就維持多久)
    image
    • 用LED4來觀察GPIO output的部份
    • LED4對應的腳位是PD12,當LED4亮的時候,我們可以看到波形產生變化(從0v左右的位置升到高電位2.8v左右)
    image
    • 我們在接Pin的過程的時候,發現有些燈會亮起來,圖中紅色鱷魚夾線把PD12跟PD14同時夾起來,LED5在LED4亮起來的時候也會亮,對照PD14的位置是LED5。
    • 我們觀察示波器用的Code只有對button跟LED4做設定,我們推測原因是LED4亮起來的時候,PD12處於高電位狀態,而鱷魚夾線連通PD14讓此腳位也處於高電位使LED5也亮起來了。

    Code Section

    sample code download :

    git clone https://github.com/shengwen1997/stm32_GPIO_demo.git
    cd stm32_GPIO_demo/

    test for code :

    make
    make flash

    測試方法 :

    • input使用button作為範例,output是LED控制。

    stm32f4_discovery library的預先定義(in libstm/Utilities/STM32F4-Discovery/stm32f4_discovery.h) :

    #define LEDn                             4
    
    #define LED4_PIN                         GPIO_Pin_12
    #define LED4_GPIO_PORT                   GPIOD
    #define LED4_GPIO_CLK                    RCC_AHB1Periph_GPIOD  
    
    #define LED3_PIN                         GPIO_Pin_13
    #define LED3_GPIO_PORT                   GPIOD
    #define LED3_GPIO_CLK                    RCC_AHB1Periph_GPIOD  
    
    #define LED5_PIN                         GPIO_Pin_14
    #define LED5_GPIO_PORT                   GPIOD
    #define LED5_GPIO_CLK                    RCC_AHB1Periph_GPIOD  
    
    #define LED6_PIN                         GPIO_Pin_15
    #define LED6_GPIO_PORT                   GPIOD
    #define LED6_GPIO_CLK                    RCC_AHB1Periph_GPIOD
    
    #define BUTTONn                          1  
    
    #define USER_BUTTON_PIN                GPIO_Pin_0
    #define USER_BUTTON_GPIO_PORT          GPIOA
    #define USER_BUTTON_GPIO_CLK           RCC_AHB1Periph_GPIOA
    #define USER_BUTTON_EXTI_LINE          EXTI_Line0
    #define USER_BUTTON_EXTI_PORT_SOURCE   EXTI_PortSourceGPIOA
    #define USER_BUTTON_EXTI_PIN_SOURCE    EXTI_PinSource0
    #define USER_BUTTON_EXTI_IRQn          EXTI0_IRQn 
    • LED是屬於GPIO port D,第12-15個pin分別是控制,LED4、LED3、LED5、LED6。
    • Button是屬於GPIO port A,第0個pin是可以用來檢查button狀態的腳位。在文件中,有時會看到Wake-up button這一名稱,其實就是在說User button,兩者是指同一個東西。

    input 設定 :

    • button initialization(in libstm/Utilities/STM32F4-Discovery/stm32f4_discovery.c) :
    void STM_EVAL_PBInit(Button_TypeDef Button, ButtonMode_TypeDef Button_Mode)
    {
       GPIO_InitTypeDef GPIO_InitStructure;
       EXTI_InitTypeDef EXTI_InitStructure;
       NVIC_InitTypeDef NVIC_InitStructure;
    
       /* 要設定好Clock才能正確更新Button的State,BUTTON_CLK[Button]是指RCC_AHB1Periph_GPIOA */
       RCC_AHB1PeriphClockCmd(BUTTON_CLK[Button], ENABLE);
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    
       /* 設定為input mode,我們不給pin任何預設狀態,所PuPd的部份設成NOPULL */
       GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
       GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
       GPIO_InitStructure.GPIO_Pin = BUTTON_PIN[Button];
       GPIO_Init(BUTTON_PORT[Button], &GPIO_InitStructure);
    
       if (Button_Mode == BUTTON_MODE_EXTI)
       {
         /* 啟用interrupt並建立好與button腳位的連結 */
         SYSCFG_EXTILineConfig(BUTTON_PORT_SOURCE[Button], BUTTON_PIN_SOURCE[Button]);
    
         /* Configure Button EXTI line */
         EXTI_InitStructure.EXTI_Line = BUTTON_EXTI_LINE[Button];
         EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
         EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;  
         EXTI_InitStructure.EXTI_LineCmd = ENABLE;
         EXTI_Init(&EXTI_InitStructure);
    
         /* Enable and set Button EXTI Interrupt to the lowest priority */
         NVIC_InitStructure.NVIC_IRQChannel = BUTTON_IRQn[Button];
         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    
         NVIC_Init(&NVIC_InitStructure); 
       }
     }
    • Button interrupt handler(in main.c)
    void EXTI0_IRQHandler(void) 
    {
      /* 當Button按下後觸發interrupt,用自定義變數紀錄Button state的改變。 */
      UserButtonPressed = 0x01;
    
      /* Clear the EXTI line pending bit */
      EXTI_ClearITPendingBit(USER_BUTTON_EXTI_LINE);
    }

    output 設定 :

    • LED initialization (in libstm/Utilities/STM32F4-Discovery/stm32f4_discovery.c) :
    void STM_EVAL_LEDInit(Led_TypeDef Led)
    {
      GPIO_InitTypeDef  GPIO_InitStructure;
    
      /* LED是屬於Port D,要設定好Clk讓Port D可以正確被更新 */
      RCC_AHB1PeriphClockCmd(GPIO_CLK[Led], ENABLE);
    
      /* 設定各LED對應的腳位,output type設成push-pull,並使用pull-up電阻,LED初始化完成時,會呈現高電位狀態(亮燈)。 */
      GPIO_InitStructure.GPIO_Pin = GPIO_PIN[Led];
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIO_PORT[Led], &GPIO_InitStructure);
    }

    main.c :

    • main function :
    int main(void)
    {
      RCC_ClocksTypeDef RCC_Clocks;
    
      /* button初始化,並使用interrupt。 */
      STM_EVAL_PBInit(BUTTON_USER, BUTTON_MODE_EXTI); 
    
      /* 初始化需要用到的LED。 */
      STM_EVAL_LEDInit(LED4);
      STM_EVAL_LEDInit(LED3);
      STM_EVAL_LEDInit(LED5);
      STM_EVAL_LEDInit(LED6);
    
      /* 初始化有使用到pull-up電阻,預設會亮燈,在這邊把燈關掉。 */
      STM_EVAL_LEDOff(LED4);
      STM_EVAL_LEDOff(LED3);
      STM_EVAL_LEDOff(LED5);
      STM_EVAL_LEDOff(LED6);
    
      /* 初始化自定義變數 */
      UserButtonPressed = 0x00;
    
      /* Create a task to flash the LED. */
      xTaskCreate(LED_task,
             (signed portCHAR *) "LED Flash",
             512 /* stack size */, NULL,
             tskIDLE_PRIORITY + 5, NULL);
    
      /* Create a task to button check. */
      xTaskCreate(button_task,
             (signed portCHAR *) "User Button",
             512 /* stack size */, NULL,
             tskIDLE_PRIORITY + 5, NULL);
    
      /* Start running the tasks. */
      vTaskStartScheduler(); 
    
      return 0;
    }
    • LED control task
    static void LED_task(void *pvParameters)
    {
      RCC_ClocksTypeDef RCC_Clocks;
      uint8_t togglecounter = 0x00;
    
      while(1)
      {    
          /* Toggle LED5 */
          STM_EVAL_LEDToggle(LED5);
          vTaskDelay(100);
          /* Toggle LED6 */
          STM_EVAL_LEDToggle(LED6);
          vTaskDelay(100);
      }
    }
    • Button check task :
    static void button_task(void *pvParameters)
    {
       	    while (1)
            {
                /* Waiting User Button is pressed */
    	        if (UserButtonPressed == 0x01)
    	        {
      	            /* Toggle LED4 */
      	            STM_EVAL_LEDToggle(LED4);
      	            vTaskDelay(100);
      	            /* Toggle LED3 */
      	            STM_EVAL_LEDToggle(LED3);
      	            vTaskDelay(100);
      	        }
      	        /* Waiting User Button is Released */
      	        while (STM_EVAL_PBGetState(BUTTON_USER) == Bit_SET);
      	        UserButtonPressed = 0x00;
      	   }
      }

    Supplement

    • 一些有預設控制元件的腳位(詳見- STM32F4-Discovery 中文使用手冊P.16)
      • LD3:橙色,連接到STM32F407VGT6的PD13
      • LD4:綠色,連接到STM32F407VGT6的PD12
      • LD5:红色,連接到STM32F407VGT6的PD14
      • LD6:藍色,連接到STM32F407VGT6的PD15
      • B1(USER):連接到STM32F407VGT6的PA0
      • B2(RESET):連接到NRST,用於重置STM32F407VGT6

    Q & A

    1. Pull-up與Pull-down的電阻是多少?

    (請參考Datasheet p.110,Table 47. I/O static characteristics)

    image

    實際測量:

    • 將三用電表調到測量電阻的功能
    • 將三用電表的正極接在要測的I/O pin上(此處使用PA14,並設成pull-down),負極接地
    • 觀察電表的數字即可得當前電阻

    2. GPIO中取樣頻率的意義?

    假設input data是0、1、0、1、……的方波,並以V0的速度變化,此時若GPIO本身的取樣頻率是1/2 V0,則取到的data會全是1或全是0,所以了解GPIO的取樣頻率可以讓使用者設計input data時不以過快的速度做資料的輸入。

    3. 何謂TTL?

    全名Transistor-Transistor Logic,數位IC的種類之一,依製程不同可分為TTL與CMOS(complement metal oxide semiconductor)兩種:

    TTL:內部零件多以雙極性電晶體組成。

    CMOS:內部零件多以金屬氧化物半導體組成。

    (補充)差異性比較:

    TTL電路的速度快,傳輸延遲時間短(5-10ns),但是功耗大。

    CMOS電路的速度慢,傳輸延遲時間長(25-50ns),但功耗低。

    4. STM32 RCC clock

    http://www.oliverbehr.de/?option=com_content&view=article&id=52:stm32-clock-configuration&catid=39:technik&Itemid=83

    System clock setup

    • Internal High Speed Clock (HSI)

    • External High Speed Clock (HSE)

    • Phase locked Loop (PLL)

    Bus clock setup

    • Advanced High Performance Bus (AHB)

    • Low speed Advanced Peripherial Bus (APB1)

    • High speed Advanced Peripherial Bus (APB2)

    5. 波形抖動問題

    Sampling jitter [from Wikipedia]

    http://en.wikipedia.org/wiki/Jitter

    In analog to digital and digital to analog conversion of signals, the sampling is normally assumed to be periodic with a fixed period—the time between every two samples is the same. If there is jitter present on the clock signal to the analog-to-digital converter or a digital-to-analog converter, the time between samples varies and instantaneous signal error arises.

    取樣頻率的設定:

    image

    Reference

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值