/******************************************************************************** * メイン・プログラム:PIC24F_BME280モジュールテスト * * PIC24Fトレーニング基板使用 * 2.4インチQVGA液晶モジュール(aitendo): UL024TF * 温湿度・気圧センサモジュール:BME280 * * 原典参考先: * @ スイッチ・サイエンスの記事 * * Condition: * 8MHz Internal RC oscillator, 4x PLL (8MHzx4= 32MHz) * Fcy=32MHz/2=16MHz, Tcy=62.5ns * * CPU: PIC24FJ64GA002 * * Step1:BME280の、Chip IDを読取り、正解であれば初期化する所までのテスト * 2017.3.14 N.Ishii * * Step2:測定値の生データを読込んで、hex表示するテスト * 2017.3.15 N.Ishii * * Step3:センサー固有の補正パラメータをレジスタから読込んで、hex表示するテスト * 2017.3.16 N.Ishii * * Step4:補正計算後、各液晶表示値に変換して表示するまでの最終テスト * 2017.3.17 N.Ishii ********************************************************************************/ #include "p24FJ64GA002.h" #include "stdio.h" #include "colorlcd_libdsPICVH.h" #include "skI2C_PIC24F_lib.h" /// コンフィギュレーション ビットの設定 _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 BME280_ADRS 0x76 // BME280のI2Cアドレス #define BME280_ID 0x60 // BME280のChip ID /// 受信データバッファ unsigned char rec_data[24]; // 読出し時の最大バイト数=24バイト:温度・気圧補正値を連続して読込む時) // レジスタ数(総バイト数)は全部で、56個(バイト単位) /// センサー固有の補正パラメータ格納用変数宣言 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; unsigned char dig_H1; int dig_H2; unsigned char dig_H3; int dig_H4; int dig_H5; char dig_H6; /// 生データ格納用変数宣言 unsigned long hum_raw, temp_raw, pres_raw; /// 補正計算関連変数宣言 long t_fine; // 表示値を、浮動小数点型に宣言し、0.0に初期化 double temp_act = 0.0, press_act = 0.0,hum_act=0.0; long temp_cal; // 温度補正結果格納変数を、符号付32bit整数型に宣言 unsigned long press_cal,hum_cal; // 気圧・湿度補正結果格納変数を、符号無し32bit整数型に宣言 //------------------------------------------------------------------------- /// LEDのポート宣言定義 #define LED LATAbits.LATA3 /// SWのポート宣言定義 #define SW1 PORTBbits.RB0 #define SW2 PORTBbits.RB1 //------------------------------------------------------------------------ /// プロトタイピング void WriteBME280(unsigned char, unsigned char); void ReadBME280(unsigned char, char); char BME280_Init(char,char); void ReadData(void); void ReadTrim(void); long calibration_T(long); unsigned long calibration_P(long); unsigned long calibration_H(long); //------------------------------------------------------------------------- /// Function Main void main(void) { char ans; char buf[32]; /// CPU Clock Pre Scalere 1:1 CLKDIV = 0; /// I/O設定 AD1PCFG = 0xFFFF; // A/D Digi 選択:全デジタルI/Oに設定 /// Setup PORT In/Out TRISB = 0x001F; // RB0,1SW入力、他(QVGAポート)は出力 // RB2 is SDA2 (Hi), RB3 is SCL2 (Hi), RB4:入力 TRISA = 0x0007; // RA4(LCD_RST/),RA3(LED) is Out, Other is Input(未使用) /// Inittalize LED OFF LED = 1; /// Set Pull Up CNPU1 = 0x0030; // Pull Up Port is RB0(SW2), RB1(SW1) /// Initialize I2C2 I2C2BRG = 0x9E; // 100kHz I2C2CON = 0x8000; // Enable I2C2 /// 液晶表示器の初期化と開始メッセージ表示 lcd_Init(); lcd_Clear(BLACK); lcd_Str(0, 0, "Start Test", CYAN, BLACK); delay_ms(3000); // 3秒後に開始 lcd_Clear(BLACK); /// センサの初期化を行う ans = BME280_Init(BME280_ID ,BME280_ADRS); if (ans == 0) { lcd_Str(0, 0, "Init OK", CYAN, BLACK); sprintf((char *)buf,"%x", rec_data[0]); // "0x60" lcd_Str(0, 2, "ID= ", CYAN, BLACK); lcd_Str(4, 2, buf, CYAN, BLACK); ReadTrim(); //補正データの読み取り(合計32バイト) delay_ms(1000); // データレートが1Hzなので1秒後から開始する lcd_Clear(BLACK); } else { lcd_Str(0, 0, "Init NG", CYAN, BLACK); while(1); // プログラム終了 } /// メイン・ループ while(1) { /// 生データ取得 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; /// 液晶に表示 sprintf((char *)buf,"%.2f ", temp_act); buf[6]= '゚'; buf[7]= 'C'; lcd_Str(0, 0, buf, CYAN, BLACK); // 温度(℃)の表示 sprintf((char *)buf,"%.2f ", hum_act); buf[6] = '%'; lcd_Str(0, 2, buf, CYAN, BLACK); // 湿度(%)の表示 sprintf((char *)buf,"%.2f ", press_act); buf[8] = 'h'; buf[9] = 'P'; buf[10] = 'a'; lcd_Str(0, 4, buf, CYAN, BLACK); // 気圧(hPa)の表示 delay_ms(1000); } } /********************************************************************* * BME280 I2C書き込み関数(1バイト書込み) * * <引数> * @ reg_adrs:レジスタ・アドレス *  A data:書込みデータ * ***********************************************************************/ void WriteBME280(unsigned char reg_adrs, unsigned char data) { I2C_Start(BME280_ADRS,RW_0); // スタートコンディションを発行〜 I2Cアドレス + Wビットを送信〜 ACK応答が、'0' になるまで待つ I2C_Send(reg_adrs); // レジスタ・アドレス送信〜 ACK応答が、'0' になるまで待つ I2C_Send(data); // 当該レジスタへデータを書き込む I2C_Stop(); // ストップコンディションを発行する } /*********************************************************************************** * BME280 I2C読込み関数 * * <引数> * @ start_adrs:読出し開始レジスタ・アドレス *  A byte_count:読出しバイト数(1〜8バイト) * ************************************************************************************/ void ReadBME280(unsigned char start_adrs, char byte_count) { unsigned char i; I2C_Start(BME280_ADRS,RW_0); // スタートコンディションを発行〜I2Cアドレス + Wビットを送信〜ACK応答が、'0' になるまで待つ I2C_Send(start_adrs); // 読出し開始番地送信〜 ACK応答が、'0' になるまで待つ I2C_rStart(BME280_ADRS,RW_1) ; // リピート・スタートコンディションを発行する〜I2Cアドレス + Rビットを送信〜ACK応答が、'0' になるまで待つ //// 当該BME280レジスタのデータを、開始アドレスから指定バイト数読出す。 (アドレスは自動インクリメント) for (i = 0; i != byte_count-1; ++i) { rec_data[i] = I2C_Receive(ACK); // 最終アドレスの前までは、読出し後、マスタへ、ACK送信 } /// 最終アドレスになって抜けて来る rec_data[i] = I2C_Receive(NOACK); // 最終アドレスの読出し後、マスタへ、NACK送信 I2C_Stop() ; // ストップコンディションを発行する } /************************************************ * BME280 初期化関数 *************************************************/ char BME280_Init(char id ,char Sensor_adrs) { char ans; /// デバイスの識別IDをチェックする処理 ReadBME280(0xD0, 1); // 読込んだIDは、rec_data[0]に格納されている。 if (rec_data[0] == BME280_ID) { //// IDが一致したならデバイスを初期化する処理 ans= 0; /// 初期値テーブルの値を、当該レジスタに書込む。 WriteBME280(0xF2, 0x01); // Ctri Hum REG: 湿度測定の有効:オーバーサンプリング値= x1 WriteBME280(0xF4, 0x27); // Ctri Meas REG: 温度・気圧の有効:オーバーサンプリング値= x1、ノーマルモード(繰り返し測定) WriteBME280(0xF5, 0xA0); // Config REG:スタンバイ時間:1秒、フィルタ無し、I2C制御で使用 } else ans = 1 ; // IDが一致しない return ans ; } /************************************************************** * 測定値の生データ読込み関数 * 各32bitで、*_raw変数に格納 ***************************************************************/ void ReadData(void) { ReadBME280(0xF7, 8); // 読込んだ各測定生データは、rec_data[0]〜[7]に、バイト型で格納されている。 /// 読込んだ各バイトデータを、ワード型で、それぞれの生データ変数に格納 pres_raw= ((unsigned long)rec_data[0] << 12) | ((unsigned long)rec_data[1] << 4) | ((unsigned long)rec_data[2] >> 4); temp_raw= ((unsigned long)rec_data[3] << 12) | ((unsigned long)rec_data[4] << 4) | ((unsigned long)rec_data[5] >> 4); hum_raw = ((unsigned long)rec_data[6] << 8) | (unsigned long)rec_data[7]; } /****************************************** * センサー補正データの取得 *******************************************/ void ReadTrim(void) { /// calibレジスタ・アドレス:0x88〜0x9Fまでの24バイトを配列(rec_data{})に読み込む ReadBME280(0x88, 24); // rec_data{0}〜 rec_data{23}に、バイト型で格納 /// まずここまで読み込んだ補正係数を、補正変数に格納 dig_T1= ((unsigned int)rec_data[1] << 8) | (unsigned int)rec_data[0]; dig_T2= ((int)rec_data[3] << 8) | (int)rec_data[2]; dig_T3= ((int)rec_data[5] << 8) | (int)rec_data[4]; dig_P1= ((unsigned int)rec_data[7] << 8) | (unsigned int)rec_data[6]; dig_P2= ((int)rec_data[9] << 8) | (int)rec_data[8]; dig_P3= ((int)rec_data[11] << 8) | (int)rec_data[10]; dig_P4= ((int)rec_data[13] << 8) | (int)rec_data[12]; dig_P5= ((int)rec_data[15] << 8) | (int)rec_data[14]; dig_P6= ((int)rec_data[17] << 8) | (int)rec_data[16]; dig_P7= ((int)rec_data[19] << 8) | (int)rec_data[18]; dig_P8= ((int)rec_data[21] << 8) | (int)rec_data[20]; dig_P9= ((int)rec_data[23] << 8) | (int)rec_data[22]; /// calibレジスタ・アドレス:0xA1の1バイトを配列(rec_data{})に読み込む ReadBME280(0xA1, 1); // rec_data{0}に、バイト型で格納 /// 読み込んだ補正係数を、補正変数に格納 dig_H1= rec_data[0]; /// calibレジスタ・アドレス:0xE1〜0xE7までの7バイトを配列(rec_data{})に読み込む ReadBME280(0xE1, 7); // rec_data{0}〜 rec_data{6}に、バイト型で格納 /// 読み込んだ補正係数を、補正変数に格納(ここで全32バイト終了) dig_H2 = ((int)rec_data[1] << 8) | (int)rec_data[0]; dig_H3 = rec_data[2]; dig_H4 = ((int)rec_data[3] << 4) | (0x0F & (int)rec_data[4]); dig_H5 = ((int)rec_data[5] << 4) | (((int)rec_data[4] >> 4) & 0x0F); dig_H6 = (char)rec_data[6]; } /************************************************ * 温度の補正計算 *************************************************/ long calibration_T(long adc_T) { long var1, var2, T; var1= ((((adc_T >> 3) - ((long)dig_T1<<1))) * ((long)dig_T2)) >> 11; var2= (((((adc_T >> 4) - ((long)dig_T1)) * ((adc_T>>4) - ((long)dig_T1))) >> 12) * ((long)dig_T3)) >> 14; t_fine= var1 + var2; T = (t_fine * 5 + 128) >> 8; return T; } /************************************************ * 気圧の補正計算 *************************************************/ unsigned long calibration_P(long adc_P) { long var1, var2; unsigned long P; var1= (((long)t_fine)>>1) - (long)64000; var2= (((var1>>2) * (var1>>2)) >> 11) * ((long)dig_P6); var2= var2 + ((var1*((long)dig_P5))<<1); var2= (var2>>2)+(((long)dig_P4)<<16); var1= (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((long)dig_P2) * var1)>>1))>>18; var1= ((((32768+var1))*((long)dig_P1))>>15); if (var1 == 0) return 0; P= (((unsigned long)(((long)1048576)-adc_P)-(var2>>12)))*3125; if (P < 0x80000000) P = (P << 1) / ((unsigned long) var1); else P = (P / (unsigned long)var1) * 2; var1= (((long)dig_P9) * ((long)(((P>>3) * (P>>3))>>13)))>>12; var2= (((long)(P>>2)) * ((long)dig_P8))>>13; P= (unsigned long)((long)P + ((var1 + var2 + dig_P7) >> 4)); return P; } /************************************************ * 湿度の補正計算 *************************************************/ unsigned long calibration_H(long adc_H) { long v_x1; v_x1= (t_fine - ((long)76800)); v_x1= (((((adc_H << 14) -(((long)dig_H4) << 20) - (((long)dig_H5) * v_x1)) + ((long)16384)) >> 15) * (((((((v_x1 * ((long)dig_H6)) >> 10) * (((v_x1 * ((long)dig_H3)) >> 11) + ((long) 32768))) >> 10) + ((long)2097152)) * ((long) dig_H2) + 8192) >> 14)); v_x1= (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((long)dig_H1)) >> 4)); v_x1= (v_x1 < 0 ? 0 : v_x1); v_x1= (v_x1 > 419430400 ? 419430400 : v_x1); return (unsigned long)(v_x1 >> 12); }