トラ技08年8月号の付録78K0 USBマイコン基板を使ったUSB I2C 変換の実験


下記のプログラムは、NECのWEBサイトに掲載されている 78K0S用ソ フトウェアI2Cバス・マスタ通信プログラム(78K0S/Kx1+共通、プログラム例はKY1+をターゲット)  を参考にして CQ出版社のトランジスタ技術(トラ技)2008年8月号の付録のUSBマイコン基板を使ってI2C接続のEEPROMの読み書きをする 実験用に作ったものである。I2Cの標準 モード (~100Kbit/s)の動作スペッ クを満たせない部分もあり 叉 動作も遅いですが、何かの参考になれば幸いです。


特徴:
・ソフトウエアによるバスマスター(機能は限定的)。専用のI2C処理のハードウエ アが内臓されていないため。
・汎用のIOポートを利用。オープン ドレインポートが余っていないため。 
・データの読み書き部分をC言語で記述。アセンブラが分からない人でも作れた。  
・スピードは100Kbit/sよりさらに遅い。簡易的な実験用途には十分かな。   



名前:sample2.c

動作環境:ROM

説明:

USBマイコン基板とEEPROMが一対一でI2C接続されたマスターモードのみを想定しており、衝突検出の処理など高度?なことは行っていない。汎用 ポー トのP0.0をクロックに、P0.1をデータとして使っている。クロックとデータは電源に抵抗でプルアップすること。クロックがローのままだと、プログラ ムが無限ループに入り込んでしまう可能性がある。プログラムの中の、#asm NOP .... NOP #endasm の行はセットアップ時間やホールド時間を稼ぐ目的で挿入しているつもりだが無駄もあるかもしれない。処理時間がまちまちなため、クロック周期は安定してお らず、遅かったり(EEPROMのデータを読むときとか)早かった(ACK部分とか)している。アセ ンブラでプログラムをかける能力があれば多少高速化できるだろう。クロックをローからハイに変化させる直前でEEPROMからのデータを読み込んでいる。 多分、クロックの立ち上がりエッジでデータを読みとるのが正しい方 法 と思われるが、ソフトウエアで実現する都合上、これを完全に実現することはできない。よって、EEPROMのデータの変化時とクロックの変化時が近接した 場 合、データを読み間違えるデットタイミングが存在する。




使い方:
sample2.c をビルドして作ったHEXファイルを、右図のトラ技BIOSの画面のようにして、USBマイコン基板のフラッシュ・メモリに書き込む。
最後まで書き終えたら、動作確認のため、トラ技BIOSでjmp 2000と入力してみて、 read ex: R .a1 S 00 00 J 4 (中略) + i2c port P0.1 sda initilize が表示されることを確かめる。
動作確認できれば、いったん USBマイコン基板をUSBから抜いて、USBマイコン基板のUSER_EN(J2)をショートする。これで、以後、USB に挿すと、sample2.cが起動するようになる。

ちなみに、USBマイコン基板はPCとUSBで接続するのであるが、PC側からは仮想COMポートと して見える。右図の画面はWINDOWSのハイパー ターミナルの画面である。自分の使って いるPCは古いのでCOM3として見えた。新しいPCの場合は、COM7とかCOM15など別の番号になった。





I2C接続のEEPROMをUSBマイコン基板に接続する。接続方法の違いによってEEPROMも何種類 かある。
USBマイコン基板をUSBに刺して、WINDOWSのハイパー ターミナなどのソフトを立ち上げてCOMポートと通信を確立してENTERキーを押すと、画面に 右図のように read ex: R   (中略)  pull up が表示されるはずである。

EEPROMにデータを書き込むには、たとえば、

w a0 s 00 j 1f 2f 3f 4f

と入力してENTERを押す。 a0 はEEPROMのI2Cのアドレスで、sの次の00は、サブアドレスである。 jの次は、書き込みたいデータで、サブアドレスの00番に1f、01番地に 2f、02番地に3f、03番地に4fが書かれる。1個だけ書き込みたいときは、 w a0 s 00 j 1f と入力すればよい。

EEPROMのデータを読み込むには、

r a1 s 00 j 4

と入力してENTERを押すと、a1 はEEPROMのI2Cのアドレスで、サブアドレス00番地から、jの次の値の4、つまり4個分のデータを読み出す。 たとえば、j  aと書くと、10個分になる。HEX(16進)値である。

容量が大きいEEPROMでサブアドレスが2バイトあるときは、

r a1 s 01 00 j 4

のようにすれば sの次の2バイトの 0100番地がサブアドレスになる。

読みrと書きw以外に、/ 以下はコメントとして無視する、v はUSBマイコン基板からの文字の戻りエコーをトグルでON・OFFする、?は、read ex: R   (中略)  pull up を表示するなどがある。但し、かな漢字などの2バイト文字を使うと誤動作してしまう可能性がある。通常、EEPROMに連続して書き込むときには、 EEPROMが次の書き込みを許可するまで待たなくてはならないが、幸い? にしてか、このUSBマイコン 基板の動 作は遅いので、NAK待ち検出などの特別なことはしなくてよいみたいである。

EEPROMの書き読みのテストの例




#pragma sfr
#include "trgbios.h"


typedef unsigned char   u8, uint8,  /* same as "byte"   */
            *u8Ptr, *uint8Ptr;  /* same as "bytePtr"    */
           
typedef boolean      bool8;

           
/*  エラー・フラグ操作関係処理関数  */
u8  i2c_error;               //エラー・フラグ
bool8  acke;                    //ACK制御フラグ

/*  ACK応答制御関係処理関数      */

void    ACK_EN(void) { acke=1;}
void    ACK_DS(void) { acke=0;}


/*  エラー・フラグ状態定義          */
enum{
    I2C_NO_ERROR        = 0x00, // エラー無し(0)
    I2C_BUS_NOT_FREE    = 0x01, // バスが開放されていなかった
    I2C_ADDR_NACK       = 0x02, // スレーブがアドレスに反応なし
    I2C_RADDR_NACK      = 0x03, // スレーブがREADアドレスに反応なし
    I2C_REG_ADDR_NACK   = 0x04, // 予期せぬ NACK が帰って来た(レジスタ)
    I2C_DATA_NACK       = 0x05  // 予期せぬ NACK が帰って来た(データ)
};

u8  set_i2c_error(u8 error){ i2c_error=error; return i2c_error;}
u8  get_i2c_error(void){ return  i2c_error; }
u8  clear_i2c_error(void){ i2c_error= I2C_NO_ERROR; return i2c_error; }


bool8      free_i2c_bus(void)
// 戻り値 正常 、0 異常 1
{
    PM0.0=1;   // scl 入力ポートでハイ
    PM0.1=1;   // sda 入力ポートでハイ
    // 使っていたら復活させないで とりあえず エラーで終わる
   if (( P0.0 == 1) && (P0.1 == 1)) return 0;
   else return 1;
}

/*  I2Cバス初期化関係処理関数    */

/* CPU最高動作速度の 1クッロクは 0.125uS  */
#define WAIT0   2

void    I2C_STR(void)
{
 
   
    PM0.1=1;   // sda 入力ポートでハイ
    // 途中にスタート発行のため SDAハイを少し長めにとっておく
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    PM0.0=1;   // scl 入力ポートでハイ
 
    // 10:SCLの立ち上がり検出 無限ループになる危険な行!
    wait_loop1:
    if( !P0.0 ) goto wait_loop1;      // 15
   
  
   PM0.1=0;   // sda 出力ポートでロー  スタート・コンディション発行
  
   // start condition hold time
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
  
}

void    I2C_STPR(void)
{
 
   
    PM0.1=0;   // sda 出力ポートでロー
    // stop condition setup time
    // delay 2x8x0.125=2uS
    #asm
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    #endasm
   

    PM0.0=1;   // scl 入力ポートでハイ
   
    // 10:SCLの立ち上がり検出  無限ループになる危険な行!
    wait_loop2:
    if( !P0.0 ) goto wait_loop2;
    // delay 2x8x0.125=2uS
    #asm
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    NOP
    #endasm
   
   
  
   PM0.1=1;   // sda 入力ポートでハイ  ストップ・コンディション発行
  
   // stop condition hold time
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
  

}

/*  I2Cバスバイト転送基本関数    */

bool8   put_i2c(u8 data)
// 戻り値 正常 0, 異常 1
{
    register unsigned char  i,a;
    u8 f0;
   
    a=data;
    f0=0;
   
  for(i=0;i<8;++i)
  {
    // SCLを立ち下げてデータ出力準備
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    if( (a & 0x80) != 0 )   // MSBビットの抽出
    // 1を出力
    {
       PM0.1=1;   // sda 入力ポートでハイ
    }else  // 0を出力
    {
        PM0.1=0;   // sda 出力ポートでロー
    }
    // 次のために1ビットシフトしておく
    a<<=1;
    // delay 2x4x0.125=1uS
    // メモリー呼び出しで 加算のASMになっているので、ディレー不要かも
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    PM0.0=1;   // scl 入力ポートでハイ
   
    // 10:SCLの立ち上がり検出  無限ループになる危険な行!
    wait_loop3:
    if( !P0.0 ) goto wait_loop3;
    // delay 2x4x0.125=1uS
    // for(i=0;i<9;..) メモリー呼び出しで、ディレー不要かも
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
  } // for(i=0;i<8;++i) 
 
  // ACK入力のためSCLをローレベルにして SDAを入力にする
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    PM0.1=1;  //  SDAを入力にする
    // 相手側が SDAをローにするための時間をNOPで待つ
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    PM0.0=1;   // scl 入力ポートでハイ
    // 10:SCLの立ち上がり検出  無限ループになる危険な行!
    wait_loop4:
    if( P0.1 ) f0=1;   // sda がハイのままなら、ACKが返ってこなかったのでエラーね。
    if( !P0.0 ) goto wait_loop4;
    // if( P0.1 ) f0=1;   // sda がハイのままなら、ACKが返ってこなかったのでエラーね。
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
   
    //最後に クロックをローにしておく
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
  
   if( f0 ) return 1;
   else return 0;

}

bool8   put_i2c2(u8 data)
// 戻り値 正常 、0 異常 1
{
    if( put_i2c( data ))
    {  // when error
       I2C_STPR();
       return 1;
    }else return 0;
}

u8  get_i2c(void)
{
    register unsigned char  i,a,f0;
  
   
    a=0x00;
 
   
  for(i=0;i<8;++i)
  {
    //  f0=0;    // sda の値を一時的に蓄えておくエリア
    // SCLを立ち下げてデータ出力準備
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    PM0.1=1;  //  SDAを入力にする
    // 相手側が SDAを制御するのを待つ
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
       
   
    PM0.0=1;   // scl 入力ポートでハイ
    // 10:SCLの立ち上がり検出  無限ループになる危険な行!
    wait_loop5:
    if( P0.1 ) f0=1;
    else f0=0;
    if( !P0.0 ) goto wait_loop5;
   
    if( f0 )
    {
       a= a | 0x01;   // LSBビットの設定
    }
    // 次のために1ビットシフトしておく  i=7 なら最後のBITなのでそのまま
    if( i < 7) a<<=1;
   
   
    // delay 2x4x0.125=1uS
    // for(i=0;i<9;..) メモリー呼び出しで、ディレー不要かも
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
  } // for(i=0;i<8;++i) 
 
  // ACK入力のためSCLをローレベルにして
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    if( acke) PM0.1=0;  // ACKを返す sda 出力ポートでロー
    else PM0.1=1;       // NAKを返す
    //の時間を待つ
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
   
    PM0.0=1;   // scl 入力ポートでハイ
    // 10:SCLの立ち上がり検出  無限ループになる危険な行!
    wait_loop6:
    if( !P0.0 ) goto wait_loop6;
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
    // delay 2x4x0.125=1uS
    #asm
    NOP
    NOP
    NOP
    NOP
    #endasm
   
    //最後に クロックをローにしておく
    PM0.0=0;   // scl 出力ポートでロー
    // delay 2x2x0.125=0.5uS
    #asm
    NOP
    NOP
    #endasm
    PM0.1=1;  //  SDAを入力にする
   
   return a;
 

}




/*  I2Cバスブロック転送処理関数  */
/*
;**************************************************************
;*                                                            *
;*  I2C デバイスにブロックデータ送信                           *
;*  対象はサブアドレスもつデバイス                             *
;*                                                            *
;**************************************************************
;*  [i] : u8 i2c_adr    ... I2C スレーブのアドレス             *
;*  [i] : u8 reg_adr_num    ... スレーブ内部のアドレスの数    *
;*  [i] : u8 *reg_adr    ... スレーブ内部のアドレス           *
;*  [i] : u8 *data      ... 書き込みデータのアドレス          *
;*  [i] : u8 size       ... バイト数              *
;*  [r] : u8            ... error code                        *
;*                                                            *
*/
u8 write_i2c_block(u8 i2c_adr, u8 reg_adr_num, u8 *reg_adr, u8 *data, u8 size)
{
    i2c_adr &= 0xfe;
    if (free_i2c_bus())         // バスを開放させる。
        return  set_i2c_error(I2C_BUS_NOT_FREE);  // バスが開放されない場合にはエラー・フラグをセットして戻る

    I2C_STR();                   // スタート・コンディション発行

    if (put_i2c2( i2c_adr))      // I2C アドレス送信
        return  set_i2c_error(I2C_ADDR_NACK); // 対象デバイスがノーリアクションならエラー・フラグをセットして戻る

 
   
    do
    {
     if (put_i2c2( *reg_adr++))      // レジスタアドレス送信
         return  set_i2c_error(I2C_REG_ADDR_NACK); // サブ・アドレスでNACK発生ならエラー・フラグをセットして戻る
    }while(--reg_adr_num);

    do{
        if (put_i2c2(*data++))  // データ送信
            return  set_i2c_error(I2C_DATA_NACK); // データ送信でNACK発生
    }while(--size);
    I2C_STPR();                  // 正常終了でバスを開放
    return  clear_i2c_error();   // エラー・フラグをクリアして戻る
}


/*
;****************************************************************
;*                                                              *
;*  I2C デバイスからブロックデータを受信                         *
;*  対象はサブ・アドレスをもつデバイス                           *
;*                                                              *
;****************************************************************
;*  [i] : u8 i2c_adr    ... I2C スレーブのアドレス               *
;*  [i] : u8 reg_adr_num    ... スレーブ内部のアドレスの数    *
;*  [i] : u8 *reg_adr    ... スレーブ内部のアドレス               *
;*  [i] : u8 *data      ... 書き込みデータのアドレス             *
;*  [i] : u8 size       ... バイト数                 *
;*  [r] : u8            ... 途中でSTOPコンディションを挿入      *
;*                   するかどうか。1で挿入(特別)。0で無し(普通)*
;*  [r] : u8            ... error code                          *
*/

u8 read_i2c_block(u8 i2c_adr, u8 reg_adr_num,  u8 *reg_adr, u8 *data, u8 size, u8 fstop)
{
    u8  d;
    i2c_adr &= 0xfe;
    if (free_i2c_bus())
        return  set_i2c_error(I2C_BUS_NOT_FREE);

    I2C_STR();                     // スタート・コンディション発行


    if (put_i2c2(i2c_adr))        // I2C アドレス送信
        return  set_i2c_error(I2C_ADDR_NACK); // 対象デバイスがノーリアクションなら、エラー・フラグを設定して戻る


    do
    {
     if (put_i2c2(*reg_adr++))        // レジスタアドレス送信
        return  set_i2c_error(I2C_REG_ADDR_NACK); // サブ・アドレスでNACKならエラー・フラグを設定して戻る
    }while(--reg_adr_num);
   
   
   
    if( fstop ) I2C_STPR;
   
   
    I2C_STR();                     // リスタート

    if (put_i2c2(i2c_adr | 0x01)) // I2C アドレス(READ)送信
        return  set_i2c_error(I2C_RADDR_NACK);  // 対象デバイスがノーリアクションならエラー・フラグを設定して戻る

    ACK_EN();              // ACK 許可
    do{
        if (size == 1)      // 最後のバイト?
            ACK_DS();      // マスタ受信最後のバイトならNACKに設定
        d = get_i2c();     // データの読み込み
        *data++ = d;        // 読み込みデータをバッファにセット
    }while(--size);

    I2C_STPR();            // バスを開放


    return  clear_i2c_error(); // エラー・フラグをクリアして戻る
}


void conv_ascii(u8 in0, u8 *out0)
{
   u8  a,b;
  
   a=in0 & 0x0f;
   b=in0 & 0xf0;
   b>>=4;
  
   if( a < 10) a+=48;
   else   a=(a-10)+65;
  
   if( b < 10) b+=48;
   else   b=(b-10)+65;

   out0[0]=b;
   out0[1]=a;
}

void conv_ascii2(u8 *in0, u8 *out0)
// 入力は 0x0f以下の数字
{
   u8  a,b;
  
   a=in0[0];
   a<<=4;
   b=in0[1];
 
   *out0= a | b;
}

void disp_help()
{
#define DISPH

#ifdef DISPH  
    trg_puts("\n");
    trg_puts("read ex: R a1 S 00 00 J 4\n");
    trg_puts("write ex: W a0 S 00 00 J 42 3e\n");
    trg_puts("read with stopcondition ex:  R a1 T 00 00 J 4\n");
    trg_puts("I2C address a1\n");
    trg_puts("sub address 00 or 00 00 ( 1 or 2 btyes only)\n");
    trg_puts("J read-quantity or J write-datas,  size<=FF(256)\n");
    trg_puts("LF=0x0a enter done, / comment,v echo on/off,? help, x stop\n");
    trg_puts("port P0.0 clock,  portP0.1 data, both ports must be pull up\n");
    trg_puts("\n");
#endif


}

void main() {


u8  i,rt0;
u8  c0,c1;

#define BUFFER_SIZE0 256
#define BUFFER_SUBADR0 2

u8      eep_buf[ BUFFER_SIZE0 ];   // read/write buffer
u8      eep_subadress_buf[  BUFFER_SUBADR0 ];
u8      in_buf[2];
u8      out_buf[2];
u8      i2c_adr0,size_sub0,size0,fstop0,frw0,cmd0,fskip0;
u8      each0;  // each on off
u8      first0;


#define     ADR_EEP     0xa0    // slave address


u8 biosExists = 0;
#define NULL ((void *)0)

    PM6.1 = 0; // LED のポートを出力用にする
   
    if((trg_getstatus(NULL) & 0x10) == 0) // Connected
    {
        // 既に接続しているならばBIOSから起動している
        biosExists = 1;
    }
    if(!biosExists)
    {
        trg_usbopen();
    }
   
   
    disp_help();
   
    // i2c port initilize
    PU0=0x00;   // 内臓プルアップしない
    P0=0x00;   // 出力データは零に固定
    PM0.0=1;   // scl 入力ポートでハイ
    PM0.1=1;   // sda 入力ポートでハイ
    trg_puts("+ i2c port P0.0 scl initilize\n");
    trg_puts("+ i2c port P0.1 sda initilize\n");
  
 
// #define TEST1
   
#ifdef TEST1   
    eep_subadress_buf[0]=0x00;
    eep_subadress_buf[1]=0x00;
    rt0=read_i2c_block(ADR_EEP, 2,  eep_subadress_buf, eep_buf, 12, 0);
    rt0=rt0+48;  // ascii code 0 is 48
    trg_senddata( &rt0,1);
    trg_puts("+ i2c get data are\n");
    for(i=0;i<12;++i)
    {
     conv_ascii( eep_buf[i], out_buf);
     trg_senddata( out_buf, 2);
     trg_puts("\n");
    }
   
#endif   
  
   
    fstop0=0;
    frw0=9;
    size_sub0=1;
    size0=1;
    i2c_adr0= ADR_EEP;
    eep_subadress_buf[0]=0x00;
    eep_subadress_buf[1]=0x00;
    fskip0=0;
    cmd0=0;
    c1=0;
    each0=1;
    first0=1;
   
    while(1) {
        char c = trg_getc(); // USB から1 文字取得  キーが押されるまで待機する関数
        if (each0)  trg_senddata(&c,1);  // USB へ1 文字出力

// #define DISP99
#ifdef DISP99          
            conv_ascii( c, out_buf);
            trg_senddata( out_buf, 2);
#endif

        if( (c == 0x56) || (c == 0x76))  // V  each0 をトグルでスイッチする
        {
          if ( each0 ) each0=0;
          else each0 = 1;
        }
        if( c ==  0x3f) disp_help();  // ?
        if( (c == 0x0a) && (first0)) { disp_help(); first0=0; }
        //++++++++++++++++++++++++++++++++++++++++++++++++++
        // 0x0a LF ===> command done
        if( c == 0x0a)
        {
       
          if( frw0 == 1 )
          {
            if( (c1 > 0) && (cmd0 == 4))
            {
                if( size0 <  BUFFER_SIZE0)
                {
                 conv_ascii2(in_buf,( eep_buf + size0 ) );
                 ++size0;  
                }       
            }
           
// #define DISP2

#ifdef DISP2
            trg_puts("i2c_addr ");
            conv_ascii( i2c_adr0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\nsize_sub0 ");
            conv_ascii( size_sub0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\n sub_address ");
            conv_ascii( eep_subadress_buf[0], out_buf);
            trg_senddata( out_buf, 2);
            conv_ascii( eep_subadress_buf[1], out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\nsize0 ");
            conv_ascii( size0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\neep_buf[0] ");
            conv_ascii( eep_buf[0], out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\n");
           
#endif           

            rt0=write_i2c_block(i2c_adr0, size_sub0,  eep_subadress_buf, eep_buf, size0);
            rt0=rt0+48;  // ascii code 0 is 48
           
             if ( (each0) || (rt0 > 48))   //  each ON または エラー時に表示する
             {
              if (rt0 > 48) trg_puts("\n- i2c data wrote. ERROR code is ");  // エラーが発生
              else trg_puts("\n+ i2c data wrote. return code is ");
              trg_senddata( &rt0,1);
              trg_puts("\n");
             }
         
          }
          else if ( frw0 == 0 )// when frw0 = 0 then read
          {
            if( cmd0 == 5) conv_ascii2(in_buf, &size0 );
            if( size0 >  BUFFER_SIZE0) size0= BUFFER_SIZE0;
// #define DISP1

#ifdef DISP1
            trg_puts("i2c_addr ");
            conv_ascii( i2c_adr0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\nsize_sub0 ");
            conv_ascii( size_sub0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\n sub_address ");
            conv_ascii( eep_subadress_buf[0], out_buf);
            trg_senddata( out_buf, 2);
            conv_ascii( eep_subadress_buf[1], out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\nsize0 ");
            conv_ascii( size0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\nfstop0 ");
            conv_ascii( fstop0, out_buf);
            trg_senddata( out_buf, 2);
           
            trg_puts("\n");
           
#endif           

            rt0=read_i2c_block(i2c_adr0, size_sub0,  eep_subadress_buf, eep_buf, size0, fstop0);
            rt0=rt0+48;  // ascii code 0 is 48
            if ( (each0) || (rt0 > 48))  // each ON または エラー時に表示する
            {
              if (rt0 > 48)  // エラーが発生
              {
                trg_puts("\n- i2c data read. ERROR code is ");
                trg_senddata( &rt0,1);
              }
              else
              {
                trg_puts("\n+ i2c read return code is ");
                trg_senddata( &rt0,1);
                trg_puts(". data are\n");
                for(i=0;i<size0;++i)
                {
                  conv_ascii( eep_buf[i], out_buf);
                  trg_senddata( out_buf, 2);
                  if(i != (size0-1)) trg_puts(" ");
                }
              }
            }else if ( (!each0) && (rt0 == 48))  // each OFF で エラー無しに表示する
            {
                for(i=0;i<size0;++i)
                {
                  conv_ascii( eep_buf[i], out_buf);
                  trg_senddata( out_buf, 2);
                  if(i != (size0-1)) trg_puts(" ");
                }
            }
           
           
            trg_puts("\n");
          }
         
          // 次のための念のため初期化しておく
          fstop0=0;
          frw0=9;
          size_sub0=1;
          size0=1;
          i2c_adr0= ADR_EEP;
          eep_subadress_buf[0]=0x00;
          eep_subadress_buf[1]=0x00;
          fskip0=0;
          cmd0=0;
          c1=0;
         
          // 改行しておく。
          trg_puts("\n");
        }
        else  // if( c0 == 0x0a)
        {
          if( !fskip0 )
          {
         
          // 入力Cを整頓する
          c0=c;
          if( (c0 >0x60) && (c0<0x7b)) c0-=32;   // 大文字にそろえる
          // 数字を0から15までに変換する
          if ( (c0 >= 0x30) && (c0 <= 0x39)) // 0,,,9
          {
            c0-=48;
          }
          else if ( (c0 >= 0x41) && (c0 <= 0x46)) // A,,,F
          {
            c0=c0-65+10;
          }
       
          if( c0 == 0x52 )  // R
          {
            frw0=0;
            in_buf[1]=0;
            in_buf[0]=0;
            c1=0;
          }
          else if ( c0 == 0x57 ) // W
          {
            frw0=1;
            in_buf[1]=0;
            in_buf[0]=0;
            c1=0;
          }
          else if ( c0 == 0x53 )  // S
          {
            conv_ascii2(in_buf, &i2c_adr0 );  // 直前の入力データをアドレスとして設定
            fstop0=0;
            cmd0=2;
            size_sub0=0;
            in_buf[1]=0;
            in_buf[0]=0;
            c1=0;
          }
          else if ( c0 == 0x54 )  // T 
          {
            conv_ascii2(in_buf, &i2c_adr0 );   // 直前の入力データをアドレスとして設定
            fstop0=1;
            cmd0=2;
            size_sub0=0;
            in_buf[1]=0;
            in_buf[0]=0;
            c1=0;
          }
          else if ( c0 == 0x4A )  // J
          {
          
           if(( c1 > 0 ) && (size_sub0 < BUFFER_SUBADR0))   // もし入力があった場合で 2バイト以内ならば
           {
             conv_ascii2(in_buf,( eep_subadress_buf + size_sub0 ) );
             ++size_sub0;
           } 
            if( frw0 == 1)  // write
            {
              cmd0=4;
              size0=0;
              in_buf[1]=0;
              in_buf[0]=0;
              c1=0;
            }
            else if( frw0 == 0)  // read
            {
               cmd0=5;
               size0=1;
               in_buf[1]=0;
               in_buf[0]=0;
               c1=0;
            }
          
          }
          else if ( c0 == 0x2f )  // /
          {
         
            fskip0=1;
          }
          else if ( c0 == 0x20 ) // space
          {
          
            if( c1 > 0)
            {
              if( cmd0 == 2)   // sub address
              {
               if( size_sub0 < BUFFER_SUBADR0)
               {
                conv_ascii2(in_buf,( eep_subadress_buf + size_sub0 ) );
                ++size_sub0;
               }
               in_buf[1]=0;
               in_buf[0]=0;
               c1=0;
              }     
             else if ( cmd0 == 4)   // input data
             {
                if( size0 <  BUFFER_SIZE0)
                {
                 conv_ascii2(in_buf,( eep_buf + size0 ) );
                 ++size0;
               
                }
                in_buf[1]=0;
                in_buf[0]=0;
                c1=0;
             }
            
         
            } // if( c1 > 0)
          }
          else if ( (c0 >= 0) && (c0 <= 15))  // 数字
          {
           in_buf[0]=in_buf[1];
           in_buf[1]=c0;
           ++c1;
          }
       
          } //skip_else:
        } //else of  if( c0 == 0x0d)
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       
       
        if(c == 'x') break;  // 文字がx ならば終了
        P6.1 ^= 0x01;        // LED のポートを点滅
    }
   
   
}

ビルドして作ったHEXファイル sample2hex (7,968  バイト)

version 3.14

警告
USBマイコン基板をつかって接続する場合は、電気的なことをよく理解した上でお 使いください。そうしないと、PCとUSBマイコン基板と接続した相手などを破壊する危険があります。接続にあたっては、例えば保護 素子(電源ラインにポリスイッチとか信号ラインに抵抗など)を入れるなど、十分注意してくださいね。I2Cの標準モードのスペックを満たしていないので、 上手 く動かないときもあるかもしれません。ポートに最大絶対定格電圧(VDD+0.3Vまで *但しさいだいでも6.5Vまで)以上を加えるとUSBマイコン基板のマイコン内部が破壊する恐れがあります。

免責

(1)プログラムやデータの使用により、使用者に損失が生じたとしても、その責任 を負いません。
(2)プログラムやデータにバグや欠陥があったとしても、修正や改良の義務を負い ません。

既知のバグ

(1)表示size<=FF(256)。16進FFは256ではなく10進で255が正しい。