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. 環境、使用機器
- Raspberry Pi 3 (Rasbpian Stretch)
- 4線抵抗膜型タッチスクリーン(4.3インチ)
- 1.25mmピッチ4P、FFCコネクタ
- http://www.aitendo.com/product/16196
- タッチコントローラモジュールADS7843
- 1.0mmピッチ4ピンFFCコネクタ(下接点)
- http://www.aitendo.com/product/2308
3. 参考サイト
-
- 公式サイト
-
gpio - pigpio spiXfer in C++ - Raspberry Pi Stack Exchange
- pigpioでSPIを使うサンプルコードがあまり多くなく、この回答がとても参考になりました。
-
windows で Node.js の child_process.exec を利用する - 自習室
- Node.jsでCからデータを受け取る方法として参考にしました。
-
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言語のプログラムを書く
# 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;
}
コンパイルします。
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座標の変数に入れます。
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でも書きましたが、私はデーモンをサービスに登録してしまっていたので、実行時にエラーが発生することが多々ありました。
エラーの種類がいくつかありましたが、例えば以下のようなエラーが発生します。
err : 2018-04-09 10:21:18 initInitialise: Can't lock /var/run/pigpio.pid
err : 2018-04-18 13:28:16 initInitialise: bind to port 8888 failed (Address already in use)
解決策はこちらのサイトに以下のように記載されており、デーモンを終了して、該当ファイルを削除してみてください。
sudo killall -9 pigpiod # kill the daemon
sudo rm /var/run/pigpio.pid
最終的な解決はサービスのファイル/lib/systemd/system/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