/* avr-gcc \ -mmcu=atmega168 -DF_CPU=8000000UL \ -gdwarf-2 -std=gnu99 -Os -fwhole-program -flto -mstrict-X -fmerge-all-constants \ -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums \ -Wall -Wundef -Wno-main -Wno-comment -Werror=implicit-function-declaration \ -fstack-usage -Wstack-usage=4 \ -I. main.c \ -o main.elf avrdude -p atmega168 -c usbasp -U flash:w:main.elf */ #include #include #include #include #define SHIFT_DS PB3 #define SHIFT_SH PB5 #define SHIFT_ST PB0 static uint8_t seg7data[4] = { 0, 0, 0, 0 }; static void shiftreg_set32() { for (signed int j = 3; j >= 0; j--) { uint8_t s = seg7data[j]; for (signed int i = 7; i >= 0; i--) { if ((s >> i) & 1) { PORTB |= (1 << SHIFT_DS); } else { PORTB &= ~(1 << SHIFT_DS); } PORTB |= (1 << SHIFT_SH); PORTB &= ~(1 << SHIFT_SH); } } PORTB |= (1 << SHIFT_ST); PORTB &= ~(1 << SHIFT_ST); } static void shiftreg_zero32() { PORTB &= ~(1 << SHIFT_DS); for (int i = 0; i < 32; i++) { PORTB |= (1 << SHIFT_SH); PORTB &= ~(1 << SHIFT_SH); } PORTB |= (1 << SHIFT_ST); PORTB &= ~(1 << SHIFT_ST); } #define Db1 (1<<0) #define De1 (1<<1) #define Dd1 (1<<2) #define Df1 (1<<3) #define Da1 (1<<4) #define Dg1 (1<<5) #define Dp1 (1<<6) #define Dc1 (1<<7) #define Dp2 (1<<0) #define De2 (1<<1) #define Dc2 (1<<2) #define Dg2 (1<<3) #define Df2 (1<<4) #define Db2 (1<<5) #define Dd2 (1<<6) #define Da2 (1<<7) #define C10 (Da1 | Db1 | Dc1 | Dd1 | De1 | Df1) #define C20 (Da2 | Db2 | Dc2 | Dd2 | De2 | Df2) #define C11 (Db1 | Dc1) #define C21 (Db2 | Dc2) #define C12 (Da1 | Db1 | Dg1 | De1 | Dd1) #define C22 (Da2 | Db2 | Dg2 | De2 | Dd2) #define C13 (Da1 | Db1 | Dg1 | Dc1 | Dd1) #define C23 (Da2 | Db2 | Dg2 | Dc2 | Dd2) #define C14 (Df1 | Dg1 | Db1 | Dc1) #define C24 (Df2 | Dg2 | Db2 | Dc2) #define C15 (Da1 | Df1 | Dg1 | Dc1 | Dd1) #define C25 (Da2 | Df2 | Dg2 | Dc2 | Dd2) #define C16 (Da1 | Df1 | Dg1 | Dc1 | Dd1 | De1) #define C26 (Da2 | Df2 | Dg2 | Dc2 | Dd2 | De2) #define C17 (Da1 | Db1 | Dc1) #define C27 (Da2 | Db2 | Dc2) #define C18 (Da1 | Db1 | Dc1 | Dd1 | De1 | Df1 | Dg1) #define C28 (Da2 | Db2 | Dc2 | Dd2 | De2 | Df2 | Dg2) #define C19 (Dg1 | Df1 | Da1 | Db1 | Dc1 | Dd1) #define C29 (Dg2 | Df2 | Da2 | Db2 | Dc2 | Dd2) static const __flash uint16_t num1[10] = { C10, C11, C12, C13, C14, C15, C16, C17, C18, C19 }; static const __flash uint16_t num2[10] = { C20, C21, C22, C23, C24, C25, C26, C27, C28, C29 }; static void disp_num(uint8_t which /* 0 or 1 */, uint8_t num) { uint8_t nh = num2[num / 10]; uint8_t nl = num1[num % 10]; seg7data[which*2 + 0] = nl; seg7data[which*2 + 1] = nh; } volatile uint16_t duty1 = 1500; volatile uint16_t duty2 = 1500; ISR(TIMER1_COMPA_vect) { if (!OCR1A) { OCR1A = duty2; } else { OCR1A = 0; } } ISR(TIMER1_COMPB_vect) { if (!OCR1B) { OCR1B = duty1; } else { OCR1B = 0; } } /* Converts poti value from ADC-range to microseconds 0.5 ... 2.5 */ static uint16_t adc2us(uint16_t av) { return 500 + (((uint32_t)av * 2000) >> 10); } /* Display microseconds value in display. * For 1000-2000us, the hundreds and tens are shown (ex.: 1536 us -> 53) * Outside of this range, also shows hundreds and tens :) but additionally in * main() some blinking is done to indicate "out of normal range" */ static void disp_dv(uint8_t which, uint16_t dv) { disp_num(which, (dv % 1000) / 10); } void main() { DDRB |= (1 << SHIFT_DS) | (1 << SHIFT_SH) | (1 << SHIFT_ST); ADMUX = (1 << REFS0); /* AVcc */ ADCSRA = (1 << ADEN); DDRB |= (1 << PB1) | (1 << PB2); /* Setup timer: ICR is TOP for CTC mode, 20ms */ ICR1 = 20000; OCR1A = 0; OCR1B = 0; TCCR1A = (1 << COM1A0) | (1 << COM1B0); TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11); TIMSK1 |= (1 << OCIE1A) | (1 << OCIE1B); sei(); uint16_t blink_ctr = 0; while (1) { /* read pot 1 */ ADMUX = (1 << REFS0) | (1 << MUX0); _delay_us(10); ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)) { } uint16_t av1 = ADC; /* read pot 2 */ ADMUX = (1 << REFS0) | (0 << MUX0); _delay_us(10); ADCSRA |= (1 << ADSC); while (ADCSRA & (1 << ADSC)) { } uint16_t av2 = ADC; uint16_t dv1 = adc2us(av1); uint16_t dv2 = adc2us(av2); duty1 = dv1; duty2 = dv2; blink_ctr++; if (blink_ctr & (1 << 10)) { disp_num(0, dv1 / 100); disp_num(1, dv2 / 100); seg7data[1] |= Dp2; seg7data[3] |= Dp2; } else { disp_dv(0, dv1); disp_dv(1, dv2); if (blink_ctr & (1 << 7)) { if ((dv1 < 1000) || (dv1 >= 2000)) { seg7data[0] = 0; seg7data[1] = 0; } if ((dv2 < 1000) || (dv2 >= 2000)) { seg7data[2] = 0; seg7data[3] = 0; } } } shiftreg_set32(); _delay_us(1000); /* display dimming to prevent it from heating up too much (disabled for now) */ if (0) for (int x = 0; x < 10; x++) { shiftreg_zero32(); _delay_us(2500-700); shiftreg_set32(); _delay_us(700); } } }