//============================================================================ // BME280気候センサーとLCD表示器を使用した温湿度気圧計測表示器 //============================================================================ // // BME280データ処理部分は「SWITCHSCIENCE」さんのサイトから // 使用させていただきました //============================================================================ //------------------------ // 初期設定 //------------------------ #include #include #include #pragma config FOSC = HS //高速オシレーター(4MHz以上)使用 #pragma config WDTE = OFF //ウォッチドッグタイマーOFF #pragma config CP = OFF //コードプロテクションOFF #pragma config PWRTE = ON //パワーアップタイマーON #pragma config LVP = OFF// //PICのクロック設定 #define _XTAL_FREQ 20000000 //PICのクロックをHzで設定(20MHz) //モニター確認用LED #define RED_led RA0 //Red LED #define YELLOW_led RA1 //Yelloe LED #define GREEN1_led RA2 //Green LED1 #define GREEN2_led RA3 //Green LED2 #define I2C_SCL RC3 //I2c SCL (clock) #define I2C_SDA RC4 //I2c SDA (data) #define RS232_TX RC6 //RS232 TX #define RS232_RX RC7 //RS232 RX //-------------------------------------------------------- // 関数定義エリア // i2c 基本入出力関数 //-------------------------------------------------------- void i2c_CONF(void); //i2c初期設定 void i2c_START(void); //スタートコンディション発行 void i2c_ReSTART(void); //再スタートコンディション発行 void i2c_STOP(void); //ストップコンディション発行 void i2c_WRITE(unsigned char); //1バイト書き込み unsigned char i2c_READ(void); //1バイト読み込み unsigned char i2c_READC(void); //1バイト連続読み込み //--------------------------------------------------------- // LCS表示制御コマンド //--------------------------------------------------------- void LCD_init(void); //LCDの初期設定 void LCD_Clear(int); //LCDクリア(0=全面、1=1行目、2=2行目) void LCD_puts(const char *p); //LCDへ連続文字表示 void LCD_Locate(unsigned char, unsigned char); //文字表示位置の設定 void LCD_CW(unsigned char); //LCDコマンド1バイト書き込み void LCD_DW(unsigned char); //LCDデータ1バイト書き込み //--------------------------------------------------------- // 気圧気温湿度センサーコマンド(PTHセンサー) //--------------------------------------------------------- unsigned char pth_IDread(void); //センサーのソフトリセットとID読み取り void pth_BREAD(unsigned char, unsigned char, unsigned char); //ブロック読み込み void pth_readTrim(void); //センサー補正値の取得 void pth_setup(void); //センサー初期設定 void pth_readData(void); //センサー計測値読み取り long int calibration_T(long int); //温度補正 unsigned long int calibration_P(signed long int); //気圧補正 unsigned long int calibration_H(signed long int); //湿度補正 //------------------------------ // その他関数 //------------------------------ void PIC_init(void); //PIC初期化 void Debug_RED(void); //デバッグ用赤色LED点滅 void Hex_Out(int); //整数を16進数で表示(ゼロサプレスしない) void FloatDisp(float); //少数を少数以下1桁で表示 //--------------------------------------------------------- // 変数定義 //--------------------------------------------------------- int i, j; //ループカウンター int disp; //文字変換する数値を代入 unsigned char S_ADRS1 = 0xA0; // LCD Slave Address1 unsigned char S_ADRS2 = 0xEC; // Senser Slave Address2 unsigned char RDDAT; //i2c受信関数データの一時保管 char str[5]; //16進文字変換結果代入 unsigned char para; //----- センサー関連変数定義 -------- float temp_act = 0.0, press_act = 0.0, hum_act = 0.0; long int temp_cal; unsigned long int press_cal, hum_cal; int buff[32]; //補正係数バッファ unsigned long int hum_raw, temp_raw, pres_raw; long int t_fine; unsigned int dig_T1; int dig_T2; int dig_T3; unsigned int dig_P1; int dig_P2; int dig_P3; int dig_P4; int dig_P5; int dig_P6; int dig_P7; int dig_P8; int dig_P9; signed char dig_H1; int dig_H2; signed char dig_H3; int dig_H4; int dig_H5; signed char dig_H6; //------------------------------------------------------- // メインプログラム //------------------------------------------------------- main() { PIC_init(); // PICの入出力ポート、割り込み、AD変換など初期設定 i2c_CONF(); // PIC設定i2c用 LCD_init(); // LCD初期化、クリアディスプレイ LCD_CW(0x0C); // LCDカーソル非表示、ブリンクなし。 //----------------------------- // PIC 起動確認用LED点滅 4回 //----------------------------- RED_led = 0; // RED LED on YELLOW_led = 0; GREEN1_led = 0; GREEN2_led = 0; __delay_ms(500); RED_led = 1; // RED LED off __delay_ms(500); RED_led = 0; // RED LED on __delay_ms(500); RED_led = 1; // RED LED off YELLOW_led = 1; GREEN1_led = 1; GREEN2_led = 1; __delay_ms(500); //------------------------ // LCD 初期メッセージ表示 //------------------------ LCD_puts("Copy_Right@"); __delay_ms(1000); LCD_Locate(0, 1); // カーソルセット LCD_puts(" VividHobby"); __delay_ms(1000); LCD_Clear(0); //LCD全クリア LCD_puts("Ready"); //1行目に表示 //------------------------------------------------------------------ // センサー読み取り、計算、表示、処理開始 //------------------------------------------------------------------ //センサーIDを読み込む disp = pth_IDread(); itoa(str, disp, 16); // 整数dispを16進文字変換 LCD_Locate(0, 1); //カーソル移動 LCD_puts("Sensor ID = "); LCD_puts(str); __delay_ms(1000); //センサーの初期設定(補正係数読み込み含む) pth_setup(); //補正係数読み込み pth_readTrim()は以下 pth_readTrim(); //補正データの読み取り(合計32バイト) //------------------------------------------------------------- //計測を連続して行う //------------------------------------------------------------- LCD_Clear(0); //LCD全クリア LCD_puts(" C % hPa"); while (1) { //センサーから生の計測データを読み出す pth_readData(); temp_cal = calibration_T(temp_raw); press_cal = calibration_P(pres_raw); hum_cal = calibration_H(hum_raw); temp_act = (double) temp_cal / 100.0; press_act = (double) press_cal / 100.0; hum_act = (double) hum_cal / 1024.0; //-- 温度表示-- LCD_Locate(0, 1); FloatDisp(temp_act); //-- 湿度表示-- LCD_Locate(6, 1); FloatDisp(hum_act); LCD_puts(" "); //-- 気圧表示-- disp = press_act; itoa(str, disp, 10); // 整数dispを16進文字変換 LCD_Locate(12, 1); LCD_puts(str); LCD_puts(" "); __delay_ms(4000); } //------------------------- ここまでを繰り返す---------------------------- } //-------------------- End of Main program -------------------------------- //======================================== //関数定義エリア //======================================== //-------------------------------------------- // センサーセットアップ(補正係数読み込み含む) //-------------------------------------------- void pth_setup(void) { unsigned int osrs_t = 3; //Temperature oversampling x 4 unsigned int osrs_p = 3; //Pressure oversampling x 4 unsigned int osrs_h = 3; //Humidity oversampling x 4 unsigned int mode = 3; //Normal mode unsigned int t_sb = 5; //Tstandby 1000ms unsigned int filter = 0; //Filter off unsigned int spi3w_en = 0; //3-wire SPI Disable unsigned int ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode; unsigned int config_reg = (t_sb << 5) | (filter << 2) | spi3w_en; unsigned int ctrl_hum_reg = osrs_h; //---------- センサーレジスターに初期設定を書き込み(各1バイト)--------- i2c_START(); i2c_WRITE(S_ADRS2); i2c_WRITE(0xF2); para = ctrl_hum_reg; i2c_WRITE(para); i2c_WRITE(0xF4); para = ctrl_meas_reg; i2c_WRITE(para); i2c_WRITE(0xF5); para = config_reg; i2c_WRITE(para); i2c_STOP(); } //------------------------------------- // センサー補正データの取得 //------------------------------------- void pth_readTrim(void) { //--------------------------------------------- // h88からA1までの25バイトを配列に読み込み表示 //--------------------------------------------- pth_BREAD(0x88, 24, 0); // レジスターアドレス 88-9F 24bytes pth_BREAD(0xA1, 1, 24); // レジスターアドレス A1 1 pth_BREAD(0xE1, 7, 25); // レジスターアドレス E1-E7 7 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 以下はデータ確認用 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LCD_Clear(0); //LCD全クリア LCD_puts("Data read OK"); __delay_ms(500); LCD_Clear(0); //LCD全クリア __delay_ms(500); //------------------------------------------- // 読み込んだデータを順次表示する(確認表示) //------------------------------------------- for (i = 0; i <= 31; i++) { LCD_Clear(0); disp = i + 0x88; LCD_puts("Adrs = "); Hex_Out(disp); disp = buff[i]; LCD_Locate(0, 1); LCD_puts("Data = "); Hex_Out(disp); __delay_ms(100); } //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // ここまでデータ確認用 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 読み込んだ補正係数を変数に代入 //----------------------------------------- dig_T1 = (buff[1] << 8) | buff[0]; dig_T2 = (buff[3] << 8) | buff[2]; dig_T3 = (buff[5] << 8) | buff[4]; dig_P1 = (buff[7] << 8) | buff[6]; dig_P2 = (buff[9] << 8) | buff[8]; dig_P3 = (buff[11] << 8) | buff[10]; dig_P4 = (buff[13] << 8) | buff[12]; dig_P5 = (buff[15] << 8) | buff[14]; dig_P6 = (buff[17] << 8) | buff[16]; dig_P7 = (buff[19] << 8) | buff[18]; dig_P8 = (buff[21] << 8) | buff[20]; dig_P9 = (buff[23] << 8) | buff[22]; dig_H1 = buff[24]; dig_H2 = (buff[26] << 8) | buff[25]; dig_H3 = buff[27]; dig_H4 = (buff[28] << 4) | (0x0F & buff[29]); dig_H5 = (buff[30] << 4) | ((buff[29] >> 4) & 0x0F); dig_H6 = buff[31]; } //------------------------------------------------------- // センサーから生の計測データを読みだす //------------------------------------------------------- void pth_readData(void) { int i = 0; unsigned long int data[8]; //レジスタアドレス F7 - FE を読み込む i2c_START(); i2c_WRITE(S_ADRS2); i2c_WRITE(0xF7); i2c_ReSTART(); //再スタート i2c_WRITE(S_ADRS2 + 0x01); for (i = 0; i <= 7; i++) { data[i] = i2c_READC(); //同じ変数の型であること。連続読み込みREADC } data[i + 1] = i2c_READ(); //同じ変数の型であること。最後の読み込みREADC i2c_STOP(); pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4); temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4); hum_raw = (data[6] << 8) | data[7]; } //------------------------------------------------------ // 温度補正 //------------------------------------------------------ long int calibration_T(long int adc_T) { long int var1, var2, T; var1 = ((((adc_T >> 3) - ((long int) dig_T1 << 1))) * ((long int) dig_T2)) >> 11; var2 = (((((adc_T >> 4) - ((long int) dig_T1)) * ((adc_T >> 4) - ((long int) dig_T1))) >> 12) * ((long int) dig_T3)) >> 14; t_fine = var1 + var2; T = (t_fine * 5 + 128) >> 8; return T; } //------------------------------------------------------ // 気圧補正 //------------------------------------------------------ unsigned long int calibration_P(long int adc_P) { long int var1, var2; unsigned long int P; var1 = (((long int) t_fine) >> 1) - (long int) 64000; var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((long int) dig_P6); var2 = var2 + ((var1 * ((long int) dig_P5)) << 1); var2 = (var2 >> 2)+(((long int) dig_P4) << 16); var1 = (((dig_P3 * (((var1 >> 2)*(var1 >> 2)) >> 13)) >> 3) + ((((long int) dig_P2) * var1) >> 1)) >> 18; var1 = ((((32768 + var1))*((long int) dig_P1)) >> 15); if (var1 == 0) { return 0; } P = (((unsigned long int) (((long int) 1048576) - adc_P)-(var2 >> 12)))*3125; if (P < 0x80000000) { P = (P << 1) / ((unsigned long int) var1); } else { P = (P / (unsigned long int) var1) * 2; } var1 = (((long int) dig_P9) * ((long int) (((P >> 3) * (P >> 3)) >> 13))) >> 12; var2 = (((long int) (P >> 2)) * ((long int) dig_P8)) >> 13; P = (unsigned long int) ((long int) P + ((var1 + var2 + dig_P7) >> 4)); return P; } //------------------------------------------------------ // 湿度補正 //------------------------------------------------------ unsigned long int calibration_H(long int adc_H) { long int v_x1; v_x1 = (t_fine - ((long int) 76800)); v_x1 = (((((adc_H << 14) -(((long int) dig_H4) << 20) - (((long int) dig_H5) * v_x1)) + ((long int) 16384)) >> 15) * (((((((v_x1 * ((long int) dig_H6)) >> 10) * (((v_x1 * ((long int) dig_H3)) >> 11) + ((long int) 32768))) >> 10) + ((long int) 2097152)) * ((long int) dig_H2) + 8192) >> 14)); v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((long int) dig_H1)) >> 4)); v_x1 = (v_x1 < 0 ? 0 : v_x1); v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1); return (unsigned long int) (v_x1 >> 12); } //---------------------------------- // PIC 初期設定 //---------------------------------- void PIC_init(void) { //PICのポート設定 ADCON0 = 0b10000000; //アナログ使用しない ADCON1 = 0b00000110; //For degital I/O TRISA = 0b00000000; TRISB = 0b00000000; TRISC = 0b10011000; // i2cポートは「入力モード」 //ポート初期化 PORTA = 0b11111111; PORTB = 0b11111111; PORTC = 0b11111111; //割り込み不使用 INTCON = 0b00000000; //TMRはフリーラン OPTION_REG = 0b11000000; TMR0 = 0; //周辺機器割り込み不使用 PIE1 = 0; //周辺機器割り込みフラグクリア PIR1 = 0; } //------------------------------------ // i2C READ one : 受信 = RDDAT //------------------------------------ unsigned char i2c_READ(void) { ACKDT = 1; RCEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す RDDAT = SSPBUF; SSPIF = 0; ACKEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す SSPIF = 0; return RDDAT; } //------------------------------------ // i2C READ Continue : 受信 = read_data //------------------------------------ unsigned char i2c_READC(void) { ACKDT = 0; RCEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す RDDAT = SSPBUF; SSPIF = 0; ACKEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す SSPIF = 0; return RDDAT; } //------------------------------------- // i2C WRITE (write_data) //------------------------------------- void i2c_WRITE(unsigned char w_data) { // unsigned char w_data; while (BF == 1); //BFが0になるまで待つ。1の間繰り返す。 SSPBUF = w_data; SSPIF = 0; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す if (ACKSTAT == 1) { SSPIF = 0; } else { SSPIF = 0; } } //----------------------------------- // i2C STOP Condition //----------------------------------- void i2c_STOP(void) { PEN = 1; while (SSPIF == 0); SSPIF = 0; } //---------------------------------- // i2C START Condition //---------------------------------- void i2c_START(void) { SEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す SSPIF = 0; } //---------------------------------- // i2C Re-START Condition //---------------------------------- void i2c_ReSTART(void) { RSEN = 1; while (SSPIF == 0); //SSPIFが1になるまで待つ。0の間繰り返す SSPIF = 0; } //---------------------------------- // i2C 設定初期化 //---------------------------------- void i2c_CONF(void) { SSPM3 = 1; SSPM2 = 0; SSPM1 = 0; SSPM0 = 0; SMP = 1; CKE = 0; SSPADD = 0x3F; SSPEN = 1; WCOL = 0; SSPOV = 0; } //------------------------------------------------------- // pth センサーリセットとID読み取り //------------------------------------------------------- unsigned char pth_IDread(void) { //--- Soft Reset --- i2c_START(); i2c_WRITE(S_ADRS2); i2c_WRITE(0xDE0); // soft resetaddress i2c_WRITE(0xB6); // reset value B6 i2c_STOP(); //--- Sensor ID read out --- i2c_START(); i2c_WRITE(S_ADRS2); i2c_WRITE(0xD0); //Sensor ID resister address i2c_ReSTART(); i2c_WRITE(S_ADRS2 + 1); i2c_READ(); // 読み取り結果はRDDAT ID shouled be h60 i2c_STOP(); return RDDAT; } //------------------------------------------------------------------------ // pth Block Read ブロック読み込み // 引数(Regis_Address, No# of bytes、配列書き込み位置) // 結果は、buff[32]に格納。 転送バイト数は、 nod、配列書き込み位置ip //------------------------------------------------------------------------ void pth_BREAD(unsigned char r_adrs, unsigned char nod, unsigned char ip) { unsigned char ipp; i2c_START(); i2c_WRITE(S_ADRS2); i2c_WRITE(r_adrs); i2c_ReSTART(); //再スタート i2c_WRITE(S_ADRS2 + 0x01); if (nod >= 2) { for (ipp = ip; ipp <= ip + nod - 2; ipp++) { buff[ipp] = i2c_READC(); //同じ変数の型であること。連続読み込みREADC } buff[ipp] = i2c_READ(); //同じ変数の型であること。最後の読み込みREADC(判断条件修正) } else { buff[ip] = i2c_READ(); //同じ変数の型であること。最後の読み込みREADC } i2c_STOP(); } //--------------------------------------------------------- // Clear LCD Screen (ACM1602) // 引数=0 全面 // 引数=1 1行目のみ // 引数=2 2行目のみ // 画面をクリア。カーソルはホームポジションに。 //--------------------------------------------------------- void LCD_Clear(int para) { if (para == 0) { LCD_CW(0x01); //LCDクリアリセット return; } if (para == 1) { LCD_Locate(0, (para - 1)); LCD_puts(" "); return; } if (para == 2) { LCD_Locate(0, (para - 1)); LCD_puts(" "); return; } } //----------------------------------------------------------- // Debug Red LED (OK) // 赤色LEDを点滅させてプログラム停止 (PORT RB7接続のLED) //------------------------------------------------------------ void Debug_RED() { while (1) { RED_led ^= 1; __delay_ms(50); } } //---------------------------------------------- // LCD Initialization // 画面クリア後カーソルはホームへセット // RAMメモリーポインター先頭 //----------------------------------------------- void LCD_init() { LCD_CW(0x01); // LCDリセット LCD_CW(0x38); LCD_CW(0x0F); LCD_CW(0x06); LCD_CW(0x80); // 表示RAM領域アドレスポインターを先頭に } //----------------------------------------------- // LCD文字表示(連続) // 現在のカーソル位置から連続して文字を書き込む // 1行目、2行目の終端を越えた文字は無視される //------------------------------------------------ void LCD_puts(const char *p) { while (*p != '\0') { LCD_DW(*p); p++; } } //----------------------------------------- // LCD Cursor Control (x, y)) //----------------------------------------- void LCD_Locate(unsigned char x, unsigned char y) { unsigned char pos; pos = 0x40 * y + x; pos = pos + 0x80; LCD_CW(pos); } //--------------------------------------------- // LCD コマンド1バイト書き込み //--------------------------------------------- void LCD_CW(unsigned char lcd_cmd) { i2c_START(); i2c_WRITE(S_ADRS1); i2c_WRITE(0x00); i2c_WRITE(lcd_cmd); i2c_STOP(); __delay_ms(5); } //--------------------------------------------- // LCD データ1バイト書き込み //--------------------------------------------- void LCD_DW(unsigned char lcd_dat) { i2c_START(); i2c_WRITE(S_ADRS1); i2c_WRITE(0x80); i2c_WRITE(lcd_dat); i2c_STOP(); __delay_ms(5); } //---------------------------------------------- // 整数を16進数x4に変換表示(ゼロサプレスしない) //---------------------------------------------- void Hex_Out(int z_hex) { if (z_hex <= 0x0FFF) LCD_puts("0"); //頭のゼロを表示 if (z_hex <= 0x00FF) LCD_puts("0"); //'0'ではだめ if (z_hex <= 0x000F) LCD_puts("0"); itoa(str, z_hex, 16); // 16進表示 LCD_puts(str); } //--------------------------------------------------- // 浮動小数を小数点以下1位で文字表示(LCD) //--------------------------------------------------- void FloatDisp(float suji) { int seisu; int syousu; seisu = suji; syousu = suji * 10 - (float) seisu * 10; itoa(str, seisu, 10); LCD_puts(str); LCD_puts("."); itoa(str, syousu, 10); LCD_puts(str); } //////////////////// End Of Program ///////////////////////////