訳あって久しぶりにRaspberryPiを触っています。しっかし、日々いろんな事が起きるせいか、忘れていることだらけです。
今回はGPIOを使ってちょっとしたシーケンスを組んでいます。はっきりいって、Arduinoの方が簡単にできるんですが、PCなしでプログラムを変更しないといけない環境なので、セルフコンパイルが可能なRaspberryPiに白羽の矢が立ちました。
で、以前の自分の記事を元に、いろいろやってみたのですが、スマートになりません。そこで、再びググってみると、いろいろ便利になっているようです。
簡単そうなのは、「C library for Broadcom BCM 2835 as used in Raspberry Pi」を使うことです。リンク先の記述に沿って、ダウンロード&インストールしました。
インストールが完了すると、こちらの記事で紹介されているような簡単な記述でGPIOが扱えます。(ちなみにリンク先では他の言語でのI/O制御も紹介されています)
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
// Rpi P1ヘッダの26ピン(GPIO 7)をPINと定義する
#define PIN RPI_V2_GPIO_P1_26
// 割り込みコールバック関数
void signal_callback_handler(int signum)
{
printf("\ndetect key interrupt\n",signum);
bcm2835_close();
printf("Program exit\n");
exit(0);
}
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
signal(SIGINT, signal_callback_handler);
printf("press ^C to exit program ...\n");
while (1)
{
bcm2835_gpio_write(PIN, HIGH);
delay(500); // 0.5秒待つ
bcm2835_gpio_write(PIN, LOW);
delay(500); // 0.5秒待つ
}
}
こんな感じで26ピンに接続したLEDが点滅します。(リンク先との差はGPIOの端子だけです)
コンパイル&実行の方法は下記。
$ gcc blink_led.c -o blink_led -l rt -l bcm2835 $ sudo ./blink_led
次にポート入力の方法は以下のような感じ。
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
// Rpi P1ヘッダの24ピン(GPIO 8)をPINと定義する
#define PIN RPI_V2_GPIO_P1_24
// 割り込みコールバック関数
void signal_callback_handler(int signum)
{
printf("\ndetect key interrupt\n",signum);
bcm2835_close();
printf("Program exit\n");
exit(0);
}
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
// VCCまでプルアップする
bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP);
signal(SIGINT, signal_callback_handler);
printf("press ^C to exit program ...\n");
while (1)
{
uint8_t value = bcm2835_gpio_lev(PIN);
printf("read from pin 24: %d\n", value);
delay(500); // 0.5秒待つ
}
}
これだけじゃ芸がないので、HRTとSCHEDULERをいじってみます。
まず、LED点滅はこんな感じ。0.5秒周期の点滅にHRTを使ってます。
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
// Rpi P1ヘッダの26ピン(GPIO 7)をPINと定義する
#define PIN RPI_V2_GPIO_P1_26
// 割り込みコールバック関数
void signal_callback_handler(int signum)
{
printf("\ndetect key interrupt\n",signum);
bcm2835_close();
printf("Program exit\n");
exit(0);
}
///////////////////////////
// HRTを使ったポート入力
//
#include <sched.h>
#include <time.h>
static struct timespec hrt_now;
static struct timespec hrt_next;
void test(long tick)
{
int v=1;
// HRT処理
clock_gettime(CLOCK_MONOTONIC, &hrt_now);
while(1){
hrt_next.tv_nsec = hrt_now.tv_nsec + tick;
if(hrt_next.tv_nsec >= 1000000000){
hrt_next.tv_nsec -= 1000000000;
hrt_next.tv_sec = hrt_now.tv_sec + 1;
} else {
hrt_next.tv_sec = hrt_now.tv_sec;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &hrt_next, NULL);
hrt_now = hrt_next;
// 周期処理
{
if(v){
bcm2835_gpio_write(PIN, HIGH);
} else {
bcm2835_gpio_write(PIN, LOW);
}
v=1-v;
}
}
}
int main(int argc, char **argv)
{
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
signal(SIGINT, signal_callback_handler);
printf("press ^C to exit program ...\n");
test(500000000);
return EXIT_SUCCESS;
}
次に、ポート入力はこんな感じ。
#include <stdio.h>
#include <stdlib.h>
#include <bcm2835.h>
#include <signal.h>
// Rpi P1ヘッダの24ピン(GPIO 8)をPINと定義する
#define PIN RPI_V2_GPIO_P1_24
// 割り込みコールバック関数
void signal_callback_handler(int signum)
{
printf("\ndetect key interrupt\n",signum);
bcm2835_close();
printf("Program exit\n");
exit(0);
}
///////////////////////////
// HRTを使ったポート入力
//
#include <sched.h>
#include <time.h>
static struct timespec hrt_now;
static struct timespec hrt_next;
void test(long tick)
{
// HRT処理
clock_gettime(CLOCK_MONOTONIC, &hrt_now);
while(1){
hrt_next.tv_nsec = hrt_now.tv_nsec + tick;
if(hrt_next.tv_nsec >= 1000000000){
hrt_next.tv_nsec -= 1000000000;
hrt_next.tv_sec = hrt_now.tv_sec + 1;
} else {
hrt_next.tv_sec = hrt_now.tv_sec;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &hrt_next, NULL);
hrt_now = hrt_next;
// 周期処理
{
uint8_t value = bcm2835_gpio_lev(PIN);
printf("read from pin 24: %d\n", value);
}
}
}
int main(int argc, char *argv[]) {
int MinPriority;
int MaxPriority;
struct sched_param prio;
// SCHED_FIFOポリシーの優先度の最大値/最小値を得る
MinPriority=sched_get_priority_min(SCHED_FIFO);
printf("Min priority for FIFO policy is %d\n",MinPriority);
MaxPriority=sched_get_priority_max(SCHED_FIFO);
printf("Max priority for FIFO policy is %d\n",MaxPriority);
// スケジューリングポリシーと優先度最大を設定する
prio.sched_priority = MaxPriority;
if(sched_setscheduler(0,SCHED_FIFO,&prio)<0){
perror("Schedule set error\n");
exit(0);
}
if (!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
// VCCまでプルアップする
bcm2835_gpio_set_pud(PIN, BCM2835_GPIO_PUD_UP);
// CTRL-C 押下時の処理
signal(SIGINT, signal_callback_handler);
printf("press ^C to exit program ...\n");
test(500000000);
return EXIT_SUCCESS;
}
