kivantium活動日記

プログラムを使っていろいろやります

Raspberry PiでLチカ

Raspberry PiのGPIO機能のメモ。とりあえずLチカをやってみる

Raspberry PiのGPIOについて

ピン配列はこのようになっている。
RPi.GPIO Quick Reference updated for Raspberry Pi B+ and A+ » RasPi.TV

http://raspi.tv/wp-content/uploads/2014/07/Raspberry-Pi-GPIO-pinouts.png

GPIO25とGNDの間にLEDと抵抗を挟む回路をブレッドボード上に作成した。

C言語

こじ研 Raspberry Pi 応用編のソースを利用

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
//レジスタブロックの物理アドレス
#define PERI_BASE     0x20000000
#define GPIO_BASE     (PERI_BASE + 0x200000)
#define BLOCK_SIZE    4096
//  gpio[n]: GPIO 関連レジスタ (volatile=必ず実メモリにアクセスさせる)
static volatile unsigned int *Gpio = NULL;
//  gpio_init: GPIO 初期化(最初に1度だけ呼び出すこと)
void gpio_init ()
{
    //  既に初期化済なら何もしない
    if (Gpio) return;
    //  ここから GPIO 初期化
    int fd;
    void *gpio_map;
    //  /dev/mem(物理メモリデバイス)を開く(sudo が必要)
    fd = open("/dev/mem", O_RDWR | O_SYNC);
    if (fd == -1) {
        printf("error: cannot open /dev/mem (gpio_setup)\n");
        exit(-1);
    }
    //  mmap で GPIO(物理メモリ)を gpio_map(仮想メモリ)に対応づける
    gpio_map = mmap(NULL, BLOCK_SIZE,
                    PROT_READ | PROT_WRITE, MAP_SHARED,
                    fd, GPIO_BASE );
    if ((int) gpio_map == -1) {
        printf("error: cannot map /dev/mem on the memory (gpio_setup)\n");
        exit(-1);
    }
    //  mmap 後は不要な fd をクローズ
    close(fd);
    //  Gpio[index]: 整数 uint32 の配列としてレジスタへのアクセスを確立
    Gpio = (unsigned int *) gpio_map;
}
//  ピン機能(BCM2835)
#define GPIO_INPUT    0x0       //  入力
#define GPIO_OUTPUT   0x1       //  出力
#define GPIO_ALT0     0x4
#define GPIO_ALT1     0x5
#define GPIO_ALT2     0x6
#define GPIO_ALT3     0x7
#define GPIO_ALT4     0x3
#define GPIO_ALT5     0x2
//  gpio_configure: ピン機能を設定する(ピンを使用する前に必ず設定)
//      pin : (P1) 2,3,4,7,8,9,10,11,14,15,17,18,22,23,24,25,27
//            (P5) 28,29,30,31
//      mode: GPIO_INPUT, _OUTPUT, _ALT0, _ALT1, _ALT2, _ALT3, _ALT4, _ALT5
void gpio_configure (int pin, int mode)
{
    //  ピン番号チェック
    if (pin < 0 || pin > 31) {
        printf("error: pin number out of range (gpio_configure)\n");
        exit(-1);
    }
    //  レジスタ番号(index)と3ビットマスクを生成
    int index = pin / 10;
    unsigned int mask = ~(0x7 << ((pin % 10) * 3));
    //  GPFSEL0/1 の該当する FSEL (3bit) のみを書き換え
    Gpio[index] = (Gpio[index] & mask) | ((mode & 0x7) << ((pin % 10) * 3));
}
//  gpio_set/clear: ピンをセット (3.3V),クリア (0V)
void gpio_set (int pin)
{
    //  ピン番号チェック(スピードを追求するなら省略してもよい)
    if (pin < 0 || pin > 31) {
        printf("error: pin number out of range (gpio_set)\n");
        exit(-1);
    }
    //  ピンに1を出力(3.3V 出力)
    Gpio[7] = 0x1 << pin;   //  GPSET0
}
void gpio_clear (int pin)
{
    //  ピン番号チェック(スピードを追求するなら省略してもよい)
    if (pin < 0 || pin > 31) {
        printf("error: pin number out of range (gpio_clear)\n");
        exit(-1);
    }
    //  ピンに0を出力(0V 出力)
    Gpio[10] = 0x1 << pin;  //  GPCLR0
}
int main ()
{
    gpio_init();                        //  オマジナイ
    gpio_configure(25, GPIO_OUTPUT);    //  GPIO_25 を出力に設定
    while (1) {
        gpio_set(25);                   //  1 を出力(3.3V)
        usleep(500000);                 //  0.5秒待ち
        gpio_clear(25);                 //  0 を出力(0V)
        usleep(500000);                 //  0.5秒待ち
    }
}

実行は

gcc gpio.c
sudo ./a.out

のように管理者権限が必要。

Python

Raspberry Pi GPIO入出力のサンプル(Python, C言語, shellスクリプト) (r271-635)から。ピン番号しか改変してない……。

#!/usr/bin/python
 
import RPi.GPIO as GPIO
import time
 
IO_NO = 25 
 
print("press ^C to exit program ...\n")
 
GPIO.setmode(GPIO.BCM)
GPIO.setup(IO_NO, GPIO.OUT)
 
try:
 while True:
  GPIO.output(IO_NO, True)
  time.sleep(0.5)
  GPIO.output(IO_NO, False)
  time.sleep(0.5)
except KeyboardInterrupt:
 print("detect key interrupt\n")
 
GPIO.cleanup()
print("Program exit\n")

これも管理者権限が必要。

sudo ./gpio.py

結果


プルアップやアナログ入力機能などもあるらしいので使ってみたい。