/**************************************************************************** * メイン・プログラム:グラフ表示気圧・温湿度計テスト_5 * * GLCD:ノキア液晶5110 * 温湿度センサ:HDC1000 * 大気圧センサ:LPS25H * * 原典参考先: * @ トラ技2006年3月号 山本さんの記事 * A 「太田さんのホームページ」の記事 * * ※ TEST_5:グラフ表示温湿度計にしてみる。2CH分離表示 * * Condition: * 8MHz Internal RC oscillator * Fcy=8MHz/2=4MHz, Tcy=250ns (電池駆動を想定し、最高速:16M/4で使用) * * CPU: PIC24FJ64GA002 * * 2017.1.13-3 N.Ishii *****************************************************************************/ #include "p24FJ64GA002.h" #include "stdio.h" #include "nokiaGlcdlib.h" #include "skI2C_PIC24F_lib.h" // I2C通信用ライブラリ #include "skHDC_PIC24F.h" // HDC1000用関数ライブラリ #include "skLPS25H_PIC24F.h" // LPS25H用関数ライブラリ #define HDC1000_ADRS 0x40 // HDC1000のI2Cアドレス #define LPS25H_ADRS 0x5D // LPS25HのI2Cアドレス(SDO/SAO is HIGH) /// コンフィギュレーション ビットの設定 _CONFIG1( JTAGEN_OFF // JTAGの使用:無効 & GCP_OFF // コードプロテクト:しない & GWRP_OFF // 書き込みプロテクト:しない & BKBUG_OFF // バックグラウンドデバッグ:無効 & COE_OFF // クリップオンエミュレーション:無効 & ICS_PGx1 // EMUC/EMUDをPCG1/PGD1と共用 & FWDTEN_OFF // WDT:無効 ) /// Fosc = FRC (8MHz) _CONFIG2( IESO_OFF // 2速度スタートアップ:無効 & FNOSC_FRC // 発振器の選択:FRCを選択する & FCKSM_CSDCMD // クロック切り替え・クロックモニタ:供に無効 // & OSCIOFNC_OFF // OSCOピン機能:OSCOまたはFosc/2の出力する & OSCIOFNC_ON // OSCOピン機能:RA3ポートとする 161118 & IOL1WAY_OFF // RPレジスタプロテクト:プロテクトしない & I2C1SEL_PRI // I2C1のピン選択:主ピンを使用する & POSCMOD_NONE // 主発振器:使用しない ) #define GRAPH_LOOP_MAX 60 #define HIST_MAX 45 #define GET_NONEXT (-1) #define GET_EMPTY (-2) //// リングバッファ用 /// 温度用 char temp_hist[HIST_MAX]; // temp_hist[45]:温度値データ履歴バッファ int temp_hist_head = 0; int temp_hist_full = 1; /// 湿度用 char humi_hist[HIST_MAX]; // humi_hist[45]:温度値データ履歴バッファ int humi_hist_head = 0; int humi_hist_full = 1; /* #define HUMI_HIST_MAX 45 #define GRAPH_LOOP_MAX 60 #define HUMI_GET_NONEXT (-1) #define HUMI_GET_EMPTY (-2) */ /* /// リングバッファ用 char humi_hist[HUMI_HIST_MAX]; // humi_hist[45]:温度値データ履歴バッファで、グラフX軸間のドット数(45dot)分の要素数を持つ。 int humi_hist_head = 0; int humi_hist_full = 1; */ int graph_count = GRAPH_LOOP_MAX; // 浮動小数変数 double Humi ; // 湿度の値を保存する変数 double Temp ; // 温度の値を保存する変数 double Press ; // 大気圧の値を保存する変数 // 関数のプロトタイプ宣言 //void PressureRead() ; void HDC_Read() ; //void print_temp(char Temperature, char temp_sign); void print_Yaxis(void); void print_graph(void); void draw_memori(int, int); void add_temp(char); int get_temp(int, char *); void add_humi(char); int get_humi(int, char *); void main(void) { int ans1,ans2 ; char buf[12] ; //// I/O設定 AD1PCFG = 0xFFFF; // A/D Digi 選択:全デジタルI/Oに設定 CLKDIV = 0x0000; // System Clock devider 1:1 /// Setup PORT In/Out TRISB = 0x000F; // RB0,1:プロット間隔設定ピン入力、他は出力 // RB2 is SDA2 (Hi), RB3 is SCL2 (Hi) /// Set Pull Up CNPU1 = 0x0030; // Pull Up Port is RB0(ピン1), RB1(ピン2) /// Initialize I2C2 I2C2BRG = 0x27; // (Fcy/Fscl-FCY/10E6)-1=(4E6/100E3-4E6/10E6)-1=38.6=39 I2C2CON = 0x8000; // Enable I2C2 TRISAbits.TRISA3= 0; // 赤LED:デバッグ用 TRISAbits.TRISA4= 0; // 緑LED:デバッグ用 LATAbits.LATA3 = 1; // 赤LED消灯 LATAbits.LATA4 = 1; // 緑LED消灯 /// 液晶表示器の初期化と開始メッセージ表示 LCD_init(); LCD_locate(0,0); // 原点(左上)に設定 LCD_clear(LCD_WIDTH * LCD_BANKS); // 全画面クリア LCD_ROMstr("Start Test !!"); // 開始メッセージ表示 delay_ms(3000); // 3秒後に開始 LCD_clear(LCD_WIDTH * LCD_BANKS); // 全画面クリア LCD_locate(0,0); /// 両センサの初期化を行う ans1 = HDC_Init(HDC1000_ID,HDC1000_ADRS) ; // 湿度センサーの初期化を行う ans2 = PressureInit(LPS25H,LPS25H_ADRS) ; // 大気圧センサーの初期化を行う if ((ans1 == 0) && (ans2 == 0)) { LCD_ROMstr("Init OK") ; delay_ms(1000) ; // データレートが1Hzなので1秒後から開始する } else { LCD_ROMstr("Init NG") ; while(1) ; // プログラム終了 } while(1) { LCD_clear(LCD_WIDTH * LCD_BANKS); // 全画面クリア LCD_locate(0,0); /// 温湿度センサーから湿度・温度値を読出し、液晶表示する HDC_Read() ; sprintf((char *)buf,"%.2f",Temp) ; LCD_locate(0,0) ; LCD_ROMstr(buf) ; // 温度(℃)の表示 LCD_locate(18,1) ; LCD_ROMstr("゚C") ; sprintf((char *)buf,"%.2f ",Humi) ; LCD_locate(0,3) ; LCD_ROMstr(buf) ; // 湿度(%)の表示 LCD_locate(24,4) ; LCD_char('%') ; //// 1分ごとの温度を保存する(リングバッファによる温度履歴の管理処理) ++graph_count; if (graph_count >= GRAPH_LOOP_MAX) { graph_count = 0; /// 温度データをリングバッファに格納 add_temp((char)Temp); /// 湿度データをリングバッファに格納 add_humi((char)Humi); } print_Yaxis(); // グラフのY軸を表示 print_graph(); // 温度値履歴グラフを表示 delay_ms(1000) ; } } /******************************************************************************* * ans = HDC_Read() * * 湿度・温度を読込む処理 * * 読み込まれた湿度(%)はHumi変数に、温度値(℃)はTemp変数に其々格納されます。 * * この処理は約15ms程時間が掛かります。 * * ans : 0=正常 1=異常(相手からACKが返ってこない) * * ============================================================================ * * * * PIC24F用に改修 * * 2017/1/2 N.Ishii * *******************************************************************************/ void HDC_Read() { union { unsigned int i ; unsigned char c[2] ; } data ; // 湿度データを受信する HDC_Receive(HUMI_ADRS,(unsigned char *)data.c) ; Humi = (double)data.i / 65536.0 ; Humi = Humi * 100.0 ; // 温度データを受信する HDC_Receive(TEMP_ADRS,(unsigned char *)data.c) ; Temp = (double)data.i / 65536.0 ; Temp = (Temp * 165.0) - 40.0 ; } /******************************************************************************* * ans = PressureRead() * * 圧力・温度を読込み気圧値を計算する処理 * * 計算された気圧値(hPa)はPress変数に、温度値(℃)はTemp変数に其々格納されます。* * ans : 0=正常 1=異常(相手からACKが返ってこない) * * ============================================================================ * * * * PIC24F用に改修 * * 2017/1/2 N.Ishii * *******************************************************************************/ void PressureRead() { unsigned char data[6] ; // 圧力と温度データを受信する(このデータはデバイス内部で移動平均化されています) PressureReceive(PRESS_OUT_ADRS,&data[0],3) ; // 圧力値 PressureReceive(TEMP_OUT_ADRS,&data[3],2) ; // 温度値 // 大気圧の計算を行う Press = ((unsigned long)data[2]<<16) + ((unsigned long)data[1]<<8) + data[0] ; Press = Press / 4096.0 ; // hPa /* // 温度の計算を行う→ 温度は、HDC1000の方で行うので、コメントアウト Temp = (int)(1 + ~((unsigned int)data[4]<<8 | data[3])) * -1 ; Temp = 42.5 + (Temp / 480.0) ;// ℃ */ } /************************** * グラフのY軸表示 ***************************/ void print_Yaxis(void) { int x, y; unsigned char c; c = 0xff; x = LCD_MAX_X - HIST_MAX - 2; /// 縦線を表示 for (y = 0; y < 6; y++) { LCD_locate(x, y); LCD_set_data(&c, 1); LCD_locate(x + HIST_MAX + 1, y); LCD_set_data(&c, 1); } //// 以下、分離表示にした場合の、刻み(目盛)描画には、ライブラリの、draw_point関数は不適当なので、draw_memori関数をメインに追加し使用した。 /// 温度軸:2℃ごとの刻みを表示→ 0〜 44℃ for (y = 25; y < 48; y += 11) { draw_memori(x-1, y); draw_memori(x + HIST_MAX + 2, y); } /// 湿度軸:4%ごとの刻みを表示→ 0〜 92% for (y = 0; y < 23; y += 11) { draw_memori(x-1, y); draw_memori(x + HIST_MAX + 2, y); // 後で、HIST_MAXは、両社共通なので、HIST_MAXにする予定 } } /********************************************************************************** * 目盛描画関数 *---------------------------------------------------------------------------------- * 入力: int x, int y * 出力: 無し *---------------------------------------------------------------------------------- * 備考: Y軸は、下側が最小、上側が最大(ノキアLCDのY軸を反転して表示する)。 * 0 <= x <= 83 , 0 <= y <= 47 * ライブラリの、draw_point関数とは違い、yの最大・最小値に対するリミッタ * がない目盛のドット描画専用 *================================================================================== * 2ch分離表示のため修正追加:N.Ishii 170113-3 ***********************************************************************************/ void draw_memori(int x, int y) { int bank_y; unsigned char pat_y; bank_y = LCD_MAX_BANK - (y / 8); // y軸反転位置にバンクを決定 pat_y = 0b10000000 >> (y % 8); // バンク内のMSB側を最小値とすることでY軸表現が下側が0となる LCD_locate(x, bank_y); // x位置のバンクy LCD_set_data(&pat_y, 1); // バンクyへ8ビットパターンを書き込む } /*********************************** * 温湿度値履歴グラフを表示 ************************************/ void print_graph() { char temp_hist_val; char humi_hist_val; int temp, humi, p, col; p = -1; col = 0; /// 温度値履歴グラフを表示 while ((p = get_temp(p, &temp_hist_val)) != GET_EMPTY) { temp = (int)temp_hist_val; draw_point(LCD_MAX_X - col - 2, 25+(temp/2), 1); if (p < 0) break; ++col; } p = -1; col = 0; /// 湿度値履歴グラフを表示 while ((p = get_humi(p, &humi_hist_val)) != GET_EMPTY) { humi = (int)humi_hist_val; draw_point(LCD_MAX_X - col - 2, humi/4, 0); if (p < 0) break; ++col; } } //// 以下は、リングバッファ用関数------------------------------------------------------------------------- /**************************************************** * 温度データをリングバッファに格納 *****************************************************/ void add_temp(char t) { temp_hist[temp_hist_head] = t; // 温度データ履歴バッファ(temp_hist[0]から順)に、温度値を格納 ++temp_hist_head; // バッファアドレスをインクリメント if (temp_hist_head >= HIST_MAX) { // temp_hist[44]まで(つまり、HIST_MAX=45)格納したら temp_hist_full = 1; // fullフラグをセットし、 temp_hist_head = 0; // headフラグをリセット } } /**************************************************** * 湿度データをリングバッファに格納 *****************************************************/ void add_humi(char h) { humi_hist[humi_hist_head] = h; // 温度データ履歴バッファ(humi_hist[0]から順)に、温度値を格納 ++humi_hist_head; // バッファアドレスをインクリメント if (humi_hist_head >= HIST_MAX) { // humi_hist[44]まで(つまり、TEMP_HIST_MAX=45)格納したら humi_hist_full = 1; // fullフラグをセットし、 humi_hist_head = 0; // headフラグをリセット } } /**************************************************** * リングバッファから温度データを取得 *****************************************************/ int get_temp(int p, char *t) { int i; if (!temp_hist_full && (temp_hist_head == 0)) { *t = 0; return GET_EMPTY; } if (p < 0) { i = temp_hist_head; } else { i = p; } --i; if (i < 0) { i = HIST_MAX - 1; } *t = temp_hist[i]; if (temp_hist_full) { if (i == temp_hist_head) return GET_NONEXT; else return i; } else { if (i == 0) return GET_NONEXT; else return i; } } /**************************************************** * リングバッファから湿度データを取得 *****************************************************/ int get_humi(int p, char *h) { int i; if (!humi_hist_full && (humi_hist_head == 0)) { *h = 0; return GET_EMPTY; } if (p < 0) { i = humi_hist_head; } else { i = p; } --i; if (i < 0) { i = HIST_MAX - 1; } *h = humi_hist[i]; if (humi_hist_full) { if (i == humi_hist_head) return GET_NONEXT; else return i; } else { if (i == 0) return GET_NONEXT; else return i; } }