#include #include #include #include #include "sed1335.h" #include "graphics.h" #include "touch.h" #include "gui.h" #include "bitmaps.h" unsigned char buffer[32]; volatile unsigned short count_2ms; #define ON 1 #define OFF 0 #define BACKLIGHT(a) ((a==1)?(PORTD|=_BV(7)):(PORTD&=(~_BV(7)))) //#define BACKLIGHT_TIME 2500 // 5s #define BACKLIGHT_TIME 1000 // 2s volatile unsigned short backlight_timer; volatile unsigned char backlight_mode; #define BACKLIGHT_ON 0 #define BACKLIGHT_OFF 1 #define BACKLIGHT_TIMED 2 // time keeping variables volatile unsigned char seconds, minutes, hours, am_pm; #define AM 0 #define PM 1 // draws main clock gui void draw_main_gui(); // updates varius clock displays void LCD_update_hours(); void LCD_update_minutes(); void LCD_update_seconds(); void LCD_update_ampm(); void LCD_update_time(); void LCD_update_backlight_mode(); unsigned char LCD_update_ready; // debounce time for touch screen #define DEB_TIME 1000 // 2 seconds #define SET_TIME 100 // 1/2 second // debounce counters unsigned char deb_hours_up, deb_hours_down, deb_mins_up, deb_mins_down; unsigned char deb_backlight; // callback functions for each button // comments in other functions are ommited because they are the same as this one void on_hours_up () { // reset all other debounce timers deb_hours_down = deb_mins_up = deb_mins_down = DEB_TIME; deb_backlight = DEB_TIME; deb_hours_up--; // if debounce period is up, perform action and update screen if (deb_hours_up == 0) { hours++; seconds = 0; count_2ms = 0; LCD_update_seconds(); LCD_update_hours(); deb_hours_up = SET_TIME; } } void on_hours_down () { deb_hours_up = deb_mins_up = deb_mins_down = DEB_TIME; deb_backlight = DEB_TIME; deb_hours_down--; if (deb_hours_down == 0) { hours--; seconds = 0; count_2ms = 0; LCD_update_seconds(); LCD_update_hours(); deb_hours_down = SET_TIME; } } void on_mins_up () { deb_hours_up = deb_hours_down = deb_mins_down = DEB_TIME; deb_backlight = DEB_TIME; deb_mins_up--; if (deb_mins_up == 0) { minutes++; seconds = 0; count_2ms = 0; LCD_update_seconds(); LCD_update_minutes(); deb_mins_up = SET_TIME; } } void on_mins_down () { deb_hours_up = deb_hours_down = deb_mins_up = DEB_TIME; deb_backlight = DEB_TIME; deb_mins_down--; if (deb_mins_down == 0) { minutes--; seconds = 0; count_2ms = 0; LCD_update_seconds(); LCD_update_minutes(); deb_mins_down = SET_TIME; } } void on_backlight () { deb_hours_up = deb_hours_down = deb_mins_up = deb_mins_down = DEB_TIME; deb_backlight--; if (deb_backlight == 0) { backlight_mode = backlight_mode + 1; // cycle through backlight mode if (backlight_mode == 3) { backlight_mode = 0; } deb_backlight = DEB_TIME; LCD_update_backlight_mode(); } } // 2ms interrupt interrupt [TIM0_COMP] void timer0_compare (void) { count_2ms++; if (backlight_timer > 0) { backlight_timer--; } if (count_2ms == 500) // 1s { count_2ms = 0; seconds++; if (seconds == 60) { seconds = 0; minutes++; if (minutes == 60) { minutes = 0; hours++; if (hours == 12) { am_pm = 1 - am_pm; } else if (hours == 13) { hours = 1; } } // end minutes } // end seconds //LCD_update_time(); LCD_update_ready = 1; } // end count_2ms } // end timer interrupt // LED drivers #define LED_RED(a) ((a==1)?(PORTD|=_BV(4)):(PORTD&=(~_BV(4)))) #define LED_GREEN(a) ((a==1)?(PORTD|=_BV(5)):(PORTD&=(~_BV(5)))) #define LED_BLUE(a) ((a==1)?(PORTD|=_BV(6)):(PORTD&=(~_BV(6)))) // hardrive clock variables unsigned char current_hand; unsigned char hand_order[3]; unsigned short delay_order[3]; unsigned short delays[60]; #define H_SECONDS 0 #define H_MINUTES 1 #define H_HOURS 2 // 500ns, used for hard drive clock delays interrupt [TIM1_COMPA] void timer1_compare (void) { unsigned char next_hand = 0; TCNT1 = 0; // determine current hand type and turn on right led if (hand_order[current_hand] == H_SECONDS) { LED_BLUE(1); } else if (hand_order[current_hand] == H_MINUTES) { LED_GREEN(1); } else if (hand_order[current_hand] == H_HOURS) { LED_RED(1); } // check if two or more hands are in the same place (delay = 0) if (current_hand <= 1) { next_hand = current_hand + 1; if (delay_order[next_hand] == 0) // if so { // turn on corresponding hand if (hand_order[next_hand] == H_SECONDS) { LED_BLUE(1); } else if (hand_order[next_hand] == H_MINUTES) { LED_GREEN(1); } else if (hand_order[next_hand] == H_HOURS) { LED_RED(1); } next_hand++; } } // end if (current_hand == 1) // check if all three hands are in one place else if (current_hand == 0) { // if so, turn on all leds if ((delay_order[current_hand+1] == 0) && (delay_order[current_hand+2] == 0)) { LED_BLUE(1); LED_GREEN(1); LED_RED(1); current_hand = 2; } } delay_us(20); // this determines the width of the hand // turn off all leds LED_BLUE(0); LED_GREEN(0); LED_RED(0); // if all hands have been displayed if (current_hand == 2) { OCR1A = 0xffff; // don't need any more delays, wait for ext.int. } // otherwise, sent delay for next hand else { current_hand = next_hand; OCR1A = delay_order[current_hand]; } } // slotted optical switch interrupt interrupt [EXT_INT0] void ext0_interrupt (void) { unsigned char hours_60; TCNT1 = 0; // since hours only go from 1 to 12, convert to 0-59 format hours_60 = hours * 5; if (hours_60 == 60) { hours_60 = 0; } // determine the order of hands in relation to the optical slot interrupt // then set relative delays and order which will be read by the timer1 interrupt if ((delays[seconds] <= delays[minutes]) && (delays[minutes] <= delays[hours_60])) { delay_order[0] = delays[seconds]; delay_order[1] = delays[minutes] - delays[seconds]; delay_order[2] = delays[hours_60] - delays[minutes]; hand_order[0] = H_SECONDS; hand_order[1] = H_MINUTES; hand_order[2] = H_HOURS; } else if ((delays[seconds] <= delays[hours_60]) && (delays[hours_60] <= delays[minutes])) { delay_order[0] = delays[seconds]; delay_order[1] = delays[hours_60] - delays[seconds]; delay_order[2] = delays[minutes] - delays[hours_60]; hand_order[0] = H_SECONDS; hand_order[1] = H_HOURS; hand_order[2] = H_MINUTES; } else if ((delays[minutes] <= delays[seconds]) && (delays[seconds] <= delays[hours_60])) { delay_order[0] = delays[minutes]; delay_order[1] = delays[seconds] - delays[minutes]; delay_order[2] = delays[hours_60] - delays[seconds]; hand_order[0] = H_MINUTES; hand_order[1] = H_SECONDS; hand_order[2] = H_HOURS; } else if ((delays[minutes] <= delays[hours_60]) && (delays[hours_60] <= delays[seconds])) { delay_order[0] = delays[minutes]; delay_order[1] = delays[hours_60] - delays[minutes]; delay_order[2] = delays[seconds] - delays[hours_60]; hand_order[0] = H_MINUTES; hand_order[1] = H_HOURS; hand_order[2] = H_SECONDS; } else if ((delays[hours_60] <= delays[seconds]) && (delays[seconds] <= delays[minutes])) { delay_order[0] = delays[hours_60]; delay_order[1] = delays[seconds] - delays[hours_60]; delay_order[2] = delays[minutes] - delays[seconds]; hand_order[0] = H_HOURS; hand_order[1] = H_SECONDS; hand_order[2] = H_MINUTES; } else if ((delays[hours_60] <= delays[minutes]) && (delays[minutes] <= delays[seconds])) { delay_order[0] = delays[hours_60]; delay_order[1] = delays[minutes] - delays[hours_60]; delay_order[2] = delays[seconds] - delays[minutes]; hand_order[0] = H_HOURS; hand_order[1] = H_MINUTES; hand_order[2] = H_SECONDS; } // set 1st hand interrupt delay current_hand = 0; OCR1A = delay_order[0]; // timer1 takes over } void main(void) { unsigned short i; struct Point* coord; // set up external int 0 MCUCR |= 0x02; //interrupt EXT0 on falling edge GICR |=0x40; //enable interrupt #asm ("sei"); //delete this DDRD = 0b11111000; //delete this // set up timer 0 TIMSK = 0x12; // turn on timer 0 cmp match and timer1 ISR //TIMSK = 0x10; OCR0 = 124; // 125 timer ticks (2mS) // prescalar to 256 and turn on clear-on-match TCCR0=0b00001100; // 16uS per tick OCR1A = 16550; //16572 interrupt once per disk revolution TCCR1B = 0b00000010; //full speed; clear-on-match TCCR1A = 0b00000000; //turn off pwm and oc lines // calculate delays for HDD lights delays[0] = 3350; for (i=1; i<60; i++) { if (delays[i-1] > 138) { delays[i] = delays[i-1] - 138; } else { delays[i] = 8333 + delays[i-1] - 138; } } for (i=0; i<60; i++) { delays[i] = delays[i]<<1; } delay_ms(10); DDRC = 0xff; nRS(1); // turn off LCD reset SED1335_init(); SED1335_clear_text_layer(); SED1335_clear_graphics_layer(); TOUCH_init(); TOUCH_get_coord(); // skip first conversion, puts TOUCH to sleep // display main clock gui on LCD draw_main_gui(); // reset debounce timers deb_hours_up = deb_hours_down = deb_mins_up = deb_mins_down = DEB_TIME; deb_backlight = DEB_TIME; // init backlight backlight_mode = BACKLIGHT_TIMED; backlight_timer = 0; BACKLIGHT(OFF); // init clock hours = 12; minutes = 0; seconds = 0; count_2ms = 0; LCD_update_time(); SED1335_bitmap(colon, 48, 126); SED1335_bitmap(bulb_timed, 40, 304); #asm("sei"); while(1) { // only update LCD if something has changed if (LCD_update_ready) { LCD_update_time(); LCD_update_ready = 0; } GUI_poll(); if ((*coord).x != OOB) // touching screen { backlight_timer = BACKLIGHT_TIME; if (backlight_mode != BACKLIGHT_OFF) { BACKLIGHT(ON); } } // take care of backlight if (backlight_mode == BACKLIGHT_ON) { BACKLIGHT(ON); } else if (backlight_mode == BACKLIGHT_OFF) { BACKLIGHT(OFF); } else if (backlight_timer == 0 & (backlight_mode == BACKLIGHT_TIMED)) { BACKLIGHT(OFF); } delay_ms(2); } // end for } // end main void draw_main_gui () { line(0,40,320,HORIZONTAL); line(0,185,320,HORIZONTAL); GUI_init(); // button dimmensions #define BUTTON_WIDTH 48 #define BUTTON_HEIGHT 40 #define FIRST_X 16 #define FIRST_Y 190 #define INTER_SPACE 0 #define FUNC_SPACE 24 #define X_INCR (BUTTON_WIDTH+INTER_SPACE) // add and draw all the buttons GUI_add_button(FIRST_X,FIRST_Y,BUTTON_WIDTH,BUTTON_HEIGHT,arrow_up,on_hours_up); GUI_add_button(FIRST_X+X_INCR,FIRST_Y,BUTTON_WIDTH,BUTTON_HEIGHT,arrow_down,on_hours_down); GUI_add_button(FIRST_X+2*X_INCR+FUNC_SPACE,FIRST_Y,BUTTON_WIDTH,BUTTON_HEIGHT,arrow_up,on_mins_up); GUI_add_button(FIRST_X+3*X_INCR+FUNC_SPACE,FIRST_Y,BUTTON_WIDTH,BUTTON_HEIGHT,arrow_down,on_mins_down); GUI_add_button(FIRST_X+4*X_INCR+2*FUNC_SPACE,FIRST_Y,BUTTON_WIDTH,BUTTON_HEIGHT,bulb_button,on_backlight); // draw title SED1335_bitmap(title, 0, 0); // invert gui SED1335_invert_rows( 0, 40); SED1335_invert_rows(185, 240); } // bitmap number pointers unsigned char* flash* digit_ptr[10] = {num0, num1, num2, num3, num4, num5, num6, num7, num8, num9}; unsigned char* flash* digit_ptr_small[10] = {num10, num11, num12, num13, num14, num15, num16, num17, num18, num19}; #define DISPLAY_OFF 0x58 #define DISPLAY_ON 0x59 void LCD_update_time () { LCD_update_seconds(); // update everythign else once a minute if (seconds == 0) { LCD_update_hours(); LCD_update_minutes(); LCD_update_ampm(); } // end update everything else } void LCD_update_hours () { if (hours == 12) // take care of am/pm when increasing { am_pm = 1 - am_pm; LCD_update_ampm(); } else if (hours == 13) { hours = 1; } else if (hours == 0) // take care of am/pm when decreasing { hours = 12; am_pm = 1 - am_pm; LCD_update_ampm(); } if (hours < 10) { SED1335_bitmap(digit_ptr[0], 48, 10); // 1st digit (0) SED1335_bitmap(digit_ptr[hours], 50, 70); // 2nd digit } else { SED1335_bitmap(digit_ptr[1], 48, 10); // 1st digit (1) SED1335_bitmap(digit_ptr[hours-10], 50, 70); // 2nd digit } } // end LCD_update_hours void LCD_update_minutes () { unsigned char first_dig; if (minutes == 60) { minutes = 0; } else if (minutes == 255) // negative rollover { minutes = 59; } first_dig = minutes/10; SED1335_bitmap(digit_ptr[first_dig], 48, 150); // 1st digit SED1335_bitmap(digit_ptr[minutes-10*first_dig], 48, 210); // 2nd digit } void LCD_update_seconds () { unsigned char first_dig; // SECONDS first_dig = seconds/10; SED1335_bitmap(digit_ptr_small[first_dig], 120, 264); // 1st digit SED1335_bitmap(digit_ptr_small[seconds-10*first_dig], 120, 288); // 2nd digit } void LCD_update_ampm () { if (am_pm == AM) { SED1335_bitmap(am, 55, 272); } else { SED1335_bitmap(pm, 55, 272); } } // update backlight icon void LCD_update_backlight_mode() { if (backlight_mode == BACKLIGHT_ON) { SED1335_bitmap(bulb_on, 40,304); } else if (backlight_mode == BACKLIGHT_OFF) { SED1335_bitmap(bulb_off, 40, 304); } else if (backlight_mode == BACKLIGHT_TIMED) { SED1335_bitmap(bulb_timed, 40, 304); } }