本ページでは、analogReadの処理時間を見かけ上、高速化するためのテクニックを紹介します。
たとえば、以下のようなコードがあります。analogReadをコールすると、おおよそ100us、変換時間のためウェイトが入ります。
if( (millis() - gPreviousL8) >= 200) { //Reset task gPreviousL8 = millis(); //LED Control taskLED(); /* Sensor check */ aEdc = analogRead(A1); /* OV check */ if( aEdc > gThreshold_OV ) { aErrNo = 2; } /* LV check */ if( aEdc < gThreshold_LV ) { aErrNo = 1; } /* エラー処理 */ if( aErrNo > 0) { if( DSCore.IsPower() == 1) { PowerOffByErr(aErrNo); } } }
ADCは、通常、変換開始→変換完了までは自由にCPUを動かすことが出来ます。ただし、ArduinoのanalogRead関数は、whileで強制ウェイトを掛けています。
そこで、analogRead関数を以下のように分割することで、ウェイト中に他の処理をして見かけ上の高速化を行うことが出来るようになります。
void analogRead_trigger(uint8_t pin) { if (pin >= 14) pin -= 14; // allow for channel or pin numbers // set the analog reference (high two bits of ADMUX) and select the // channel (low 4 bits). this also sets ADLAR (left-adjust result) // to 0 (the default). ADMUX = (analog_reference << 6) | (pin & 0x07); // start the conversion sbi(ADCSRA, ADSC); } int analogRead_get() { uint8_t low, high; // ADSC is cleared when the conversion finishes while (bit_is_set(ADCSRA, ADSC)); // we have to read ADCL first; doing so locks both ADCL // and ADCH until ADCH is read. reading ADCL second would // cause the results of each conversion to be discarded, // as ADCL and ADCH would be locked when it completed. low = ADCL; high = ADCH; // combine the two bytes return (high << 8) | low; }
上記の分割した関数を使って直した、コードが以下の通りです。
if( (millis() - gPreviousL8) >= 200) { //Reset task gPreviousL8 = millis(); /* Sensor check */ analogRead_trigger(A1); //LED Control taskLED(); /* Sensor check */ aEdc = analogRead_get(); /* OV check */ if( aEdc > gThreshold_OV ) { aErrNo = 2; } /* LV check */ if( aEdc < gThreshold_LV ) { aErrNo = 1; } /* エラー処理 */ if( aErrNo > 0) { if( DSCore.IsPower() == 1) { PowerOffByErr(aErrNo); } } }