/* 気圧センサ LPS25Hの動作テスト センサーをSPIモードで動かし、結果をSPIの液晶に表示 液晶はaitendoのFSTN液晶、モノクロ、128x64、SPI(UC1701) 海面気圧はロータリーエンコーダーで設定しEEPROMに記憶。 次回起動時は前回設定した値を使う。 スケッチサイズ27664バイト, 内部8MMHz用にスピード調整 2015/4/14 ラジオペンチ、http://radiopench.blog96.fc2.com/ */ #include // FSTN液晶 #include #include #include // ロータリーエンコーダー読取り用割込み #include #define enc_A 2 // ロータリーエンコーダ A相 #define enc_B 3 //            B相 #define LED 4 // LEDピン(Powと状態表示) #define LPS25H_cs 8 // LPS25HのCS(Chip SElect) float p0, hpa, qnh, elev; float Pdiff = -4.9; // 気圧補正値(センサ誤差の補整値) unsigned int p0x10; // 海面気圧(p0 hPa)の10倍の値をint型で保持 unsigned int p0_EEPROM; volatile int diff = 0; U8GLIB_MINI12864 u8g(10, 9); // u8glibをハードウエアSPIで動かす,(UC1701) void setup(void) { pinMode(enc_A, INPUT); // ロータリーエンコーダーA digitalWrite(2, HIGH); // プルアップ pinMode(enc_B, INPUT); // ロータリーエンコーダーB digitalWrite(3, HIGH); // プルアップ pinMode(LED, OUTPUT); // LED表示(HIGHでLED点灯 digitalWrite(LED, HIGH); // 電源ON表示 pinMode(LPS25H_cs, OUTPUT); // 気圧センサーのCS digitalWrite(LPS25H_cs, HIGH); SPI.begin() ; // SPI開始 SPI.setBitOrder(MSBFIRST) ; // ビットオーダー SPI.setClockDivider(SPI_CLOCK_DIV4) ; // SPI CLK倍率設定(16MHz/4) SPI.setDataMode(SPI_MODE3) ; // クロックとデータ定義 p0_EEPROM = EEPROM.read(0) * 256 + EEPROM.read(1); // EEPROMから海面気圧を読み出し if ( (p0_EEPROM > 10400) || ( p0_EEPROM < 9800)) { // 変な値だったら p0_EEPROM = 10130; // 1013hPaに修正 EEPROM.write(0, p0_EEPROM / 256); EEPROM.write(1, p0_EEPROM % 256); } p0x10 = p0_EEPROM; // 海面気圧の値を設定 u8g.setContrast(175); // 液晶のコントラスト設定 LPS25H_setup(); // LPS25Hに測定条件設定 delay(100); // 状態が落ち着くまでちょっと待つ MsTimer2::set(1, timerIRQ); // ロータリーエンコーダ読取り用の割込み MsTimer2::start(); } void loop(void) { hpa = LPS25H_mesure(); // 気圧測定 p0 = rotary_value() / 10.0; // ロータリーエンコーダで海面気圧設定 qnh = p0 * 0.029536; // QNH換算値算出 elev = 153.8 * (15 + 273.2) * (1 - pow(hpa / p0, 0.1902)); // 標高計算 u8g.firstPage(); // ディスプレイ ループ開始 do { lcdDisp(); } while ( u8g.nextPage() ); delay(20); // 8MHzクロック用設定(16MHzなら100) } void LPS25H_setup() { // 気圧センサ測定条件設定 LPS25H_write(0x10, 0x05); // アベレージング回数=気圧32回、温度16回 LPS25H_write(0x20, 0x84); // PD=1, OneShot Mode, BDU=1 LPS25H_write(0x2E, 0xDF); // FIFO移動平均モード、サンプル数=32 LPS25H_write(0x21, 0x40); // FIFO=Enable } float LPS25H_mesure() { // センサーから気圧読み出し float p; unsigned long val, data; MsTimer2::stop(); // タイマー割込み禁止 LPS25H_write(0x21, LPS25H_read(0x21) | 0x01); // 変換スタートビットを立て while ((LPS25H_read(0x21) & 0x01) == true) { // 変換完了まで待つ } val = LPS25H_read(0x28); // read XL data = LPS25H_read(0x29); // read L data = data << 8; val = val | data; data = LPS25H_read(0x2A); // read H data = data << 16; val = val | data; p = val / 4096.0; // 換算係数を掛けてhpaを計算 p = p + Pdiff; // センサ誤差補正 MsTimer2::start(); // タイマー割込み再開 return p; // 気圧の値をhPa単位で返す } void LPS25H_write(byte adr, byte data) { digitalWrite(LPS25H_cs, LOW); // LPS25H CS ON SPI.transfer(adr); SPI.transfer(data); digitalWrite(LPS25H_cs, HIGH); // LPS25H CS off } byte LPS25H_read(byte adr) { byte ret; adr = adr | 0x80; // 最上位ビット=1でWrite digitalWrite(LPS25H_cs, LOW); // LPS25H CS ON SPI.transfer(adr); ret = SPI.transfer(0); digitalWrite(LPS25H_cs, HIGH); // LPS25H CS off return ret; } void lcdDisp() { // 液晶表示 u8g.setFont(u8g_font_helvB24); // 大きい文字で u8g.setPrintPos(20, 30); u8g.print(elev, 1); // 標高表示 u8g.setFont(u8g_font_unifont); u8g.print("m"); u8g.setPrintPos(0, 48); u8g.print("Px="); u8g.print(hpa, 2); u8g.print("hPa"); // 気圧測定値 u8g.setPrintPos(0, 63); u8g.print("Po="); u8g.print(p0, 1); u8g.print("("); // 海面気圧 hPa u8g.print(qnh, 2); u8g.print(")"); // 海面気圧 QNH } unsigned int rotary_value() { // ロータリーエンコーダの値を海面気圧に反映 static int n = 0; noInterrupts(); p0x10 += diff; // 海面気圧設定値を反映 diff = 0; interrupts(); p0_EEPROM = EEPROM.read(0) * 256 + EEPROM.read(1); if (p0x10 == p0_EEPROM) { // EEPROMの値と同じだったら n = 0; // カウンタリセット return p0x10; // 海面気圧返してすぐに抜ける } else { n++; if (n == 50) { // 違う状態が10秒続いたら(0.2秒×50回=10秒) MsTimer2::stop(); // タイマー割込み停止 EEPROM.write(0, p0x10 / 256); // EEPROMを現在値に書き換え EEPROM.write(1, p0x10 % 256); MsTimer2::start(); // タイマー割込み再開 n = 0; } return p0x10; // どちらにしても海面気圧を返して抜ける } } void timerIRQ() { // MsTimer2割込み処理(ロータリーエンコーダ読取り) static byte bp = 0; // エンコーダーの状態記録バッファ bp = bp << 1; if (digitalRead(enc_A) == HIGH) { // A相の状態を bp |= 0x01; // bpの末尾に記録 } bp = bp << 1; if (digitalRead(enc_B) == HIGH) { // B相の状態を bp |= 0x01; // bpの末尾に記録 } bp &= 0x0F; // 下位4ビットを残して上位をクリア // if (bp == 0b0111) { // このビットパターンと一致していたら if ((bp == 0b0111) | (bp == 0b1000)) { // 倍クリックタイプの場合はこちら diff ++; // インクリメント } // if (bp == 0b1011) { // このビットパターンと一致していたら、 if ((bp == 0b1011) | (bp == 0b0100)) { // 倍クリックタイプの場合はこちら diff --; // デクリメント } if (diff != 0) { // 値がゼロでなかったら digitalWrite(LED, LOW); // ロータリーエンコーダーLED消灯 } else { digitalWrite(LED, HIGH); // ロータリーエンコーダーLED点灯 } }