diff --git a/code/main.c b/code/main.c index ca210bb..6b4cc91 100644 --- a/code/main.c +++ b/code/main.c @@ -68,10 +68,10 @@ uint32_t ms = 0; const uint8_t PROGMEM rot_table[16] = { - EVENT_NONE, EVENT_ROT_CW, EVENT_ROT_CCW, EVENT_NONE, - EVENT_ROT_CCW, EVENT_NONE, EVENT_NONE, EVENT_ROT_CW, + EVENT_NONE, EVENT_ROT_CCW, EVENT_ROT_CW, EVENT_NONE, EVENT_ROT_CW, EVENT_NONE, EVENT_NONE, EVENT_ROT_CCW, - EVENT_NONE, EVENT_ROT_CCW, EVENT_ROT_CW, EVENT_NONE + EVENT_ROT_CCW, EVENT_NONE, EVENT_NONE, EVENT_ROT_CW, + EVENT_NONE, EVENT_ROT_CW, EVENT_ROT_CCW, EVENT_NONE }; const uint8_t PROGMEM unfold_table[16] = @@ -121,7 +121,7 @@ void display_init(); void display_enable(uint8_t en); void get_symbol16(uint8_t index, uint8_t *out); void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert); -void print_mm(uint32_t value, uint32_t highlight); +void print_mm(uint32_t value, uint8_t highlight); void print_direction(uint8_t is_up, uint8_t invert); void print_voltage(uint16_t value); uint16_t adc_measure(); @@ -131,6 +131,7 @@ void read_eeprom_val(uint16_t idx, uint32_t *value, uint8_t *dir); void write_eeprom_val(uint16_t idx, uint32_t value, uint8_t dir); void do_sleep(); void update_display(uint32_t value, uint32_t highlight, uint8_t dir, uint8_t dir_highlight); +uint8_t extract_digit(uint32_t value, uint8_t digit_num); ISR(TIMER1_OVF_vect) { @@ -198,9 +199,10 @@ int main() uint16_t eeprom_idx = 0; uint8_t move_dir = 0; int8_t rot_value = 0; + uint8_t dir_highlight = 0; + uint8_t highlight = 0; + uint8_t needs_update = 0; - uint32_t highlight; - uint8_t dir_highlight; uint8_t curr_event; uint8_t state; @@ -217,6 +219,8 @@ int main() { eeprom_idx = 0; state = STATE_SETTING; + highlight = 6; + needs_update = 1; } else { @@ -224,6 +228,8 @@ int main() if (0 == eeprom_value) { state = STATE_SETTING; + highlight = 6; + needs_update = 1; } else { @@ -234,6 +240,7 @@ int main() if (STATE_COUNTING == state) { + sleep_when_ms = 1; display_enable(0); } @@ -243,7 +250,7 @@ int main() switch (state) { case STATE_COUNTING: - if (event_count > 0) + while (event_count > 0) { // Consume Event cli(); @@ -259,7 +266,7 @@ int main() long_press_when_ms = ms + LONG_PRESS; sleep_when_ms = ms + DISPLAY_DELAY; display_enable(1); - update_display(count_value, 0, move_dir, 0); + needs_update = 1; break; case EVENT_BUTTON_UP: @@ -303,13 +310,30 @@ int main() adjust = -1; } - count_value_fine += (rot_coeff * adjust * rot_abs); - count_value = (uint32_t) count_value_fine; rot_value -= (rot_abs * adjust); + count_value_fine += (rot_coeff * adjust * rot_abs); + + if (count_value_fine < 0) + { + count_value_fine = 0; + state = STATE_SETTING; + display_enable(1); + needs_update = 1; + sleep_when_ms = 0; + } + + // Update EEPROM When Meter Value Changes + if ((uint32_t)count_value_fine / 1000 != count_value / 1000) + { + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE; + write_eeprom_val(eeprom_idx, (uint32_t)count_value_fine, move_dir); + } + count_value = (uint32_t) count_value_fine; if (0 != sleep_when_ms) { - update_display(count_value, 0, move_dir, 0); + needs_update = 1; } } @@ -317,14 +341,13 @@ int main() { sleep_when_ms = 0; long_press_when_ms = 0; - highlight = 100000; - update_display(count_value, highlight, move_dir, 0); + highlight = 6; + needs_update = 1; state = STATE_SETTING; } if ((0 != sleep_when_ms) && (sleep_when_ms < ms)) { - sleep_when_ms = 0; display_enable(0); do_sleep(); } @@ -333,7 +356,7 @@ int main() break; case STATE_SETTING: - if (event_count > 0) + while (event_count > 0) { // Consume Event cli(); @@ -347,7 +370,6 @@ int main() { case EVENT_BUTTON_DOWN: long_press_when_ms = ms + LONG_PRESS; - display_enable(1); break; case EVENT_BUTTON_UP: @@ -370,15 +392,23 @@ int main() if (0 != highlight) { uint32_t temp_count = count_value; - temp_count = count_value % (highlight * 10); + uint32_t div = 1; + uint8_t i; + + for (i = 1; i < highlight; ++i) + { + div *= 10; + } + + temp_count = count_value % (div * 10); count_value -= temp_count; - temp_count += highlight; - temp_count %= highlight * 10; + temp_count += div; + temp_count %= div * 10; count_value += temp_count; count_value_fine = count_value; } - update_display(count_value, highlight, move_dir, dir_highlight); + needs_update = 1; } long_press_when_ms = 0; @@ -393,29 +423,37 @@ int main() if (0 != highlight) { - highlight /= 10; + --highlight; if (0 == highlight) { dir_highlight = 1; } + needs_update = 1; } else if (0 != dir_highlight) { dir_highlight = 0; state = STATE_COUNTING; + sleep_when_ms = ms + DISPLAY_DELAY; + needs_update = 1; ++eeprom_idx; eeprom_idx %= EEPROM_SIZE; write_eeprom_val(eeprom_idx, count_value, move_dir); } - update_display(count_value, highlight, move_dir, dir_highlight); + needs_update = 1; long_press_when_ms = 0; } // STATE_SETTING break; } + if (needs_update) + { + update_display(count_value, highlight, move_dir, dir_highlight); + needs_update = 0; + } } } @@ -424,8 +462,8 @@ void simple_init() // Set pull-ups on button and rotary encoder PORTB = (1 << 1) | (1 << 3) | (1 << 4); - // Prescaler 1024 - TCCR1 = (1 << CS13) | (1 << CS11) | (1 << CS10); + // Prescaler 4 (1 MHz / 256 / 4 ~ 1000) + TCCR1 = (1 << CS11) | (1 << CS10); // Enable Interrupt on overflow TIMSK = (1 << TOIE1); @@ -442,8 +480,8 @@ void simple_init() // Measure Vbg(1.1V) with Vcc reference ADMUX = (1 << MUX3) | (1 << MUX2); - // ADC prescaler 16 - ADCSRA = (1 << ADPS2); + // ADC prescaler 8 + ADCSRA = (1 << ADPS1) | (1 << ADPS0); // Power reduction - Disable timer 0 PRR = (1 << PRTIM0); @@ -623,29 +661,26 @@ void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert) display_send_data(unfolded_symbol, sizeof(unfolded_symbol)); } -void print_mm(uint32_t value, uint32_t highlight) +void print_mm(uint32_t value, uint8_t highlight) { + static uint32_t old_value = 0; + static uint8_t old_highlight = 0; uint8_t x; uint8_t y; uint8_t symbol; uint8_t invert; uint8_t is_first; - uint32_t div_factor; + uint8_t i; x = 0; y = 0; - div_factor = 1000000; - value %= div_factor; - div_factor /= 10; is_first = 1; - // Print 6 digits - while (div_factor != 0) + // Print 6 digits (only needed ones) + for (i = 6; i > 0; --i) { - symbol = value / div_factor; - value %= div_factor; - - if (div_factor == highlight) + symbol = extract_digit(value, i); + if (highlight == i) { invert = 1; } @@ -654,8 +689,7 @@ void print_mm(uint32_t value, uint32_t highlight) invert = 0; } - // Check if we need to print (for leading zeroes) - if (is_first && (0 == highlight) && (0 == symbol)) + if (is_first && (0 == highlight) && (0 == symbol) && (1 != i)) { symbol = 0xFF; } @@ -663,20 +697,30 @@ void print_mm(uint32_t value, uint32_t highlight) { is_first = 0; } - print_symbol(symbol, x, y, invert); + + if ((0 == old_value) || (symbol != extract_digit(old_value, i)) || (old_highlight != highlight)) + { + print_symbol(symbol, x, y, invert); + } x += (CHAR_SIZE + 1) * 2; - div_factor /= 10; } // Print 'mm' - print_symbol(10, x, y, 0); - x += (CHAR_SIZE + 1) * 2; - print_symbol(10, x, y, 0); + if (0 == old_value) + { + print_symbol(10, x, y, 0); + x += (CHAR_SIZE + 1) * 2; + print_symbol(10, x, y, 0); + } + old_value = value; + old_highlight = highlight; } void print_direction(uint8_t is_up, uint8_t invert) { uint8_t symbol_index[2]; + static uint8_t old_is_up = 0; + static uint8_t old_invert = 1; if (is_up) { @@ -689,44 +733,53 @@ void print_direction(uint8_t is_up, uint8_t invert) symbol_index[1] = 15; } - print_symbol(symbol_index[0], OLED_X_SIZE - CHAR_SIZE * 2, 0, invert); - print_symbol(symbol_index[1], OLED_X_SIZE - CHAR_SIZE * 2, 1, invert); + if ((old_is_up != is_up) || (old_invert != invert)) + { + print_symbol(symbol_index[0], OLED_X_SIZE - CHAR_SIZE * 2, 0, invert); + print_symbol(symbol_index[1], OLED_X_SIZE - CHAR_SIZE * 2, 1, invert); + } + old_is_up = is_up; + old_invert = invert; } void print_voltage(uint16_t value) { + static uint16_t old_value = 0; uint8_t x; uint8_t y; uint8_t symbol; - uint32_t div_factor; + uint8_t i; x = 0; y = 1; - div_factor = 1000; - value %= div_factor; - div_factor /= 10; // Print 3 digits - while (div_factor != 0) + for (i = 3; i > 0; --i) { - symbol = value / div_factor; - value %= div_factor; + symbol = extract_digit(value, i); + if ((0 == old_value) || (symbol != extract_digit(old_value, i))) + { + print_symbol(symbol, x, y, 0); + } - print_symbol(symbol, x, y, 0); if (0 == x) { x += (CHAR_SIZE + 1) * 2; } + x += (CHAR_SIZE + 1) * 2; - div_factor /= 10; } - // Print 'V' - print_symbol(11, x, y, 0); + if (0 == old_value) + { + // Print 'V' + print_symbol(11, x, y, 0); - // Print '.' - x = (CHAR_SIZE + 1) * 2; - print_symbol(12, x, y, 0); + // Print '.' + x = (CHAR_SIZE + 1) * 2; + print_symbol(12, x, y, 0); + } + old_value = value; } uint16_t adc_measure() @@ -742,6 +795,11 @@ uint16_t adc_measure() // Read ADC value result = ADC; + // Redo to get a better reading + ADCSRA |= (1 << ADSC); + while (ADCSRA & (1 << ADSC)); + result = ADC; + // Disable ADC ADCSRA &= ~(1 << ADEN); @@ -754,7 +812,7 @@ uint16_t measure_voltage() uint16_t result; val = 110; - val *= 1024; + val *= 1023; val /= adc_measure(); result = val; @@ -763,6 +821,7 @@ uint16_t measure_voltage() uint16_t find_eeprom_idx() { + // TODO: double check everything uint16_t idx = 0; uint8_t found = 0; @@ -865,3 +924,13 @@ void update_display(uint32_t value, uint32_t highlight, uint8_t dir, uint8_t dir print_direction(dir, dir_highlight); print_voltage(measure_voltage()); } + +uint8_t extract_digit(uint32_t value, uint8_t digit_num) +{ + while (1 != digit_num) + { + value /= 10; + --digit_num; + } + return value % 10; +}