RM新时代网站-首页

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

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

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

GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)篇) 第6章 按鍵

嵌入式大雜燴 ? 來(lái)源:嵌入式大雜燴 ? 作者:嵌入式大雜燴 ? 2023-05-11 08:57 ? 次閱讀

開(kāi)發(fā)環(huán)境:

MDK:Keil 5.30

開(kāi)發(fā)板:GD32F207I-EVAL

MCU:GD32F207IK

1 普通方式

1.1 普通方式工作原理

按鍵 GPIO 端口有兩個(gè)方案可以選擇,一是采用上拉輸入模式,因?yàn)榘存I在沒(méi)按下的時(shí)候,是默認(rèn)為高電平的,采且內(nèi)部上拉模式正好符合這個(gè)要求。第二個(gè)方案是直接采用浮空輸入模式,因?yàn)榘凑?a target="_blank">硬件電路圖,在芯片外部接了上拉電阻,其實(shí)就沒(méi)必要再配置成內(nèi)部上拉輸入模式了,因?yàn)樵谕獠可侠c內(nèi)部上拉效果是一樣的。

1683728778172wwrwwyb44i

筆者本文將會(huì)使用KEY1。

1.2 普通方式實(shí)現(xiàn)

主函數(shù)代碼如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    //systick init
    sysTick_init();
	
    /* configure LED1 GPIO port */
    led_init(LED1);

    /* configure LED2 GPIO port */
    led_init(LED2);

    /* configure LED3 GPIO port */
    led_init(LED3);

    /* configure LED4 GPIO port */
    led_init(LED4);

    //key init
    key_init(KEY_WAKEUP);
	
    while(1) 
    {
        delay_ms(100);
        if(key_scan(KEY_WAKEUP))
        {
            /* turn toggle LED */
            led_toggle(LED1);
            led_toggle(LED2);
            led_toggle(LED3);
            led_toggle(LED4);
        }
    }
}
  • GPIO 初始化配置
/*
    brief      configure key
    param[in]  keynum: specify the key to be configured
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[out] none
    retval     none
*/
void key_init(key_typedef_enum keynum)
{
    /* enable the key clock */
    rcu_periph_clock_enable(KEY_CLK[keynum]);
    rcu_periph_clock_enable(RCU_AF);

    /* configure button pin as input */
    gpio_init(KEY_PORT[keynum], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[keynum]);
}

key_init()與 LED 的 GPIO 初始化函數(shù) led_init()類(lèi)似,區(qū)別只是在這個(gè)函數(shù)中,要開(kāi)啟的 GPIO 的端口時(shí)鐘不一樣,并且把檢測(cè)按鍵用的引腳 Pin 的模式設(shè)置為適合按鍵應(yīng)用的上拉輸入模式(由于接了外部上拉電阻,也可以使用浮空輸入,讀者可自行修改代碼做實(shí)驗(yàn))。

  • 按鍵消抖
/*
    brief      return the key state
    param[in]  keynum: specify the key to be checked
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[out] none
    retval     the key's GPIO pin value
*/
key_state_enum key_scan(key_typedef_enum keynum)
{
    /* check whether the button is pressed */
    if(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
    {
        delay_ms(100);

        /* check whether the button is pressed */
        if(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
        {
            while(RESET == gpio_input_bit_get(KEY_PORT[keynum], KEY_PIN[keynum]))
            {
                return KEY_ON;
            }
        }
    }
    return KEY_OFF;
}

相信延時(shí)消抖的原理大家在學(xué)習(xí)其他單片機(jī)時(shí)就已經(jīng)了解了,本函數(shù)的功能就是掃描輸入參數(shù)中指定的引腳,檢測(cè)其電平變化,并作延時(shí)消抖處理,最終對(duì)按鍵消息進(jìn)行確認(rèn)。

  • 利用 gpio_input_bit_get() 讀取輸入數(shù)據(jù),若從相應(yīng)引腳讀取的數(shù)據(jù)等于 0(KEY_ON),低電平,表明可能有按鍵按下,調(diào)用延時(shí)函數(shù)。否則返回 KEY_OFF,表示按鍵沒(méi)有被按下。
  • 延時(shí)之后再次利用 gpio_input_bit_get()讀取輸入數(shù)據(jù),若依然為低電平,表明確實(shí)有按鍵被按下了。否則返回 KEY_OFF,表示按鍵沒(méi)有被按下。
  • 循環(huán)調(diào)用gpio_input_bit_get() 一直檢測(cè)按鍵的電平,直至按鍵被釋放,被釋放后,返回表示按鍵被按下的標(biāo)志 KEY_ON。以上是按鍵消抖的流程,調(diào)用了一個(gè)庫(kù)函數(shù) gpio_input_bit_get()。輸入?yún)?shù)為要讀取的端口、引腳,返回引腳的輸入電平狀態(tài),高電平為 1,低電平為 0。

2 EXTI方式

2.1 EXTI的工作原理

EXTI(External Interrupt) 就是指外部中斷,通過(guò) GPIO 檢測(cè)輸入脈沖,引起中斷事件,打斷原來(lái)的代碼執(zhí)行流程,進(jìn)入到中斷服務(wù)函數(shù)中進(jìn)行處理,處理完后再返回到中斷之前的代碼中執(zhí)行。

  • GD32的中斷和異常

Cortex內(nèi)核具有強(qiáng)大的異常響應(yīng)系統(tǒng),它把能夠打斷當(dāng)前代碼執(zhí)行流程的事件分為異常(exception)和中斷(interrupt),并把它們用一個(gè)表管理起來(lái),編號(hào)為 0 ~ 15 的稱(chēng)為內(nèi)核異常,而 16 以上的則稱(chēng)為外部中斷(外是相對(duì)內(nèi)核而言),這個(gè)表就稱(chēng)為中斷向量表。

而 GD32 對(duì)這個(gè)表重新進(jìn)行了編排,把編號(hào)從-3 至 6 的中斷向量定義為系統(tǒng)異常,編號(hào)為負(fù)的內(nèi)核異常不能被設(shè)置優(yōu)先級(jí),如復(fù)位(Reset)、不可屏蔽中斷 (NMI)、硬錯(cuò)誤(Hardfault)。從編號(hào) 7 開(kāi)始的為外部中斷,這些中斷的優(yōu)先級(jí)都是可以自行設(shè)置的。詳細(xì)的 GD32中斷向量表見(jiàn)下表。

168372877887081545qixac

16837287794042gup5an3bx

……

完整向量表請(qǐng)參考《GD32F20x_User_Manual_EN_Rev2.4》。

GD32的中斷如此之多,配置起來(lái)并不容易,因此我們需要一個(gè)強(qiáng)大而方便的中斷控制器 NVIC (Nested Vectored Interrupt Controller)。NVIC 是屬于 Cortex 內(nèi)核的器件,不可屏蔽中斷 (NMI)和外部中斷都由它來(lái)處理,而 SYSTICK 不是由 NVIC 來(lái)控制的。

1683728779796q7jzrhgrc4

  • NVIC 結(jié)構(gòu)體成員

當(dāng)我們要使用 NVIC 來(lái)配置中斷時(shí),自然想到GD庫(kù)肯定也已經(jīng)把它封裝成庫(kù)函數(shù)了。查找?guī)鞄椭臋n,發(fā)現(xiàn)在 gd32f20x_misc查找到一個(gè)nvic_irq_enable() 函數(shù)。

/*!
    \\brief      enable NVIC request
    \\param[in]  nvic_irq: the NVIC interrupt request, detailed in IRQn_Type
    \\param[in]  nvic_irq_pre_priority: the pre-emption priority needed to set
    \\param[in]  nvic_irq_sub_priority: the subpriority needed to set
    \\param[out] none
    \\retval     none
*/
void nvic_irq_enable(uint8_t nvic_irq,
                     uint8_t nvic_irq_pre_priority,
                     uint8_t nvic_irq_sub_priority)
{
    uint32_t temp_priority = 0x00U, temp_pre = 0x00U, temp_sub = 0x00U;

    /* use the priority group value to get the temp_pre and the temp_sub */
    switch((SCB->AIRCR) & (uint32_t)0x700U) {
    case NVIC_PRIGROUP_PRE0_SUB4:
        temp_pre = 0U;
        temp_sub = 0x4U;
        break;
    case NVIC_PRIGROUP_PRE1_SUB3:
        temp_pre = 1U;
        temp_sub = 0x3U;
        break;
    case NVIC_PRIGROUP_PRE2_SUB2:
        temp_pre = 2U;
        temp_sub = 0x2U;
        break;
    case NVIC_PRIGROUP_PRE3_SUB1:
        temp_pre = 3U;
        temp_sub = 0x1U;
        break;
    case NVIC_PRIGROUP_PRE4_SUB0:
        temp_pre = 4U;
        temp_sub = 0x0U;
        break;
    default:
        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
        temp_pre = 2U;
        temp_sub = 0x2U;
        break;
    }

    /* get the temp_priority to fill the NVIC->IP register */
    temp_priority = (uint32_t)nvic_irq_pre_priority << (0x4U - temp_pre);
    temp_priority |= nvic_irq_sub_priority & (0x0FU >> (0x4U - temp_sub));
    temp_priority = temp_priority << 0x04U;
    NVIC->IP[nvic_irq] = (uint8_t)temp_priority;

    /* enable the selected IRQ */
    NVIC->ISER[nvic_irq >> 0x05U] = (uint32_t)0x01U << (nvic_irq & (uint8_t)0x1FU);
}

該函數(shù)有三個(gè)參數(shù),需要配置的中斷向量,中斷向量搶占優(yōu)先級(jí)和中斷向量的響應(yīng)優(yōu)先級(jí)。

前面兩個(gè)結(jié)構(gòu)體成員都很好理解,首先要用 nvic_irq參數(shù)來(lái)選擇將要配置的中斷向量。用nvic_irq_pre_priority參數(shù)要配置中斷向量的搶占優(yōu)先級(jí),用nvic_irq_sub_priority參數(shù)配置中斷向量的響應(yīng)優(yōu)先級(jí)。對(duì)于中斷的配置,最重要的便是配置其優(yōu)先級(jí),但 GD32 的同一個(gè)中斷向量為什么需要設(shè)置兩種優(yōu)先級(jí)?這兩種優(yōu)先級(jí)有什么區(qū)別?

  • 搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)

GD32的中斷向量具有兩個(gè)屬性,一個(gè)為搶占屬性,另一個(gè)為響應(yīng)屬性,其屬性編號(hào)越小,表明它的優(yōu)先級(jí)別越高。

搶占,是指打斷其他中斷的屬性,即因?yàn)榫哂羞@個(gè)屬性會(huì)出現(xiàn)嵌套中斷(在執(zhí)行中斷服務(wù)函數(shù) A 的過(guò)程中被中斷 B 打斷,執(zhí)行完中斷服務(wù)函數(shù) B 再繼續(xù)執(zhí)行中斷服務(wù)函數(shù)A),搶占屬性由nvic_irq_pre_priority參數(shù)配置。

而響應(yīng)屬性則應(yīng)用在搶占屬性相同的情況下,當(dāng) 兩個(gè)中斷向量的搶占優(yōu)先級(jí)相同時(shí),如 果兩個(gè)中斷同時(shí)到達(dá),則先處理響應(yīng)優(yōu)先級(jí)高的中斷,響應(yīng)屬性 由nvic_irq_sub_priority參數(shù)配置。例如,現(xiàn)在有三個(gè)中斷向量,見(jiàn)下表。

中斷向量 搶占優(yōu)先級(jí) 響應(yīng)優(yōu)先級(jí)
A 0 0
B 1 0
C 1 1

若內(nèi)核正在執(zhí)行 C 的中斷服務(wù)函數(shù),則它能被搶占優(yōu)先級(jí)更高的中斷 A 打斷,由于 B和 C 的搶占優(yōu)先級(jí)相同,所以 C 不能被 B 打斷。但如果 B 和 C 中斷是同時(shí)到達(dá)的,內(nèi)核就會(huì)首先響應(yīng)響應(yīng)優(yōu)先級(jí)別更高的 B 中斷。

  • NVIC 的優(yōu)先級(jí)組

在配置優(yōu)先級(jí)的時(shí)候,還要注意一個(gè)很重要的問(wèn)題,即中斷種類(lèi)的數(shù)量。NVIC 只可以配置 16 種中斷向量的優(yōu)先級(jí),也就是說(shuō),搶占優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)的數(shù)量由一個(gè) 4 位的數(shù)字來(lái)決定,把這個(gè) 4 位數(shù)字的位數(shù)分配成搶占優(yōu)先級(jí)部分和響應(yīng)優(yōu)先級(jí)部分。有 5 組分配方式 :

  • 第 0 組:所有 4 位用來(lái)配置響應(yīng)優(yōu)先級(jí)。即 16 種中斷向量具有都不相同的響應(yīng)優(yōu)先級(jí)。
  • 第 1 組:最高 1 位用來(lái)配置搶占優(yōu)先級(jí),低 3 位用來(lái)配置響應(yīng)優(yōu)先級(jí)。表示有 21=2 種級(jí)別的搶占優(yōu)先級(jí)(0 級(jí),1 級(jí)),有 23=8 種響應(yīng)優(yōu)先級(jí),即在 16 種中斷向量之中,有8 種中斷,其搶占優(yōu)先級(jí)都為 0 級(jí),而它們的響應(yīng)優(yōu)先級(jí)分別為 0~7,其余 8 種中斷向量的搶占優(yōu)先級(jí)則都為 1 級(jí),響應(yīng)優(yōu)先級(jí)別分別為 0~7。
  • 第 2 組:2 位用來(lái)配置搶占優(yōu)先級(jí),2 位用來(lái)配置響應(yīng)優(yōu)先級(jí)。即 22=4 種搶占優(yōu)先級(jí),22=4 種響應(yīng)優(yōu)先級(jí)。
  • 第 3 組:高 3 位用來(lái)配置搶占優(yōu)先級(jí),最低 1 位用來(lái)配置響應(yīng)優(yōu)先級(jí)。即有 8 種搶占優(yōu)先級(jí),2 種響應(yīng) 2 優(yōu)先級(jí)。
  • 第 4 組:所有 4 位用來(lái)配置搶占優(yōu)先級(jí),即 NVIC 配置的 24 =16 種中斷向量都是只有搶占屬性,沒(méi)有響應(yīng)屬性。

要配置這些優(yōu)先級(jí)組,可以采用庫(kù)函數(shù) nvic_priority_group_set(),可輸入的參數(shù)為NVIC_PRIGROUP_PRE0_SUB4 ~ NVIC_PRIGROUP_PRE4_SUB0,分別為以上介紹的 5 種分配組。

GD32的所有 I/O 端口都可以配置為 EXTI 中斷模式,用來(lái)捕捉外部信號(hào),可以配置為下降沿中斷、上升沿中斷和上升下降沿中斷這三種模式。它們以圖2所示方式連接到外部中斷 / 事件線上。

  • EXTI 外部中斷

GD32的所有 GPIO 都引入到 EXTI 外部中斷線上,使得所有的 GPIO 都能作為外部中斷的輸入源。GPIO 與 EXTI 的連接方式見(jiàn)下表。

由下表可知,PA0 ~ PI0 連接到 EXTI0 、PA1~ PI1 連接到 EXTI1、……、PA15 ~ PI15 連接到 EXTI15。這里大家要注意的是 :PAx ~ PIx 端口的中斷事件都連接到了 EXTIx,即同一時(shí)刻 EXTIx 只能響應(yīng)一個(gè)端口的事件觸發(fā),不能夠同一時(shí)間響應(yīng)所有GPIO 端口的事件,但可以分時(shí)復(fù)用。它可以配置為上升沿觸發(fā)、下降沿觸發(fā)或雙邊沿觸發(fā)。EXTI 最普通的應(yīng)用就是接上一個(gè)按鍵,設(shè)置為下降沿觸發(fā),用中斷來(lái)檢測(cè)按鍵。

16837287803731iicow74v2

2.2 2 EXTI的寄存器描述

EXTI 寄存器的寄存器主要有6個(gè),下面分別描述。

  • 中斷使能寄存器(EXTI_INTEN)

168372878086925fpvkv808

  • 事件使能寄存器(EXTI_EVEN)

1683728781270z65ikushbx

1683728781667lr52pege20

  • 上升沿觸發(fā)選擇寄存器(EXTI_RTEN)

16837287819546y9sa7lt8l

注意: 外部喚醒線是邊沿觸發(fā)的,這些線上不能出現(xiàn)毛刺信號(hào)。在寫(xiě)EXTI_RTSR寄存器時(shí),在外部中斷線上的上升沿信號(hào)不能被識(shí)別,掛起位也不會(huì)被置位。在同一中斷線上,可以同時(shí)設(shè)置上升沿和下降沿觸發(fā)。即任一邊沿都可觸發(fā)中斷。

  • 下降沿觸發(fā)選擇寄存器(EXTI_FTEN)

1683728782395kdebg1j966

注意: 外部喚醒線是邊沿觸發(fā)的,這些線上不能出現(xiàn)毛刺信號(hào)。在寫(xiě)EXTI_FTSR寄存器時(shí),在外部中斷線上的下降沿信號(hào)不能被識(shí)別,掛起位不會(huì)被置位。在同一中斷線上,可以同時(shí)設(shè)置上升沿和下降沿觸發(fā)。即任一邊沿都可觸發(fā)中斷。

  • 軟件中斷事件寄存器(EXTI_SWIEV)

1683728782836102ykdro3b

  • 掛起寄存器(EXTI_PD)

1683728783212gqkpbuuo0g

2.3 EXTI方式實(shí)現(xiàn)

主函數(shù)代碼如下:

/*
    brief      main function
    param[in]  none
    param[out] none
    retval     none
*/
int main(void)
{
    //systick init
    sysTick_init();
	
    /* configure LED1 GPIO port */
    led_init(LED1);

    /* configure LED2 GPIO port */
    led_init(LED2);

    /* configure LED3 GPIO port */
    led_init(LED3);

    /* configure LED4 GPIO port */
    led_init(LED4);
	
    //key init
    key_init(KEY_WAKEUP, KEY_MODE_EXTI);
	
    while(1) 
    {
        delay_ms(100);
    }
}
  • 配置外部中斷

現(xiàn)在我們重點(diǎn)分析 key_init() 這個(gè)函數(shù),它完成了配置一個(gè) I/O 為 EXTI 中斷的一般步驟,主要有以下功能 :

1)使能 EXTIx 線的時(shí)鐘和第二功能 AFIO 時(shí)鐘。

2)配置 EXTIx 線的中斷優(yōu)先級(jí)。

3)配置 EXTI 中斷線 I/O。

4)選定要配置為 EXTI 的 I/O 口線和 I/O 口的工作模式。

5)EXTI 中斷線工作模式配置。

/*
    brief      configure key
    param[in]  keynum: specify the key to be configured
      arg        KEY_TAMPER: tamper key
      arg        KEY_WAKEUP: wakeup key
      arg        KEY_USER: user key
    param[in]  keymode: specify button mode
      arg        KEY_MODE_GPIO: key will be used as simple IO
      arg        KEY_MODE_EXTI: key will be connected to EXTI line with interrupt
    param[out] none
    retval     none
*/
void key_init(key_typedef_enum keynum, keymode_typedef_enum keymode)
{
    /* enable the key clock */
    rcu_periph_clock_enable(KEY_CLK[keynum]);
    rcu_periph_clock_enable(RCU_AF);

    /* configure button pin as input */
    gpio_init(KEY_PORT[keynum], GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, KEY_PIN[keynum]);

    if (keymode == KEY_MODE_EXTI) 
    {
        /* enable and set key EXTI interrupt to the lowest priority */
        nvic_irq_enable(KEY_IRQn[keynum], 2U, 0U);

        /* connect key EXTI line to key GPIO pin */
        gpio_exti_source_select(KEY_PORT_SOURCE[keynum], KEY_PIN_SOURCE[keynum]);

        /* configure key EXTI line */
        exti_init(KEY_EXTI_LINE[keynum], EXTI_INTERRUPT, EXTI_TRIG_FALLING);
        exti_interrupt_flag_clear(KEY_EXTI_LINE[keynum]);
    }
}

key_init()代碼中,不僅配置了NVIC ,還對(duì)按鍵的GPIO進(jìn)行了初始化,這部分和按鍵輪詢的設(shè)置類(lèi)似。

接下來(lái),調(diào)用 gpio_exti_source_select () 函數(shù)把 GPIOA、Pin0 與EXTI連接起來(lái)。

最后調(diào)用 exti_init() 把 EXTI 初始化,函數(shù)如下:

/*!
    \\brief      initialize the EXTI
    \\param[in]  linex: EXTI line number, refer to exti_line_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_x (x=0..19): EXTI line x
    \\param[in]  mode: interrupt or event mode, refer to exti_mode_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_INTERRUPT: interrupt mode
      \\arg        EXTI_EVENT: event mode
    \\param[in]  trig_type: interrupt trigger type, refer to exti_trig_type_enum
                only one parameter can be selected which is shown as below:
      \\arg        EXTI_TRIG_RISING: rising edge trigger
      \\arg        EXTI_TRIG_FALLING: falling trigger
      \\arg        EXTI_TRIG_BOTH: rising and falling trigger
      \\arg        EXTI_TRIG_NONE: without rising edge or falling edge trigger
    \\param[out] none
    \\retval     none
*/
void exti_init(exti_line_enum linex, exti_mode_enum mode, exti_trig_type_enum trig_type)
{
    /* reset the EXTI line x */
    EXTI_INTEN &= ~(uint32_t)linex;
    EXTI_EVEN &= ~(uint32_t)linex;
    EXTI_RTEN &= ~(uint32_t)linex;
    EXTI_FTEN &= ~(uint32_t)linex;

    /* set the EXTI mode and enable the interrupts or events from EXTI line x */
    switch(mode) {
    case EXTI_INTERRUPT:
        EXTI_INTEN |= (uint32_t)linex;
        break;
    case EXTI_EVENT:
        EXTI_EVEN |= (uint32_t)linex;
        break;
    default:
        break;
    }

    /* set the EXTI trigger type */
    switch(trig_type) {
    case EXTI_TRIG_RISING:
        EXTI_RTEN |= (uint32_t)linex;
        EXTI_FTEN &= ~(uint32_t)linex;
        break;
    case EXTI_TRIG_FALLING:
        EXTI_RTEN &= ~(uint32_t)linex;
        EXTI_FTEN |= (uint32_t)linex;
        break;
    case EXTI_TRIG_BOTH:
        EXTI_RTEN |= (uint32_t)linex;
        EXTI_FTEN |= (uint32_t)linex;
        break;
    case EXTI_TRIG_NONE:
    default:
        break;
    }
}
  • AFIO 時(shí)鐘

代碼中調(diào)用rcu_periph_clock_enable(RCU_AF)表示開(kāi)啟 AFIO的時(shí)鐘。

AFIO (alternate-function I/O),指 GPIO 端口的復(fù)用功能,GPIO 除了用作普通的輸入輸出(主功能),還可以作為片上外設(shè)的復(fù)用輸入輸出,如串口、ADC,這些就是復(fù)用功能。大多數(shù) GPIO 都有一個(gè)默認(rèn)復(fù)用功能,有的 GPIO 還有重映射功能。重映射功能是指把原來(lái)屬于 A 引腳的默認(rèn)復(fù)用功能,轉(zhuǎn)移到B引腳進(jìn)行使用,前提是 B 引腳具有這個(gè)重映射功能。

當(dāng)把 GPIO 用作 EXTI 外部中斷或使用重映射功能的時(shí)候,必須開(kāi)啟 AFIO 時(shí)鐘,而在使用默認(rèn)復(fù)用功能的時(shí)候,就不必開(kāi)啟 AFIO 時(shí)鐘了。

  • 編寫(xiě)中斷服務(wù)函數(shù)

在這個(gè) EXTI 設(shè)置中我們把 PA0 連接到內(nèi)部的 EXTI0,GPIO 配置為上拉輸入,工作在下降沿中斷。在外圍電路上我們將 PA0 接到了 key上。當(dāng)按鍵沒(méi)有按下時(shí),PA0 始終為高,當(dāng)按鍵按下時(shí) PA0 變?yōu)榈?,從?PA0 上產(chǎn)生一個(gè)下降沿跳變,EXTI0 會(huì)捕捉到這一跳變,并產(chǎn)生相應(yīng)的中斷,中斷服務(wù)程序在 gd32f20x_it.c 中實(shí)現(xiàn)。gd32f20x_it.c 文件是專(zhuān)門(mén)用來(lái)存放中斷服務(wù)函數(shù)的。文件中默認(rèn)只有幾個(gè)關(guān)于系統(tǒng)異常的中斷服務(wù)函數(shù),而且都是空函數(shù),在需要的時(shí)候自行編寫(xiě)。那么中斷服務(wù)函數(shù)名是不是可以自己定義呢?不可以。中斷服務(wù)函數(shù)的名字必須要與啟動(dòng)文件startup_gd32f20x_cl.s 中的中斷向量表定義一致。

16837287836368hav0m3p26

EXTI0_IRQHandler 表示為 EXTI0 中斷向量的服務(wù)函數(shù)名。于是,我們就可以在 gd32f20x_it.c文件中加入名為 EXTI0_IRQHandler() 的函數(shù)。

/*!
    \\brief      this function handles external lines 0 interrupt request
    \\param[in]  none
    \\param[out] none
    \\retval     none
*/
void EXTI0_IRQHandler(void)
{
    if(RESET != exti_interrupt_flag_get(EXTI_0))
    {
        /* turn toggle LED */
        led_toggle(LED1);
        led_toggle(LED2);
        led_toggle(LED3);
        led_toggle(LED4);

       exti_interrupt_flag_clear(EXTI_0);
   }
}

其內(nèi)容比較容易理解,進(jìn)入中斷后,調(diào)用exti_interrupt_flag_get() 庫(kù)函數(shù)來(lái)重新檢查是否產(chǎn)生了 EXTI_Line 中斷,接下來(lái)把 LED 取反,操作完畢后,調(diào)用 exti_interrupt_flag_clear()清除中斷標(biāo)志位再退出中斷服務(wù)函數(shù)。

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

編譯好程序后,下載到板子上,不管是普通方式還是中斷方式,當(dāng)按在按鍵KEY1時(shí),LED或亮或滅。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • mcu
    mcu
    +關(guān)注

    關(guān)注

    146

    文章

    17123

    瀏覽量

    350973
  • 按鍵
    +關(guān)注

    關(guān)注

    4

    文章

    223

    瀏覽量

    57595
  • 開(kāi)發(fā)板
    +關(guān)注

    關(guān)注

    25

    文章

    5032

    瀏覽量

    97371
  • Cortex-M
    +關(guān)注

    關(guān)注

    2

    文章

    229

    瀏覽量

    29752
  • GD32
    +關(guān)注

    關(guān)注

    7

    文章

    403

    瀏覽量

    24326
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 1 開(kāi)發(fā)環(huán)境搭建

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 GD32F207I-EVAL
    的頭像 發(fā)表于 05-07 23:35 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>1<b class='flag-5'>章</b> <b class='flag-5'>開(kāi)發(fā)</b>環(huán)境搭建

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 4 GD32啟動(dòng)流程詳解(Keil版)

    ,所有的一切都需要由開(kāi)發(fā)者來(lái)設(shè)置,這里處理器是沒(méi)有堆棧,沒(méi)有中斷,更沒(méi)有外圍設(shè)備,這些工作是需要軟件來(lái)指定的,而且不同的CPU類(lèi)型、不同大小的內(nèi)存和不同種類(lèi)的外設(shè),其初始化工作都是不同的。本文將以GD32F207IK (基于Cortex-M3)為例進(jìn)行講解。
    的頭像 發(fā)表于 05-10 09:00 ?1.7w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>4<b class='flag-5'>章</b> <b class='flag-5'>GD32</b>啟動(dòng)流程詳解(Keil版)

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 7 定時(shí)器

    系統(tǒng)滴答定時(shí)器一般用來(lái)提供“心跳”作用,而GD32定時(shí)器最基本功能也是定時(shí),可以設(shè)置不同時(shí)間長(zhǎng)度的定時(shí)。定時(shí)器除了最基本的定時(shí)功能外,定時(shí)器與GPIO有掛鉤使得它可以發(fā)揮強(qiáng)大的作用,比如可以輸出
    的頭像 發(fā)表于 05-11 09:00 ?1.2w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>7<b class='flag-5'>章</b> 定時(shí)器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 8 定時(shí)器

    Modulation” 的縮寫(xiě),簡(jiǎn)稱(chēng)脈寬調(diào)制,是利用微處理器的數(shù)字輸出來(lái)對(duì)模擬電路進(jìn)行控制的一種非常有效的技術(shù)。簡(jiǎn)單一點(diǎn),就是對(duì)脈沖寬度的控制。 GD32 的定時(shí)器除了 TIMER5 和 6(基本定時(shí)器
    的頭像 發(fā)表于 05-12 22:14 ?7924次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>8<b class='flag-5'>章</b> 定時(shí)器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 11 CPU的高級(jí)代理-DMA

    或者存儲(chǔ)器和存儲(chǔ)器之間的高速數(shù)據(jù)傳輸,因而被廣泛地使用。早在 8086 的應(yīng)用中就已經(jīng)有 Intel 的 8237 這種典型的 DMA 控制器,而 GD32的 DMA 則是以類(lèi)似外設(shè)的形式添加到 Cortex 內(nèi)核之外的??梢哉f(shuō),DMA就是CPU的高級(jí)代理,DMA大大減輕了CPU的負(fù)擔(dān)。
    的頭像 發(fā)表于 05-16 08:59 ?3862次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>11<b class='flag-5'>章</b> CPU的高級(jí)代理-DMA

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 12 ADC

    GD32F2系列有 3 個(gè)逐次逼近型的ADC,精度為 12 位,有18個(gè)多路復(fù)用通道,可以轉(zhuǎn)換來(lái)自16個(gè)外部通道和2個(gè)內(nèi)部通道的模擬信號(hào)。其中ADC0 和 ADC1都有 16 個(gè)外部通道, ADC2
    的頭像 發(fā)表于 05-16 09:03 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>12<b class='flag-5'>章</b> ADC

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 14 內(nèi)部溫度傳感器

    GD32 有一個(gè)內(nèi)部的溫度傳感器,可以用來(lái)測(cè)量 CPU 及周?chē)臏囟?TA)。該溫度傳感器在內(nèi)部和 ADCx_IN16 輸入通道相連接,此通道把傳感器輸出的電壓轉(zhuǎn)換成數(shù)字值。溫度傳感器模擬輸入
    的頭像 發(fā)表于 05-17 08:58 ?5334次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>14<b class='flag-5'>章</b> 內(nèi)部溫度傳感器

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 15 低功耗

    GD32的工作電壓(VDD)為2.0~3.6V。通過(guò)內(nèi)置的電壓調(diào)節(jié)器提供所需的1.8V電源。當(dāng)主電源VDD掉電后,通過(guò)VBAT腳為實(shí)時(shí)時(shí)鐘(RTC)和備份寄存器提供電源。
    的頭像 發(fā)表于 05-17 08:59 ?8047次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>15<b class='flag-5'>章</b> 低功耗

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 16 RTC

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK 1 RTC工作原理 1.1 RTC簡(jiǎn)介
    的頭像 發(fā)表于 05-18 22:14 ?7151次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>16<b class='flag-5'>章</b> RTC

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 17 看門(mén)狗

    開(kāi)發(fā)環(huán)境: MDK:Keil 5.30 開(kāi)發(fā)板:GD32F207I-EVAL MCU:GD32F207IK GD32 有兩個(gè)看門(mén)狗, 一個(gè)是
    的頭像 發(fā)表于 06-03 16:00 ?1.1w次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>17<b class='flag-5'>章</b> 看門(mén)狗

    【圖書(shū)分享】《STM32庫(kù)開(kāi)發(fā)實(shí)戰(zhàn)指南

    GPIO入門(mén)之流水燈 4 深入分析流水燈例程 5 調(diào)試程序第二部分 庫(kù)開(kāi)發(fā)中級(jí) 
    發(fā)表于 03-13 17:01

    Arduino開(kāi)發(fā)實(shí)戰(zhàn)指南 AVR

    第一基礎(chǔ)1初識(shí)Arduino2編寫(xiě)Arduino程序
    發(fā)表于 08-03 16:14

    GD32 MCU原理及固件庫(kù)開(kāi)發(fā)指南》 + 初讀感悟

    GD32 MCU原理固件庫(kù)開(kāi)發(fā)指南這本書(shū)內(nèi)容豐富,囊括了GD32中的所有外設(shè),書(shū)中首先介紹了如何使用MDK或IAR軟件搭建GD32工程環(huán)境,讓初學(xué)者能快速基于工程上手編程。書(shū)中主要對(duì)
    發(fā)表于 03-31 22:11

    GD32 MCU原理及固件庫(kù)開(kāi)發(fā)指南》+讀后感

    。 2介紹GD32 MCU快速入門(mén)與開(kāi)發(fā)平臺(tái)搭建的方法,包括對(duì)軟硬件開(kāi)發(fā)平臺(tái)、調(diào)試工具、GD32
    發(fā)表于 06-06 21:52

    GD32開(kāi)發(fā)實(shí)戰(zhàn)指南(基礎(chǔ)) 19 程序加密

    GD32通過(guò)讀取芯片唯一ID號(hào)來(lái)實(shí)現(xiàn)程序的保護(hù),防止被抄襲。96位的產(chǎn)品唯一身份標(biāo)識(shí)所提供的參考號(hào)碼對(duì)任意一個(gè)GD32微控制器
    的頭像 發(fā)表于 05-20 09:10 ?4138次閱讀
    <b class='flag-5'>GD32</b><b class='flag-5'>開(kāi)發(fā)</b><b class='flag-5'>實(shí)戰(zhàn)</b><b class='flag-5'>指南</b>(基礎(chǔ)<b class='flag-5'>篇</b>) <b class='flag-5'>第</b>19<b class='flag-5'>章</b> 程序加密
    RM新时代网站-首页