GR-SAKURAです。
スレーブの受信で、受信ハンドラーのEventReceive関数を呼ばれるのですが、loop関数に戻ってこない。
マスターから1文字送ると受信文字数available()で0を読みます。この時loop関数から割り込みでWireの割り込みになっていると思います。
もう一度1文字送るとavailable()は1をだして、送った文字がreadで読めます。
この事からEventReceive関数は受信のたびに呼ばれていることはわかります。
しかしloop関数に戻ってこない。
間違いが分かる方いたら教えてください。
以下ソースです。
/* GR-SAKURA Sketch Template V2.24 */#include <Arduino.h>#include <wire.h>void requestEvent( void ){ Wire8.write( "Hello ") ; Serial.println("I2c Request");}char I2cRcvData[32] ;char iat; // I2C 1 Byte Readint bufc ;void EventReceive( int numbyte ){ digitalWrite(PIN_LED0,1); // LED1 ON bufc = 0 ; while( Wire8.available() ) { digitalWrite(PIN_LED1,1); // LED OFF! bufc++ ; iat = Wire8.read() ; // 1バイトの読込み bufc++ ; I2cRcvData[bufc] = iat ; if( iat == 0x0a ) { I2cRcvData[0] = bufc ; // 受信受信文字数 I2cRcvData[bufc+1] = '\0' ; } Serial.print( iat ); // 受信文字 }}void setup(){ Serial.begin(57600); pinMode(PIN_LED0,OUTPUT); pinMode(PIN_LED1,OUTPUT); pinMode(PIN_LED2,OUTPUT); pinMode(PIN_LED3,OUTPUT);}void loop(){ Serial.println("I2c INIT"); Wire8.begin(0x40) ; Wire8.onRequest(requestEvent); // 送信要求がMasterから来たら呼ばれる Wire8.onReceive(EventReceive); // Masuterからデータ受信したら呼ばれる while( 1 ) { digitalWrite(PIN_LED2,1); // LED2 ON Ether ON delay(500) ; digitalWrite(PIN_LED2,0); // LED2 ON Ether OFF! delay(500) ; }}
Arduino Wireライブラリを使ったことはないですが、Arduinoのloopは基本的にちゃんと定期的に戻りが必要だったはずです(がじぇっとルネサスもかは確証なし)。まずはwhile(1)というのはやめましょう。loopの呼び出し元がloopの前後で色々やってるはず。
Wireの使い方は以下をご参考に
https://deepbluembedded.com/arduino-i2c-slave/なぜloop()で止まってダメなのかは実際のloop呼び出しコードをみてみればわかりますが、古いコードの時の場合、loop呼び出し戻ってきた時にシリアルバッファ処理が実行されてます。while(1)でブロックしてしまうと非同期な処理が止まってしまいます。https://forum.arduino.cc/t/void-loop/297970/8
回答ありがとうございます。
loop()に戻すようにしてみましたが結果は同じでした。マスターから1Byte 送るとスレーブのLEDの点滅が止まってしまう同じ結果でした。void setup(){ Serial.begin(57600); pinMode(PIN_LED0,OUTPUT); pinMode(PIN_LED1,OUTPUT); pinMode(PIN_LED2,OUTPUT); pinMode(PIN_LED3,OUTPUT); Wire8.begin(0x40) ; Wire8.onRequest(requestEvent); // 送信要求がMasterから来たら呼ばれる Wire8.onReceive(EventReceive); // Masuterからデータ受信したら呼ばれる}void loop(){ digitalWrite(PIN_LED2,1); // LED2 ON Ether ON 接続! delay(500) ; digitalWrite(PIN_LED2,0); // LED2 ON Ether ON 接続! delay(500) ; }
EventReceiveはwhileから抜けてますか?
Wire8.read()はデータがない場合、ブロックする仕様だったはず
void EventReceive( int numbyte ){ digitalWrite(PIN_LED0,1); // LED1 ON bufc = 0 ; while( numbyte ) { digitalWrite(PIN_LED1,1); // LED OFF! bufc++ ; iat = Wire8.read() ; // 1バイトの読込み bufc++ ; I2cRcvData[bufc] = iat ; if( iat == 0x0a ) { I2cRcvData[0] = bufc ; // 受信受信文字数 I2cRcvData[bufc+1] = '\0' ; } Serial.print( iat ); // 受信文字
numbyte --; }}
こうだとどうですか?これで解決ならWire8.available() の実装がおかしい可能性もありますね。
read()ですが確認したらStreamの派生だったので戻り値はintでデータない時は-1を返す仕様でした。ブロックはないです。Wire8.read()の戻り値でwhile終了判定をしてもいいかもしれませんね。github.com/.../Wire.h
numbyteをfor文にして実行しましたが、結果は同じでした。
もっと簡単に以下にして1文字を送信したところ、1回目にはLED0が点灯しない。
EventReceiveが呼ばれていない状態で、loop()の点滅も止まっている状態です。
2文字目を送ると、EventReceiveが呼ばれて、LED1,LED2が点灯します。
loop()の点滅も止まっている状態です。
このことから、1文字目送信のどこかのハードステータスを読んでいる所でループしている?
void EventReceive( int numbyte ){ digitalWrite(PIN_LED0,1); // LED ON iat = Wire8.read() ; // 1バイトの読込み digitalWrite(PIN_LED1,1); // LED ON }
これは実際の信号波形やマスタ側のI2Cコードの確認も必要な気がします。マスタ側もGR-SAKURAでWireライブラリを使っていますか?ぶっちゃけ、マイコン間通信はUARTでいいような気がします。そういう意味でWireのスレーブモードは使ったことがありません。