/* 簡易オシロ (_20190226_OLEDoscilloscope.ino) スケッチ:21152byte、ローカル変数:1285byte free 2019/02/26版 ラジオペンチ 200msレンジ追加中。レスポンス改善対策中 */ #include #include #include #include #define SCREEN_WIDTH 128 // OLED display width #define SCREEN_HEIGHT 64 // OLED display height #define REC_LENGTH 200 // 波形データのバッファサイズ #define MIN_TRIG_SWING 5 // ミニマムトリガスイング(この振幅以下ならUnsybc表示を出す) // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) #define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // レンジの表示名をフラッシュメモリに保存 const char vRangeName[10][5] PROGMEM = {"A50V", "A 5V", " 50V", " 20V", " 10V", " 5V", " 2V", " 1V", "0.5V", "0.2V"}; // 縦軸表示文字(\0含んだ文字数が必要) const char * const vstring_table[] PROGMEM = {vRangeName[0], vRangeName[1], vRangeName[2], vRangeName[3], vRangeName[4], vRangeName[5], vRangeName[6], vRangeName[7], vRangeName[8], vRangeName[9]}; const char hRangeName[10][6] PROGMEM = {"200ms", "100ms", " 50ms", " 20ms", " 10ms", " 5ms", " 2ms", " 1ms", "500us", "200us"}; // 横軸表示文字(60バイト) const char * const hstring_table[] PROGMEM = {hRangeName[0], hRangeName[1], hRangeName[2], hRangeName[3], hRangeName[4], hRangeName[5], hRangeName[6], hRangeName[7], hRangeName[8], hRangeName[9]}; int waveBuff[REC_LENGTH]; // 波形データー記録メモリ (RAMがギリギリ) char chrBuff[8]; // 表示フォーマットバッファ char hScale[] = "xxxAs"; // 横軸スケール名 char vScale[] = "xxxx"; // 縦軸スケール名 float lsb5V = 0.0055549; // 5Vレンジの感度係数 標準値:0.005371 V/1LSBで定義 float lsb50V = 0.0503931; // 50Vレンジの感度係数 0.05371 volatile int vRange; // 垂直レンジ 0:A50V, 1:A 5V, 2:50V, 3:20V, 4:10V, 5:5V, 6:2V, 7:1V, 8:0.5V volatile int hRange; // 水平レンジ 0:50m, 1:20m, 2:10m, 3:5m, 4;2m, 5:1m, 6:500u, 7;200u volatile int trigD; // トリガ方向(極性)0:ポジ、1:ネガ volatile int scopeP; // 操作スコープ位置 0:垂直レンジ, 1:水平レンジ, 2:トリガ方向 volatile boolean hold = false; // ホールド volatile boolean switchPushed = false; // スイッチが押された!フラグ volatile int saveTimer; // EEPROM保存までの残り時間 int timeExec; // 現在のレンジの概算実行時間(ms) int dataMin; // バッファの最小値(min:0) int dataMax; // バッファの最大値(max:1023) int dataAve; // バッファの平均値(精度確保のため10倍で保存 max:10230) int rangeMax; // グラフをフルスケールにするバッファの値 int rangeMin; // グラフを下限にするバッファの値 int rangeMaxDisp; // max表示の値(100倍で指定) int rangeMinDisp; // min表示の値 int trigP; // データバッファ上のトリガ位置 boolean trigSync; // トリガ検出フラグ int att10x; // 入力アッテネーター(1で有効) void setup() { pinMode(2, INPUT_PULLUP); // ボタン入力割込み(int.0割込み) pinMode(8, INPUT_PULLUP); // Selectボタン pinMode(9, INPUT_PULLUP); // Upボタン pinMode(10, INPUT_PULLUP); // Downボタン pinMode(11, INPUT_PULLUP); // Hold スイッチ pinMode(12, INPUT); // アッテネーター1/10 pinMode(13, OUTPUT); // 状態表示 // Serial.begin(115200); // これを使うとRAMを大量に消費する if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64 // Serial.println(F("SSD1306 failed")); for (;;); // Don't proceed, loop forever } auxFunctions(); // 電圧測定機能(無限ループで戻ってこない) loadEEPROM(); // EEPROMから前回の設定内容を読み出し analogReference(INTERNAL); // ADCのフルスケール1.1Vに設定(内部vrefを使用) attachInterrupt(0, pin2IRQ, FALLING); // スイッチ操作検出割り込みを起動(int.0) startScreen(); // 起動画面表示 } void loop() { setConditions(); // 測定条件設定 digitalWrite(13, HIGH); readWave(); // 波形読み取り (1.6-400ms ) digitalWrite(13, LOW); // setConditions(); // 測定条件再設定(測定中の変更を表示に反映) dataAnalize(); // データーの各種情報を収集(0.5-0.6ms) writeCommonImage(); // 固定イメージの描画(2.6ms) plotData(); // 波形プロット(10-18ms) dispInf(); // 各種情報表示(6.5-8.5ms) display.display(); // バッファを転送してOLEDに表示(37ms) saveEEPROM(); // 必要があればEEPROMに設定内容を保存 while (hold == true) { // Holdボタンが押されていたら待つ dispHold(); delay(10); } // ループ回転速度:60-470ms(@波形バッファ=200) } void setConditions() { // 測定条件設定 // レンジ名をPROGMEMから持ってくる strcpy_P(hScale, (char*)pgm_read_word(&(hstring_table[hRange]))); // 横軸レンジ名設定 strcpy_P(vScale, (char*)pgm_read_word(&(vstring_table[vRange]))); // 縦軸レンジ名設定 switch (vRange) { // 縦軸のレンジごとの設定 case 0: { // Auto50Vレンジ att10x = 1; // 入力アッテネーター使用 break; } case 1: { // Auto 5Vレンジ att10x = 0; // 入力アッテネーターを使わない break; } case 2: { // 50Vレンジ rangeMax = 50 / lsb50V; // フルスケール画素数の設定 rangeMaxDisp = 5000; // 縦軸目盛り。100倍の値で設定 rangeMin = 0; rangeMinDisp = 0; att10x = 1; // 入力アッテネーター使用 break; } case 3: { // 20Vレンジ rangeMax = 20 / lsb50V; // フルスケール画素数の設定 rangeMaxDisp = 2000; rangeMin = 0; rangeMinDisp = 0; att10x = 1; // 入力アッテネーター使用 break; } case 4: { // 10Vレンジ rangeMax = 10 / lsb50V; // フルスケール画素数の設定 rangeMaxDisp = 1000; rangeMin = 0; rangeMinDisp = 0; att10x = 1; // 入力アッテネーター使用 break; } case 5: { // 5Vレンジ rangeMax = 5 / lsb5V; // フルスケール画素数の設定 rangeMaxDisp = 500; rangeMin = 0; rangeMinDisp = 0; att10x = 0; // 入力アッテネーターを使わない break; } case 6: { // 2Vレンジ rangeMax = 2 / lsb5V; // フルスケール画素数の設定 rangeMaxDisp = 200; rangeMin = 0; rangeMinDisp = 0; att10x = 0; // 入力アッテネーターを使わない break; } case 7: { // 1Vレンジ rangeMax = 1 / lsb5V; // フルスケール画素数の設定 rangeMaxDisp = 100; rangeMin = 0; rangeMinDisp = 0; att10x = 0; // 入力アッテネーターを使わない break; } case 8: { // 0.5Vレンジ rangeMax = 0.5 / lsb5V; // フルスケール画素数の設定 rangeMaxDisp = 50; rangeMin = 0; rangeMinDisp = 0; att10x = 0; // 入力アッテネーターを使わない break; } case 9: { // 0.5Vレンジ rangeMax = 0.2 / lsb5V; // フルスケール画素数の設定 rangeMaxDisp = 20; rangeMin = 0; rangeMinDisp = 0; att10x = 0; // 入力アッテネーターを使わない break; } } } void writeCommonImage() { // 共通画面の作画 display.clearDisplay(); // 画面全消去(0.4ms) display.setTextColor(WHITE); // 白文字で描く display.setCursor(86, 0); // Start at top-left corner display.println(F("av V")); // 1行目固定文字 display.drawFastVLine(26, 9, 55, WHITE); // 左縦線 display.drawFastVLine(127, 9, 55, WHITE); // 左縦線 display.drawFastHLine(24, 9, 7, WHITE); // Max値の補助マーク display.drawFastHLine(24, 36, 2, WHITE); // display.drawFastHLine(24, 63, 7, WHITE); // display.drawFastHLine(51, 9, 3, WHITE); // Max値の補助マーク display.drawFastHLine(51, 63, 3, WHITE); // display.drawFastHLine(76, 9, 3, WHITE); // Max値の補助マーク display.drawFastHLine(76, 63, 3, WHITE); // display.drawFastHLine(101, 9, 3, WHITE); // Max値の補助マーク display.drawFastHLine(101, 63, 3, WHITE); // display.drawFastHLine(123, 9, 5, WHITE); // 右端Max値の補助マーク display.drawFastHLine(123, 63, 5, WHITE); //   for (int x = 26; x <= 128; x += 5) { display.drawFastHLine(x, 36, 2, WHITE); // 中心線(水平線)を点線で描く } for (int x = (127 - 25); x > 30; x -= 25) { for (int y = 10; y < 63; y += 5) { display.drawFastVLine(x, y, 2, WHITE); // 縦線を点線で3本描く } } } void readWave() { // 波形をメモリーに記録 if (att10x == 1) { // もし1/10アッテネーターが必要なら pinMode(12, OUTPUT); // アッテネーター制御ピンを出力にして digitalWrite(12, LOW); // LOWを出力 } else { // アッテネーター不使用なら pinMode(12, INPUT); // アッテネーター制御ピンをHi-zにする(入力にする) } switchPushed = false; // スイッチ操作フラグをクリア switch (hRange) { // レンジに応じ記録速度を変更 case 0: { // 200msレンジ timeExec = 1600 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(7888); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら switchPushed = false; break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 1: { // 100msレンジ timeExec = 800 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(3888); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら switchPushed = false; break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 2: { // 50msレンジ timeExec = 400 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(1888); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 3: { // 20msレンジ timeExec = 160 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(688); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 4: { // 10 msレンジ timeExec = 80 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(288); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 5: { // 5 msレンジ timeExec = 40 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x07; // 分周比128 (arduinoのオリジナル) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約112μs delayMicroseconds(88); // サンプリング周期調整 if (switchPushed == true) { // スイッチ操作があったら break; // 記録中止(ループを抜けてレスポンス改善) } } break; } case 6: { // 2 msレンジ timeExec = 16 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x06; // 分周比64 (0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約56μs delayMicroseconds(24); // サンプリング周期調整 } break; } case 7: { // 1 msレンジ timeExec = 8 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x05; // 分周比16 (0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約28μs delayMicroseconds(12); // サンプリング周期調整 } break; } case 8: { // 500usレンジ timeExec = 4 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x04; // 分周比16(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約16μs delayMicroseconds(4); // サンプリング周期調整 // 時間微調整 1.875μs(nop 1つで1クロック、0.0625μs @16MHz) asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); } break; } case 9: { // 200usレンジ timeExec = 2 + 60; // 概算実行時間(ms) EEPROM保存までのカウントダウンに使用 ADCSRA = ADCSRA & 0xf8; // 下3ビットをクリア ADCSRA = ADCSRA | 0x02; // 分周比:4(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128) for (int i = 0; i < REC_LENGTH; i++) { // REC_LENGTHの回数 waveBuff[i] = analogRead(0); // 約6μs // 時間微調整 1.875μs(nop 1つで1クロック、0.0625μs @16MHz) asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); } break; } } } void dataAnalize() { // 作図のための各種情報を設定 int d; long sum = 0; // 最大最小値を求める dataMin = 1023; // 最小 dataMax = 0; // 最大値記録変数を初期化 for (int i = 0; i < REC_LENGTH; i++) { // 最大と最小値を求める d = waveBuff[i]; sum = sum + d; if (d < dataMin) { // 最小と dataMin = d; } if (d > dataMax) { // 最大値を求める dataMax = d; } } // 平均値を求める dataAve = (sum + 10) / 20; // 平均値計算(精度確保のため10倍値で計算) // 表示範囲のmax,minを決める if (vRange <= 1) { // Autoレンジなら(レンジ番号が1かそれ以下) rangeMin = dataMin - 20; // 表示レンジ下限を-20下に設定 rangeMin = (rangeMin / 10) * 10; // 10ステップに丸め if (rangeMin < 0) { rangeMin = 0; // 但し下限は0 } rangeMax = dataMax + 20; // 表示レンジ上限を+20上に設定 rangeMax = ((rangeMax / 10) + 1) * 10; // 切り上げで10ステップに丸め if (rangeMax > 1020) { rangeMax = 1023; // 但し1020以上なら1023で抑える } if (att10x == 1) { // アッテネータ有 rangeMaxDisp = 100 * (rangeMax * lsb50V); // 表示範囲はデーターで決める。つまり上限はADCのフルスケールまで rangeMinDisp = 100 * (rangeMin * lsb50V); // 下限は測定結果によるが、最低でもゼロ } else { // アッテネータ無し rangeMaxDisp = 100 * (rangeMax * lsb5V); rangeMinDisp = 100 * (rangeMin * lsb5V); } } else { // 固定レンジなら // 必要な処理をここに書く(今のところ無し) } // トリガ位置を探す for (trigP = ((REC_LENGTH / 2) - 51); trigP < ((REC_LENGTH / 2) + 50); trigP++) { // データー範囲の中央で、中央値を跨いでいるポイントを探す if (trigD == 0) { // トリガ方向が0(正トリガ)なら if ((waveBuff[trigP - 1] < (dataMax + dataMin) / 2) && (waveBuff[trigP] >= (dataMax + dataMin) / 2)) { break; // 立ち上がりトリガ検出! } } else { // 0でなかったら(負トリガ) if ((waveBuff[trigP - 1] > (dataMax + dataMin) / 2) && (waveBuff[trigP] <= (dataMax + dataMin) / 2)) { break; } // 立下りトリガ検出! } } trigSync = true; if (trigP >= ((REC_LENGTH / 2) + 50)) { // トリガが範囲内で見つからなければ trigP = (REC_LENGTH / 2); // とりあえず中央に設定しておいて、 trigSync = false; // Unsync表示用フラグ } if ((dataMax - dataMin) <= MIN_TRIG_SWING) { // 波形の振幅が規定値より小さければ trigSync = false; // Unsync表示用フラグ } } void startScreen() { // 開始時の画面表示 display.clearDisplay(); display.setTextSize(2); // 文字を2倍角で、 display.setTextColor(WHITE); display.setCursor(10, 15); display.println(F("DSO start")); // 開始画面表示 display.setCursor(10, 35); display.println(F(" v1.0")); display.display(); // 表示 delay(1000); display.clearDisplay(); display.setTextSize(1); // 以降は標準文字サイズ } void dispHold() { // 画面にHoldを表示 display.fillRect(42, 11, 24, 8, BLACK); // 4文字分黒塗り display.setCursor(42, 11); display.print(F("Hold")); // Hold 表示 display.display(); // } void dispInf() { // 各種情報表示 float voltage; // 垂直感度表示 display.setCursor(2, 0); // 画面の左上に display.print(vScale); // 垂直感度常時 if (scopeP == 0) { // スコープが当たっていたら display.drawFastHLine(0, 7, 27, WHITE); // 下側枠線を表示 display.drawFastVLine(0, 5, 2, WHITE); display.drawFastVLine(26, 5, 2, WHITE); } // 水平感度表示 display.setCursor(34, 0); // display.print(hScale); // 横軸スケール(time/div)表示 if (scopeP == 1) { // スコープが当たっていたら display.drawFastHLine(32, 7, 33, WHITE); // 下側枠線を表示 display.drawFastVLine(32, 5, 2, WHITE); display.drawFastVLine(64, 5, 2, WHITE); } // トリガ極性表示 display.setCursor(75, 0); // 波形の中央上に if (trigD == 0) { display.print(char(0x18)); // トリガ極性表示↑ } else { display.print(char(0x19)); // ↓ } if (scopeP == 2) { // スコープが当たっていたら display.drawFastHLine(71, 7, 13, WHITE); // 下側枠線を表示 display.drawFastVLine(71, 5, 2, WHITE); display.drawFastVLine(83, 5, 2, WHITE); } // 平均電圧表示 if (att10x == 1) { // 10倍アッテネーターが入っていたら voltage = dataAve * lsb50V / 10.0; // 50Vレンジの感度係数で電圧計算 } else { voltage = dataAve * lsb5V / 10.0; // 5Vレンジの感度係数で電圧計算 } if (voltage < 10.0) { // 電圧が10V未満なら dtostrf(voltage, 4, 2, chrBuff); // 小数点以下2桁(x.xx 形式) } else { // 10V以上なら dtostrf(voltage, 4, 1, chrBuff); // 小数点以下1桁(xx.x 形式) } display.setCursor(98, 0); // 画面の右上に display.print(chrBuff); // 電圧の平均値を表示 // display.print(saveTimer); // デバッグ用の表示はここを使うと便利 // 縦軸目盛り表示 voltage = rangeMaxDisp / 100.0; // Max電圧を換算 if (vRange == 1 || vRange > 4) { // 感度が5V以下もしくはAuto5Vなら dtostrf(voltage, 4, 2, chrBuff); // *.** 形式に変換 } else { // dtostrf(voltage, 4, 1, chrBuff); // **.* 形式に変換 } display.setCursor(0, 9); display.print(chrBuff); // Max値表示 voltage = (rangeMaxDisp + rangeMinDisp) / 200.0; // 中央値を計算 if (vRange == 1 || vRange > 4) { // 感度が5V以下もしくはAuto5Vなら dtostrf(voltage, 4, 2, chrBuff); // 小数点以下2桁 } else { // dtostrf(voltage, 4, 1, chrBuff); // 小数点以下1桁 } display.setCursor(0, 33); display.print(chrBuff); // 中心値表示 voltage = rangeMinDisp / 100.0; // Min値を計算 if (vRange == 1 || vRange > 4) { // 感度が5V以下もしくはAuto5Vなら dtostrf(voltage, 4, 2, chrBuff); // 数点以下2桁 } else { dtostrf(voltage, 4, 1, chrBuff); // 小数点以下1桁 } display.setCursor(0, 57); display.print(chrBuff); // Min値表示 // トリガ検出ミス表示 if (trigSync == false) { // トリガの検出に失敗していたら display.fillRect(85, 11, 24, 8, BLACK); // 4文字分黒塗り display.setCursor(85, 11); // グラフエリアの右上に display.print(F("Unsync")); // Unsync を表示 } } void plotData() { // 配列の値に基づきデーターをプロット long y1, y2; for (int x = 0; x <= 98; x++) { y1 = map(waveBuff[x + trigP - 50], rangeMin, rangeMax, 63, 9); // プロット座標へ変換 y1 = constrain(y1, 9, 63); // はみ出し部は潰す y2 = map(waveBuff[x + trigP - 49], rangeMin, rangeMax, 63, 9); // y2 = constrain(y2, 9, 63); // display.drawLine(x + 27, y1, x + 28, y2, WHITE); // 点間を線で結ぶ } } void saveEEPROM() { // ボタン操作が終わって少し待ってから、EEPROMに設定値を保存 if (saveTimer > 0) { // タイマーの値が正、つまり負でなければ saveTimer = saveTimer - timeExec; // タイマー減算 if (saveTimer < 0) { // タイマーが負、つまりタイムアップしたら EEPROM.write(0, vRange); // 現在の設定状態を保存 EEPROM.write(1, hRange); EEPROM.write(2, trigD); EEPROM.write(3, scopeP); } } } void loadEEPROM() { // EEPROMに保存した設定値の読み出し(異常値はデフォルトに修正) int x; x = EEPROM.read(0); // vRange if ((x < 0) || (x > 9)) { // 0-9の範囲外だったら x = 3; // デフォルト値設定 } vRange = x; x = EEPROM.read(1); // hRange if ((x < 0) || (x > 7)) { // 0-9の範囲外だったら x = 3; // デフォルト値設定 } hRange = x; x = EEPROM.read(2); // trigD if ((x < 0) || (x > 1)) { // 0-9の範囲外だったら x = 1; // デフォルト値設定 } trigD = x; x = EEPROM.read(3); // scopeP if ((x < 0) || (x > 2)) { // 0-9の範囲外だったら x = 1; // デフォルト値設定 } scopeP = x; } void auxFunctions() { // 電圧測定ルーチン float voltage; if (digitalRead(8) == LOW) { // SELECTボタンが押されていたら、バッテリー電圧 analogReference(DEFAULT); // ADCフルスケールをVccに設定 while (1) { // 無限ループで voltage = 5.0 * analogRead(1) / 1023.0; // バッテリー電圧(A1ピン)の電圧測定 display.clearDisplay(); // 画面全消去(0.4ms) display.setTextColor(WHITE); // 白文字で描く display.setCursor(20, 16); // display.setTextSize(1); // 文字を2倍角で、 display.println(F("Battery voltage")); display.setCursor(35, 30); // display.setTextSize(2); // 文字を2倍角で、 dtostrf(voltage, 4, 2, chrBuff); // x.xx 形式でバッテリー電圧表示 display.print(chrBuff); display.println(F("V")); display.display(); delay(150); } } if (digitalRead(9) == LOW) { // +(UP)ボタンが押されていたら、5Vレンジ analogReference(INTERNAL); pinMode(12, INPUT); // アッテネーター制御ピンをHi-zにする(入力にする) while (1) { // 無限ループで digitalWrite(13, HIGH); // LEDフラッシュ voltage = analogRead(0) * lsb5V; // 入力端子の電圧測定 display.clearDisplay(); // 画面全消去(0.4ms) display.setTextColor(WHITE); // 白文字で描く display.setCursor(26, 16); // display.setTextSize(1); // 標準文字サイズで、 display.println(F("DVM 5V Range")); display.setCursor(35, 30); // display.setTextSize(2); // 2倍角で、 dtostrf(voltage, 4, 2, chrBuff); // x.xx 形式で入力電圧表示 display.print(chrBuff); display.println(F("V")); display.display(); digitalWrite(13, LOW); delay(150); } } if (digitalRead(10) == LOW) { // −(DOWN)ボタンが押されていたら、50Vレンジ analogReference(INTERNAL); pinMode(12, OUTPUT); // アッテネーター制御ピンを出力にして digitalWrite(12, LOW); // LOWを出力(入力アッテネーター = 1/10) while (1) { // 無限ループで digitalWrite(13, HIGH); // LEDフラッシュ voltage = analogRead(0) * lsb50V; // 入力端子の電圧測定 display.clearDisplay(); // 画面全消去(0.4ms) display.setTextColor(WHITE); // 白文字で描く display.setCursor(26, 16); // display.setTextSize(1); // 標準文字サイズで、 display.println(F("DVM 50V Range")); display.setCursor(35, 30); // display.setTextSize(2); // 文字を2倍角で、 dtostrf(voltage, 4, 1, chrBuff); // 小数点以下1桁(xx.x 形式) display.print(chrBuff); display.println(F("V")); display.display(); digitalWrite(13, LOW); delay(150); } } } void pin2IRQ() { // Pin2(int.0)割込みの処理(この処理中は割り込み禁止した方が良いかも) // 操作ボタン(タクトスイッチ)のpin8,9,10,11はダイオードで束ねてPin2に // 接続されている。つまりいずれかのボタンが押されればこのルーチン起動 int x; // ポート情報保持変数 x = PINB; // ポートBの情報を読む if ( (x & 0x07) != 0x07) { // 下位3ビットが全部Highで無ければ(どれかが押されていたら) saveTimer = 5000; // EEPROM保存タイマーを5秒に設定(ms単位で設定) switchPushed = true; // スイッチ押された!フラグON(波形保存中断に使用) } if ((x & 0x01) == 0) { // SELECTボタン(Pin8)が押されていたら scopeP++; // スコープに位置を一つずらす if (scopeP > 2) { // 上限だったら scopeP = 0; // 最初の位置に戻す } } if ((x & 0x02) == 0) { // UPボタン(Pin9)が押されていて、 if (scopeP == 0) { // 垂直レンジにスコープが当たっていたら vRange++; // レンジUP if (vRange > 9) { // 上限だったら vRange = 9; } } if (scopeP == 1) { // 水平レンジにスコープが当たっていたら hRange++; if (hRange > 9) { // 上限だったら hRange = 9; // そこで止める } } if (scopeP == 2) { // トリガ方向ボタンにスコープが当たっていたら trigD = 0; // プラストリガ } } if ((x & 0x04) == 0) { // DOWNボタン(Pin10)が押されていて、 if (scopeP == 0) { // 垂直レンジにスコープが当たっていたら vRange--; // レンジDOWN if (vRange < 0) { // 下限だったら vRange = 0; // そこで止める } } if (scopeP == 1) { // 水平レンジにスコープが当たっていたら hRange--; // レンジDOWN if (hRange < 0) { // 下限だったら hRange = 0; // そこで止める } } if (scopeP == 2) { // トリガ方向ボタンにスコープが当たっていたら trigD = 1; // マイナストリガ } } if ((x & 0x08) == 0) { // HOLDボタン(pin11)が押されていたら hold = ! hold; // フラグ反転 } }