ALFAT chip  ALFAT chip

PIC マイコンでCF(コンパクトフラッシュ)で制御しよう!
以前、PICマイコンに温度・湿度センサを接続し、LCDモジュールに表示する装置を、 トランジスタ技術の2003年12月号で紹介したのですが、温度・湿度を記憶できなくて、 ちょっと不満足でした。

そこで、GHI Electronics社のALFATchipを用いて、測定データをCF(コンパクトフラッシュ) に保存することにしました。

先ずは、ヒューマンデータで販売しているALFATchipの評価ボードFAT-002を使って、PICマイコンで CFへのデータ書込みにチャレンジしました。【プログラム1】

ALFATchip及びFAT-002については、 ヒューマンデータのホームページを参照してください。

そして、温度・湿度を表示及び測定結果をCFに記憶するプログラムも完成しました。【プログラム2】

壁掛け温度・湿度計です!(電源を乾電池から5.6V出力のACアダプタに変更しました)


LCD表示パネルのクイックタイム・ムービー

今後の課題は、CFに記憶されたデータを解析するプログラムの作成

回路図
回路図は下図の通りです。赤枠内がFAT-002ボードで、トランジスタ技術で紹介した回路に追加した部分です。



【解説】PIC16F873とALFATchipとの接続には、I2Cを使いました。

ALFATchipは、UART(シリアルポート)、SPI、I2Cで接続するようになっていますが、 今回はI2Cを用いてPICマイコンと接続することにしました。

I2Cで接続する場合には、上図のように、SCL及びSDAのI2C用ラインの他に、 I2C-DATARDYとI2C-BUSYラインをハンドシェイク用に接続します。

SCLとSDAラインは10kΩでプルアップしてあります。

PIC16F873にはハードウェアI2Cが内蔵されていますが、既にLEDモジュール用でポートをI/Oピンとして 使用しているので、PORT Aの汎用I/Oポートを使いました。

PICマイコンはI2Cのマスターとなるため、高速処理も必要ではないので、汎用I/Oポートで十分です。 よって、PIC16F84のようにハードウェアI2Cを内蔵しないPICマイコンでも大丈夫です。

下の写真が、接続した状態です。


プログラム
まず、最初のステップとして、PICマイコンからCFにデータを書き込めることを確認するプログラムを作成しました。

開発に使用したのは、CCS Cコンパイラーです(扱いはデータダイナミクス)です。
CCS CコンパイラーにはハードウェアI2Cを内蔵しない場合でも利用可能なI2C用関数が用意されていて、PICマイコンの I2Cデバイス開発にはうってつけです。

下記は、PIC16F873のタイマー1のデータを、CFに書き込む為のプログラムです。

LCDモジュールをデバッグ用の表示デバイスとして使用していますが、UART(シリアルポート)を使って パソコン等に出力しても良いと思います。

とにかく、デバッグ用の表示デバイスは、開発用には欠かせません。

下記【プログラムリスト1】はCFにデータを書き込むテスト。
【プログラムリスト2】が温度・湿度を表示及び測定結果をCFに記憶するもの(とりあえず完成版)

【プログラムリスト1】


// FAT002 Test Program
// By Yasuo Ikushima
//
// 約3秒間隔で TIME1 のカウント値をテキストで TEST.TXT ファイルに書き込んでいく
//
// FAT002ジャンパピンの設定
// JP2
// 1-2 : ショート
//
// JP3
// 2-3 : ショート
// 5-6 : ショート
//
// JP5
// 1-2 : ショート
// 3-4 : ショート

#include <16F873.h>


// Pointer size = 16bit
#device adc=10 *=16

// Clock = 2MHz
#use delay(clock=2000000)

// Configuration Fuses
#fuses XT, NOWDT, NOWRT,NOPROTECT, NOPUT, NOBROWNOUT, NOLVP, NOCPD

// マスターモードで使用、内蔵I2Cは未使用、汎用ポートをI2Cで使用
#use I2C(master, sda=PIN_A1, scl=PIN_A0)

// FAT002 のI2Cアドレス(固定)
#define FATADR (0xa4)

// 各ピンの割り当て
//
// I2C SCL
#define USR_I2C_SCL PIN_A0

// I2C SDA
#define USR_I2C_SDA PIN_A1

// I2C_DATARDY は ALFATピン番号19(FAT002基板では TTL-TXD)
#define I2C_DATARDY PIN_A2
//
// このピンは ALFATに出力データが残っている場合に 1 となる
// FAT002基板上のLED L3

// I2C_BUSY は ALFATピン番号21(FAT002基板では EXT-RXD)
#define I2C_BUSY    PIN_A3
//
// このピンは ALFATがBusyの時に 1 となる
// FAT002基板上のLED L4

// LCDパネルの設定
//
// LCD Control & Data signals line

// RB2 : RS (Register select)
// RB1 : R/W
// RB0 : E (Enable signal)
//
// RC0 : DB0
// RC1 : DB1
// RC2 : DB2
// RC3 : DB3
// RC4 : DB4
// RC5 : DB5
// RC6 : DB6
// RC7 : DB7

// LCD Control Signals
#define RS_LOW  0b000
#define RS_HIGH 0b100
#define RW_R    0b10
#define RW_W    0b00
#define E_LOW   0b0
#define E_HIGH  0b1

// PortAは入出力固定
#use fast_io(A)

// Delay Time
#define DLTIMEu 10

// バッファ
char  lbuf[21];
char  sbuf[21];

// ackシグナル格納用
int   ansc;

// *******************************
// LCD RS Line = Low, DATA Wite
// *******************************
void LCD_RSLOW_RW(int lcd_data)
{
   int8 i;

   i = lcd_data;
   output_c(i);

   i = RS_LOW + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_LOW + RW_W + E_HIGH;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_LOW + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

}

// *******************************
// LCD RS Line = High, DATA Wite
// *******************************
void LCD_RSHI_RW(int lcd_data)
{
   int8 i;

   i = lcd_data;
   output_c(i);

   i = RS_HIGH + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_HIGH + RW_W + E_HIGH;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_HIGH + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

}

// *******************************
// LCD Data output
// *******************************
void   LCD_Dataout(int8 i)
{
   i += 0b10000000;
   LCD_RSLOW_RW(i);
   i = 0;
   while(lbuf[i] != 0) {
      LCD_RSHI_RW(lbuf[i]);
      i ++;
   }
}


// *******************************************************************
// ALFATからデータを取得
//
// I2C_DATARDY をチェックして、
//   ALFAT側に未送信データがあるときは取得したデータを返す
//   未送信データが無い場合は 0x100 を返す
// *******************************************************************
long Get_I2C_Data()
{
   long rd;

   if (input(I2C_DATARDY) == 1) {
      i2c_start();

      // リード時のアドレスは +1 する
      i2c_write(FATADR+1);

      rd= i2c_read();
      i2c_stop();
   } else {
      rd = 0x100;
   }

   return(rd);
}

// *******************************************************************
// ALFATにデータを送信
//
// 最初に、ALFAT側に未送信データがある場合は、全て読む
//
// 次に、I2C_BUSYをチェックして、データを送信
// *******************************************************************
int Send_I2C_Data(int idata)
{
   int rd;

  rd = 0;
  while(input(I2C_DATARDY) == 1) {
      i2c_start();
      i2c_write(FATADR+1);
      rd = i2c_read();
      i2c_stop();
   }

   while(input(I2C_BUSY) == 1);
   i2c_start();
   i2c_write(FATADR);
   i2c_write(idata);
   i2c_stop();

   return(rd);
}

// *******************************************************************
// 複数データの送信を行う
//
// 送信方法は wmode 変数で制御
//
// wmode = 0 : sbufに格納されているデータを0に達するまで送信
//             送信後、ALFAT側からのデータを受信
//             I2C_DATARDYが0となったら受信停止
//
// wmode = 1 : フレームモード用データ送信
//             sbuf[0] の下位5ビットに格納されているデータ数を送信し
//             チェックサムを計算し送信
//             送信後、ALFAT側から送信されてきたACKシグナルの先頭Byte
//             の下位5ビット分のデータを受信
//             上位3ビットはACK/NACKの判別に使用する
//
// wmode = 2 : sbufに格納されているデータを0に達するまで送信
//             送信後、ALFAT側から送信されてきたACKシグナルの先頭Byte
//             の下位5ビット分のデータを受信
//             上位3ビットはACK/NACKの判別に使用する
//
// wmode = 3 : sbufに格納されているデータを0に達するまで送信
//             受信は無し
//
// *******************************************************************
void  SendLine_I2C_Data(int wmode)
{
   int i;
   int j;
   int len;
   int accode;
   int acbyte;
   int csum;
   long rd;

// 書き部分は、LCDでALFATからのシグナルをモニタするためのコード
//   for (i = 0 ; i < 20 ; i ++) lbuf[i] = ' ';
//   lbuf[20] = 0;
//   LCD_Dataout(0x14);
//   delay_ms(100);

//   i = 0;
//   while((lbuf[i++] = Get_I2C_Data()) != 0);

   j = 0;
   csum = 0;
   // ---------------------------------------------------------------
   if (wmode == 1) {
      len = sbuf[0] & 0x1F;
      len ++;
      for (i = 0; i < len ; i++) {
         csum += sbuf[i];
         Send_I2C_Data(sbuf[i]);
      }

      Send_I2C_Data(csum);

      while ((rd = Get_I2C_Data()) == 0x100);

      i = 0;
      acbyte = rd & 0x1F;
      accode = rd & 0xE0;
      lbuf[i] = rd; //rd;
      i ++;
      for (j = 0 ; j <= acbyte ; j ++) {
         lbuf[i] = Get_I2C_Data(); i ++;
      }
   // ---------------------------------------------------------------
   } else if (wmode == 2) {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

      while ((rd = Get_I2C_Data()) == 0x100);

      i = 0;
      acbyte = rd & 0x1F;
      accode = rd & 0xE0;
      lbuf[i] = rd; //rd;
      i ++;
      for (j = 0 ; j <= acbyte ; j ++) {
         lbuf[i] = Get_I2C_Data(); i ++;
      }
   // ---------------------------------------------------------------
   } else if (wmode == 3) {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

   // ---------------------------------------------------------------
   } else {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

      i = 0;
      while((rd = Get_I2C_Data()) != 0x100) { lbuf[i] = rd; i ++; }
   }

   // 下位動作は wmode = 3 以外で行う
   if (wmode != 3) {

      // ACK/NACKシグナルをグローバル変数に格納
      ansc = lbuf[0];

     // 以下の部分は、LCDに受信データを表示するための設定
//      for (j = 0 ; j < i ; j ++) {
//         if (lbuf[j] < 0x20) lbuf[j] += 0xB0;
//      }
//      lbuf[i] = '<';
//      lbuf[i+1] = 0;
//      LCD_Dataout(0x14);
   }
}

// *******************************
// main function
// *******************************
void main()
{
   int8 i;

   int rd;
   long tmr1;


   // ADC is not used.
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);

   //TIMER 1を内蔵クロック、8分周で使用
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );

   // Port initial value
   output_a(0xFF);
   output_b(0xFF);
   output_c(0xFF);

   // All PORTB and PORTC are output.
   SET_TRIS_C( 0b00000000);
   SET_TRIS_B( 0b00000000);

   // Setting of PORTA
   // I2C部分は入力で固定
   SET_TRIS_A( 0b001111 );




// -------------------------------
// LCD module 初期化
// -------------------------------

	delay_ms(50);

	LCD_RSLOW_RW(0b00110000);

	delay_ms(5);

	LCD_RSLOW_RW(0b00110000);

	delay_us(100);

	LCD_RSLOW_RW(0b00110000);

	// 8bit,1/16 duty
	LCD_RSLOW_RW(0b00111000);

	// Display ON(bit2 = 1),Cursor OFF(bit1 = 0),NO Blink(bit0 = 0)
	LCD_RSLOW_RW(0b00001100);

	// Display Clear
	LCD_RSLOW_RW(0b00000001);

	// Cursor Home
	LCD_RSLOW_RW(0b00000010);


   delay_ms(10);

// -------------------------------
// LCDに文字表示
// -------------------------------
//               1234567890
   sprintf(lbuf,"FAT002    ");
   LCD_Dataout(0x00);

// -------------------------------------------------------------------
// ALFAT は電源投入後、ブートローダーモードになるので
// 'BL' のメッセージをチェック
// -------------------------------------------------------------------

   // 'B'が来るまで受信を続ける
   while(Get_I2C_Data() != 'B');

   // 'B'の次は'L'であることを確認
   if (Get_I2C_Data() == 'L') {
      // LCDに表示
      //            1234567890
      sprintf(lbuf,"BL OK!    ");
      LCD_Dataout(0x0A);
   } else {
      // LCDにエラー表示
      //            1234567890
      sprintf(lbuf,"NG! Stop! ");
      LCD_Dataout(0x0A);

      // エラーの場合はPICをスリープ
      sleep();
   }

// 以下の部分は、ファームウェアをCFに書き込んで、アップデートする場合に
// 用いる(CF のドライブは B ドライブとなる)
//   sprintf(sbuf,"LQUB");
//   SendLine_I2C_Data(0);
//
//   下記部分は、500ms毎にALFATから送信されるデータをチェックするもの
//   ALFAT側からはファームウェアアップデート中にW01\n W02\n....W99\n
//   のように進捗状況を%で出力してくる
//
//   書込みが完了すると、受信データは0x00となり、LED3/LED4が点等
//   while(1) {
//   i = Get_I2C_Data();
//   sprintf(lbuf,"%X:",i);
//   LCD_Dataout(0x54);
//   delay_ms(500);
//   }
//while(1);

// -------------------------------------------------------------------
// "BL"メッセージを確認したら、'R'キャラクタを送信
// -------------------------------------------------------------------
   Send_I2C_Data('R');

// 下記部分は、Rキャラクタを送信しても、ALFATが"Z:/>"を送信してこない
// 場合に、ブートローダーのエラーをLCDに表示させて確認するもの
//   while(1) {
//   i = Get_I2C_Data();
//   sprintf(lbuf,"%X:",i);
//   LCD_Dataout(0x54);
//   delay_ms(500);
//   }


// -------------------------------------------------------------------
// ブートが正常に行われると、"GHI Electoro...(略) Z:\> "を送信してくる
// ので、'>'をキャッチする
// -------------------------------------------------------------------
   i = 0;
   while (Get_I2C_Data() != '>') {
   }
   // キャッチできたら、LCDに"Z:>"を表示
   sprintf(lbuf,"Z:>");
   LCD_Dataout(0x0A);

// 下記部分は、echoをoffにするためのもの
// フレームモードを使用する場合は不要
//   sprintf(sbuf,"EE 0\n\r");
//   SendLine_I2C_Data(0);
//   delay_ms(500);
//   delay_ms(500);
//   while(1);

// 下記部分は、ファームウェアのバージョンをLCDに表示するためのもの
//   delay_ms(500);
//   sprintf(sbuf,"VR\r");
//   SendLine_I2C_Data(0);
//while(1);

   // このディレーは、LCDの文字を確認するためのもの(以下も同様)
   delay_ms(500);


// -------------------------------------------------------------------
// フレームモードに移行するための、コマンドを送信
// -------------------------------------------------------------------
   sprintf(sbuf,"FM\r");
   SendLine_I2C_Data(0);

// デバッグ用のブレークポイント
//   while(1);


// 下記部分は、日付と時刻を設定するもの
//   delay_ms(500);
//   // 32384A8F
//   sprintf(sbuf,"\x85\x14\x8F\x4A\x38\x32");
//   SendLine_I2C_Data(1);
//   if ((ansc & 0xE0) == 0x00) {
//      //            12345678901
//      sprintf(lbuf,"T/D set er!");
//      LCD_Dataout(0x54);
//      sleep();
//   } else {
//      //            12345678901
//      sprintf(lbuf,"T/D set ok!");
//      LCD_Dataout(0x54);
//   }

// -------------------------------------------------------------------
// FAT002基板ではCFは'B'ドライブに割り当てられるので、Bドライブに移動
// -------------------------------------------------------------------
   delay_ms(500);
   sprintf(sbuf,"\xE1B");
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"B: cmd er!");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"B: cmd ok! ");
      LCD_Dataout(0x0A);
   }

// 以下の部分は、test.txtファイルを検索し、ファイル属性を表示するもの
//   delay_ms(500);
//   sprintf(sbuf,"\x8A\x08test.txt\x00");
//   SendLine_I2C_Data(1);
//   if ((ansc & 0xE0) == 0x00) {
//      //            12345678901
//      sprintf(lbuf,"FI cmd er! ");
//      LCD_Dataout(0x54);
//      sleep();
//   } else {
//      //            12345678901
//      sprintf(lbuf,"FI cmd ok! ");
//      LCD_Dataout(0x54);
//   }
//while(1);


// -------------------------------------------------------------------
// ファイル名 test.txtを書込みモードで新規作成(ファイルハンドル 0x01)
// -------------------------------------------------------------------
   delay_ms(500);
   sprintf(sbuf,"\x8C\x04\x77\x01test.txt\x00");
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Open er!  ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Open OK!  ");
      LCD_Dataout(0x0A);
   }
//   while(1);

// -------------------------------------------------------------------
// 繰返しループ
// -------------------------------------------------------------------
Loop:


// -------------------------------------------------------------------
// ファイルハンドル 0x01に、6byte書き込むことをALFATに知らせる
// -------------------------------------------------------------------
   delay_ms(100);
     // 下記部分のsprintfはCCSCコンパイラで処理できなかったため、
     // sbufに直接挿入
//   sprintf(sbuf,"\xC5\x08\0\0\0\x01");
   sbuf[0] = 0xC5;
   sbuf[1] = 0x06;
   sbuf[2] = 0x00;
   sbuf[3] = 0x00;
   sbuf[4] = 0x00;
   sbuf[5] = 0x01;
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"W cmd er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"W cmd ok! ");
      LCD_Dataout(0x0A);
   }
//   while(1);


// -------------------------------------------------------------------
// ALFAT側から書込み許可がきたら、データ6byte送信
// -------------------------------------------------------------------
   delay_ms(100);
     // 定数の場合は下記のようにしても良い
//   sprintf(sbuf,"54321\n");

   // タイマ1のカウント値を5byte、そして \n を sbuf に格納
   tmr1 = get_timer1();
   sprintf(sbuf,"%5Lu\n",tmr1);
   SendLine_I2C_Data(2);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Write er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Write ok! ");
      LCD_Dataout(0x0A);
   }


// -------------------------------------------------------------------
// 書き込んだら、ALFAT内のバッファに残っているデータをCFに書き込む
// -------------------------------------------------------------------
   delay_ms(100);
   sprintf(sbuf,"\x82\x0E\x01");
   SendLine_I2C_Data(1);
   if ((ansc & 0xF0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Flush er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Flush OK! ");
      LCD_Dataout(0x0A);
   }

// -------------------------------------------------------------------
// 約2秒間、LCDに"SLEEP"を表示させ、これが表示されているときに
// 電源を切ると、ファイルを壊さないかもしれない
// -------------------------------------------------------------------
   delay_ms(100);
   //            1234567890
   sprintf(lbuf,"Sleep     ");
   LCD_Dataout(0x0A);
   delay_ms(2000);

// -------------------------------------------------------------------
// 以後繰返し
// -------------------------------------------------------------------
   goto Loop;
//   while(1);


// -------------------------------------------------------------------
// 下記部分は、ファイルをクローズする場合のコマンド
// -------------------------------------------------------------------
//   delay_ms(500);
//   sprintf(sbuf,"\x82\x05\x01");
//   SendLine_I2C_Data(1);
//   if ((ansc & 0xF0) == 0x00) {
//      //            1234567890
//      sprintf(lbuf,"Close er! ");
//      LCD_Dataout(0x0A);
//      sleep();
//   } else {
//      //            1234567890
//      sprintf(lbuf,"Close OK! ");
//      LCD_Dataout(0x0A);
//   }

}





【プログラムリスト2】

上記、リスト1から余分なコメントを外し、温度・湿度センサの読み込みプログラムと タイマ1、温度、湿度をCFに書き込むプログラムを追加しました。

// FAT002 Test Program
// By Yasuo Ikushima
//
// 約3秒間隔で温度・湿度センサに書き込んでいく
//
// FAT002ジャンパピンの設定
// JP2
// 1-2 : ショート
//
// JP3
// 2-3 : ショート
// 5-6 : ショート
//
// JP5
// 1-2 : ショート
// 3-4 : ショート

// *******************************************************************
#include <16F873.h>

// Pointer size = 16bit
#device adc=10 *=16

// Clock = 2MHz
#use delay(clock=2000000)

// Configuration Fuses
#fuses XT, NOWDT, NOWRT,NOPROTECT, NOPUT, NOBROWNOUT, NOLVP, NOCPD

// マスターモードで使用、内蔵I2Cは未使用、汎用ポートをI2Cで使用
#use I2C(master, sda=PIN_A1, scl=PIN_A0)

// FAT002 のI2Cアドレス(固定)
#define FATADR (0xa4)

// 各ピンの割り当て
//
// I2C SCL
#define USR_I2C_SCL PIN_A0

// I2C SDA
#define USR_I2C_SDA PIN_A1

// I2C_DATARDY は ALFATピン番号19(FAT002基板では TTL-TXD)
#define I2C_DATARDY PIN_A2
//
// このピンは ALFATに出力データが残っている場合に 1 となる
// FAT002基板上のLED L3

// I2C_BUSY は ALFATピン番号21(FAT002基板では EXT-RXD)
#define I2C_BUSY    PIN_A3
//
// このピンは ALFATがBusyの時に 1 となる
// FAT002基板上のLED L4

// *******************************************************************
// LCDパネルの設定
//
// LCD Control & Data signals line

// RB2 : RS (Register select)
// RB1 : R/W
// RB0 : E (Enable signal)
//
// RC0 : DB0
// RC1 : DB1
// RC2 : DB2
// RC3 : DB3
// RC4 : DB4
// RC5 : DB5
// RC6 : DB6
// RC7 : DB7

// LCD Control Signals
#define RS_LOW  0b000
#define RS_HIGH 0b100
#define RW_R    0b10
#define RW_W    0b00
#define E_LOW   0b0
#define E_HIGH  0b1

// *******************************************************************
// CRC
int8  crcdata;

int8 const crc_table[256]= {
0, 49, 98, 83, 196, 245,166, 151,185, 136,219, 234,125, 76, 31, 46, 67, 114,33, 16,
135, 182,229, 212,250, 203,152, 169,62, 15, 92, 109,134, 183,228, 213,66, 115,32, 17,
63, 14, 93, 108,251, 202,153, 168,197, 244,167, 150,1, 48, 99, 82, 124, 77, 30, 47,
184, 137,218, 235,61, 12, 95, 110,249, 200,155, 170,132, 181,230, 215,64, 113,34, 19,
126, 79, 28, 45, 186, 139,216, 233,199, 246,165, 148,3, 50, 97, 80, 187, 138,217, 232,
127, 78, 29, 44, 2, 51, 96, 81, 198, 247,164, 149,248, 201,154, 171,60, 13, 94, 111,
65, 112,35, 18, 133, 180,231, 214,122, 75, 24, 41, 190, 143,220, 237,195, 242,161, 144,
7, 54, 101, 84, 57, 8, 91, 106,253, 204,159, 174,128, 177,226, 211,68, 117,38, 23,
252, 205,158, 175,56, 9, 90, 107,69, 116,39, 22, 129, 176,227, 210,191, 142,221, 236,
123, 74, 25, 40, 6, 55, 100, 85, 194, 243,160, 145,71, 118,37, 20, 131, 178,225, 208,
254, 207,156, 173,58, 11, 88, 105,4, 53, 102, 87, 192, 241,162, 147,189, 140,223, 238,
121, 72, 27, 42, 193, 240,163, 146,5, 52, 103, 86, 120, 73, 26, 43, 188, 141,222, 239,
130, 179,224, 209,70, 119,36, 21, 59, 10, 89, 104,255, 206,157, 172};

// LCDパネルのアドレス
// 1行目 : 0x00 - 0x13
// 2行目 : 0x40 - 0x53
// 3行目 : 0x14 - 0x27
// 4行目 : 0x54 - 0x67


// *******************************************************************

// PortAは入出力固定
#use fast_io(A)

// Delay Time
#define DLTIMEu 10

// バッファ
char  lbuf[21];
char  sbuf[21];

// ackシグナル格納用
int   ansc;

// 書込み回数格納用
long  wcount;

// *******************************************************************
// SHT1x Control signal

// *******************************
// DATA Line = Low, SCK Line = Low
// *******************************
void DL_SL()
{
   output_a(0b001111);
   delay_us(DLTIMEu);
}

// *******************************
// DATA Line = High, SCK Line = Low
// *******************************
void DH_SL()
{
   output_a(0b011111);
   delay_us(DLTIMEu);
}

// *******************************
// DATA Line = Low, SCK Line = High
// *******************************
void DL_SH()
{
   output_a(0b101111);
   delay_us(DLTIMEu);
}

// *******************************
// DATA Line = High, SCK Line = High
// *******************************
void DH_SH()
{
   output_a(0b111111);
   delay_us(DLTIMEu);
}

// *******************************
// "Transmission Start" sequence
// *******************************
void  SHT_Trans_Start()
{
   // PORTA initial value
   output_a(0xFF);

   SET_TRIS_A( 0b001111 ); // RA4 = output

   DH_SL();
   DH_SH();
   DL_SH();
   DL_SL();
   DL_SH();
   DH_SH();
   DH_SL();

   // Wait
   delay_ms(10);

}

// *******************************
// LCD RS Line = Low, DATA Wite
// *******************************
void LCD_RSLOW_RW(int lcd_data)
{
   int8 i;

   i = lcd_data;
   output_c(i);

   i = RS_LOW + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_LOW + RW_W + E_HIGH;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_LOW + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

}

// *******************************
// LCD RS Line = High, DATA Wite
// *******************************
void LCD_RSHI_RW(int lcd_data)
{
   int8 i;

   i = lcd_data;
   output_c(i);

   i = RS_HIGH + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_HIGH + RW_W + E_HIGH;
   output_b(i);
   delay_us(DLTIMEu);

   i = RS_HIGH + RW_W + E_LOW;
   output_b(i);
   delay_us(DLTIMEu);

}

// *******************************
// LCD Data output
// *******************************
void   LCD_Dataout(int8 i)
{
   i += 0b10000000;
   LCD_RSLOW_RW(i);
   i = 0;
   while(lbuf[i] != 0) {
      LCD_RSHI_RW(lbuf[i]);
      i ++;
   }
}

// *******************************
// SHT Command transmission
// *******************************
void SHT_Trans(int8 data)
{
   int8 i;

// crc
   crcdata = 0;
   crcdata ^= data;
   crcdata = crc_table[crcdata];

   // Command transmission
   DH_SL();
   for(i = 0 ; i < 8 ; i++) {
      if((data & 0b10000000) == 0) {
         DL_SL();
         DL_SH();
         DL_SL();
      } else {
         DH_SL();
         DH_SH();
         DH_SL();
      }
      data <<= 1;
   }

   // The ACK signal is received.
   SET_TRIS_A( 0b011111 ); // RA4 = input
   DH_SL();
   DH_SH();
   if (input(PIN_A4) == 1) {
      // Display Clear
      LCD_RSLOW_RW(0b00000001);
      // Cursor Home
      LCD_RSLOW_RW(0b00000010);
      delay_ms(10);
      // Error Message
      sprintf(lbuf,"ERROR;");
      LCD_Dataout(0x00);
      sprintf(lbuf,"SHT does not respond");
      LCD_Dataout(0x40);
      sprintf(lbuf," to the command.");
      LCD_Dataout(0x14);

      sleep();
   }
   DH_SL();
}


// *******************************
// SHT data recived
// *******************************
int16   SHT_data_recive()
{
   int8 rdata1,rdata2;
   int16 rdata;
   int8 i;
   int8  read_crc;

   // MSB 8bit of the temperature data is received.
   rdata1 = 0;
   for(i = 0 ; i < 8 ; i++) {
      DH_SH();
      rdata1 <<= 1;
      if(input(PIN_A4) == 1) rdata1 ++;
      DH_SL();
   }

   crcdata ^= rdata1;
   crcdata = crc_table[crcdata];

   // The ACK signal is transmitted.
   SET_TRIS_A( 0b001111 ); // RA4 = output

   // ACK Puls
   DL_SL();
   DL_SH();
   DL_SL();

   SET_TRIS_A( 0b011111 ); // RA4 = input

   // LSB 8bit of the temperature data is received.
   rdata2 = 0;
   for(i = 0 ; i < 8 ; i++) {
      DH_SH();
      rdata2 <<= 1;
      if(input(PIN_A4) == 1) rdata2 ++;
      DH_SL();
   }
   crcdata ^= rdata2;
   crcdata = crc_table[crcdata];

   SET_TRIS_A( 0b001111 ); // RA4 = output

   // ACK Puls(CRC used)
   DL_SL();
   DL_SH();
   DL_SL();

   // The CRC signal is received.
   SET_TRIS_A( 0b011111 ); // RA4 = input

   read_crc = 0;
   for(i = 0 ; i < 8 ; i ++) {
      DH_SH();
      read_crc >>= 1;
      if(input(PIN_A4) == 1) read_crc += 0b10000000;
      DH_SL();
   }
   DH_SL();

   // ACK Puls
   DL_SL();
   DH_SH();
   DH_SL();

   // CRC check
   if (crcdata != read_crc) {
      // Display Clear
      LCD_RSLOW_RW(0b00000001);
      // Cursor Home
      LCD_RSLOW_RW(0b00000010);
      delay_ms(10);
      // Error Message
      sprintf(lbuf,"ERROR;");
      LCD_Dataout(0x00);
      sprintf(lbuf,"CRC Error!");
      LCD_Dataout(0x40);
      sprintf(lbuf,"Calc CRC : %02X",crcdata);
      LCD_Dataout(0x14);
      sprintf(lbuf,"Read CRC : %02X",read_crc);
      LCD_Dataout(0x54);

      sleep();
   }

   // MSB and LSB of the temperature data are stored in 16bit variable.
   rdata = (int16)rdata1*256 + (int16)rdata2;

   // Wait
   delay_ms(100);

   return(rdata);
}

// *******************************************************************
// ALFATからデータを取得
//
// I2C_DATARDY をチェックして、
//   ALFAT側に未送信データがあるときは取得したデータを返す
//   未送信データが無い場合は 0x100 を返す
// *******************************************************************
long Get_I2C_Data()
{
   long rd;

   if (input(I2C_DATARDY) == 1) {
      i2c_start();

      // リード時のアドレスは +1 する
      i2c_write(FATADR+1);

      rd= i2c_read();
      i2c_stop();
   } else {
      rd = 0x100;
   }

   return(rd);
}

// *******************************************************************
// ALFATにデータを送信
//
// 最初に、ALFAT側に未送信データがある場合は、全て読む
//
// 次に、I2C_BUSYをチェックして、データを送信
// *******************************************************************
int Send_I2C_Data(int idata)
{
   int rd;

  rd = 0;
  while(input(I2C_DATARDY) == 1) {
      i2c_start();
      i2c_write(FATADR+1);
      rd = i2c_read();
      i2c_stop();
   }

   while(input(I2C_BUSY) == 1);
   i2c_start();
   i2c_write(FATADR);
   i2c_write(idata);
   i2c_stop();

   return(rd);
}

// *******************************************************************
// 複数データの送信を行う
//
// 送信方法は wmode 変数で制御
//
// wmode = 0 : sbufに格納されているデータを0に達するまで送信
//             送信後、ALFAT側からのデータを受信
//             I2C_DATARDYが0となったら受信停止
//
// wmode = 1 : フレームモード用データ送信
//             sbuf[0] の下位5ビットに格納されているデータ数を送信し
//             チェックサムを計算し送信
//             送信後、ALFAT側から送信されてきたACKシグナルの先頭Byte
//             の下位5ビット分のデータを受信
//             上位3ビットはACK/NACKの判別に使用する
//
// wmode = 2 : sbufに格納されているデータを0に達するまで送信
//             送信後、ALFAT側から送信されてきたACKシグナルの先頭Byte
//             の下位5ビット分のデータを受信
//             上位3ビットはACK/NACKの判別に使用する
//
// wmode = 3 : sbufに格納されているデータを0に達するまで送信
//             受信は無し
//
// *******************************************************************
void  SendLine_I2C_Data(int wmode)
{
   int i;
   int j;
   int len;
   int accode;
   int acbyte;
   int csum;
   long rd;

// 書き部分は、LCDでALFATからのシグナルをモニタするためのコード
//   for (i = 0 ; i < 20 ; i ++) lbuf[i] = ' ';
//   lbuf[20] = 0;
//   LCD_Dataout(0x14);
//   delay_ms(100);

//   i = 0;
//   while((lbuf[i++] = Get_I2C_Data()) != 0);

   j = 0;
   csum = 0;
   // ---------------------------------------------------------------
   if (wmode == 1) {
      len = sbuf[0] & 0x1F;
      len ++;
      for (i = 0; i < len ; i++) {
         csum += sbuf[i];
         Send_I2C_Data(sbuf[i]);
      }

      Send_I2C_Data(csum);

      while ((rd = Get_I2C_Data()) == 0x100);

      i = 0;
      acbyte = rd & 0x1F;
      accode = rd & 0xE0;
      lbuf[i] = rd; //rd;
      i ++;
      for (j = 0 ; j <= acbyte ; j ++) {
         lbuf[i] = Get_I2C_Data(); i ++;
      }
   // ---------------------------------------------------------------
   } else if (wmode == 2) {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

      while ((rd = Get_I2C_Data()) == 0x100);

      i = 0;
      acbyte = rd & 0x1F;
      accode = rd & 0xE0;
      lbuf[i] = rd; //rd;
      i ++;
      for (j = 0 ; j <= acbyte ; j ++) {
         lbuf[i] = Get_I2C_Data(); i ++;
      }
   // ---------------------------------------------------------------
   } else if (wmode == 3) {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

   // ---------------------------------------------------------------
   } else {
      while(sbuf[j] != 0) {
         Send_I2C_Data(sbuf[j++]);
      }

      i = 0;
      while((rd = Get_I2C_Data()) != 0x100) { lbuf[i] = rd; i ++; }
   }

   // 下位動作は wmode = 3 以外で行う
   if (wmode != 3) {

      // ACK/NACKシグナルをグローバル変数に格納
      ansc = lbuf[0];

     // 以下の部分は、LCDに受信データを表示するための設定
//      for (j = 0 ; j < i ; j ++) {
//         if (lbuf[j] < 0x20) lbuf[j] += 0xB0;
//      }
//      lbuf[i] = '<';
//      lbuf[i+1] = 0;
//      LCD_Dataout(0x14);
   }
}

// *******************************
// main function
// *******************************
void main()
{
   int8 i;

   int rd;
   long tmr1;

   float tval;
   float rhval;
   float x;
   int16 rdata;

   // ADC is not used.
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);

   //TIMER 1を内蔵クロック、8分周で使用
   setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_8 );

   // Port initial value
   output_a(0xFF);
   output_b(0xFF);
   output_c(0xFF);

   // All PORTB and PORTC are output.
   SET_TRIS_C( 0b00000000);
   SET_TRIS_B( 0b00000000);

   // Setting of PORTA
   // I2C部分は入力で固定
   SET_TRIS_A( 0b001111 );


  // 書込み回数初期化
   wcount = 0;

// -------------------------------
// LCD module 初期化
// -------------------------------

   delay_ms(50);

   LCD_RSLOW_RW(0b00110000);

   delay_ms(5);

   LCD_RSLOW_RW(0b00110000);

   delay_us(100);

   LCD_RSLOW_RW(0b00110000);

   // 8bit,1/16 duty
   LCD_RSLOW_RW(0b00111000);

   // Display ON(bit2 = 1),Cursor OFF(bit1 = 0),NO Blink(bit0 = 0)
   LCD_RSLOW_RW(0b00001100);

   // Display Clear
   LCD_RSLOW_RW(0b00000001);

   // Cursor Home
   LCD_RSLOW_RW(0b00000010);


   delay_ms(10);

// -------------------------------
// LCDに文字表示
// -------------------------------
//               1234567890
   sprintf(lbuf,"FAT002    ");
   LCD_Dataout(0x00);

// -------------------------------------------------------------------
// ALFAT は電源投入後、ブートローダーモードになるので
// 'BL' のメッセージをチェック
// -------------------------------------------------------------------

   // 'B'が来るまで受信を続ける
   while(Get_I2C_Data() != 'B');

   // 'B'の次は'L'であることを確認
   if (Get_I2C_Data() == 'L') {
      // LCDに表示
      //            1234567890
      sprintf(lbuf,"BL OK!    ");
      LCD_Dataout(0x0A);
   } else {
      // LCDにエラー表示
      //            1234567890
      sprintf(lbuf,"NG! Stop! ");
      LCD_Dataout(0x0A);

      // エラーの場合はPICをスリープ
      sleep();
   }


// -------------------------------------------------------------------
// "BL"メッセージを確認したら、'R'キャラクタを送信
// -------------------------------------------------------------------
   Send_I2C_Data('R');



// -------------------------------------------------------------------
// ブートが正常に行われると、"GHI Electoro...(略) Z:\> "を送信してくる
// ので、'>'をキャッチする
// -------------------------------------------------------------------
   i = 0;
   while (Get_I2C_Data() != '>') {
   }
   // キャッチできたら、LCDに"Z:>"を表示
   sprintf(lbuf,"Z:>");
   LCD_Dataout(0x0A);


   // このディレーは、LCDの文字を確認するためのもの(以下も同様)
   delay_ms(500);


// -------------------------------------------------------------------
// フレームモードに移行するための、コマンドを送信
// -------------------------------------------------------------------
   sprintf(sbuf,"FM\r");
   SendLine_I2C_Data(0);


// -------------------------------------------------------------------
// FAT002基板ではCFは'B'ドライブに割り当てられるので、Bドライブに移動
// -------------------------------------------------------------------
   delay_ms(500);
   sprintf(sbuf,"\xE1B");
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"B: cmd er!");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"B: cmd ok! ");
      LCD_Dataout(0x0A);
   }



// -------------------------------------------------------------------
// ファイル名 mes.datを書込みモードで新規作成(ファイルハンドル 0x01)
// -------------------------------------------------------------------
   delay_ms(500);
   sprintf(sbuf,"\x8B\x04\x77\x01mes.dat\x00");
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Open er!  ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Open OK!  ");
      LCD_Dataout(0x0A);
   }
//   while(1);

// -------------------------------------------------------------------
// 繰返しループ
// -------------------------------------------------------------------
Loop:

   // "Transmission Start" sequence
   SHT_Trans_Start();

// *******************************
// Temperature measurement command
// *******************************
   SHT_Trans(0b00000011); // Command transmission


   // SHT Time to measure temperature by 14bit accuracy
   // 210ms * 1.15 = 315ms
   delay_ms(210);

   // End Conversion check
   while(input(PIN_A4) == 1);

   // SHT data recived
   rdata = SHT_data_recive();

   // Temperature = d1 + d2 x rdata
   // d1 = -40 (VDD = 5V), d2 = 0.01 (14bit)
   tval = (float)rdata * 0.01 - 40.0;

   // "Transmission Start" sequence
   SHT_Trans_Start();

// *******************************
// Humidity measurement command
// *******************************
   SHT_Trans(0b00000101); // Command transmission

   // Time to measure temperature by 12bit accuracy
   // 55ms
   delay_ms(210);

   // End Conversion check
   while(input(PIN_A4) == 1);

   // SHT data recived
   rdata = SHT_data_recive();

   // RH = C1 + C2 x rdata + C3 x rdata x rdata
   x = (float)rdata;
   rhval = -4 + 0.0405 * x - 0.0000028 * x * x;

// *******************************
// DATA output
// *******************************

   // Temperature output
   i = 0xDF;

// 2行目に温度表示
   sprintf(lbuf,"Tmp = %5.1f (%CC)",tval,i);

   // Data output
   LCD_Dataout(0x40);


   // Humidity is written in the third line.
   sprintf(lbuf,"RH  = %5.1f (%%)",rhval);

// 3行目に湿度表示
   LCD_Dataout(0x14);

// 4行目に書込み回数を表示
   wcount ++;
   sprintf(lbuf,"Write Cnt. = %5Lu",wcount);
   LCD_Dataout(0x54);


// -------------------------------------------------------------------
// タイマ1のカウント値を取得
// -------------------------------------------------------------------
   tmr1 = get_timer1();

// -------------------------------------------------------------------
// ファイルハンドル 0x01に、19byte書き込むことをALFATに知らせる
// -------------------------------------------------------------------
   delay_ms(100);
     // 下記部分のsprintfはCCSCコンパイラで処理できなかったため、
     // sbufに直接挿入
//   sprintf(sbuf,"\xC5\x13\0\0\0\x01");
   sbuf[0] = 0xC5;
   sbuf[1] = 0x13;
   sbuf[2] = 0x00;
   sbuf[3] = 0x00;
   sbuf[4] = 0x00;
   sbuf[5] = 0x01;
   SendLine_I2C_Data(1);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"W cmd er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"W cmd ok! ");
      LCD_Dataout(0x0A);
   }
//   while(1);

// -------------------------------------------------------------------
// CFに保存するデータ
// -------------------------------------------------------------------

   sprintf(sbuf,"%5Lu %5.1f %5.1f\r\n",tmr1,tval,rhval);

// Byte数
// "%5Lu "   : 6byte
// "%5.1lf " : 6byte
// "%5.1lf"  : 5byte
// "\r\n"    : 2byte
//         計 19byte


// -------------------------------------------------------------------
// ALFAT側から書込み許可がきたら、データを送信
// -------------------------------------------------------------------
   delay_ms(100);

   SendLine_I2C_Data(2);
   if ((ansc & 0xE0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Write er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Write ok! ");
      LCD_Dataout(0x0A);
   }


// -------------------------------------------------------------------
// 書き込んだら、ALFAT内のバッファに残っているデータをCFに書き込む
// -------------------------------------------------------------------
   delay_ms(100);
   sprintf(sbuf,"\x82\x0E\x01");
   SendLine_I2C_Data(1);
   if ((ansc & 0xF0) == 0x00) {
      //            1234567890
      sprintf(lbuf,"Flush er! ");
      LCD_Dataout(0x0A);
      sleep();
   } else {
      //            1234567890
      sprintf(lbuf,"Flush OK! ");
      LCD_Dataout(0x0A);
   }

// -------------------------------------------------------------------
// 約2秒間、LCDに"SLEEP"を表示させ、これが表示されているときに
// 電源を切ると、ファイルを壊さないかもしれない
// -------------------------------------------------------------------
   delay_ms(100);
   //            1234567890
   sprintf(lbuf,"Sleep     ");
   LCD_Dataout(0x0A);
   delay_ms(2000);

// -------------------------------------------------------------------
// 以後繰返し
// -------------------------------------------------------------------
   goto Loop;

}




トップページに戻る