ESP32とPICをI2Cで繋いでみる(その3)PICからのデータ受信
ESP32をマスター、PICをスレーブ の状態でとして今度はPICからESP32にデータを送信してみます。💪
PICからESP32にデータを送信と言っても、I2Cの場合はPICの送信タイミングはESP32がリクエストすることになります。つまりESP32が『俺にデータを送ってこい』ってPICに命令して、PICは『かしこまりました』っていう感じでデータを送ります。
1、回路図
回路は受信の時と同じです!
2、PIC側のプログラム
前回の受信プログラムを送信に変えました。今回はタイマー割り込みの処理も組み込んでいます。PICの割り込みは1個しかないので割り込み処理で割り込み要因を調べて、その要因に合わせて処理を行います。
イメージとしてはマスターからの送信命令が来てから、送信データをセットするのではなく、タイマー割り込みで、予め送信データを格納しておきマスターから送信命令が来たらセットされているデータを送信するようにします。
プログラムはタイマー割り込み毎にデータをセットしていますが、送信データはセンサー値なら移動積分などしてした値をセットしておくと良いでしょう。移動積分などのフィルタリング処理を考慮してタイマー割り込みも組み込んでいます。
基本的に、マスターの送信命令のタイミングとPICの送信データ用意は非同期で動いてますが、プロトコルの設計で電源投入時コマンドなどを用意しておき同期させることもできます。その場合は、受信プログラムなども必要になるかもしれませんね。(送信命令だけでもできるけど)
#include <xc.h>
#define T0COUT 255-125 // 1ms timer interruput valu 32/4/64*125=1ms
//タイマー関連
volatile int TIMER_FLAG=0;
//I2C関連
#define rcvBuffSize 16
volatile short rcvCnt=0;
volatile short readCnt=0;
volatile char rcvData[rcvBuffSize];
#define senBuffSize 16
volatile short senCnt=0;
volatile char senData[senBuffSize];
//割り込み処理
void interrupt InterHandol( void )
{
//タイマー割り込みに関する処理
if(TMR0IF ==1 ){
TMR0 = T0COUT ;
TMR0IF = 0 ;
TIMER_FLAG =1;
}
//I2Cに関する処理
if (SSP1IF == 1) { // I2C割込み発生
if (SSP1STAT & 0b00000100) { //SSP1STAT R/W(送信?)
if (SSP1STAT & 0b00000001) { //SSP1BUFにデータがある?
// アドレス受信後の割り込み
char dummy = SSP1BUF ; // アドレスデータを空読み
while((SSP1CON1 & 0b00010000)|(SSP1STAT & 0b00000001));
senCnt = 0;//送信バッファのポインターリセット
SSP1BUF = senData[senCnt];// 送信データのセット(1回目のデータ)
SSP1IF = 0 ; // 割込みフラグクリア
SSP1CON1 = SSP1CON1 | 0b00010000; // SCLラインを開放
} else {
// データの送信後のACK受け取りによる割り込みと判断する
if (!(SSP1CON2 & 0b01000000)) { //NACKが返信された?
// マスターがACK応答
while((SSP1CON1 & 0b00010000)|(SSP1STAT & 0b00000001));
senCnt++;
SSP1BUF = senData[senCnt]; // 送信データのセット
SSP1IF = 0 ; // 割込みフラグクリア
SSP1CON1 = SSP1CON1 | 0b00010000; // SCLラインを開放
} else {
// マスターからはNOACKで応答された時(送信終了)
SSP1IF = 0 ; // 割込みフラグクリア
SSP1CON1 = SSP1CON1 | 0b00010000; // SCLラインを開放
}
}
}
}
}
void main(void) {
OSCCON = 0b01110000; //clock set16MHz PLLEN=ON 32MHz
TRISA = 0B00001110; //port set
//timer
OPTION_REG = 0b00000101 ; // timer0 1:64
TMR0 = T0COUT; // timer0 count
//I2C
SSP1STAT= 0b10000000 ; // 標準速度モードに設定する(100kHz)
SSP1CON1= 0b00100110 ; // SDA/SCLピンはI2Cで使用し、スレーブモードとする
SSP1CON2bits.SEN = 1 ; // SCL制御(クロックストレッチ)を行う
SSP1ADD = 8 << 1 ; // マイアドレス(8)の設定
SSP1MSK = 0b11111110 ; // アドレス比較用マスクデータ
SSP1IF = 0 ; // SSP(I2C)割り込みフラグをクリアする
SSP1IE = 1 ; // SSP(I2C)割り込みを許可する
TMR0IF = 0; // timer0 interruot clear
TMR0IE = 1; // timer0 interrupt ok
PEIE = 1 ; // 周辺装置割り込みを許可する
GIE = 1 ; // 全割り込み処理を許可する
PORTA = 0b00000000;
while(1){
if(TIMER_FLAG){
TIMER_FLAG =0;
GIE = 0 ; // 全割り込み禁止
senData[0] = 0xaa;
senData[1] = 0x55;
GIE = 1 ; // 全割り込み処理許可
PORTA = 0b00100000;
}
}
}
3、ESP32側のプログラム
こちらはめっちゃ簡単です。(手を抜いてますが😙)
I2Cの受信はよく知ってると思うので解説する必要もないでしょうね。😉
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin(21,22);//define(SDA,SCL)
}
void loop() {
Wire.requestFrom(0x08,2);
char c = Wire.read(); // 1バイトを受信
char d = Wire.read();
Serial.printf("%x-%x\n",c,d);
delay(3000);
}
動作テストをしてみると、PICをなしで、このプログラムを走らせると、PICからのデータ送信がない時は、受信データが0xFF(-1)になりますね。
電源投入時に接続テストなどのプログラムを入れるなら、この0xFF(-1)が使えそうです。もし0xFFを未接続のキーワードにするならPIC側は0xFFは送信しないとか何かしらの細工が必要になりますけどね。💯
通信テストのデータは0xaa、0x55でやりました。これはデータ受信のときに解説した通りです。
4、まとめ
ESP32とPICをI2C接続することによってI2Cコントロールのデバイスを安価に作れるようになりますね。温度センサーなどもアナログ式のものをPICに接続してフィルタリングなどの処理はPICでやりI2CでESP32が読み込むなんてこともできます。😃
では🤚
この記事が気に入ったらサポートをしてみませんか?