commit de681b31bc16e0e9a696ee857289794f02524078 Author: DWW Date: Sun Jun 27 16:01:56 2021 +0300 Added Code & OpenSCAD files diff --git a/code/i2c_master.c b/code/i2c_master.c new file mode 100644 index 0000000..137bd88 --- /dev/null +++ b/code/i2c_master.c @@ -0,0 +1,131 @@ +#include "i2c_master.h" +#include + +uint8_t i2c_clock(uint8_t type); + +void i2c_init(void) +{ + // Define SCL and SDA as Output + DDRB |= (1 << 0) | (1 << 2); + + // Preload dataregister with "released level" data + USIDR = 0xFF; + + // Use SCL and SDA pins + // Select clock sources + USICR = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK); + + // Clear flags and reset counter + USISR = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC); +} + +uint8_t i2c_start(uint8_t address) +{ + // FOR REPEATED START + // Release SCL + PORTB |= (1 << 2); + // Verify that SCL becomes high + while (!( PINB & (1 << 2) )); + + // GENERATE START CONDITION + // Force SDA LOW + PORTB &= ~(1 << 0); + + // Pull SCL LOW + PORTB &= ~(1 << 2); + // Release SDA + PORTB |= (1 << 0); + + return i2c_write(address); +} + +uint8_t i2c_write(uint8_t data) +{ + // Pull SCL LOW + PORTB &= ~(1 << 2); + // Setup data + USIDR = data; + + // Send 8 bits on bus + i2c_clock(8); + + // Enable SDA as input + DDRB &= ~(1 << 0); + + // Receive 1 bit on bus & Check for NACK + if (i2c_clock(1) & (1 << 0)) + { + return 1; + } + return 0; +} + +uint8_t i2c_read(uint8_t nack) +{ + // Enable SDA as input. + DDRB &= ~(1 << 0); + // Read 8 bits + uint8_t result = i2c_clock(8); + + if (nack) + { + // Load NACK + USIDR = 0xFF; + } + else + { + // Load ACK + USIDR = 0x00; + } + + i2c_clock(1); + return result; +} + +void i2c_stop(void) +{ + // Pull SDA low + PORTB &= ~(1 << 0); + // Release SCL + PORTB |= (1 << 2); + // Wait for SCL to go high + while (!( PINB & (1 << 2) )); + + // Release SDA + PORTB |= (1 << 0); +} + +uint8_t i2c_clock(uint8_t count) +{ + uint8_t reg_temp = (1 << USISIF) | (1 << USIOIF) | (1 << USIPF) | (1 << USIDC); + // Counter counts number of edges + // Overflow signals end of transmission + reg_temp |= 16 - (count * 2); + + USISR = reg_temp; + + // Set clock source & toggle clock prepare + reg_temp = (1 << USIWM1) | (1 << USICS1) | (1 << USICLK) | (1 << USITC); + do + { + // Generate positve SCL edge. + USICR = reg_temp; + + // Wait for SCL to go high + while (!( PINB & (1 << 2))); + + // Generate negative SCL edge + USICR = reg_temp; + } + // Wait for counter overflow (all edges are completed) + while (!( USISR & (1 << USIOIF))); + + // Read data + reg_temp = USIDR; + // Load dataregister with "released level" data + USIDR = 0xFF; + + // Enable SDA as output + DDRB |= (1 << 0); + return reg_temp; +} diff --git a/code/i2c_master.h b/code/i2c_master.h new file mode 100644 index 0000000..42bba16 --- /dev/null +++ b/code/i2c_master.h @@ -0,0 +1,15 @@ +#include + +#ifndef I2C_MASTER_H +#define I2C_MASTER_H + +#define I2C_READ 0x01 +#define I2C_WRITE 0x00 + +void i2c_init(void); +uint8_t i2c_start(uint8_t address); +uint8_t i2c_write(uint8_t data); +uint8_t i2c_read(uint8_t nack); +void i2c_stop(void); + +#endif // I2C_MASTER_H diff --git a/code/main.c b/code/main.c new file mode 100644 index 0000000..3880d91 --- /dev/null +++ b/code/main.c @@ -0,0 +1,848 @@ +#include +#include +#include +#include +#include + +#include + +#include "i2c_master.h" + +#define EEPROM_SIZE 512 + +#define CHAR_SIZE 5 + +#define OLED_ADDRESS (0x3C << 1) + +#define OLED_X_SIZE 128 +#define OLED_Y_SIZE 32 + +// Time(ms) to keep the display on before sleep +#define DISPLAY_DELAY 3000 + +// Time(ms) to assume long button press +#define LONG_PRESS 500 + +// Rotary Encoder Parameters +#define ROT_PULSE_COUNT 12 +#define ROT_WHEEL_RAD 12 + +// Input masks +#define BUTTON_V 0x01 +#define BUTTON_S 1 +#define BUTTON_M (BUTTON_V << BUTTON_S) + +#define ENCODER_V 0x03 +#define ENCODER_S 3 +#define ENCODER_M (ENCODER_V << ENCODER_S) + +#define INPUT_MASK (BUTTON_M | ENCODER_M) + +// Event queue macros +#define MAX_EVENT_COUNT 16 +#define PTR_INC(x) ((x) = events + ((((x) - events) + 1) % MAX_EVENT_COUNT)) + +enum event_e +{ + EVENT_BUTTON_DOWN, + EVENT_BUTTON_UP, + EVENT_ROT_CW, + EVENT_ROT_CCW, + EVENT_NONE +}; + +enum state_e +{ + STATE_COUNTING, + STATE_SETTING +}; + +uint8_t old_input_state; + +uint8_t events[MAX_EVENT_COUNT]; +uint8_t event_count = 0; +uint8_t *event_read = events; +uint8_t *event_write = events; + +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_ROT_CW, EVENT_NONE, EVENT_NONE, EVENT_ROT_CCW, + EVENT_NONE, EVENT_ROT_CCW, EVENT_ROT_CW, EVENT_NONE +}; + +const uint8_t PROGMEM symbols[80] = +{ + 0x3D, 0x51, 0x49, 0x45, 0x3D, // 0 + 0x00, 0x42, 0x7F, 0x40, 0x00, // 1 + 0x42, 0x61, 0x51, 0x49, 0x46, // 2 + 0x21, 0x41, 0x45, 0x4B, 0x31, // 3 + 0x18, 0x14, 0x12, 0x7F, 0x10, // 4 + 0x27, 0x45, 0x45, 0x45, 0x39, // 5 + 0x3C, 0x4A, 0x49, 0x49, 0x30, // 6 + 0x03, 0x71, 0x09, 0x05, 0x03, // 7 + 0x36, 0x49, 0x49, 0x49, 0x36, // 8 + 0x06, 0x49, 0x49, 0x29, 0x1D, // 9 + 0x7C, 0x04, 0x78, 0x04, 0x78, // m + 0x1F, 0x20, 0x40, 0x20, 0x1F, // V + 0x00, 0x60, 0x60, 0x00, 0x00, // . + 0x00, 0x00, 0xFF, 0x00, 0x00, // | + 0x04, 0x06, 0xFF, 0x06, 0x04, // Up-arrow + 0x20, 0x60, 0xFF, 0x60, 0x20 // Down-arrow +}; + +void simple_init(); +void display_send_cmd(uint8_t cmd); +void display_send_data(const uint8_t *data, uint16_t buflen); +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_direction(uint8_t is_up); +void print_voltage(uint16_t value); +uint16_t adc_measure(); +uint16_t get_voltage(); +uint16_t find_eeprom_idx(); +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); + +ISR(TIMER1_OVF_vect) +{ + cli(); + ++ms; + sei(); +} + +ISR(PCINT0_vect) +{ + // Check button and encoder inputs + uint8_t input_state = PINB & INPUT_MASK; + uint8_t rot_event = EVENT_NONE; + uint8_t rot_idx; + + cli(); + + // Check if button has changed + if (((input_state ^ old_input_state) & BUTTON_M) && + (event_count != MAX_EVENT_COUNT)) + { + // Button is unpressed + if (input_state & BUTTON_M) + { + *event_write = EVENT_BUTTON_UP; + } + else + { + *event_write = EVENT_BUTTON_DOWN; + } + ++event_count; + PTR_INC(event_write); + } + + // Check if encoder has changed + if (((input_state ^ old_input_state) & ENCODER_M) && + (event_count != MAX_EVENT_COUNT)) + { + rot_idx = ((old_input_state & ENCODER_M) >> (ENCODER_S - 2)) | + ((input_state & ENCODER_M) >> ENCODER_S); + rot_event = pgm_read_byte(&(rot_table[rot_idx])); + + if (EVENT_NONE != rot_event) + { + *event_write = rot_event; + ++event_count; + PTR_INC(event_write); + } + } + + old_input_state = input_state; + + sei(); +} + +int main() +{ + // 1 / (4 * ROT_PULSE_COUNT) * (2 * pi * ROT_WHEEL_RAD) + const float rot_coeff = 1.57f * ROT_WHEEL_RAD / ROT_PULSE_COUNT; + uint32_t sleep_when_ms = 0; + uint32_t long_press_when_ms = 0; + uint32_t count_value = 0; + float count_value_fine = 0; + uint32_t eeprom_value = 0; + uint16_t eeprom_idx = 0; + uint8_t move_dir = 0; + int8_t rot_value = 0; + + uint32_t highlight; + uint8_t dir_highlight; + uint8_t curr_event; + uint8_t state; + + // Init Direct Hardware + simple_init(); + + i2c_init(); + display_init(); + + state = STATE_COUNTING; + + eeprom_idx = find_eeprom_idx(); + if (EEPROM_SIZE == eeprom_idx) + { + eeprom_idx = 0; + state = STATE_SETTING; + } + + read_eeprom_val(eeprom_idx, &eeprom_value, &move_dir); + if (0 == eeprom_value) + { + state = STATE_SETTING; + } + else + { + count_value = eeprom_value; + count_value_fine = eeprom_value; + } + + if (STATE_COUNTING == state) + { + display_enable(0); + } + + while(1) + { + switch (state) + { + case STATE_COUNTING: + if (event_count > 0) + { + // Consume Event + cli(); + curr_event = *event_read; + PTR_INC(event_read); + --event_count; + sei(); + + // Process Event + switch(curr_event) + { + case EVENT_BUTTON_DOWN: + long_press_when_ms = ms + LONG_PRESS; + sleep_when_ms = ms + DISPLAY_DELAY; + display_enable(1); + update_display(count_value, 0, move_dir, 0); + break; + + case EVENT_BUTTON_UP: + long_press_when_ms = 0; + break; + + case EVENT_ROT_CW: + if (0 != move_dir) + { + --rot_value; + } + else + { + ++rot_value; + } + break; + + case EVENT_ROT_CCW: + if (0 != move_dir) + { + ++rot_value; + } + else + { + --rot_value; + } + break; + } + } + + if (rot_value / 2 != 0) + { + int8_t rot_abs; + int8_t adjust; + + rot_abs = rot_value; + adjust = 1; + if (rot_value < 0) + { + rot_abs = -rot_abs; + adjust = -1; + } + + count_value_fine += (rot_coeff * adjust * rot_abs); + count_value = (uint32_t) count_value_fine; + rot_value -= (rot_abs * adjust); + + if (0 != sleep_when_ms) + { + update_display(count_value, 0, move_dir, 0); + } + } + + if ((0 != long_press_when_ms) && (long_press_when_ms < ms)) + { + sleep_when_ms = 0; + long_press_when_ms = 0; + highlight = 100000; + update_display(count_value, highlight, move_dir, 0); + state = STATE_SETTING; + } + + if ((0 != sleep_when_ms) && (sleep_when_ms < ms)) + { + sleep_when_ms = 0; + display_enable(0); + do_sleep(); + } + break; + + case STATE_SETTING: + if (event_count > 0) + { + // Consume Event + cli(); + curr_event = *event_read; + PTR_INC(event_read); + --event_count; + sei(); + + // Process Event + switch(curr_event) + { + case EVENT_BUTTON_DOWN: + long_press_when_ms = ms + LONG_PRESS; + display_enable(1); + break; + + case EVENT_BUTTON_UP: + if (long_press_when_ms > ms) + { + // Short Press + + if (0 != dir_highlight) + { + if (0 == move_dir) + { + move_dir = 1; + } + else + { + move_dir = 0; + } + } + + if (0 != highlight) + { + uint32_t temp_count = count_value; + temp_count = count_value % (highlight * 10); + count_value -= temp_count; + temp_count += highlight; + temp_count %= highlight * 10; + count_value += temp_count; + count_value_fine = count_value; + } + + update_display(count_value, highlight, move_dir, dir_highlight); + } + long_press_when_ms = 0; + break; + } + } + + if ((0 != long_press_when_ms) && (long_press_when_ms < ms)) + { + // Long press + + if (0 != highlight) + { + highlight /= 10; + if (0 == highlight) + { + dir_highlight = 1; + } + } + else if (0 != dir_highlight) + { + dir_highlight = 0; + state = STATE_COUNTING; + + ++eeprom_idx; + eeprom_idx %= EEPROM_SIZE; + write_eeprom_val(idx, count_value, move_dir); + } + + update_display(count_value, highlight, move_dir, dir_highlight); + long_press_when_ms = 0; + } + + break; + } + } +} + +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); + + // Enable Interrupt on overflow + TIMSK = (1 << TOIE1); + + // Interrupt on button and rotary encoder pins + PCMSK = (1 << PCINT1) | (1 << PCINT3) | (1 << PCINT4); + + // Interrupt type is any logical change + MCUCR = (1 << ISC00); + + // Enable Interrupt on pin-change + GIMSK = (1 << PCIE); + + // Measure Vbg(1.1V) with Vcc reference + ADMUX = (1 << MUX3) | (1 << MUX2); + + // ADC prescaler 16 + ADCSRA = (1 << ADPS2); + + // Power reduction - Disable timer 0 + PRR = (1 << PRTIM0); + + old_input_state = INPUT_MASK; +} + +void display_send_cmd(uint8_t cmd) +{ + i2c_start(OLED_ADDRESS | I2C_WRITE); + i2c_write(0x00); // Command Indicator + i2c_write(cmd); + i2c_stop(); +} + +void display_send_data(const uint8_t *data, uint16_t buflen) +{ + uint16_t i; + + for (i = 0; i < buflen; ++i) + { + if (0 == (i % 0x0F)) + { + i2c_start(OLED_ADDRESS | I2C_WRITE); + i2c_write(0x40); // Data Indicator + } + + i2c_write(data[i]); + + if (0x0F == (i % 0x0F)) + { + i2c_stop(); + } + } + + if (0 != (i % 0x0F)) + { + i2c_stop(); + } +} + +void display_init() +{ + uint16_t i; + uint8_t buf[16]; + + const uint8_t cmd_list[] = + { + 0xAE, // Display OFF + 0xD5, // Set Clock Divider / Oscillator Frequency + 0x80, // Default OSC / No Div + 0xA8, // Set Multiplex Ratio + OLED_Y_SIZE - 1, + 0xD3, // Set Display Offset + 0x00, // 0 Offset + 0x40 | 0x00, // Set Start Line To 0 + 0x8D, // Set Charge Pump + 0x14, // Enable Charge Pump When Display Is On + 0x20, // Set Memory Mode + 0x00, // Horizontal Mode + 0xA0 | 0x01, // Set Segment Remap - column 127 is seg 0 + 0xC8, // Set COM Scan Direction To Decrement + 0xDA, // Set COM Pin Configuration + 0x02 | 0x00, // Row 0 = COM63, Row 31 = COM32 + 0x81, // Set Contrast + 0xFF, // Contrast Value + 0xD9, // Set Precharge Period + 0x01 | 0xF0, // Phase 1 - 1 CLK, Phase 2 - 15 CLK + 0xDB, // Set VCOM Deselect Level +#if 1 + 0x30, // 0.83 x Vcc +#else + 0x40, // UNKNOWN (0.90 x Vcc Assumed) +#endif + 0xA4, // Display RAM Contents + 0xA6, // Set Normal Display (1 is white) + 0x2E, // Deactivate Scroll + 0xAF, // Display ON + + // Commands to send to RAM + 0x21, // Set Column Address + 0x00, + OLED_X_SIZE - 1, + 0x22, // Set Page Address + 0x00, + (OLED_Y_SIZE / 8) - 1 + }; + + // Send Commands + for (i = 0; i < sizeof(cmd_list); ++i) + { + display_send_cmd(cmd_list[i]); + } + + // Fill Buffer With Black + for (i = 0; i < sizeof(buf); ++i) + { + buf[i] = 0; + } + + // Black Entire Screen + for (i = 0; i < OLED_X_SIZE * OLED_Y_SIZE / 8 / sizeof(buf); ++i) + { + display_send_data(buf, sizeof(buf)); + } +} + +void display_enable(uint8_t en) +{ + display_send_cmd(0xAE | (en & 0x01)); +} + +void get_symbol16(uint8_t index, uint8_t *out) +{ + uint8_t i; + uint8_t data_byte; + const uint8_t PROGMEM unfold_table[16] = + { + 0x00, + 0x02, + 0x08, + 0x0A, + 0x20, + 0x22, + 0x28, + 0x2A, + 0x80, + 0x82 + 0x88, + 0x8A, + 0xA0, + 0xA2, + 0xA8, + 0xAA + }; + + for (i = 0; i < CHAR_SIZE * 4; ++i) + { + out[i] = 0; + } + + for (i = 0; i < CHAR_SIZE; ++i) + { + data_byte = pgm_read_byte(&(symbols[index * CHAR_SIZE + i])); + out[i * 2 + 1] = pgm_read_byte(&(unfold_table[data_byte & 0x0F])); + out[CHAR_SIZE * 2 + i * 2 + 1] = pgm_read_byte(&(unfold_table[(data_byte >> 4) & 0x0F])); + } +} + +void print_symbol(uint8_t symbol_idx, uint8_t x, uint8_t y, uint8_t invert) +{ + uint8_t unfolded_symbol[CHAR_SIZE * 4]; + uint8_t cmd_list[6] + { + 0x21, // Set Column Address + 0x00, // Start Address + 0x00, // End Address + 0x22, // Set Page Address + 0x00, // Start Page 0 + 0x00 // End Page + }; + uint8_t i; + + get_symbol16(symbol_idx, unfolded_symbol); + if (invert) + { + for (i = 0; i < sizeof(unfolded_symbol); ++i) + { + unfolded_symbol[i] = ~(unfolded_symbol[i]); + } + } + + x = x % (OLED_X_SIZE); + y = y % (OLED_Y_SIZE / (8 * 2)); + + if (x > (OLED_X_SIZE - CHAR_SIZE * 2) + { + x = OLED_X_SIZE - CHAR_SIZE * 2; + } + + cmd_list[1] = x; + cmd_list[2] = x + CHAR_SIZE * 2 - 1; + cmd_list[4] = y * 2; + cmd_list[5] = y * 2 + 1; + + for (i = 0; i < sizeof(cmd_list); ++i) + { + display_send_cmd(cmd_list[i]); + } + + display_send_data(unfolded_symbol, sizeof(unfolded_symbol)); +} + +void print_mm(uint32_t value, uint32_t highlight) +{ + uint8_t x; + uint8_t y; + uint8_t symbol; + uint8_t invert; + uint8_t is_first; + uint32_t div_factor; + + x = 0; + y = 0; + div_factor = 1000000; + value %= div_factor; + div_factor /= 10; + is_first = 1; + + // Print 6 digits + while (div_factor != 0) + { + symbol = value / div_factor; + value %= div_factor; + + if (div_factor == highlight) + { + invert = 1; + } + else + { + invert = 0; + } + + // Check if we need to print (for leading zeroes) + if (!(is_first && (0 == highlight) && (0 == symbol))) + { + is_first = 0; + print_symbol(symbol * CHAR_SIZE, x, y, invert); + } + x += (CHAR_SIZE + 1) * 2; + div_factor /= 10; + } + + // Print 'mm' + print_symbol(10 * CHAR_SIZE, x, y, 0); + x += (CHAR_SIZE + 1) * 2; + print_symbol(10 * CHAR_SIZE, x, y, 0); +} + +void print_direction(uint8_t is_up, uint8_t invert) +{ + uint8_t symbol_index[2]; + + if (is_up) + { + symbol_index[0] = 14 * CHAR_SIZE; + symbol_index[1] = 13 * CHAR_SIZE; + } + else + { + symbol_index[0] = 13 * CHAR_SIZE; + symbol_index[1] = 15 * CHAR_SIZE; + } + + 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); +} + +void print_voltage(uint16_t value) +{ + uint8_t x; + uint8_t y; + uint8_t symbol; + uint32_t div_factor; + + x = 0; + y = 1; + div_factor = 1000; + value %= div_factor; + div_factor /= 10; + + // Print 3 digits + while (div_factor != 0) + { + symbol = value / div_factor; + value %= div_factor; + + print_symbol(symbol * CHAR_SIZE, x, y, 0); + if (0 == x) + { + x += (CHAR_SIZE + 1) * 2; + } + x += (CHAR_SIZE + 1) * 2; + div_factor /= 10; + } + + // Print 'V' + print_symbol(11 * CHAR_SIZE, x, y, 0); + + // Print '.' + x = (CHAR_SIZE + 1) * 2; + print_symbol(12 * CHAR_SIZE, x, y, 0); +} + +uint16_t adc_measure() +{ + uint16_t result; + + // Enable and start ADC + ADCSRA |= (1 << ADEN) | (1 << ADSC); + + // Wait for conversion + while (ADCSRA & (1 << ADSC)); + + // Read ADC value + result = ADC; + + // Disable ADC + ADCSRA &= ~(1 << ADEN); + + return result; +} + +uint16_t measure_voltage() +{ + uint32_t val; + uint16_t result; + + val = 110 * 1023; + val /= adc_measure(); + result = val; + + return result; +} + +uint16_t find_eeprom_idx() +{ + uint16_t idx = 0; + uint8_t found = 0; + + for (idx = 0; idx < EEPROM_SIZE; ++idx) + { + if (0xFF != eeprom_read_byte((uint8_t *) idx)) + { + found = 1; + break; + } + } + + if (!found) + { + return EEPROM_SIZE; + } + + if (0 == idx) + { + for (idx = EEPROM_SIZE - 3; idx < EEPROM_SIZE; ++idx) + { + if (0xFF != eeprom_read_byte((uint8_t *) idx)) + { + break; + } + } + } + + idx += EEPROM_SIZE; + --idx; + idx %= EEPROM_SIZE; + + return idx; +} + +void read_eeprom_val(uint16_t idx, uint32_t *value, uint8_t *dir) +{ + uint8_t curr_byte; + uint8_t i; + + (*value) = 0; + for (i = 0; i < 4; ++i) + { + curr_byte = eeprom_read_byte((uint8_t *) idx); + (*value) |= (curr_byte << (24 - 8 * i)); + ++idx; + idx %= EEPROM_SIZE; + } + + *dir = ((*value) & 0x00800000) >> 23; + (*value) &= 0x007FFFFF; +} + +void write_eeprom_val(uint16_t idx, uint32_t value, uint8_t dir) +{ + uint8_t curr_byte; + uint8_t i; + + value |= 0xFF000000; + if (0 != dir) + { + value |= 0x00800000; + } + + for (i = 0; i < 4; ++i) + { + curr_byte = (value >> (24 - 8 * i)) & 0xFF; + eeprom_update_byte((uint8_t *) idx, curr_byte); + ++idx; + idx %= EEPROM_SIZE; + } +} + +void do_sleep() +{ + // Disable clock to Timer1, USI, ADC + PRR |= (1 << PRTIM1) | (1 << PRUSI) | (1 << PRADC); + + // Enable sleep + MCUCR |= (1 << SE); + + // Sleep + sleep_cpu(); + + // Reset ms counter + cli(); + ms = 0; + sei(); + + // Disable sleep + MCUCR &= ~(1 << SE); + + // Enable clock to Timer1, USI, ADC + PRR &= ~((1 << PRTIM1) | (1 << PRUSI) | (1 << PRADC)); +} + +void update_display(uint32_t value, uint32_t highlight, uint8_t dir, uint8_t dir_highlight) +{ + print_mm(value, highlight); + print_direction(dir, dir_highlight); + print_voltage(get_voltage()); +} diff --git a/openscad/spool_holder.scad b/openscad/spool_holder.scad new file mode 100644 index 0000000..26e6ed7 --- /dev/null +++ b/openscad/spool_holder.scad @@ -0,0 +1,37 @@ +thickness = 5; +hole_rad = 5; +spool_rad = 150; +square_size = spool_rad + hole_rad * 4; +triangle_rad = square_size * 2 / 3; +filament_width = 10; +filament_height = 20; +filament_offset = 2; +// -1 = Left; 1 = Right +side = -1; + +difference() +{ + // Base Shape + union() + { + translate([square_size / 2 * side, 0, 0]) + cube([square_size, square_size, thickness], center = true); + + translate([0, -square_size / 6, 0]) + rotate([0, 0, -30]) + cylinder(thickness, triangle_rad, triangle_rad, $fn = 3, center = true); + } + + // Holes + for (i = [0:1:2]) + { + translate([0, -square_size / 6, 0]) + rotate(-30 + i*120) + translate([triangle_rad - hole_rad * 3, 0, 0]) + cylinder(thickness + 2, hole_rad, hole_rad, $fn = 360, center = true); + } + + // Filament Sensor + translate([square_size * side - side * (filament_width / 2 + filament_offset), square_size / 2 - filament_height / 2, thickness / 2]) + cube([filament_width, filament_height, thickness], center = true); +} \ No newline at end of file diff --git a/openscad/zippy_cover.scad b/openscad/zippy_cover.scad new file mode 100644 index 0000000..8921def --- /dev/null +++ b/openscad/zippy_cover.scad @@ -0,0 +1,6 @@ +difference() +{ + cylinder(5, 11, 11, $fn=360, center = true); + translate([0, 0, 1.5]) + cylinder(5, 10.5, 10.5, $fn=360, center = true); +} \ No newline at end of file