Saturday, June 21, 2014

LPC1114FN28的GPIO使用方式

在學習微控制器最基礎的想必是動動I/O接腳, 推個LED燈或是讀取外部按鈕輸入.但經過實驗發現, 改變上次實驗內容的電路圖接法,將LED接至其他GPIO並單純的修改程式碼中的腳位設定,其實是無法直接驅動LED的!
作為一顆32位元的多功能ARM微處理器, 對於GPIO的設定與操作使用自然比較複雜些, 此次的心得將紀錄LPC1114FN28的GPIO使用方式, 以及在datasheet中的相關章節閱讀提示.

元件列表

  1. NXP LPC1114FN28 x 1
  2. 按鈕 x 3
  3. 電阻 330 Ω x 1
  4. 電阻 4.7k Ω x 2
  5. LED x 1

使用工具

  1. USB轉UART轉接線
  2. 3.3V位準電源

電路圖

LPC1114_GPIO_experiment_schematic

電路說明

於本次實驗將LED接至PIO1_0接腳,藉以測試在多功能的IO接腳上如何進行功能的切換;同時將燒錄按鍵PIO0_1作為此次實驗的外部輸入.

操作原理

在這次的實驗中, 希望能夠藉由一組按鈕接腳輸入(PIO0_1)來改變另一組LED接腳(PIO1_0)輸出, 藉以驗證基礎的GPIO功能; 當按鈕按下時, LED燈熄滅, 反之當沒有按下按鈕時, LED啟動.

有別於AVR ATmega系列的8位元微控制器, 以ARM Cortex-M0作為核心的LPC1114內部結構較為複雜些, 對於時脈的掌控更是需要注意; 在LPC1114的使用手冊中第3.4節中, 便提示了有一組名為SYSAHBCLKCTRL的暫存器掌控了所有週邊界面的時脈. 在本次的實驗中需要使用GPIO, 因此在系統啟動時,必須開啟I/O部份的時脈輸入;在手冊3.5.14章節中有對SYSAHBCLKCTRL之內容進行說明, 針對I/O時脈引入的設定在第16位元(IOCON),需將此暫存器內容寫入1:

LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_IOCON;

為了達成多種應用, 現今的微控制器需要支援多種界面(peripheral),從一般GPIO,ADC轉換的單一接腳用途,以至於多組接腳所一起組成的通訊界面如SPI,UART,I2C等,加上計數器…如此眾多的功能需要在有限的接腳資源內完成, 想必一定有些接腳是具備多種功能以備切換的,這樣的狀況在LPC1114FN28接腳數較少(Low Pin Count)的封裝中格外明顯.
參閱手冊10.4的Table 168.可發現這次實驗中要連接LED的PIO1_0腳位除了可作為一般數位I/O外, 還能作為A/D類比轉換以及計數器使用. 因此在開始點滅LED前,必須指定該接腳作為一般數位I/O功能:

LPC_IOCON->R_PIO1_0 |= (1 << 0);    //GPIO function select, manual 8.4.29

而按鈕輸入的接腳PIO0_1在預設狀態下便已經是一般數位I/O功能, 此時可設定該接腳內部直接接上上拉電阻(Pull-up resistor), 在未有輸入的狀況下直接測得高位電位; 而透過與一按鈕與電阻串接至地, 可藉由按鈕按下時測得低電位.

 LPC_IOCON->PIO0_1 |= (1 << 4);     //Pull-up enable, manual 8.4.4

在設定完各接腳模式後, 接著需要設定訊號方向; 在手冊的12.3.2節提到有一組GPIO data direction register用來控制GPIO輸入輸出方向的切換,將所需設定腳位的register寫入1即為輸出, 反之0則為輸入.

LPC_GPIO0->DIR |= (1 << 0); //set PIO0_1 to be output
LPC_GPIO1->DIR &= ~(1 << 0);    //set PIO1_0 to be input

完成了接腳方向的設定後, 便可以對輸出腳位輸出高低電位的切換,以及從輸入腳位讀取外部電位資訊; 在此次實驗中的操作非常單純, 透過不斷讀取輸入接腳之按鈕狀態,直接反應在輸出接腳的LED上. 對於接腳資訊的讀取或寫入來自於GPIO data register, 其操作如下:

  LPC_GPIO1->DATA |= (1 << 0);  //write HIGH to PIO1_0
  LPC_GPIO1->DATA &= ~(1 << 0); //write LOW to PIO1_0
  LPC_GPIO0->DATA &= (1 << 1);  //check the state from PIO0_1

綜合以上的所有操作, 主程式簡短如下:
當PIO0_1的按鈕未被按下時, 由於內部已經被設定為Pull High組態, 因此讀取輸入為高電位,並將此狀態直接反應於接於PIO1_0接腳上的LED;反之, 在按鈕被按下時PIO0_1接地,讀取輸入為低電位,亦將此狀態反應於PIO1_0之LED上.

int main(void)
{
        volatile uint32_t count, count_max = 1000000; 
        pll_start(CRYSTAL, FREQUENCY);

        //generate the clock to I/O peripheral
        LPC_SYSCON->SYSAHBCLKCTRL |= SYSAHBCLKCTRL_IOCON;   

        //set PIO1_0 for GPIO function
        LPC_IOCON->R_PIO1_0 |= (1 << 0);    
        //set PIO0_1 with pull high 
        LPC_IOCON->PIO0_1 |= (1 << 4); 

        //set PIO1_0 to be output
        LPC_GPIO1->DIR |= (1 << 0); 
        //set PIO0_1 to be input
        LPC_GPIO0->DIR &= ~(1 << 1);   

        while (1)
        {
                //check the button state on PIO0_1
                if(LPC_GPIO0->DATA &= (1 << 1)){   
                    //turn on the LED on PIO1_0
                    LPC_GPIO1->DATA |= (1 << 0);    
                }else{
                    //turn down the LED
                    LPC_GPIO1->DATA &= ~(1 << 0);   
                }
        }
}

如果接線正常且程式運作順利, 應該在壓下按鍵時LED熄滅, 而在放開按鍵時LED啟動.
enter image description here

No comments:

Post a Comment