/* Supply Voltage Display - ATtiny 0/1-Series Version David Johnson-Davies - www.technoblogy.com - 13th April 2021 ATtiny414 @ 20 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 = 0b11111110; // Make PA1 to PA7 outputs PORTB.DIR = 0b00000111; // Make PB0 to PB2 outputs } // Measure voltage ********************************************** void ADCSetup () { VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc; ADC0.CTRLC = ADC_REFSEL_VDDREF_gc | ADC_PRESC_DIV256_gc; // 78kHz clock ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // Measure INTREF ADC0.CTRLA = ADC_ENABLE_bm; // Single, 10-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 = 11264/adc_reading; Buffer[0] = voltage/10; Buffer[1]= voltage%10; } // 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 & 0xFE; // Take segments high PORTB.OUT = segs & 0x01; // Take segments high if (digit == 1) { // Take digit low PORTB.OUTCLR = PIN2_bm; PORTB.OUTSET = PIN1_bm; } else { PORTB.OUTCLR = PIN1_bm; PORTB.OUTSET = PIN2_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 = 2499; // 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 () { }