/* ATtiny13 1.2MHz */ #define F_CPU 1200000L #include #include #include #include #define ADDRESS_1 8 #define ADDRESS_2 16 #define SWITCH_DDR DDRB #define SWITCH_PULL_UP PORTB #define SWITCH_PORT_IN PINB #define SWITCH_0_PIN PB0 #define SWITCH_1_PIN PB1 #define SWITCH_2_PIN PB2 #define BRIDGE_DDR DDRB #define BRIDGE_PORT_OUT PORTB #define BRIDGE_0_PIN PB3 #define BRIDGE_1_PIN PB4 #define SET_BIT(byte, bit) ((byte) |= (1UL << (bit))) #define CLEAR_BIT(byte,bit) ((byte) &= ~(1UL << (bit))) #define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit)) #define IS_PRESSED(byte,bit) (!(((byte) & (1UL << (bit))) >> (bit))) volatile uint8_t frequency, mode, frequency_old, mode_old, sequence=0, duration, duty, c, d, timer_overflow_count=0, timer_overflow_target=6; ISR(TIM0_OVF_vect) { if(++timer_overflow_count > timer_overflow_target) { // check if any button is pressed timer_overflow_target=6; // by default every 82ms /* If SWITCH_2 is pressed, change device's occlusions frequency */ if (IS_PRESSED(SWITCH_PORT_IN,SWITCH_2_PIN)) { frequency ++; timer_overflow_target=12; // wait 164ms after a button is pressed } if (frequency > 4) { frequency = 0; } /* If SWITCH_1 is pressed, change device's eye occlusion rate */ /* (how long eye is occluded in each main while loop execution) */ if (IS_PRESSED(SWITCH_PORT_IN,SWITCH_1_PIN)) { mode--; timer_overflow_target=12; // wait 164ms after a button is pressed } if (mode == 255) { mode = 8; } /* If SWITCH_0 is pressed, change device's eye occlusion rate */ /* (how long eye is occluded in each main while loop execution) */ if (IS_PRESSED(SWITCH_PORT_IN,SWITCH_0_PIN)) { mode++; timer_overflow_target=12; // wait 164ms after a button is pressed } if (mode > 8) { mode = 0; } /* If three buttons are pressed at the same time, reset to default settings */ if((IS_PRESSED(SWITCH_PORT_IN,SWITCH_2_PIN)) && (IS_PRESSED(SWITCH_PORT_IN,SWITCH_1_PIN)) && (IS_PRESSED(SWITCH_PORT_IN,SWITCH_0_PIN))) { frequency=1; mode=4; eeprom_update_byte((uint8_t*)ADDRESS_1, frequency); // update EEPROM with defaults eeprom_update_byte((uint8_t*)ADDRESS_2, mode); CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_0_PIN); // and make LCD panels transparent CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_1_PIN); _delay_ms(1000); // for one second } timer_overflow_count = 0; } } void advance_sequence(void) { // this function drives outputs switch(sequence) { case 0: SET_BIT(BRIDGE_PORT_OUT,BRIDGE_0_PIN); CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_1_PIN); break; case 1: CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_0_PIN); CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_1_PIN); break; case 2: CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_0_PIN); SET_BIT(BRIDGE_PORT_OUT,BRIDGE_1_PIN); break; case 3: CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_0_PIN); CLEAR_BIT(BRIDGE_PORT_OUT,BRIDGE_1_PIN); break; } sequence++; if(sequence>3) sequence=0; } int main(void) { uint8_t i; uint16_t delay; CLEAR_BIT(SWITCH_DDR,SWITCH_0_PIN); // set switches pins as inputs, pulled-up by internal resistors CLEAR_BIT(SWITCH_DDR,SWITCH_1_PIN); CLEAR_BIT(SWITCH_DDR,SWITCH_2_PIN); SET_BIT(SWITCH_PULL_UP,SWITCH_0_PIN); SET_BIT(SWITCH_PULL_UP,SWITCH_1_PIN); SET_BIT(SWITCH_PULL_UP,SWITCH_2_PIN); SET_BIT(BRIDGE_DDR,BRIDGE_0_PIN); // set LCD panel pins as outputs SET_BIT(BRIDGE_DDR,BRIDGE_1_PIN); frequency = eeprom_read_byte((uint8_t*)ADDRESS_1); // read previous state of device mode = eeprom_read_byte((uint8_t*)ADDRESS_2); if (frequency > 4) { frequency = 1; } // if EEPROM stored settings outside of range, set defaults if (mode > 8) { mode = 4; } SET_BIT(TCCR0B,CS01); // prescale timer to 1/64th the clock rate SET_BIT(TCCR0B,CS00); SET_BIT(TIMSK0,TOIE0); // enable timer overflow interrupt sei(); while (1) { switch(frequency) { // calculate how much time every main while loop execution will take case 0: duration=40; break; case 1: duration=20; break; case 2: duration=13; break; case 3: duration=10; break; case 4: duration=8; break; } d = d + duration; if(d > 100) { // Check approximately every second. // duration is in ms, in one cycle of main while loop duration is executed 10 times, // hence 100 "milliseconds" in a second if((frequency == frequency_old) && (mode == mode_old)) c++; // check if settings are permanent else c= 0; if(c==10) { // after approximately 10 seconds of settings being permanent eeprom_update_byte((uint8_t*)ADDRESS_1, frequency); //start updating EEPROM with stable setting eeprom_update_byte((uint8_t*)ADDRESS_2, mode); c = 0; } frequency_old = frequency; mode_old = mode; d = 0; } duty = mode; switch(frequency) { // determines how much time each tenth of main while loop cycle will take case 0: delay=12000; break; case 1: delay=6000; break; case 2: delay=4000; break; case 3: delay=3000; break; case 4: delay=2400; break; } /* Puts 10 blocks of _delay_loop_2 to properly */ /* synchronize eye occlusions. First blocks */ /* occlude the eye, next blocks are */ /* transparent. Each execution of _delay_loop_2 */ /* takes four clock cycles. */ /* -------------------------------------------- */ advance_sequence(); for(i = 0; i <= (duty); i++) _delay_loop_2(delay); advance_sequence(); for(i = 0; i < (9-duty); i++) _delay_loop_2(delay); /* -------------------------------------------- */ } }