Arduino UNOでソフトウェアI2Cスレーブで遊ぶ　その1



x まだ試していない 確認済み2022/5/8 12:21

目的
I2Cスレーブの規格を都合よく解釈して
I2Cスレーブを作ってみた。

フルの移行図なんか完全に無視

78K0S/Kx1+系の資料は、なに書いてあるんだか全くわからない。
様々なI2Cスレーブでノイズ下でいろいろ対策が必要な事もわかる
8ビット系で数MzのクロックのCPUだとI2Cは、かなり重い処理
I2Cの速度が1Mhzだと1uSで処理を完了しなくては、いけなく、タイトである。
何を言っているかわからない!!(ツンデレ系)遅いのは、わかる。
クロック8MHzで約400khzだとギリギリなのがわかる
もっと速くしなさいよ!!(ツンデレ系)葛藤していたのがわかる(笑い)
そう言う分けで8ビット系では、割り込みではなく、
I/Oポーリングで1ビット目を見た後、決め打ちで8ビットキャプチャ
しないと処理が追い付かないかも途中でゼロフラグを適当に退避させて
エラー処理で後ではじく(そんなことしないけど@)
●(普通)立ち上がりの割り込みでビットを読む(簡単らいし)
●(高速)IOポーリングでビットを読む
●(超高速)1ビット目のローの時間で約24～25ビット数を測って1から約25の
約25通りの全部読みのタイミングで処理する関数をあらかじめ用意して
全部読みする。(タイミングを決めるには、スーパーテクニシャンが必要です。)
8ビット系だとデレのない「ツン」がおお暴れしていたのが推理できて(笑い、笑い)
基本的にない、または、種類すくないのは、そういう事(わかるよね!!)
積極的には、書かなかったけどこのプログラムは、送りは、10khzで送っています。



![o_con368.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/3ca56e61-9c66-0d05-9128-b1dd4c3c6668.jpeg)



![o_con403.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/47d08998-4146-4b5a-9813-9a6127624143.jpeg)



![o_con404.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/af07c22a-9ca4-f01b-aaa2-f5e7fd82156e.jpeg)





テストて使ったI2Cマスター (修正前　0x80「0」)


https://qiita.com/caa45040/items/6cfdcb4c7319a0456ee4



資料



https://ja.na4.teamsupport.com/knowledgeBase/17796047



https://ja.na4.teamsupport.com/knowledgeBase/17793952



いろいろ
全く約に立たない情報　2022/5/8 18:15ラーメン食いにいくか
8ビット系は、たぶん処理がきついと思って最後にしたのは、正解だった。
めし食ったあと、開発方針が決まった。
「パンがなければケーキを食べればいいのよ」方式に決定
F767(216000000(216Mhz))を持ち出して100khzいくぞー
しさしぶりの真打キターーーーーー

修正済み


```c++





//soft_i2c_slave_test_UNO_1

#include <Arduino.h>

//ピン 13 LED1
//ピン Vdd
//ピン Gnd
//ピン 

//ピン 
//ピン 
//ピン A4 SDA
//ピン A5 SCL

//GPIOの初期化 //LED1
#define myled 13


#define DW   digitalWrite



#define  SDA1 A4
#define  SCL1 A5

int TinmOut1 = 100000;

//SDAがHの間は、ループ
#define SDA_START() while(digitalRead(SDA1) == 1){}

//SDAがHの間は、ループ TinmOut1付き
#define SDA_H() while(digitalRead(SDA1) == 1 && TinmOut1 != 0){TinmOut1--;}

//SDAがLの間は、ループ TinmOut1付き
#define SDA_L() while(digitalRead(SDA1) == 0 && TinmOut1 != 0){TinmOut1--;}

//SCLがHの間は、ループ TinmOut1付き
void SCL_H() {
  while (digitalRead(SCL1) == 1 && TinmOut1 != 0) {
    TinmOut1--;
  }
}

//SCLがLの間は、ループ TinmOut1付き
void SCL_L() {
  while (digitalRead(SCL1) == 0 && TinmOut1 != 0) {
    TinmOut1--;
  }
}

int input, input_bk = 1;

/*
  //立ち上がり
  void SCL_UP_H()
  {
    while(TinmOut1 != 0){

       //立ち上がり
       input = SCL1;
       if( input_bk != input ){
           if( input == 1 ) break;
       }//endif

      //バックアップの保存
      input_bk = input;

      TinmOut1--;
    }//while
  }//SCL_UP_H()
*/

//初期化関数
void setup()
{

  //シリアルの初期化
  Serial.begin(9600);

  //LED1ポートの初期化
  pinMode(myled, OUTPUT);

  //ソフトI2Cの初期化
  pinMode(SDA1, INPUT);
  pinMode(SCL1, INPUT);

}//setup

char buf[10]; //I2Cバッファー
int ii; //ループカウンター

//アドレス
int a0, a1, a2, a3, a4, a5, a6, a7;
int a[8];

//データ
int d0, d1, d2, d3, d4, d5, d6, d7;
int d[8];

//無限ループ
void loop()
{

  //スタート信号の立下りを待つ
  //タイムアウトの設定
  TinmOut1 = 100000;

  //開始
  SDA_START();

  //アドレスの取り込み
  SCL_H();
  SCL_L();
  a7 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a6 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a5 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a4 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a3 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a2 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a1 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a0 = digitalRead(SDA1);


  //a7 = 1;
  //a6 = 0;
  //a5 = 0;
  //a4 = 0;
  //a3 = 0;
  //a2 = 0;
  //a1 = 0;
  //a0 = 0;

  //アンクの処理
  SCL_H();
  SCL_L();
  //a0 = SDA1;

  //データの取り込み
  SCL_H();
  SCL_L();
  d7 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d6 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d5 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d4 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d3 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d2 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d1 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d0 = digitalRead(SDA1);

  //d7 = 0;
  //d6 = 0;
  //d5 = 1;
  //d4 = 1;
  //d3 = 0;
  //d2 = 0;
  //d1 = 0;
  //d0 = 0;


  digitalWrite(myled, HIGH); //LED ON  debug

  buf[0] = 'U';//バッファーのクリア
  buf[1] = 0;


  //I2Cスレーブの受信データの表示
  Serial.print(buf);
  Serial.print("\r\n");


  //I2Cスレーブの受信データの表示 debug
  //pc_printf("Read A: %x\r\n", buf[0]);

  digitalWrite(myled, HIGH); //LED OFF  debug


  a[7] = a0;
  a[6] = a1;
  a[5] = a2;
  a[4] = a3;
  a[3] = a4;
  a[2] = a5;
  a[1] = a6;
  a[0] = a7;

  d[7] = d0;
  d[6] = d1;
  d[5] = d2;
  d[4] = d3;
  d[3] = d4;
  d[2] = d5;
  d[1] = d6;
  d[0] = d7;

  //アドレスの表示
  for (ii = 0; ii < 8; ii++) {
    if (ii == 4) Serial.print(": ");

    if (a[ii] == 0) {
      Serial.print("__ ");
    } else {
      Serial.print("[] ");
    }//ebdif
    
  }//for
  Serial.print("\r\n");//リターン


  //データの表示
  for (ii = 0; ii < 8; ii++) {
    if (ii == 4) Serial.print(": ");

    if (d[ii] == 0) {
      Serial.print("__ ");
    } else {
      Serial.print("[] ");
    }//endif
    
  }//for
  Serial.print("\r\n");//リターン

  digitalWrite(myled, LOW); //LED OFF  debug

  delay(500);//0.5秒待つ
  
}//loop








```





たぶんバグだらけ


```c++




//soft_i2c_slave_test_UNO_1

#include <Arduino.h>

//ピン 13 LED1
//ピン Vdd
//ピン Gnd
//ピン 

//ピン 
//ピン 
//ピン A4 SDA
//ピン A5 SCL

//GPIOの初期化 //LED1
#define myled PB7


#define DW   digitalWrite



#define  SDA1 A4
#define  SCL1 A5

int TinmOut1 = 100000;

//SDAがHの間は、ループ
#define SDA_START() while(digitalRead(SDA1) == 1){}

//SDAがHの間は、ループ TinmOut1付き
#define SDA_H() while(digitalRead(SDA1) == 1 && TinmOut1 != 0){TinmOut1--;}

//SDAがLの間は、ループ TinmOut1付き
#define SDA_L() while(digitalRead(SDA1) == 0 && TinmOut1 != 0){TinmOut1--;}

//SCLがHの間は、ループ TinmOut1付き
void SCL_H() {
  while (digitalRead(SCL1) == 1 && TinmOut1 != 0) {
    TinmOut1--;
  }
}

//SCLがLの間は、ループ TinmOut1付き
void SCL_L() {
  while (digitalRead(SCL1) == 0 && TinmOut1 != 0) {
    TinmOut1--;
  }
}

int input, input_bk = 1;

/*
  //立ち上がり
  void SCL_UP_H()
  {
    while(TinmOut1 != 0){

       //立ち上がり
       input = SCL1;
       if( input_bk != input ){
           if( input == 1 ) break;
       }//endif

      //バックアップの保存
      input_bk = input;

      TinmOut1--;
    }//while
  }//SCL_UP_H()
*/

//初期化関数
void setup()
{

  //シリアルの初期化
  Serial.begin(9600);

  //TXポートの初期化
  pinMode(TX1, OUTPUT);
  DW(TX1, HIGH);

  //LED1ポートの初期化
  pinMode(myled, OUTPUT);

  //ソフトI2Cの初期化
  pinMode(SDA1, INPUT);
  pinMode(SCL1, INPUT);

}//setup

char buf[10]; //I2Cバッファー
int ii; //ループカウンター

//アドレス
int a0, a1, a2, a3, a4, a5, a6, a7;
int a[8];

//データ
int d0, d1, d2, d3, d4, d5, d6, d7;
int d[8];

//無限ループ
void loop()
{

  //スタート信号の立下りを待つ
  //タイムアウトの設定
  TinmOut1 = 100000;

  //開始
  SDA_START();

  //アドレスの取り込み
  SCL_H();
  SCL_L();
  a7 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a6 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a5 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a4 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a3 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a2 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a1 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  a0 = digitalRead(SDA1);


  //a7 = 1;
  //a6 = 0;
  //a5 = 0;
  //a4 = 0;
  //a3 = 0;
  //a2 = 0;
  //a1 = 0;
  //a0 = 0;

  //アンクの処理
  SCL_H();
  SCL_L();
  //a0 = SDA1;

  //データの取り込み
  SCL_H();
  SCL_L();
  d7 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d6 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d5 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d4 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d3 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d2 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d1 = digitalRead(SDA1);

  SCL_H();
  SCL_L();
  d0 = digitalRead(SDA1);

  //d7 = 0;
  //d6 = 0;
  //d5 = 1;
  //d4 = 1;
  //d3 = 0;
  //d2 = 0;
  //d1 = 0;
  //d0 = 0;


  digitalWrite(myled, HIGH); //LED ON  debug

  buf[0] = 'U';//バッファーのクリア
  buf[1] = 0;


  //I2Cスレーブの受信データの表示
  Serial.print(buf);
  Serial.print("\r\n");


  //I2Cスレーブの受信データの表示 debug
  //pc_printf("Read A: %x\r\n", buf[0]);

  digitalWrite(myled, HIGH); //LED OFF  debug


  a[7] = a0;
  a[6] = a1;
  a[5] = a2;
  a[4] = a3;
  a[3] = a4;
  a[2] = a5;
  a[1] = a6;
  a[0] = a7;

  d[7] = d0;
  d[6] = d1;
  d[5] = d2;
  d[4] = d3;
  d[3] = d4;
  d[2] = d5;
  d[1] = d6;
  d[0] = d7;

  //アドレスの表示
  for (ii = 0; ii < 8; ii++) {
    if (ii == 4) Serial.print(": ");

    if (a[ii] == 0) {
      Serial.print("__ ");
    } else {
      Serial.print("[] ");
    }//ebdif
    
  }//for
  Serial.print("\r\n");//リターン


  //データの表示
  for (ii = 0; ii < 8; ii++) {
    if (ii == 4) pc_printf(": ");

    if (d[ii] == 0) {
      Serial.print("__ ");
    } else {
      Serial.print("[] ");
    }//endif
    
  }//for
  Serial.print("\r\n");//リターン

  delay(500);//0.5秒待つ
  
}//loop






```