Raspberry Pi 提供了許多的 GPIO 讓使用者可以配合電路來做出許多不同的設計, 本篇文章使用 Raspbian 作為 Raspberry Pi 的系統,並透過 Python、C 語言與 newlisp 幾種類型的範例,來展示如何在 Raspberry Pi 下透過 GPIO 來操作 GPIO。
注意: 在這篇文章的範例,都必須以 root 權限 運行。
使用設備
要完成本篇文章所描述的部份,你需要以下幾種器材
- 1. Raspberry Pi
- 2. LED
- 3. 電阻 220 Ω 或其他適合阻值
- 4. 麵包板
- 5. 單蕊線
硬體線路
使用 Linux Kernel 提供的 sysfs 來控制 GPIO
在要寫程式之前,我們先來使用 Linux Kernel 提供的 sysfs 來控制 GPIO。
首先先將 GPIO4 設定成可以用 sysfs 控制
echo 4 > /sys/class/gpio/export
設定 GPIO4 為輸出腳
echo out > /sys/class/gpio/gpio4/direction
設定 GPIO4 輸出值為 1 (0: 低電位, 1: 高電位)
echo 1 > /sys/class/gpio/gpio4/value
設定 GPIO4 輸出值為 0 (0: 低電位, 1: 高電位)
echo 0 > /sys/class/gpio/gpio4/value
取消建立出來的 GPIO4 node
echo 4 > /sys/class/gpio/unexport
在你執行以上第 3 步的時候,你可以看到 LED 亮了起來,直到第 4 步時,才又變 回原本的狀態。
若想要使用 Bash 來控制 GPIO,則可以採用此種方式。
使用 debugfs 來觀看目前的 GPIO 設定
我們可以使用 debugfs 來察看目前的 GPIO 設定,首先掛載 debugfs
root@raspberrypi:/home/pi# mount -t debugfs debug /d
接著就可以使用
root@raspberrypi:/home/pi# cat /d/gpio
來取得目前 GPIO 的狀況
root@raspberrypi:/home/pi# cat /d/gpio GPIOs 0-53, bcm2708_gpio: gpio-4 (sysfs ) out hi
使用 C 語言控制 GPIO (不使用外部函式庫)
C 語言因為提供了指標,可以任意的去修改記憶體的某個部份,因此我們也可 以透過修改記憶體區塊的方式,來設定我們的 GPIO。
以下程式修改自 elinux 的範例,首先點亮 GPIO4 上的 LED 一秒後,再關閉。
/* Modified from http://elinux.org/RPi_Low-level_peripherals */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <unistd.h> #define BCM2708_PERI_BASE 0x20000000 #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ #define PAGE_SIZE (4 * 1024) #define BLOCK_SIZE (4 * 1024) int mem_fd; void *gpio_map; /* I/O access */ volatile unsigned *gpio; /* GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) */ #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) #define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) #define GPIO_SET *(gpio+7) /* sets bits which are 1 ignores bits which are 0 */ #define GPIO_CLR *(gpio+10) /* clears bits which are 1 ignores bits which are 0 */ /** * Set up a memory regions to access GPIO * */ void setup_io() { /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("can't open /dev/mem \n"); exit(-1); } /* mmap GPIO */ gpio_map = mmap( NULL, /* Any adddress in our space will do */ BLOCK_SIZE, /* Map length */ PROT_READ|PROT_WRITE, /* Enable reading & writting to mapped memory */ MAP_SHARED, /* Shared with other processes */ mem_fd, /* File to map */ GPIO_BASE /* Offset to GPIO peripheral */ ); close(mem_fd); /* No need to keep mem_fd open after mmap */ if (gpio_map == MAP_FAILED) { printf("mmap error %d\n", (int)gpio_map); /* errno also set! */ exit(-1); } /* Always use volatile pointer! */ gpio = (volatile unsigned *)gpio_map; } int main(int argc, char **argv) { /* Set up gpi pointer for direct register access */ setup_io(); /* Must use INP_GPIO before we can use OUT_GPIO */ INP_GPIO(g); OUT_GPIO(g); /* Set GPIO4 to 1 */ GPIO_SET = 1 << 4; sleep(1); /* Clear GPIO 4 */ GPIO_CLR = 1 << 4; sleep(1); return 0; }
使用 C 語言控制 GPIO (使用 BCM2835 函式庫)
BCM2835 C library 是針對 BCM2835 CPU 用的 C 語言函式庫,透過他你可以輕鬆 的使用 C 語言去控制 Raspberry Pi 的 GPIO、I²C 等裝置,第一次使用這個函式庫 時,需要自己下載來編譯。
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.25.tar.gz tar zxvf bcm2835-1.25.tar.gz cd bcm2835-1.25 ./configure make sudo make install
接著我們就可以寫如下的 C 語言程式來閃爍我們的 LED。
/* Compile with: gcc blink.c -o blink -l bcm2835 */ #include <bcm2835.h> /* Blinks on RPi pin 7 */ #define PIN RPI_GPIO_P1_7 int main(int argc, char **argv) { if ( !bcm2835_init() ) { perror("Error"); return 1; } /* Set the pin to be an output */ bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP); /* Blink LED */ while (1) { /* Turn on LED */ bcm2835_gpio_write(PIN, HIGH); /* Delay 500ms */ delay(500); /* Turn off LED */ bcm2835_gpio_write(PIN, LOW); /* Delay 500ms */ delay(500); } return 0; }
使用 Python 控制 GPIO
在 Raspbian 發行版當中,已經預先將 RPi.GPIO 模組包入,因此你可以直接 寫以下的 python 程式來控制 GPIO4,要注意的是,RPi.GPIO 設定的 GPIO 是採 用 Pin number,也就是說若我要修改 GPIO4 (Pin 7),則實際上呼叫 Rpi.GPIO 的號碼為 7 ,而不是 4 。
import RPi.GPIO as GPIO import time # blinking function def blink(pin): GPIO.output(pin,GPIO.HIGH) time.sleep(1) GPIO.output(pin,GPIO.LOW) time.sleep(1) return # to use Raspberry Pi board pin numbers GPIO.setmode(GPIO.BOARD) # set up GPIO output channel, we set GPIO4 (Pin 7) to OUTPUT GPIO.setup(7, GPIO.OUT) # blink GPIO4 (Pin 7) 50 times for i in range(0,50): blink(7) GPIO.cleanup()
使用 newlisp 控制 GPIO
newlisp 是屬於 script language,若不透過他的 FFI (Foreign Function Interface),則要在 newlisp 下控制 GPIO 的最好方法就是更改 sysfs 下的 GPIO 資訊。
我們可以使用 raspi-gpio 模組來簡化 nwelisp 下修改 GPIO 資訊的步驟,首先 先下載 raspi-gpio.lsp
wget https://raw.github.com/gatesphere/raspi-gpio-newlisp/master/raspi-gpio.lsp
接著你就可以寫以下的 newlisp 程式來閃爍 LED
#!/usr/bin/env newlisp (load "raspi-gpio.lsp") (define (blink gpio) ;; Make GPIO to 1 (GPIO:digital-write gpio GPIO:high) ;; delay 500ms (sleep 500) ;; Make GPIO to 0 (GPIO:digital-write gpio GPIO:low) ;; delay 500ms (sleep 500)) ;; Enable use GPIO4 (GPIO:enable-pin 4) ;; Set GPIO4 as output (GPIO:pin-mode 4 GPIO:out) ;; Blink GPIO4 50 times (dotimes (x 50) (blink 4)) ;; Disable use GPIO4 (GPIO:disable-pin 4) ;; End of Application (exit)