2026年4月14日星期二

NK-N9H31A2 開發板:GPIO input

NK-N9H31A2 開發板:GPIO output 中,已經可以控制 LED 亮滅,接下來偵測按鈕並控制 LED 亮滅,關於 GPIO input 的知識可以參考韌體工程師需要懂一點硬體:GPIO 輸入輸出模式與實務應用整理

實驗目的

使用提供的函式偵測板子上的按鈕,按下後 LED 亮,反之則滅掉

使用範例

在官方的 SampleCode 中,找到 GPIO,匯入方式就不再贅述,可以參考上一篇

電路說明
        由於下載下來的範例程式中,對應的腳位不一樣,所以要依照板子上的電路圖稍作調整將程式碼中的按鍵腳位設定改為 PI9 及 PH1
        由於按鍵電路使用外部 pull-up 電阻,未按下時 GPIO 讀到為 1,按下時接地,GPIO 讀到為 0,因此按鍵為 Active Low 設計。
        按鍵狀態最終會反映在 GPIO 的輸入數值中,透過函式讀取即可判斷目前按鍵狀態。
       

程式碼

        以下的程式碼可以直接複製貼上,此篇文章中主要學會使用函式偵測按鍵是否按下的數值,並控制對應的 LED 亮滅,所以將原本官方的程式進行修改,僅保留偵測按鍵及控制 LED 的部分
int main(void)
{
    int32_t i32Err;

    sysDisableCache();
    sysFlushCache(I_D_CACHE);
    sysEnableCache(CACHE_WRITE_BACK);
    sysInitializeUART();

    sysprintf("+-------------------------------------------------+\n");
    sysprintf("|                 GPIO Sample Code                |\n");
    sysprintf("+-------------------------------------------------+\n\n");

    /* Configure Port F10 to output mode and pull-up, LED_2 */
	GPIO_OpenBit(GPIOF, BIT10, DIR_OUTPUT, PULL_UP);
    /* Configure Port I10 to output mode and pull-up, LED_1 */
	GPIO_OpenBit(GPIOI, BIT10, DIR_OUTPUT, PULL_UP);
    
    /* Configure Port I10 to input mode and pull-up, KEY_2 */
	GPIO_OpenBit(GPIOH, BIT1, DIR_INPUT, PULL_UP);
    /* Configure Port I9 to input mode and pull-up, KEY_1 */
	GPIO_OpenBit(GPIOI, BIT9, DIR_INPUT, PULL_UP);

    while (1)
    {
        /* use KEY_1 control LED_1 */
        if (GPIO_ReadBit(GPIOI, BIT9) == 0) /* KEY_1 is push down */
        {
        	GPIO_SetBit(GPIOI, BIT10); /* LED_1 OFF */
        }
        else
        {
            GPIO_ClrBit(GPIOI, BIT10); /* LED_1 ON */
        }
        
        /* use KEY_2 control LED_2 */
        if (GPIO_ReadBit(GPIOH, BIT1) == 0) /* KEY_2 is push down */
        {
        	GPIO_SetBit(GPIOF, BIT10); /* LED_1 OFF */
        }
        else
        {
        	GPIO_ClrBit(GPIOF, BIT10); /* LED_1 ON */
        }
    }
    
//    GPIO_CloseBit(GPIOF, BIT10);
//    GPIO_CloseBit(GPIOI, BIT10);
//    GPIO_CloseBit(GPIOH, BIT1);
//    GPIO_CloseBit(GPIOI, BIT9);

    while(1);
}

函式說明

這裡只針對上面程式使用到的 GPIO 函式說明,更多說明可以參考 gpio.h gpio.c
  • GPIO_OpenBit 
    • 設定單一 GPIO 腳位的模式(port, bit, direction, pull)
  • GPIO_SetBit 
    • 將指定 port 的 bit 驅動為高電位(1)
  • GPIO_ClrBit 
    • 將指定 port 的 bit 驅動為低電位(0)
  • GPIO_CloseBit 
    • 將單一 bit 恢復為預設/關閉狀態
  • GPIO_ReadBit  
    • 讀取偵測到的 GOIO 狀態,高電位(1)低電位(0)

程式參考

        Nuvoton 官方 github https://github.com/OpenNuvoton/N9H31_NonOS

延伸閱讀

         

2026年4月13日星期一

NK-N9H31A2 開發板:GPIO output

開發環境建立好之後,當然就是要開始寫程式,那怎麼知道寫的程式碼動作正確運行,就是使用GPIO 控制 LED 燈閃爍啦,這篇文章僅說明腳位輸出控制,不包含中斷,未來會在別的章節進行說明,GPIO 的一些知識可以參考"GPIO 輸入輸出模式與實務應用整理"

實驗目的

透過程式控制板子上的 LED 燈亮面,使用提供的函式

使用範例

在官方的 SampleCode 中,找到 GPIO,匯入方式就不再贅述,可以參考此篇

電路說明

        由於下載下來的範例程式中,對應的腳位不一樣,所以要依照板子上的電路圖稍作調整將程式碼中的腳位設定改為 PI10 及 PF10
        在 N9H31 中,GPIO 控制 LED 的本質是透過設定對應的暫存器位元,而 LED 是否亮起,取決於外部電路的接法(開發板 Active Low)。
N9H31 開發板上的 LED

程式碼

        以下的程式碼可以直接複製貼上,此篇文章中主要學會使用函式控制 LED 亮滅,所以將原本官方的程式進行修改,僅保留控制 LED 的部分
void delay(uint32_t count)
{
	while(count--);
}

int main(void)
{
   sysDisableCache();
   sysFlushCache(I_D_CACHE);
   sysEnableCache(CACHE_WRITE_BACK);
   sysInitializeUART();
   sysprintf("+-------------------------------------------------+\n");
   sysprintf("|                 GPIO Sample Code                |\n");
   sysprintf("+-------------------------------------------------+\n\n");
   /* Configure Port F10 to output mode and pull-up, LED_2 */
	GPIO_OpenBit(GPIOF, BIT10, DIR_OUTPUT, PULL_UP);
   /* Configure Port I10 to output mode and pull-up, LED_1 */
	GPIO_OpenBit(GPIOI, BIT10, DIR_OUTPUT, PULL_UP);
   /* Blink LEDs */
   for (int i = 0; i &lt 10; i++)
   {
       GPIO_SetBit(GPIOF, BIT10);
       GPIO_SetBit(GPIOI, BIT10);
       delay(0xFFFFFF);
       GPIO_ClrBit(GPIOF, BIT10);
       GPIO_ClrBit(GPIOI, BIT10);
       delay(0xFFFFFF);
   }
   GPIO_CloseBit(GPIOF, BIT10);
   GPIO_CloseBit(GPIOI, BIT10);
   sysprintf("  [OK].\n");
   while(1);
}

函式說明

這裡只針對上面程式使用到的 GPIO 函式說明,更多說明可以參考 gpio.h gpio.c
  • GPIO_OpenBit 
    • 設定單一 GPIO 腳位的模式(port, bit, direction, pull)
  • GPIO_SetBit 
    • 將指定 port 的 bit 驅動為高電位(1)
  • GPIO_ClrBit 
    • 將指定 port 的 bit 驅動為低電位(0)
  • GPIO_CloseBit 
    • 將單一 bit 恢復為預設/關閉狀態

程式參考

    Nuvoton 官方 github https://github.com/OpenNuvoton/N9H31_NonOS

延伸閱讀






2026年4月10日星期五

韌體工程師需要懂一點硬體:GPIO 輸入輸出模式與實務應用整理

此篇說明 GPIO 在輸入時的上拉/下拉電阻配置、輸出模式的種類,以及實際應用案例,幫助建立基本且實用的設計觀念。

一、GPIO 基本分類

GPIO 從功能上可分為兩大類:
  1. 輸出(Output)
  2. 輸入(Input)
雖然在部分晶片中,GPIO 設定看似只有「輸入」與「輸出」兩種,甚至在暫存器中僅提供如 PULL_UP 或 NO_PULL_UP 的選項,但實際電氣行為與應用模式遠不只如此。
GPIO 晶片內部示意圖

 二、GPIO 輸出模式

GPIO 輸出模式主要分為:
  1. 推挽輸出(Push-Pull)
  2. 開漏輸出(Open-Drain)
※ 部分文件中提到的「一般輸出(General Output)」,多半是指 Push-Pull 模式。
 
推挽輸出(Push-Pull)
Push-Pull 為最常見的輸出方式,能主動輸出 High 或 Low,具備較佳的驅動能力與穩定性,適用於大多數數位控制情境,例如 LED 控制或一般控制訊號輸出。
(參考 GPIO 晶片內部示意圖中的藍色區塊)
 
Push-Pull 的特性為:
  1. 可主動拉高
  2. 可主動拉低
  3. 驅動能力較完整
  4. 適合單一裝置控制
開漏輸出(Open-Drain)
Open-Drain 的特性為:
  1. 只能主動輸出 Low
  2. 無法主動輸出 High
  3. High 需依靠外部或內部上拉電阻
※ Open-Drain 的 High 並不是由 GPIO 主動輸出,而是「釋放線路,讓電阻將訊號拉高」。
Open Drain 內部組合
常見應用:
  • I2C 通訊
  • 多裝置共用訊號線
  • 避免訊號衝突的設計

三、GPIO 輸入模式

GPIO 輸入模式主要包含:
  1. 上拉(Pull-up)
  2. 下拉(Pull-down)
  3. Tri-state(高阻抗 / 浮接)
※Tri-state(高阻抗)代表腳位未被明確拉高或拉低,容易受到外界雜訊影響,造成判斷不穩定。
(參考 GPIO 晶片內部示意圖中的黃色區塊) 

上拉電阻(Pull-up)
功能:
  1. 將預設電位維持在 High
  2. 避免腳位浮接
  3. 減少外部電阻需求
應用:
  1. 按鍵偵測(Active Low)
  2. Open-Drain 設計
下拉電阻(Pull-down)
功能:
  1. 將預設電位維持在 Low
  2. 避免浮接
  3. 減少外部元件
應用:
  1. Active High 設計

四、GPIO 設定與實際行為差異

在實際應用中,需考慮:
  1. Push-Pull 與 Open-Drain 輸出結構
  2. 電流驅動能力
  3. 外部電路影響
GPIO 不只是數位訊號,而是與電氣設計密切相關

五、GPIO 驅動能力與設計觀念

許多新手會習慣將 GPIO 設為輸出 HIGH,直接點亮 LED,甚至驅動小型馬達。
雖然在簡單測試中可能可行,但在工程實務上存在風險。
原因如下:
  1. GPIO 腳位電流有限制
  2. 超過負載可能導致:
    1. 電壓不穩
    2. 晶片過熱
    3. IO Driver 損壞

六、較正確的工程設計方式

GPIO 應視為「控制訊號」,而非「電源」。
設計方式應為:
  • 控制電流路徑
  • 搭配外部電路(電阻 / MOSFET / BJT)
應用說明:
  • LED 驅動
    1. 建議使用 GPIO 輸出 LOW(Sink 電流)
    2. 搭配限流電阻
LED 驅動電路示意圖
  • 馬達或高負載
    1. 不可直接由 GPIO 驅動
    2. 必須透過外部元件控制
    3. 通常控制的電源超過 MCU 本身
    4. 增加隔離避免 MCU 被干擾(ex. 光耦合或繼電器)
馬達驅動隔離電路示意圖
 註: 基礎 GPIO 結構與隔離概念參考自 Analog Devices 及 Arduino Forum 。
  • I2C 共用訊號線
    1. 使用 Open-Drain
    2. 搭配 Pull-up 電阻
I2C 匯流排之開漏輸出 (Open-Drain) 與上拉電路架構

七、GPIO 實務應用:按鍵輸入與除彈跳

在按鍵輸入應用中,除了電位判斷外,還需要考慮「彈跳(Bounce)」問題。機械按鍵在切換瞬間,訊號會在短時間內快速震盪 High / Low,若直接讀取,容易造成誤判。

常見設計方式:
  • 使用 Pull-up(Active Low)
  • 按下時接地(GND)
  • 未按為 High,按下為 Low
除彈跳(Debounce)解法:
  1. 軟體方式
    1. 延遲判斷(delay)
    2. 多次取樣確認穩定狀態
  2. 硬體方式
    1. RC 濾波
    2. Schmitt Trigger 
核心觀念總結
  • GPIO 分為輸入與輸出,但實際應用更複雜
  • Pull-up / Pull-down 可避免浮接問題
  • Tri-state 容易造成不穩定
  • Open-Drain 需搭配 Pull-up 使用
  • GPIO 電流有限,不可直接驅動高負載
  • 按鍵應考慮除彈跳問題
  • GPIO 的本質是「控制」,不是「供電」

參考文獻 (References)

  • 工業級驅動與隔離設計
    • Analog Devices, "Implementing an Isolated Half-Bridge Gate Driver". 提供了關於高壓負載隔離、半橋驅動架構與位準移位(Level Shift)的專業設計原則.
  • 硬體實作與社群案例
    • Arduino Forum, "About Optoisolator with MOSFETs for DC Motor PWM Control - General Electronics". 參考其在微控制器環境下,利用光耦合器(Optocoupler)隔離控制高功率負載的實務電路佈局.
  • 國際通訊標準規範
    • NXP Semiconductors, "UM10204: I2C-bus specification and user manual". 確立了 I2C 匯流排的電氣特性,包含 Open-Drain(開漏輸出)要求、Wired-AND(線與)邏輯、以及多電壓系統(混合電壓)的兼容性規範.

打賞按讚