RPi筆記 - GPIO

GPIO layout

使用RPi的GPIO,通常狀況P1就夠了,經常使用的SPI、I2C、UART都在這。使用時參考下面兩個圖(都是從elinux.org搬運過來的,詳細的描述能夠在這裏找到)。
RPi的GPIO只支持3.3V電壓,若是接5V的IO,要注意電平轉換。python

P1在板子上的位置:
GPIO reallinux

P1每一個Pin的功能:
GPIO layoutgit

一個例子

經過UART登陸RPi。github

首先參考上面的兩個圖鏈接PC和RPi,無非是TxD接RxD,RxD接TxD,注意共地。
我用的是一個TTL-USB的轉換模塊,因此鏈接後,PC系統中會多一個tty設備/dev/ttyUSB0。根據和PC的不一樣鏈接方式,設備節點可能會是不一樣的名字。
鏈接segmentfault

而後打開minicom鏈接RPi。建議將串口配置命名保存起來,便於下次直接使用,若是有多個串口配置,也能快速切換。數組

如下是操做過程:
操做佈局

若是不知道默認用戶名、密碼,能夠根據使用的系統類型,在官方下載頁面查找:
RaspBianui

Arch Linux

又一個例子

點燈。spa

用P1-11,P1-12,P1-13分別控制三個LED。電路很簡單,一目瞭然。BTW,原理圖,我是用Circuit Lab在線畫的,小巧方便。code

原理圖

LED接線

而後是代碼,借鑑了elinux.org的示例。

Python版:

#!/usr/bin/env python

import time
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.setup(11, GPIO.OUT)
GPIO.setup(12, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)

GPIO.output(11, GPIO.HIGH)
GPIO.output(12, GPIO.HIGH)
GPIO.output(13, GPIO.HIGH)

pin = 0;
while True:
    GPIO.output(11 + pin, GPIO.LOW)
    time.sleep(1)
    GPIO.output(11 + pin, GPIO.HIGH)
    pin = (pin + 1) % 3

C版:

/* blink.c
 * 2014/6/6
 */
#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)

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

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

void map_registers()
{
    void *gpio_map;
    int mem_fd;

    if((mem_fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0){
        printf("can't open /dev/mem\n");
        exit(-1);
    }

    gpio_map = mmap(
            NULL,
            BLOCK_SIZE,
            PROT_READ|PROT_WRITE,
            MAP_SHARED,
            mem_fd,
            GPIO_BASE
            );
    close(mem_fd);

    if(gpio_map == MAP_FAILED){
        printf("mmap error %d\n", (int)gpio_map);
        exit(-1);
    }

    gpio = (volatile unsigned *)gpio_map;
}

int main(int argc, const char *argv[])
{
    int cnt = 0;
    int pin_map[3] = {17, 18 , 27};

    map_registers();

    INP_GPIO(pin_map[0]);
    OUT_GPIO(pin_map[0]);
    INP_GPIO(pin_map[1]);
    OUT_GPIO(pin_map[1]);
    INP_GPIO(pin_map[2]);
    OUT_GPIO(pin_map[2]);

    GPIO_SET = (1 << pin_map[0]) | (1 << pin_map[1]) | (1 << pin_map[2]);

    while(1)
    {
        GPIO_CLR = 1 << pin_map[cnt];
        sleep(1);
        GPIO_SET = 1 << pin_map[cnt];
        cnt = (cnt + 1) % 3;
    }

    return 0;
}

Python版代碼簡潔不少,由於用了RPi.GPIO這個包,而C版沒有依賴任何庫。
Python版代碼,直接scp過去就可執行。C代碼須要編譯。下載編譯器,而後arm-linux-gnueabihf-gcc blink.c -o blink。一樣scp到RPi執行。

兩個版本執行都須要root權限。

這裏有一個小小的坑。
GPIO的pin有兩種命名方式,以SoC爲中心,和以RPi爲中心。
Python版代碼中GPIO.setmode(GPIO.BOARD)就是設置使用RPi爲中心的命名方式,這樣接下來GPIO.output(11, GPIO.HIGH)中的pin編號,與本文最開始的圖示是一一對應的。這種方式比較直觀。
固然也可使用另外一種,GPIO.setmode(GPIO.BCM)便可。這樣的話,pin編號與它們在RPi上的佈局有一個映射關係。詳細的能夠參考這個表格

C版代碼中用的是SoC的命名,爲了方便操做,纔有了這個數組int pin_map[3] = {17, 18 , 27};。可見GPIO17等同於P1-11,GPIO18等同於P1-12,GPIO27等同於P1-13。

另外C版代碼中直接操做了GPIO的寄存器。寄存器映射參考Data Sheet

相關文章
相關標籤/搜索