/**************************************************************************** * メイン・プログラム:QVGA表示気圧・温湿度計テスト2 * * PIC24Fトレーニング基板使用 * 2.4インチQVGA液晶モジュール(aitendo): UL024TF * 温湿度センサ:HDC1000 * 大気圧センサ:LPS25H * * 原典参考先: * @ トラ技2006年3月号 山本さんの記事 * A 「太田さんのホームページ」の記事 * B 「きむ茶工房ガレージハウス」の記事 * * Condition: * 8MHz Internal RC oscillator, 4x PLL (8MHzx4= 32MHz) * Fcy=32MHz/2=16MHz, Tcy=62.5ns * * CPU: PIC24FJ64GA002 * * 2017.1.25 初期作成 N.Ishii * 2017.2.22 ソフトVUP(TEST→ TEST_2) * @ 表示チラツキ大幅に減らした。 * A 1秒割込みにより、タイムスケジュール *****************************************************************************/ #include "p24FJ64GA002.h" #include "stdio.h" #include "colorlcd_libdsPICVH.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 (Fosc=32MHz) _CONFIG2( IESO_OFF // 2速度スタートアップ:無効 & FNOSC_FRCPLL // 8MHz Internal RC oscillator, 4x PLL-> 8MHzx4=32MHz & FCKSM_CSDCMD // クロック切り替え・クロックモニタ:供に無効 & OSCIOFNC_ON // OSCOピン機能:RA3ポートとする 161118 & IOL1WAY_OFF // RPレジスタプロテクト:プロテクトしない & I2C1SEL_PRI // I2C1のピン選択:主ピンを使用する & POSCMOD_NONE // 主発振器:使用しない ) #define HIST_MAX 151 // 履歴ポイント:151max 170121 #define GET_NONEXT (-1) #define GET_EMPTY (-2) #define PLOT_INTERVAL_SW PORTBbits.RB0 // SW2:電源ON時のみ読込み→ プロット間隔設定用でレベルセンス #define HOLD_SW PORTBbits.RB1 // SW1:更新待機期間のみ読込み→ ホールドON/OFF用でエッジセンス割込み #define LED LATAbits.LATA3 //// リングバッファ用 /// 温度 char temp_hist[HIST_MAX]; // temp_hist[151]:温度値データ履歴バッファ int temp_hist_head = 0; int temp_hist_full = 1; /// 湿度 char humi_hist[HIST_MAX]; // humi_hist[151]:湿度値データ履歴バッファ int humi_hist_head = 0; int humi_hist_full = 1; /// 気圧 int pres_hist[HIST_MAX]; // pres_hist[151]:気圧値データ履歴バッファ int pres_hist_head = 0; int pres_hist_full = 1; int graph_count; int GraphLoopMax; // 浮動小数変数 double Humi ; // 湿度の値を保存する変数 double Temp ; // 温度の値を保存する変数 double Press ; // 大気圧の値を保存する変数 char HOLD_ON_flag = 0; char hold_status = 0; char EndFlag = 0; // 関数のプロトタイプ宣言 void PressureRead() ; void HDC_Read() ; void print_axis(void); void print_graph(unsigned short, unsigned short, unsigned short); void add_temp(char); int get_temp(int, char *); void add_humi(char); int get_humi(int, char *); void add_pres(int); int get_pres(int, int *); void main(void) { int ans1,ans2 ; //// I/O設定 AD1PCFG = 0xFFFF; // A/D Digi 選択:全デジタルI/Oに設定 CLKDIV = 0x0000; // System Clock devider 1:1 /// Setup PORT In/Out TRISB = 0x000F; // RB0,1:プロット間隔設定SW、ホールドSW入力、他(QVGAポート)は出力 // RB2 is SDA2 (Hi), RB3 is SCL2 (Hi) TRISA = 0x000F; // RA4(LCD_RST/) is Out, Other is Input /// Set Pull Up CNPU1 = 0x0030; // Pull Up Port is RB0(SW2), RB1(SW1) // Set Switch Change Notification Interrupts CNEN1 = 0x0020; // Valid SW2:CN5/RB1 IPC4bits.CNIP = 5; /// Initialize I2C2 I2C2BRG = 0x9E; // 100kHz I2C2CON = 0x8000; // Enable I2C2 TRISAbits.TRISA3= 0; // 緑LED:デバッグ用 LED = 1; // 緑LED消灯 /// 液晶表示器の初期化と開始メッセージ表示 lcd_Init(); lcd_Clear(BLACK); lcd_Str(0, 0, "Start Test_2", CYAN, BLACK); delay_ms(1000); lcd_Clear(BLACK); //// 固定値表示 /// 単位 lcd_Str(3, 7, "゚C", WHITE, BLACK); lcd_Str(4, 11, "%", WHITE, BLACK); lcd_Str(4, 1, "hPa", WHITE, BLACK); //// 目盛値表示 /// 湿度 lcd_Str(21, 16, "0", WHITE, BLACK); lcd_Str(21, 13, "50", WHITE, BLACK); lcd_Str(21, 10, "100", WHITE, BLACK); /// 温度 lcd_Str(21, 9, "0", WHITE, BLACK); lcd_Str(21, 8, "20", WHITE, BLACK); lcd_Str(21, 6, "50", WHITE, BLACK); /// 気圧 lcd_Str(21, 5, "960", WHITE, BLACK); lcd_Str(21, 2, "1000", WHITE, BLACK); lcd_Str(21, 0, "1040", WHITE, BLACK); //// プロット間隔設定SW読込みと、時間軸レンジ表示 if(PLOT_INTERVAL_SW) { graph_count= 60; GraphLoopMax= 60; lcd_Str(0, 16, "30min/D", WHITE, BLACK); } else { graph_count=600; GraphLoopMax= 600; lcd_Str(0, 16, "5h/D ", WHITE, BLACK); } /// 両センサの初期化を行う ans1 = HDC_Init(HDC1000_ID,HDC1000_ADRS) ; // 湿度センサーの初期化を行う ans2 = PressureInit(LPS25H,LPS25H_ADRS) ; // 大気圧センサーの初期化を行う if ((ans1 == 0) && (ans2 == 0)) { /// タイマ1の初期設:T1= 1/(Fcy/(PR1+1))= 1/((16000000/256)/62499+1)= 1Sec (PS=1/256) PR1 = 62499; IPC0bits.T1IP = 5; // Interrupt Priority Level 5 T1CON = 0b0000000000110000; // Inittalize T1(未だタイマーoff) IFS0bits.T1IF = 0; IEC0bits.T1IE = 1; // T1割込み許可 /// T1 ON T1CONbits.TON= 1; // データレートが1Hzなので1秒後から開始する } else { lcd_Str(0, 0, "Init NG", CYAN, BLACK); while(1) ; // プログラム終了 } while(1) { if(EndFlag) { // 割込み処理終了 EndFlag= 0; IEC1bits.CNIE = 1; // SW割込み許可 この期間のみ割込み許可 print_axis(); // グラフの座標軸を表示 print_graph(MAGENTA, CYAN, YELLOW); // 温度値履歴グラフを表示 /// Cheack HOLD SW Status while (HOLD_ON_flag) { hold_status = 1; // 1秒更新待ち期間に、HOLD SWが押されたら、再度押されるまでホールド維持 IEC0bits.T1IE = 0; // T1割込み禁止 } hold_status = 0; // 再度押されたらホールド解除 IEC1bits.CNIE = 0; // SW割込み禁止 IEC0bits.T1IE = 1; // T1割込み許可 } } } /****************************************************** * タイマ1割り込み処理関数 * 1秒周期: ********************************************************/ void __attribute__ ((interrupt, no_auto_psv)) _T1Interrupt(void) { char buf[7]; IFS0bits.T1IF = 0; // 割り込みフラグクリア // LED = !LED; /// 温湿度センサーから湿度・温度値を読出し、液晶表示する HDC_Read() ; sprintf((char *)buf,"%.2f",Temp); lcd_Str(0, 6, " ", WHITE, BLACK); // 更新前の数値表示(最大6文字分)をクリアしてから、更新表示 lcd_Str(0, 6, buf, WHITE, BLACK); // 温度(℃)の表示 sprintf((char *)buf,"%.2f",Humi); lcd_Str(0, 10, " ", WHITE, BLACK); // 更新前の数値表示(最大6文字分)をクリアしてから、更新表示 lcd_Str(0, 10, buf, WHITE, BLACK); // 温度(%)の表示 /// 気圧センサーから、気圧値を読出し、液晶表示する。 PressureRead() ; // 結果は、Press(フロート型)に格納されている sprintf((char *)buf,"%.2f",Press); lcd_Str(0, 0, " ", WHITE, BLACK); // 更新前の数値表示(最大7文字分)をクリアしてから、更新表示 lcd_Str(0, 0,buf, WHITE, BLACK); // 気圧(hPa)の表示 print_graph(BLACK, BLACK, BLACK); // 過去の履歴ラインを消す //// 1分又は、10分ごとの温度を保存する(リングバッファによる温度履歴の管理処理) ++graph_count; if (graph_count >= GraphLoopMax) { graph_count = 0; /// 温度データをリングバッファに格納 add_temp((char)Temp); /// 湿度データをリングバッファに格納 add_humi((char)Humi); /// 気圧データをリングバッファに格納 add_pres((int)Press); } EndFlag= 1; } /*********************************************** * Switch Change Notification Interrupts ************************************************/ void __attribute__((interrupt, no_auto_psv)) _CNInterrupt(void) { delay_ms(10); if (!hold_status) { // hold_status -> 0: RUN if (!HOLD_SW) HOLD_ON_flag = 1; } else { // hold_status -> 1: HOLD_ON Loop if (!HOLD_SW) HOLD_ON_flag = 0; } IFS1bits.CNIF = 0; // Clear CN Interrupt Flag } /******************************************************************************* * 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) ;// ℃ */ } /************************** * グラフの座標軸表示 ***************************/ void print_axis(void) { int i; //// X、Y座標軸表示 /// 湿度座標:0〜100% 10%刻み/ 時間軸は、30分刻みで、開始点0分〜 150分後まで for(i=99; i<= 249; i+=30) lcd_Line(i, 0, i, 100, BROWN); // X axis(時間軸:x座標が変化) for(i=0; i<= 100; i+=10) lcd_Line(99, i, 249, i, BROWN); // Y axis(横線:y座標が変化) /// 温度座標:0〜50℃ 10℃刻み for(i=99; i<= 249; i+=30) lcd_Line(i, 102, i, 152, BROWN); // X axis(時間軸:x座標が変化) for(i=102; i<= 152; i+=10) lcd_Line(99, i, 249, i, BROWN); // Y axis(横線:y座標が変化) /// 気圧座標:960〜1040hPa 10hPa刻み for(i=99; i<= 249; i+=30) lcd_Line(i, 154, i, 234, BROWN); // X axis(時間軸:x座標が変化) for(i=154; i<= 234; i+=10) lcd_Line(99, i, 249, i, BROWN); // Y axis(横線:y座標が変化) } /****************************************** * 温湿度値履歴グラフを表示 *******************************************/ void print_graph(unsigned short T_Color, unsigned short H_Color, unsigned short P_Color) { char temp_hist_val; char humi_hist_val; int pres_hist_val; int temp, humi, pres, p, col; p = -1; col = 0; /// 温度値履歴グラフを表示 while ((p = get_temp(p, &temp_hist_val)) != GET_EMPTY) { temp = (int)temp_hist_val; if((temp >= 0) && (temp <= 50)) { // 通常処理 lcd_Pixel(249 - col, 137-temp ,T_Color); // x=249の位置(右端Y座標軸上)から、プロット:170121 } else { if(temp > 50) { // 50℃を超えたら、リミット処理 lcd_Pixel(249 - col, 87 ,T_Color); } else if(temp < 0) { // 0℃を下回ったら、リミット処理 lcd_Pixel(249 - col, 137 ,T_Color); } } if (p < 0) break; ++col; } p = -1; col = 0; /// 湿度値履歴グラフを表示 while ((p = get_humi(p, &humi_hist_val)) != GET_EMPTY) { humi = (int)humi_hist_val; if(humi <= 100) { // 通常処理 lcd_Pixel(249 - col, 239-humi ,H_Color); // x=248の位置から、プロット } else { // 100%を超えたら、リミット処理 lcd_Pixel(249 - col, 139 ,H_Color); } if (p < 0) break; ++col; } p = -1; col = 0; /// 気圧値履歴グラフを表示 while ((p = get_pres(p, &pres_hist_val)) != GET_EMPTY) { pres = pres_hist_val; if((pres >= 960) && (pres <= 1045)) { // 通常処理 lcd_Pixel(249 - col, 85-(pres-960) ,P_Color); // x=248の位置から、プロット } else { if(pres > 1040) { // 1040hPaを超えたら、リミット処理 lcd_Pixel(249 - col, 5 ,P_Color); } else if(pres < 960) { // 960hPaを下回ったら、リミット処理 lcd_Pixel(249 - col, 85 ,P_Color); } } 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[149]まで(つまり、HIST_MAX=150)格納したら 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[149]まで(つまり、TEMP_HIST_MAX=150)格納したら humi_hist_full = 1; // fullフラグをセットし、 humi_hist_head = 0; // headフラグをリセット } } /**************************************************** * 気圧データをリングバッファに格納 *****************************************************/ void add_pres(int pr) { pres_hist[pres_hist_head] = pr; // 気圧データ履歴バッファ(pres_hist[0]から順)に、気圧値を格納 ++pres_hist_head; // バッファアドレスをインクリメント if (pres_hist_head >= HIST_MAX) { // pres_hist[149]まで(つまり、PRES_HIST_MAX=150)格納したら pres_hist_full = 1; // fullフラグをセットし、 pres_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; } } /**************************************************** * リングバッファから気圧データを取得 *****************************************************/ int get_pres(int p, int *pr) { int i; if (!pres_hist_full && (pres_hist_head == 0)) { *pr = 0; return GET_EMPTY; } if (p < 0) { i = pres_hist_head; } else { i = p; } --i; if (i < 0) { i = HIST_MAX - 1; } *pr = pres_hist[i]; if (pres_hist_full) { if (i == pres_hist_head) return GET_NONEXT; else return i; } else { if (i == 0) return GET_NONEXT; else return i; } }