しばらく活動できていなかったのですが、自作のEC計の検討はちゃんと進めていますよー
(ง°̀ロ°́)ง
前回までは2chでEC計を作製しました。
2CH必要な理由は電圧降下と電流を見るためでした。
ですが、問題が。。。(×_×;)
ECの値って温度の影響を受けるらしいんです。ということは温度補正が必要??
ということになりますね。
温度補正をするためには温度を取得する必要があります。
つまり今のMCP3002の2chでは足りない。。計3CH以上必要ということになります。
そりゃそうなんですけど、もう一回開発かー!!と叫びたくなります。ミニマリストという言葉は憧れますが、昔の自分は単純に調査が足りなかったなーと( ಠωಠ)
あきらめて4CHのADコンバーターMCP3004を使うことにしました。
毎度のことながらラズパイでWiringPiを使って開発したのでご紹介しますね(ノ*’ω’*)ノ~
MCP3004はどんなもの?
MCP3004は秋月電子で簡単に手に入れることができる4CHのADCです。
10bitの分解能があり、EC計の用途には十分な分解能があります。MCP3002が2ch用で8chのMCP3008もあります。
スペックシートも簡単に手に入ります。これを見るとMCP3004/MCP3008は同じデータシートのようです。
ざっとみてみましたがMCP3008もほぼほぼ同じプログラムでいいようです。
ラズパイではどうやって動かす?
ラズパイからMCP3004と通信するにはSPIを使います。SPI通信には便利なWiringPiを使いましょう。
SPI通信に必要なプロトコルと使用するWiringPiのAPIについてご紹介します。
MCP3002の仕様書を確認してラズパイの設定を決めます。
ラズパイSPI通信プロトコルを確認します。
ラズパイのSPI通信は8bit単位で行われます。ここを理解していないと正しいデータを送れなくて結果として正しく通信できません。
実際にSPI通信をするときの波形を取得してみました。
黄色がSCLKでクロックです。8bit単位になっているのがわかると思います。
この8bit単位というのは意外と重要なんです。というのもシーケンシャルにデータをやりとりする方法と8bitセグメント単位で送る方法ではSPI通信を行うときのデータ送受信のプロトコルが違うからです。
実は最初の実装でなんでかうまく通信できなくて波形を取得してみたらそうだった。。。ということがありました。みなさんは気をつけてくださいね。
スペックシートからプロトコルを確認します。
MCP3004のスペックシートをみてみましょう。
こちらが連続したクロックで通信する場合です。
microchipのサイトから引用
一方、8bitセグメントの方法だとまったく送るデータは同じでもクロックのタイミングが違うことがわかりますね。
microchipのサイトから引用
連続したクロックでは送受信のために16bitのバッファーがあればいいのですが、8bitセグメント単位の場合には24bitのバッファーが必要になります。
さっき見たようにラズパイは8bitセグメントなので24bitのバッファーを使うようにします。
仕様が分かったので次はプログラムを実装します(◍•ᴗ•◍)♡ ✧*。
親クラスをWiringPiで作ります。
ADコンバーターは色々なセンサーにつなげて使うので汎用的なクラスを作ってそこから継承させたほうが良さそうです。
ということでWiringPiを使って親クラスを作ります。
WiringPiで使用するSPIのAPIって?
WiringPiのサイトにSPIのライブラリの使い方が紹介されています。簡単に解説します。
APIを使うためにheaderの取り込み
WiringPiのAPIを使うには専用のライブラリを取り込む必要があります。まずこちらをincludeしましょう。
1 |
#include <wiringPiSPI.h> |
ラズパイの初期設定。wiringPiSPISetupで通信の設定
実際にSPIでデータのやり取りをする前にラズパイのSPIの設定をする必要があります。こちらのAPIを使用します。
1 |
int wiringPiSPISetup(int channel, int speed); |
ラズパイにはSPIのチャネルが2つあるのでchannelでどちらを使うのかを設定します。
通信速度はspeedで設定でき、500,000から32,000,000Hzの間で値を選ぶことができます。
ちなみに返り値はLinuxのFD(File Descriptor)です。-1の場合にはエラーとなります。
wiringPiSPIDataRWでSPIデータの送受信
次にwiringPiSPIDataRWを使って実際にデータを送受信します。
1 |
int wiringPiSPIDataRW(int channel, unsigned char *data, int len) ; |
設定したchannelに対し、*data bufferを介して書き込み読み込みを行います。
送りたいデータをdata bufferに設定しこのコマンドを実行すると、データがdata bufferに上書きされて返ってきます。さきほどのMCP3004の仕様書でみたように後半の10bitにMCP3004からのデータが格納されるイメージです。
コンパイルの時はライブラリの指定を忘れずに
コンパイルの時には”-lwiringPi”と指定するのを忘れないようにしましょう。
実際にWiringPiを使ったサンプルプログラム
サンプルの親クラスはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#ifndef _MCP3004_H_ #define _MCP3004_H_ /* Sample program of MCP3004 from jitaku-yasai.com MCP3004 specification : http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf */ typedef unsigned int uint; typedef unsigned char uchar; // 0123456 #define MCP3004_START_BIT 0b00000001 #define MCP3004_SGL_BIT 0b10000000 #define MCP3004_DONTCARE 0b01000000 //Don't care for MCP3004 #define MCP3004_CH0_BIT 0b00000000 #define MCP3004_CH1_BIT 0b00010000 #define MCP3004_CH2_BIT 0b00100000 #define MCP3004_CH3_BIT 0b00110000 #define SPI_SPEED 500000 // SPI clock range : 500,000 through 32,000,000 #define MCP3004_CHANNEL0 0 #define MCP3004_CHANNEL1 1 #define MCP3004_CHANNEL2 2 #define MCP3004_CHANNEL3 3 #define MCP3004_CH_NUM 4 #define RP_SPI_CHANNEL0 0 // Raspberry Pi has two SPI channel. #define DATALEN 3 #define MCP3004_RESOLUTION 1024 class MCP3004 { public: MCP3004( // Constructor with default value uint theChannelOfRP = RP_SPI_CHANNEL0, uint theSpiSpeed = SPI_SPEED); virtual ~MCP3004(); // Destructor int SPISetUp(); // SPI setup int WriteRead(uint adcCH); // Send setting and recieve return value. private: unsigned int spiSpeed; // SPI communication speed unsigned char data[DATALEN]; // buffer to send/recieve for SPI communication unsigned int channelOfRP; // channel for RP communication }; #endif |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
/* Sample program of MCP3004 from jitaku-yasai.com MCP3004 specification : */ #include <stdio.h> #include <unistd.h> #include <wiringPi.h> #include <wiringPiSPI.h> #include "mcp3004.hpp" MCP3004::MCP3004(uint theChannelOfRP, uint theSpiSpeed) { // Parameters channelOfRP = theChannelOfRP; spiSpeed = theSpiSpeed; } int MCP3004::SPISetUp() { return wiringPiSPISetup(channelOfRP, spiSpeed); } int MCP3004::WriteRead(uint adcCH) { // initialize buffer memset(data, 0, DATALEN); // set buffer for inquiry data[0] = MCP3004_START_BIT; data[1] = MCP3004_SGL_BIT | MCP3004_DONTCARE; // Channel setting if (MCP3004_CHANNEL0 == adcCH) data[1] |= MCP3004_CH0_BIT; if (MCP3004_CHANNEL1 == adcCH) data[1] |= MCP3004_CH1_BIT; if (MCP3004_CHANNEL2 == adcCH) data[1] |= MCP3004_CH2_BIT; if (MCP3004_CHANNEL3 == adcCH) data[1] |= MCP3004_CH3_BIT; wiringPiSPIDataRW(channelOfRP, data, DATALEN); // Write and receive from same buffer return (int)((data[1] << 8 | data[2]) & 0x3FF); } MCP3004::~MCP3004() { } |
プログラム自体はすごいシンプルです。このクラスを継承して実際にEC計測と温度補正用のクラスを作ることになります。
まとめ
ADコンバーターMCP3004の基本クラスをWiringPiを使用して作製しました。
次回は実際にEC計測と温度測定のデモをお見せしたいとおもいます٩( ‘ω’ )و
記事を読んでいただいてありがとうございます。この記事がいいなと思ったら下記のSNSボタンのクリックをお願いします。励みになります😁