- ● 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; }