Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@yuji_miyano

Raspberry Pi 3とADS7843を使ってタッチスクリーンの情報を受け取る(Cでpigpioを使ってSPI通信→Nodejs)

1. 概要

前回、Raspberry Pi 3とADS7843を使ってタッチスクリーンの情報をNodejsで受け取る - QiitaではNode.jsを使ってセンサの値を受け取ったのですが、センサ周辺のプログラムはCで書いた方が処理が速いと聞いたのでCで書いてnode.jsで受け取ることにしました。

アプリケーション間(Cとnode.js)のデータのやり取りの方法がちょっと変わっているなと感じました。oscみないなものを使うと思っていたらnode.jsからCを起動してprintfを監視する方法でした。

Cでは最初Wiring Piを使おうとしましたがうまくいかず、pigpioを使用しました。

2. 環境、使用機器

3. 参考サイト

  1. pigpio library
    • 公式サイト
  2. gpio - pigpio spiXfer in C++ - Raspberry Pi Stack Exchange

    • pigpioでSPIを使うサンプルコードがあまり多くなく、この回答がとても参考になりました。
  3. windows で Node.js の child_process.exec を利用する - 自習室

    • Node.jsでCからデータを受け取る方法として参考にしました。
  4. node の spawn に関して調べてみた - Qiita

    • Node.jsでCからデータを受け取る方法として参考にしました。

4. 方法

4.1 配線

ADS7843 Raspberry Pi
CS GPIO8 (CE0) / GPIO7 (CE1)
DOUT GPIO9 (MISO)
DIN GPIO10 (MOSI)
DCLK GPIO11 (SCLK)
5V 5V
GND GND

4.2 pigpioの導入

参考サイト1のダウンロードのページが詳しいです。
apt-getでインストールできるけど古いと書いてあります。

$ sudo apt-get update
$ sudo apt-get install pigpio

日本語のサイトをいくつか見ているとデーモンを先に起動しないといけないということや、サービスに登録しておく手順などが紹介されていますが、バージョンが違うのか私の場合は不要でした。逆にデーモンが立ち上がっているとエラーが発生してしまいまた。公式サイトにも書いていない気がするので、デーモンのことは気にしなくても使えると思います。

私はサービスに登録してしまったので、Raspberry Pi起動時にデーモンが起動して毎回エラーが出てハマりました。エラーについては4.5で説明しています。

4.3 pigpioでSPI通信をするC言語のプログラムを書く

ads7843.c
#include <stdio.h>
#include <stdlib.h>
#include <pigpio.h>

#define PRESS_DETECTION 22  // GPIO22(pin15) screen press detection

int handle;

void onPressed();
int getValueX();
int getValueY();
int isPressed = 0;   // タッチスクリーンが押されたら1

int main()
{
  int speed= 1000000;

  // GPIO初期化
  if (gpioInitialise() < 0) {
    printf("initialize error");
    exit(1);
  }
  gpioSetMode(PRESS_DETECTION, PI_INPUT);         // GPIO22を入力に設定 
  gpioSetPullUpDown(PRESS_DETECTION, PI_PUD_UP);  // GPIO22を
  gpioSetAlertFunc(PRESS_DETECTION, onPressed);   // GPIOの値が変わったときに呼ばれる

  // SPI初期化
  handle = spiOpen(0, speed, 0);
  if (handle < 0) {
    printf("SPI open error");
  }

  while(1)
  {
    if(isPressed == 1){
      printf("x,%d,", getValueX());
      printf("y,%d\n", getValueY());
      fflush(stdout);
      usleep(10000);
    } 
  }

  // SPI、GPIO終了
  spiClose(handle);
  gpioTerminate();

  return 0;
}

void onPressed(int gpio, int level, uint32_t tick)
{
  if(level == 0 ){  // 0:change to low(a falling edge)
    isPressed = 1;
  }else{
    isPressed = 0;
  }

}

int getValueX(){
  int value;
  unsigned char buf[3] = {0x94, 0x00, 0x00};

  spiXfer(handle, buf, buf, 3);
  value = (((buf[1] & 0x7f) << 8) | buf[2]) >> 3;

  return value;
}

int getValueY(){
  int value;
  unsigned char buf[3] = {0xD4, 0x00, 0x00};

  spiXfer(handle, buf, buf, 3);
  value = (((buf[1] & 0x7f) << 8) | buf[2]) >> 3;

  return value;
}

コンパイルします。

コンパイル方法(ads7843.cというファイルをコンパイルしてads7843という実行ファイルを作る場合)
gcc -Wall -pthread -o ads7843 ads7843.c -lpigpio -lrt

ads7843.cと同じフォルダにads7843というファイルができる。

実行します。タッチスクリーンに触れるとx、yの座標が表示されます。

実行方法
sudo ./ads7843

4.4 node.jsで値を受け取るプログラムを書く

node.jsの中でcの実行ファイルを動かしてprintfの出力を受け取るプログラムになります。
受け取ったデータがカンマ区切りになっているので、カンマで分けてx座標、y座標の変数に入れます。

sensor.js
var spawn = require('child_process').spawn;

var sp = spawn("./ads7843",[]);
var valueX = 0, valueY = 0;

sp.stdout.on('data', function (data){      // データがある場合
  //console.log("data : " + data);
  var lines = data.toString().split(",");  // 文字列にしてカンマで分ける
  for(var i = 0; i < lines.length; i++){
    if (lines[i] == 'x'){
      valueX = lines[i+1];
    }
    else if (lines[i] == 'y'){
      valueY = lines[i+1];
    }
  }
  console.log("x:" + valueX);
  console.log("y:" + valueY);
});

sp.stderr.on('data', function (data){
  console.log("err : " + data);
});

以下のコマンドで実行します。表示されるデータはCのみで実行したものとほぼ同じです。

実行方法
sudo node sensor.js

4.5 エラー発生時

4.2でも書きましたが、私はデーモンをサービスに登録してしまっていたので、実行時にエラーが発生することが多々ありました。

エラーの種類がいくつかありましたが、例えば以下のようなエラーが発生します。

エラー例1
err : 2018-04-09 10:21:18 initInitialise: Can't lock /var/run/pigpio.pid
エラー例2
err : 2018-04-18 13:28:16 initInitialise: bind to port 8888 failed (Address already in use)

解決策はこちらのサイトに以下のように記載されており、デーモンを終了して、該当ファイルを削除してみてください。

image.png

対策
sudo killall -9 pigpiod # kill the daemon
sudo rm /var/run/pigpio.pid

最終的な解決はサービスのファイル/lib/systemd/system/pigpiod.serviceを削除しました。いろんなサイトを見て設定しているうちに設定していましたが、古い情報だったのかもしれません。
ちなみに中身はこれです。

pigpiod.service
[Unit]
Description=Daemon required to control GPIO pins via pigpio
[Service]
ExecStart=/usr/bin/pigpiod -l
ExecStop=/bin/systemctl kill pigpiod
Type=forking
[Install]
WantedBy=multi-user.target
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?