にほんブログ村 その他趣味ブログ 電子工作へ

2011年02月06日

Arduino で SPI

モッパーです。

しばらくアップし忘れていた記事です。

Arduino で SPI(Serial Peripheral Interface) 通信をするライブラリやスケッチでスレーブ(slave)側をサポートしているものが少ないので、例を公開しておきます。あちこちから拾ったコードの寄せ合わせです。


以下、SPI.cpp

#include "WProgram.h"
#include "SPI.h"

#define SPI_DONTCARE (0x00)
unsigned char theByte = SPI_DONTCARE;

// init as SPI-Master
void SPI_MASTER_Init(void) {
pinMode(SPI_SCK,OUTPUT);
pinMode(SPI_MOSI,OUTPUT);
pinMode(SPI_MISO,INPUT);
pinMode(SPI_SS1,OUTPUT);
pinMode(SPI_SS2,OUTPUT);

// INIT interface, Master, set clock rate
// SPI2X SPR1 SPR0
//   0    0    0    f/4 = 4Mhz
//   0    0    1    f/16 = 1Mhz
//   0    1    0    f/64 = 250Khz
//   0    1    1    f/128 = 125Khz
//   1    0    0    f/2 = 8Mhz
//   1    0    1    f/8 = 2Mhz
//   1    1    0    f/32 = 500Khz
//   1    1    1    f/64 = 250Khz

SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(1<<SPR0);
// enable double rate
SPSR = (0<<SPI2X); 
}

void SPI_SLAVE_Init(void) {
pinMode(SPI_SCK,INPUT);
pinMode(SPI_MOSI,INPUT);
pinMode(SPI_MISO,OUTPUT);
pinMode(SPI_SS,INPUT);

// INIT interface, Slave, set clock rate
// SPI2X SPR1 SPR0
//   0    0    0    f/4 = 4Mhz
//   0    0    1    f/16 = 1Mhz
//   0    1    0    f/64 = 250Khz
//   0    1    1    f/128 = 125Khz
//   1    0    0    f/2 = 8Mhz
//   1    0    1    f/8 = 2Mhz
//   1    1    0    f/32 = 500Khz
//   1    1    1    f/64 = 250Khz

SPCR = (1<<SPE)|(0<<SPR1)|(1<<SPR0);
// enable double rate
SPSR = (0<<SPI2X); // we will now gain fck/2 instead of fck/4
}

unsigned char SPI_ReadWrite(unsigned char data) {
// set data to send into SPI data register
SPDR = data;
// Wait for transmission complete
while(!(SPSR & (1<<SPIF)));
// return data read from SPI (if any)
return SPDR;
}


以下、SPI.h

#define SPI_SCK 13
#define SPI_MISO 12
#define SPI_MOSI 11
#define SPI_SS  10
#define SPI_SS1 10
#define SPI_SS2 9

void SPI_MASTER_Init(void);
void SPI_SLAVE_Init(void);
unsigned char SPI_ReadWrite(unsigned char data);

 
posted by モッパー at 18:17| Comment(14) | TrackBack(0) | Arduino
この記事へのコメント
初めまして。

 Arduinoを使って、データの入力をしようと思っているものです。

 SPIのスレーブで入力することになるので、SPIスレーブでのデータ入力をいろいろ検索していて、この記事が見つかりました。

 データを入力したいものとは、
http://www.zyaura.com/support/demo/ZG106_FW_001.ExtSpec.pdf
この二酸化炭素濃度計ZG106なのですが、ここから出力されているデータは、2kHzのクロックとデータのようで、これをArduino側で取得できればと思っています。

 どうもSPIに近いデータのようですが、クロックの立ち下がりでデータを取得するようで、SPIスレーブとしても特殊なようです。

 SPIマスターでのデータの取得はいろいろありましたが、ArduinoをSPIスレーブにして、データを取得するのはどうしたらいいのか、良く分かりませんでした。

 このスケッチを一部変更すれば、Arduino側でこのデータを確認することができるでしょうか?

 マイコンの扱い自体初めてなので、なにか参考になる情報がありましたら、教えていただけると助かります。

 また、二酸化炭素濃度計ZG106からのデータは、ロジアナで確認できて、データ自体は出力されていることが分かりました。

 ただ、必要のないデータも出力されているので、できれば、データの最初の2バイトでデータを選別して、CO2のデータ(0X50から始まるデータ)のみを取得して、そのCO2のデータのみを、Arduinoからシリアルでパソコン側に出力できればと思っています。

 このようなスケッチも簡単にできるのでしょうか?

 なにか参考になる情報などもありましたら、教えていただけると幸いです。

 よろしくお願いします。
Posted by yingshu at 2011年02月07日 12:23
yingshu 様

実は私も SPI 通信は初めてなので、正確な回答は出来ないであろうことをお許し下さい。

まず、ZG106 は VCC が 6V なことが気になります。各通信ラインも 6V 出力なら Arduino のポートの入力耐電圧超えてしまいそうです。
あと、2KHz というクロックは SPI としては非常に低いので大丈夫か気になります。スレーブ側はクロックのスピードは気にしてないはずですが...
上記が解決出来れば、yingshu 様の用途は Arduino で十分出来そうに思います。私のサンプルも、CPHAとCPOLを1(=mode3)にすれば流用出来ると思います。

SPI は mode 0〜3 と呼ばれるクロックのトリガに関する種別があり、Arduino もクロックの立ち下りでのサンプリングも可能なはずです。ZG106 は mode 3 だと思われます。
http://www.cqpub.co.jp/hanbai/books/37/37301/37301_4-4.pdf

また、SPI はかなり通信規定がかなり緩いので、汎用的なライブラリが作りにくいということが背景にあるようで、色々なサンプルやライブラリのソースコードを参考にして、目的にあったものを自分で作り上げるしかないようです。特に yingshu 様の状況だと、Arduino と SPI で検索かけるより、AVR と SPI で検索かけて、AVR の持つ SPI レジスタの仕様を理解したほうが良いと思いますよ。私も同じでした。

つたない情報で申し訳ありませんが、ご健闘をお祈り申し上げます。
Posted by モッパー at 2011年02月07日 21:16
モッパー 様

 回答ありがとうございました。

 VCCについては、5.25V程度でしたので、この程度なら大丈夫でしょうか?
 SPIスレーブの情報がほとんど無かったので、このサンプルを参考にテストしてみることにします。
 ありがとうございました。
 
 
Posted by yingshu at 2011年02月07日 21:39
yingshu 様

AVR の仕様を見る限り VCC+0.5V のようなので 5.25V ならいけると思います。うちの子供の経験によると Arduino のポートに 7V くらいまで放り込んでも壊れなかったそうです。ただし、保護回路が動作して正常動作しなかったようですが。
Posted by モッパー at 2011年02月07日 23:39
モッパー 様

 回答ありがとうございました。

 信号自体は接続して入力してみましたが、壊れるようではありませんでした。

 ただ、現状では、SPI.cppと、SPI.hをどうやって使うのかも分かっていませんので、信号線を繋いだだけしかできませんでした。

 何か、このようなデータ入力に使えそうなサンプルスケッチなどはありませんか?

 全くマイコンでの処理は初めてなので、何から初めて良いのか分かっていません。

 とりあえず、温湿度センサのSHT11や、
MPL115A2 気圧センサモジュールは入手しているので、こちらのサンプルスケッチなどを探してArduinoでのデータ入力ができるのかテストしてみようと思っていますが、これらのプログラムなどを変更すれば、今回のZG106からのデータも取得できるのでしょうか?
Posted by yingshu at 2011年02月08日 09:32
yingshu 様

SHT11もMPL115A2もSPIではなくI2Cですし、スケッチ例がネットに有るようなので、それほど苦労しないと思います。ただし、それらのスケッチ例はZG106には流用出来ません。

SHT11とMPL115A2はI2C通信の仕様やArduinoのWireライブラリの中身を理解しなくても使えるでしょうが、ZG106はそれとはレベルが全く違いSPIの仕様とAVRのレジスタの仕様を理解しないと多分無理です。
マイコン初めての方にとってはかなり敷居が高いと思いますので、まずはSHT11とMPL115A2を経験してからZG106にトライされることをお勧めします。

あと、Arduino対ArduinoでSPI通信をテスト出来るスケッチを本文の最後に上げておきました(SPItestSlave.zip)。かつて動いたはずのものですが、今テスト環境がないので本当に動くかどうか分かりません。ネットに上げておいてハマる方がいると申し訳ないので、ダウンロードしたらお知らせ下さい。削除します。
Posted by モッパー at 2011年02月08日 20:57
モッパー 様

 回答ありがとうございました。

Arduino対Arduinoのサンプルはダウンロードできました。

 参考にさせていただきます。

 とりあえず、SHT11については、完全なI2Cではないですが、SHT1xのライブラリもあり、サンプルスケッチで温度、湿度が表示できることは確認できました。
 今後は、いろいろな計算をしてみようと思っています。

 ありがとうございました。
Posted by yingshu at 2011年02月08日 23:02
yingshu 様

本文のスケッチ削除しました。また何か悩むことありましたら、ご遠慮なくご相談下さいね。
Posted by モッパー at 2011年02月08日 23:33
モッパー 様

いろいろありがとうございました。

 SHT11とMPL115A2はデータを取得できました。
さらに、I2C接続のRTCのデータも取得できるようになりました。

 今後、CO2メータからのデータの処理をしてみたいですが、1つ質問があります。

 このライブラリをライブラリにコピーすると、標準でインストールされているSPIのライブラリを同じ名前になってしまいますが、これは変更した方がいいのでしょうか?

 別のフォルダにしても、SPI.hになっているので、どうやって区別しているのか分かりませんでした。
 
Posted by yingshu at 2011年02月10日 00:26
yingshu 様

SHT11とMPL115A2 うまく行ってよかったですね!

このプログラムはライブラリを置き換えるつもりで作ったものではなく、SPI.cppとSPI.h はお渡しした SPISPItestMaster と SPISPItestSlave のスケッチの一部です。#include "SPI.h" (≠#include <SPI.h>) となっているとライブラリ中の SPI.h より スケッチのフォルダにある SPI.h のほうを優先します。

確かに間違いを起こしそうであまりほめられたやり方ではないので、名前を変えられたほうが良いかもしれません。
Posted by モッパー at 2011年02月10日 20:09
モッパー 様

 最初、名前を変えずにやってみたら、上手くいきませんでしたので、ライブラリの名前を全て変更したら、何らかのデータが出てきました。

 もう少しで上手くいきそうです。

 質問ばかりで申し訳ありませんが、

>私のサンプルも、CPHAとCPOLを1(=mode3)にすれば流用出来ると思います。

このCPHAとCPOLを1に設定するには、ライブラリのどこを設定すればいいのでしょうか?

 また、今回のデータが8bit毎に意味のあるデータで、合計で40bitのデータでひとかたまりのデータになっています(0Dのデータで終わり)。
 この40bit毎のデータで改行されるようなデータにするにはどのようなスケッチとすればいいでしょうか?

 また、2kHzのクロックに関する設定は何もしないでも、クロックの立ち下がりでデータを取得するので問題ないのでしょうか?

 現在は、
Serial.println(in,HEX);
で出力すると、以下のようなデータは出ていますが、これが正確なデータかどうかは確認できません。

F0
D4
30
9A
4F
3
D0
84
81
6A
2A
78
F1
7E
1A
A0
92
92
9A
80
54
9E
D
42
28
56
43
5B
42
58
9C
16
E5
FF
D5
85
50
2F
46
2A
B9
1
C8
D5
64
D1
E3
1A
84
4D
2F
11
A8
41
9
65

 何らかのデータが確認できましたので、もう一息で必要なデータが取得できそうです。

 よろしくお願いします。
Posted by yingshu at 2011年02月10日 21:49
yingshu様

えっと、かなり複雑な話になりそうなので、後は以下の E-Mail アドレスにて直接メールしたほうが速いと思います。
※メール頂けたので、あとはメールベースにて対応させて頂きます。
Posted by モッパー at 2011年02月10日 23:30
モッパー様

Arduinoを使ってサッカーロボットを作ろうと思っているのですが初心者で全然わかりません。なにか良いプログラムがあれば教えてください。ちなみに部品はArduinoを始めようセットに入っているものとモーター4つと車輪4つとパルスセンサー2つとラインセンサー4つと方位センサー1つです。よろしくお願いします。
Posted by 風神 at 2016年11月15日 17:50
風神さん
残念ながらそんな都合の良いプログラムは持ち合わせていません。
Arduino IDE には豊富なサンプルプログラムが含まれていることはご存知ですか? まずは LED チカチカやりましたか?
いきなりロボット本体を組み立てて動かすプログラム作ることなんて誰も出来ません。個々のセンサーやモーターを制御するプログラムを一つ一つ作ってテストしていかないと出来ないです。幸い Arduino はセンサーの型番等でググるとサンプルプログラムが見つかる可能性がかなり高いです。
Good Luck ! 頑張って下さい !!!
Posted by モッパー at 2016年11月15日 20:21
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
※ブログオーナーが承認したコメントのみ表示されます。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/43270081
※ブログオーナーが承認したトラックバックのみ表示されます。
※言及リンクのないトラックバックは受信されません。

この記事へのトラックバック
にほんブログ村 その他趣味ブログ 電子工作へ