/* LPS331APを使った気圧/高度計 ラジオペンチ 2014/5/16 http://radiopench.blog96.fc2.com/ 長針一回転を500mに変更。短針で5000mまで直読可能とした 11262バイト */ #define cwInterval 25 // デフォルト=25 #define ccwInterval 35 // デフォルト=35 #define scaleFactor 7.2 // 7.2パルス/m (500m=3600pulse) #include #include LiquidCrystal lcd(12,11,5,4,3,2); // 液晶シールド使用 float hPa, temp, alt; long hPaBin; long tempBin; long hPaDataBin[30]; // 移動平均計算用配列 max=30まで確保 long tempDataBin[30]; int lps331_I2C_adr = 0x5d; // SDO=HIGHなら0x5D long altP, altPlast, altPxx; // 針の位置指定変数 intからlongへ変更20140516 int drivePulse; boolean flag = true; // 駆動極性フラグ unsigned int cwPulse = 17; // 順回転パルス幅 標準は17mS unsigned int ccwPulse1 = 3500; // 逆回転パルス幅1 unsigned int ccwPulse2 = 12000; // 逆回転パルス幅2(値の上限は16383) void setup(){ pinMode(7, INPUT); // 針位置合わせ CW digitalWrite(7, HIGH); // プルアップ pinMode(8, INPUT); // 針位置合わせ CCW digitalWrite(8, HIGH); // プルアップ pinMode(9, OUTPUT); // conect coil thrugh 220Ω pinMode(10, OUTPUT); // coil return if(digitalRead(7)==HIGH){ // CWがoffなら通常点灯(onならWeak Pull Upで点灯) pinMode(13, OUTPUT); // 測定表示 } if(digitalRead(8)==HIGH){ // CCWがoffなら通常点灯(onならWeak Pull Upで点灯) pinMode(14, OUTPUT); // CWドライブLED表示(緑) pinMode(15, OUTPUT); // CCWドライブLED表示(赤) } Wire.begin(); Serial.begin(9600); lcd.begin(16,2); defGaiji(); // 液晶の外字を定義 if(LPS331read(0x0F) != 0xBB){ // 気圧センサーとの通信を確認 lcd.print("LPS331 not found"); for(;;){ // ダメなら無限ループ } } LPS331setup(); // 気圧センサーの初期設定 Serial.println("Press(hPa), Temp(degC), Alt(m), Posi"); // ログデータの列名 delay(100); LPS331measure(40); // 最初の高度を測定 calc(); // 気圧、気温、高度計算 altPlast=(alt * scaleFactor) + 0.5; // 針の位置の初期値として保存 } void loop(){ adjustWatch(); //ボタンが押されていれば時計の針位置を修正 LPS331measure(2); // n回測定して平均値を取得 MovingAve(20); // 移動平均を求める calc(); // 気圧、気温、高度計算 altP = (alt * scaleFactor) + 0.5; // 針の位置を計算 drivePulse = altP - altPlast; // 針の移動量を計算 LCDdisp(); // 各種表示 if( abs(drivePulse) >= 2){ // 移動量が2以上なら clockDrive(drivePulse); // 針の位置を動かす altPlast = altP; } else{ // 移動量が2以下でも if(altP == altPxx){ // 同じ値が2回目で if(drivePulse != 0){ // 移動量がゼロでなければ clockDrive(drivePulse); // 針の位置を動かす altPlast = altP; } } } altPxx = altP; } // loop void adjustWatch(){ // 指針の位置をマニュアルで調整 if( digitalRead(7)==LOW || digitalRead(8)==LOW){ // どちらかのボタンが押されていたら int n=0; while(digitalRead(7)==LOW){ // 7ピンのボタンが押されていたら n++; cwP(); // CW方向に針送り if(n > 5){ // 5回以上連続なら delay(cwInterval); // 早送り } else{ delay(200); } } while(digitalRead(8)==LOW){ // 8ピンのボタンが押されていたら n++; ccwP(); // CCW方向に針送り if(n > 5){ // 5回以上連続なら delay(ccwInterval); // 早送り } else{ delay(200); } } delay(200); // 戻る前にちょっと待つ } } void MovingAve(int n){ // n個のデータの移動平均を求める static int avCount=0; // データ数カウンタ static long hPaBinSum=0; static long tempBinSum=0; hPaBinSum =hPaBinSum -hPaDataBin[n-1] +hPaBin; // 合計値計算 tempBinSum=tempBinSum-tempDataBin[n-1]+tempBin; for(int i=n-1; i >= 1; i--){ hPaDataBin[i] = hPaDataBin[i-1]; // 配列の要素を一つ後ろにずらす tempDataBin[i] = tempDataBin[i-1]; } hPaDataBin[0]=hPaBin; // 先頭に最新値を入力 tempDataBin[0]=tempBin; avCount++; if(avCount >= n){ // カウント上限の設定 avCount = n; } hPaBin = hPaBinSum/avCount; // 平均値を求める tempBin= tempBinSum/avCount; } void LCDdisp(){ // 液晶表示 Serial.print(hPa,2); // シリアルへ測定結果を流す Serial.print(", "); Serial.print(temp,2); Serial.print(", "); Serial.print(alt,1); Serial.print(", "); Serial.println(altP); digitalWrite(13, HIGH); // 動作表示用にLED ON lcd.setCursor(0,0); // 液晶へ表示 lcd.print(temp,1); lcd.write(0x02); // 外字で℃表示 lcd.print(" "); lcd.print(alt,1); lcd.print("m "); lcd.setCursor(0,1); if(hPa < 1000.0){ lcd.print(" "); } lcd.print(hPa,2); lcd.write(0x01); // 外字でhPa表示 digitalWrite(13, LOW); // LED OFF } void LPS331setup(){ // センサーの初期設定 byte x; x = LPS331read(0x20); x = x & 0x7F; // PDビットクリア LPS331write(0x20, x); LPS331write(0x10, 0x7A); // アベレージ回数設定:気圧512回、温度128回 // LPS331write(0x10, 0x00); // アベレージ回数設定:気圧1回、温度1回 LPS331write(0x20, 0x04); // ワンショット、BDU有効、 LPS331write(0x20, 0x84); // PDビットON(パワーON) delay(2); // 設定完了まで待つ } void LPS331measure(int n){ // n回測定して気圧と温度の平均値を計算 long p=0; long t=0; for(int i=1; i <= n; i++){ // n回 LPS331exec(); // 測定開始処理 p = p + LPS331press(); // 気圧読み取り、累積 t = t + LPS331temp(); // 気温読み取り、累積 intで読んでlongで累積 } hPaBin = p / n; // 平均を求める tempBin = t / n; } void calc(){ hPa = (float) hPaBin/ 4096.0; // 気圧計算 temp = (float)(tempBin / 480.0) + 42.5; // 気温計算 alt=153.8*(20.0+273.2)*(1.0-pow(hPa/1013.25, 0.1902)); // 標高計算 } void LPS331exec(){ // 気圧測定を開始しデータが確定するまで待つ byte x; x = LPS331read(0x21); // 制御レジスタの x = x | 0x01; // ONE_SHOTビットONにして LPS331write(0x21, x); // 変換スタート while((LPS331read(0x27) & 0x03) != 0x03){ // 測定完了まで待つ } delay(1); // データが安定するまでちょっと待つ } long LPS331press(){ // 気圧データーを読んで値を返す long x, x1, x2, x3; x1 = LPS331read(0x28); x2 = LPS331read(0x29); x3 = LPS331read(0x2A); x = (x3 << 16) | (x2 << 8) | x1; // 合成 return x; } int LPS331temp(){ // 温度データーを読んで値を返す int x, x1, x2; x1 = LPS331read(0x2B); x2 = LPS331read(0x2C); x = (x2 << 8) | x1; // 合成 return x; } void LPS331write(byte adr, byte data){ // LPS331の指定アドレスに書き込み Wire.beginTransmission(lps331_I2C_adr); Wire.write(adr); Wire.write(data); Wire.endTransmission(); } byte LPS331read(byte adr){ // LPS331の指定アドレスを読み出し Wire.beginTransmission(lps331_I2C_adr); Wire.write(adr); Wire.endTransmission(); Wire.requestFrom(lps331_I2C_adr, 1); // 1バイトだけ読む return Wire.read(); } void clockDrive(int x){ // 引数の値だけ針を動かす(引数は正負) if( x != 0){ if( x > 0){ cw(x); } else{ x *= -1; ccw(x); } } } // clockDrive void cw(int n){ // 指定パルスだけ順回転 if(n !=0){ for(int x = 1; x <=n; x++){ cwP(); delay(cwInterval); // 順回転速度設定 } } } void ccw(int n){ // 指定パルスだけ逆回転 if(n !=0){ for(int x = 1; x <=n; x++){ ccwP(); delay(ccwInterval); // 逆回転速度設定 } } } void cwP(){ // 順回転パルス発生 digitalWrite(14,HIGH); // LED flash flag = ! flag; if (flag == true) { digitalWrite(9, HIGH); // coil drive foward delay(cwPulse); // wait digitalWrite(9, LOW); // coil drive end } else { digitalWrite(10, HIGH); // coil drive revers delay(cwPulse); // wait digitalWrite(10, LOW); // coil drive end } digitalWrite(14,LOW); // LED flash end } void ccwP(){ // 逆回転パルス発生 digitalWrite(15,HIGH); // LED flash flag = ! flag; if (flag == true) { digitalWrite(9, HIGH); // coil drive foward delayMicroseconds(ccwPulse1); // wait digitalWrite(9, LOW); // coil drive end digitalWrite(10, HIGH); // coil drive revers delayMicroseconds(ccwPulse2); // wait digitalWrite(10, LOW); // coil drive end } else { digitalWrite(10, HIGH); // coil drive revers delayMicroseconds(ccwPulse1); // wait digitalWrite(10, LOW); // coil drive end digitalWrite(9, HIGH); // coil drive foward delayMicroseconds(ccwPulse2); // wait digitalWrite(9, LOW); // coil drive end } digitalWrite(15,LOW); // LED flash end } // 液晶の外字設定 void defGaiji(){ byte hPascal[8] = { // hPa B10000, B10000, B11100, B10111, B10101, B00111, B00100, }; lcd.createChar(1, hPascal); byte degC[8] = { // ℃ B11000, B11000, B00110, B01001, B01000, B01001, B00110, }; lcd.createChar(2, degC); }