ADコンバーター / 二酸化炭素(CO2)センサー / 基準電圧IC REF5020AIDを使う

テキストからは逸れるが、基準電圧IC REF5020AID (2.048 V±0.1%)をADコンバーターの基準電圧に使ってみる。1 LSBが丁度2 mVになるので計算が楽。
f:id:ti-nspire:20200713095437p:plain:h300 f:id:ti-nspire:20200713095528j:plain:h300

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include "LCDClass.h"

const uint16_t mVREF      = 2048;
const uint16_t RESOLUTION = 1024;
const uint8_t  LSB        = mVREF / RESOLUTION;

int main(){
    LCDClass lcd("PB0","PD7","PD6","PD5","PB7","PB6"); // (RS,EN,D4,D5,D6,D7)の順番で指定する。
    lcd.init();
    
    //ADMUX &= ~(1 << REFS1) | (1 << REFS0); // 基準電圧はAREF。これがデフォルト。
    ADCSRA |= (0b111) | (1 << ADEN);         // 128分周。ADCペリフェラルをオン。

    uint16_t adc;
    uint16_t mV;
    uint16_t ppm;
    while(1){
        ADCSRA |= (1 << ADSC);                 // 変換を開始して、
        loop_until_bit_is_clear(ADCSRA, ADSC); // 変換し終えるのを待って、
        
        adc = ADC;                             // AD変換値を取得して、
        mV  = LSB * adc;                       // 電圧に変換して、
        
        if(mV < 200){
            lcd.clearDisplay();
            lcd.gotoRowCol(1, 1);
            lcd.print("fault");
        }
        else if(200 <= mV && mV < 400){
            lcd.clearDisplay();
            lcd.gotoRowCol(1, 1);
            lcd.print("preheating ...");
        }
        else{
            ppm = (25 * (mV - 400) + 4) / 8; // ppmに変換する。+4は小数点以下を四捨五入するため。

            lcd.clearDisplay();
            lcd.gotoRowCol(1,  1); lcd.print("AD:");
            lcd.gotoRowCol(1,  4); lcd.print(adc);
            lcd.gotoRowCol(1,  9); lcd.print("mV:");
            lcd.gotoRowCol(1, 12); lcd.print(mV);
            lcd.gotoRowCol(2,  1); lcd.print("ppm:");
            lcd.gotoRowCol(2,  5); lcd.print(ppm);
        }

        _delay_ms(1000);
    }

    return 0;
}