2014年07月06日

Raspberry Piで大気圧センサ(AE-SCP1000-D01)の動作確認

Raspberry Piと秋月電子で販売されている大気圧センサーのSCP1000を使用して大気圧計を作成しました。

SPIの有効化

使用したLinuxはdebianで、以下のバージョンです。

pi@raspberrypi ~/work/lcd $ uname -a
Linux raspberrypi 3.12.22+ #691 PREEMPT Wed Jun 18 18:29:58 BST 2014 armv6l GNU/Linux

SPIを有効化するにはraspi-configコマンドを使用します。

pi@raspberrypi ~/work/lcd $ sudo raspi-config

[8 Advanced Options -> A5 SPI -> Yes]

SCP1000の接続

SCP1000はSPIインターフェースを備えています。以下の通り配線を行いました。どちらも物理ピン番号を記載しています。

[scp1000]       -     [RaspberryPi]
 3pin(SCK)      -      23pin(SCKL)
 4pin(GND)      -      25pin(GND)
 5pin(MOSI) - 0.01uF - 19pin(MOSI)
 6pin(MISO)     -      21pin(MISO)
 7pin(CSB)      -      24pin(CE0)
 8pin(VCC)      -      17pin(3.3v)

本来、上記接続で問題なく接続できるはずですが、Raspberry Piからどんなコマンドを送っても、読み出すと0x00又は0xFFの値しか返ってこない状態となりました。そこで、SCP1000側のMOSIの近くに0.01uFを挟むと4回に1回程度ですが信号が届くようになりました。原因は不明ですが、ブレッドボードで接続しているため、ノイズ等の影響を受けて不安定になっている可能性があります。

SC2004CSWB-XA-LB-Gの接続

表示デバイスは、秋月電子で販売されているSC2004CSWB-XA-LB-Gを使用しました。このデバイスは、4行x20桁が表示でき、バックライトに白色LEDを備えています。接続は以下の通り行っています。

[LCD]         -     [RaspberryPi]
 1pin(VSS)    -      3pin(GND)
 2pin(VDD)    -      1pin(3.3v)
 3pin(Vo)  - 2kΩ -  14pin(GND)
 4pin(RS)     -      16pin(GPIO23)
 5pin(R/W)    -      5pin(GND P5-Header)
 6pin(E)      -      18pin(GPIO24)
 11pin(DB4)   -      11pin(GPIO17)
 12pin(DB5)   -      12pin(GPIO18)
 13pin(DB6)   -      13pin(GPIO21)
 14pin(DB7)   -      15pin(GPIO22)
 
[LCD LED]  - [Raspberry Pi]
 A         -  2pin(5v)
 K - 180Ω -  20pin(GND)

なお、コントラスト調整用のボリュームは測定すると1.98kΩでした。
また、LEDの駆動電源は5Vを用いています。Raspberry Piの3.3vピンは電流の制限値があることから、USBコネクタと直接つながっている5Vを使用し、制限抵抗は180Ωを用いました。

プログラミング

動作が安定しなかったため初期化に失敗した場合は、再試行を繰り返す動作にしています。一度でも正しく値を送信できると、極めて安定して気圧データを取得することができました。MOSIにコンデンサを挟むことで安定性が多少増しましたが、以下のコードの初期化の処理が誤っている可能性もあります。参考程度に留めておいて下さい。

#include<wiringPiSPI.h>
#include<wiringPi.h>
#include<stdio.h>
#include<time.h>
#include<lcd.h>

#define SPI_CHANNEL 0
#define SPI_CLK 500000

int main(void){
	double temp = 0;
	double pressure = 0;
	unsigned char buf[3];
	char str[24];
	time_t time_now;
	struct tm *local_time;
	int i,fd,flag1=0, flag2=0;

        //wiringPiライブラリの初期化
        if (wiringPiSetup () == -1){
                return (1) ;
	}

        /* LCDデバイスの初期化 */
        if((fd = lcdInit(4,20,4, 4,5, 0,1,2,3,0,0,0,0)) < 0){
                printf("[Error] open lcd device\n");
                return(-1);
        }

	//SPIデバイスの初期化
	if((wiringPiSPISetup(SPI_CHANNEL, SPI_CLK))<0){
		printf("error SPI\n");
	}

	//初期処理。失敗した場合は繰り返す。
	while(1){
		flag1 = 0;
		flag2 = 0;

		//時間の表示
		time_now = time(NULL);
		local_time = localtime(&time_now);
		strftime(str, sizeof(str), "%Y/%m/%d %a %H:%M:%S", local_time);
		printf("%s\n", str);

		//ソフトリセットコード
		buf[0] = 0x1a;
		buf[1] = 0x01;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 2);
		printf("delay...\n");
		delay(60);

		//STATUS確認
		buf[0] = 0x1c;
		buf[1] = 0xff;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 2);
		printf("STATUS:%02x\n", buf[1]);
		i= buf[1]&0x01;
		if(i == 0){
			flag1 = 1;
			printf("STATUS OK!\n");
		}

		//DATARD8確認
		buf[0] = 0x7c;
		buf[1] = 0xff;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 2);
		printf("DATARD8:%02x\n", buf[1]);
		i= buf[1]&0x01;
		if(i == 1){
			flag2 = 1;
			printf("DATARD8 OK!\n");
		}

		if(flag1==1 && flag2==1){
			printf("START...\n");
			break;
		}
	}


	//オペレーションレジスタに高精度測定モードを設定
	buf[0] = 0x0e;
	buf[1] = 0x0a;
	wiringPiSPIDataRW(SPI_CHANNEL, buf, 2);

	//メインループ
	while(1){
		//温度の測定
		buf[0] = 0x84;
		buf[1] = 0x00;
		buf[2] = 0x00;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 3);
		temp = (double)((buf[1] << (8+2)) + (buf[2] << 2)) / 20 / 4;

		//気圧の測定
		buf[0] = 0x7c;
		buf[1] = 0x00;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 2);
		pressure = buf[1] << 16;
		buf[0] = 0x80;
		buf[1] = 0x00;
		buf[2] = 0x01;
		wiringPiSPIDataRW(SPI_CHANNEL, buf, 3);
		pressure += (buf[1] << 8) + buf[2];
		pressure = pressure / 4 / 100;

		//時間の取得
		time_now = time(NULL);
		local_time = localtime(&time_now);

		//LCD表示
       		lcdClear(fd);
	        lcdPosition(fd,0,0);
		strftime(str, sizeof(str), "%Y/%m/%d %a", local_time);
		lcdPrintf(fd, "DATE=%s", str);
	        lcdPosition(fd,0,1);
		strftime(str, sizeof(str), "%H:%M:%S", local_time);
		lcdPrintf(fd, "TIME=%s", str);
	        lcdPosition(fd,0,2);
       		lcdPrintf(fd, "TEMP=%2.2f[C]", temp);
	        lcdPosition(fd,0,3);
       		lcdPrintf(fd, "PRESS=%4.4f[hPa]", pressure);


		delay(1000);
	}
}

参考文献

合同会社パレットソフト:気圧センサ SCP1000 (試食)