/* Supply Voltage Display - AVR128 DA/DB-Series Version David Johnson-Davies - www.technoblogy.com - 13th April 2021 AVR128DA28 @ 24 MHz (internal oscillator; BOD disabled) CC BY 4.0 Licensed under a Creative Commons Attribution 4.0 International license: http://creativecommons.org/licenses/by/4.0/ */ // Seven-segment definitions const int CharLen = 12; char Char[CharLen] = { // ABCDEFG Segments 0b1111110, // 0 0b0110000, // 1 0b1101101, // 2 0b1111001, // 3 0b0110011, // 4 0b1011011, // 5 0b1011111, // 6 0b1110000, // 7 0b1111111, // 8 0b1111011, // 9 0b0000000, // 10 Space 0b0000001, // 11 Dash }; const int Dash = 11; const int Space = 10; volatile int Voltage; // Tenths of a volt volatile int Buffer[2] = { Dash, Dash }; // Port setup ********************************************** void PortSetup () { PORTA.DIR = 0b11111111; // Make PA0 to PA7 outputs PORTC.DIRSET = PIN0_bm; // Make PC0 output PORTF.DIRSET = PIN0_bm; // Make PF0 output } // Measure voltage ********************************************** #if defined(__AVR_AVR128DA28__) void ADCSetup () { VREF.ADC0REF = VREF_REFSEL_1V024_gc; VREF.ACREF = VREF_REFSEL_VDD_gc; AC0.DACREF = 32; // Maximum DACREF0 voltage ADC0.MUXPOS = ADC_MUXPOS_DACREF0_gc; // Measure DACREF0 ADC0.CTRLC = ADC_PRESC_DIV64_gc; // 375kHz clock ADC0.CTRLA = ADC_ENABLE_bm; // Single, 12-bit } void MeasureVoltage () { ADC0.COMMAND = ADC_STCONV_bm; // Start conversion while (ADC0.COMMAND & ADC_STCONV_bm); // Wait for completion uint16_t adc_reading = ADC0.RES; // ADC conversion result uint16_t voltage = adc_reading/50; Buffer[0] = voltage/10; Buffer[1]= voltage%10; } #elif defined(__AVR_AVR128DB28__) void ADCSetup () { VREF.ADC0REF = VREF_REFSEL_1V024_gc; ADC0.MUXPOS = ADC_MUXPOS_VDDDIV10_gc; // VDD/10 ADC0.CTRLC = ADC_PRESC_DIV64_gc; // 375kHz clock ADC0.CTRLA = ADC_ENABLE_bm; // Single, 12-bit } void MeasureVoltage () { ADC0.COMMAND = ADC_STCONV_bm; // Start conversion while (ADC0.COMMAND & ADC_STCONV_bm); // Wait for completion uint16_t adc_reading = ADC0.RES; // ADC conversion result uint16_t voltage = adc_reading/40; Buffer[0] = voltage/10; Buffer[1]= voltage%10; } #endif // Display multiplexer ********************************************** void DisplayNextDigit() { static uint8_t digit = 0; digit = 1 - digit; // Toggle digits 0 and 1 uint8_t segs = Char[Buffer[digit]]; // Segments if (digit == 0) segs = segs | 0x80; // Decimal point PORTA.OUT = segs; // Take segments high if (digit == 1) { // Take digit low PORTC.OUTCLR = PIN0_bm; PORTF.OUTSET = PIN0_bm; } else { PORTC.OUTSET = PIN0_bm; PORTF.OUTCLR = PIN0_bm; } } // TCA setup ********************************************** volatile int Ticks = 0; const int Second = 125; // Ticks per second void TCASetup () { TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm; // Enable interrupt TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc; // Set Normal mode TCA0.SINGLE.PER = 2999; // Set the period -> 125Hz TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV64_gc; // Clock divided by 64 TCA0.SINGLE.CTRLA = TCA0.SINGLE.CTRLA | TCA_SINGLE_ENABLE_bm; // Enable } ISR(TCA0_OVF_vect) { TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm; // Clear interrupt DisplayNextDigit(); Ticks++; if (Ticks == Second) { Ticks = 0; MeasureVoltage(); } } // Setup ********************************************** void setup() { PortSetup(); ADCSetup(); TCASetup(); } // Everything done under interrupt void loop () { }