// Calendar Clock // // PIC16F648A // //------------- versions // // 100_cal original // 101_cal centered top line // cal20090823b formats (not julian) month advance (but not day suppression) // 1-2_cal missing 16 seg test // 150_cal release candidate // 151_cal tested and 30 second timeout, use for RED and GREEN // 152_cal fixed minute update for upper two time display modes // //---------------- // // Pin connections // // RA0 (17) out SCL // RA1 (18) out SDA1 // RA2 (1) out SDA2 // RA3 (2) out testbit // RA4 (3) in 32KHz Clock // RA5 (4) in power sense H=power L=loss of power // RA6 (15) open // RA7 (16) open // RB0 (6) open // RB1 (7) out to MCLR of slave PIC // RB2 (8) out to RX (pin-7) of slave PIC // RB3 (9) in pushbutton SW0 UP // RB4 (10) in pushbutton SW1 DOWN // RB5 (11) in pushbutton SW2 ENTER // RB6 (12) in pushbutton SW3 MODE // RB7 (13) open // data direction registers 1=input // trisa = 00110000 0x30 // trisb = 01111000 0x78 // 32.768KHz on TMR0 input // #include #include #pragma CLOCK_FREQ 4000000 #pragma DATA _CONFIG , _INTOSC_OSC_NOCLKOUT & _WDT_OFF & _LVP_OFF &_MCLRE_OFF & _BODEN_OFF unsigned char runflag; // true to run time volatile unsigned char cnt_p125; // prescaler volatile unsigned char cnt_seconds; // advanced in interrupt volatile unsigned char cnt_minutes; // advanced in interrupt volatile unsigned char cnt_hours; // advanced in interrupt unsigned long b1; unsigned long julian; // advanced in interrupt unsigned long savejulian; // advanced in interrupt unsigned long b2; volatile unsigned char day; // global var unsigned long b3; volatile unsigned char month; // global var unsigned long b4; volatile unsigned int year;// global var volatile unsigned char cap; // true when running on cap unsigned long b5; unsigned char dtype; // display format unsigned char flipflag; // true if flipping thru months enum TMODE_ENUM { TMODE_POWERUP=0,TMODE_RUN,TMODE_DTYPE,TMODE_SETYEAR,TMODE_SETMONTH, TMODE_SETDAY,TMODE_SETHOUR,TMODE_SETMINUTE, TMODE_PRESET, TMODE_TEST, TMODE_LAST}; enum TMODE_ENUM top_mode,last_mode; volatile unsigned char sw0; // 0 when up pressed volatile unsigned char sw1; // 0 when down pressed volatile unsigned char sw2; // 0 when mode pressed char line[17]; // this is 17 long to make room for line terminator 0 signed char sw0cnt; // debounce counter signed char sw1cnt; // debounce counter signed char sw2cnt; // debounce counter signed char capcnt; // debounce counter // // 128Hz interupt // void interrupt( void ) { // inc time cnt_p125++; if (cnt_p125>127) { cnt_p125=0; cnt_seconds++; if (cnt_seconds>59) { cnt_seconds=0; if(runflag!=0) { cnt_minutes++; if (cnt_minutes>59) { cnt_minutes=0; cnt_hours++; if (cnt_hours>23) { cnt_hours=0; julian++; } } } } } // switches if (portb.4==1) { if(sw0==0) { if(sw0cnt<3) { sw0cnt++; } else { sw0=1; } } } else { if(sw0==1) { if(sw0cnt>0) { sw0cnt--; } else { sw0=0; } } } if (portb.3==1) { if(sw1==0) { if(sw1cnt<3) { sw1cnt++; } else { sw1=1; } } } else { if(sw1==1) { if(sw1cnt>0) { sw1cnt--; } else { sw1=0; } } } if (portb.5==1) { if(sw2==0) { if(sw2cnt<3) { sw2cnt++; } else { sw2=1; } } } else { if(sw2==1) { if(sw2cnt>0) { sw2cnt--; } else { sw2=0; } } } // cap if (porta.5==1) { if(cap==1) { if(capcnt<3) { capcnt++; } else { cap=0; } } } else { if(cap==0) { if(capcnt>0) { capcnt--; } else { cap=1; } } } //clear_bit( porta, 3 ); clear_bit( intcon, T0IF ); //clear TMR0 overflow flag } // i2c connection routines, have these next 5 call bit and delay routines void sda_high(void) { set_bit( porta, 1 ); } void sda_high2(void) { set_bit( porta, 2 ); } void sda_low(void) { clear_bit( porta, 1 ); } void sda_low2(void) { clear_bit( porta, 2 ); } void scl_high(void) { set_bit( porta, 0 ); } void scl_low(void) { clear_bit( porta, 0 ); } void i2c_delay() { delay_us(10); } // i2c routines void i2c_start(void) { scl_high(); sda_high(); sda_high2(); i2c_delay(); sda_low(); sda_low2(); i2c_delay(); scl_low(); i2c_delay(); } void i2c_stop(void) { sda_low(); sda_low2(); scl_low(); i2c_delay(); scl_high(); i2c_delay(); sda_high(); sda_high2(); i2c_delay(); } void i2c_bitout(unsigned char b,unsigned char c) { // set data bit if (b!=0) { sda_high(); } else { sda_low(); } // set data bit if (c!=0) { sda_high2(); } else { sda_low2(); } // pulse clock i2c_delay(); scl_high(); i2c_delay(); scl_low(); i2c_delay(); } void i2c_ack() { i2c_delay(); scl_high(); i2c_delay(); scl_low(); i2c_delay(); } void i2c_byteout(unsigned char b,unsigned char c) { i2c_bitout(b&0x80,c&0x80); i2c_bitout(b&0x40,c&0x40); i2c_bitout(b&0x20,c&0x20); i2c_bitout(b&0x10,c&0x10); i2c_bitout(b&0x08,c&0x08); i2c_bitout(b&0x04,c&0x04); i2c_bitout(b&0x02,c&0x02); i2c_bitout(b&0x01,c&0x01); i2c_ack(); // ack cycle } // // high and low bytes for 16 segment displays starting // rom unsigned char *segments ={ 162 , 214 , 2 , 2 , 132 , 215 , 134 , 151 , 38 , 3 , 166 , 149 , 166 , 213 , 2 , 22 , 166 , 215 , 166 , 151 , 128 , 4 , 64 , 16 , 9 , 0 , 4 , 21 , 64 , 32 , 4 , 30 , 164 , 215 , 38 , 87 , 150 , 158 , 160 , 212 , 146 , 158 , 164 , 213 , 36 , 85 , 166 , 212 , 38 , 67 , 144 , 156 , 130 , 194 , 41 , 65 , 160 , 192 , 42 , 98 , 35 , 98 , 162 , 214 , 36 , 87 , 163 , 214 , 37 , 87 , 166 , 149 , 16 , 28 , 162 , 194 , 104 , 64 , 99 , 66 , 73 , 32 , 36 , 11 , 200 , 148 , 32 , 208 , 1 , 32 , 130 , 6 , 72 , 0 , // changed to / from ^ 128 , 128 , }; unsigned int asc_to_bits(unsigned char ic) { unsigned int c; unsigned char *p; unsigned int c16; c=ic; // out of bounds = "@" if ((c<0x30)||(c>0x5f)) { c16=0; } else { // zero base pointer p=c-0x30; // two bytes per character so double pointer offset p=p<<1; // retrieve 16 bits c16=(segments[p])<<8 | segments[p+1]; } return(c16); } // // send 16 characters from line[] // void send_string() { char a,a2; unsigned int l1; unsigned int l2; unsigned int r1; unsigned int r2; // sent in pairs of quad bytes, each quad fills one display chip SAA1064 for(a=0;a<4;a++) { i2c_start(); switch(a) { case 0: i2c_byteout(0x70,0x70); // address break; case 1: i2c_byteout(0x72,0x72); // address break; case 2: i2c_byteout(0x74,0x74); // address break; default: i2c_byteout(0x76,0x76); // address break; } a2=a*2; l1=asc_to_bits(line[a2]); l2=asc_to_bits(line[(a2)+1]); r1=asc_to_bits(line[(a2)+8]); r2=asc_to_bits(line[(a2)+9]); i2c_byteout(0x00,0x00); // instruction i2c_byteout(0x67,0x67); // control i2c_byteout(l1>>8,r1>>8); // high bits i2c_byteout(l2>>8,r2>>8); // high bits i2c_byteout(l1& 0xff,r1& 0xff); // low bits i2c_byteout(l2& 0xff,r2& 0xff); i2c_stop(); } } void blankline() { unsigned char i; for(i=0;i<17;i++) line[i]=0; } // // fill line // void fill_line(rom char *s) { blankline(); strcpy(line,s); // copy string into line } void fill_line_send(rom char *s) { fill_line(s); send_string(); } // make 2 digit ascii void sprint2dig(char *l,unsigned char d) { char c; c=d/10; *l=0x30|c; c=d%10; l++; *l=0x30|c; } // make 2 digit ascii // // returns 1 if blanking occured // char sprint2digblank(char *l,unsigned char d) { char c; char rv; rv=0; c=d/10; if(c>0) { *l=0x30|c; l++; } else rv=1; c=d%10; *l=0x30|c; return(rv); } void sprint2dig_send(char *l,unsigned char d) { sprint2dig(l,d); send_string(); } // // convert julian -> month day year // void julianunpack() { unsigned long p; //unsigned long q; unsigned int q; unsigned long r; //unsigned long s; unsigned int s; unsigned long t; unsigned long u; unsigned long v; // p = j + 68569 p=julian+68569; // q = int(4*p/146097) q=(4*p)/146097; // r = p - int((146097*q + 3)/4) r= p- ((146097*q)+3)/4; // s = int(4000*(r+1)/1461001) s = (4000*(r+1))/1461001; // t = r - int(1461*s/4) + 31 t = r - (1461*s/4) + 31; // u = int(80*t/2447) u = (80*t)/2447; // v = int(u/11) v = u/11; // y = 100*(q-49)+s+v year = 100*(q-49)+s+v; // m = u + 2 - 12*v month = u + 2 - 12*v; // d = t - int((2447*u)/80) day = t - (2447*u)/80; } // // convert month day year -> julian // void julianpack() { unsigned long a; unsigned long b; //unsigned long c; unsigned int c; unsigned long d; unsigned long e; unsigned long f; unsigned long v; // j = 367*y - int(7*(y + int((m+9)/12)) /4) + int((275*m)/9) + d + 1721014 a = 367*year ; b = (7*(year + ((month+9)/12))) /4; c = (275*month)/9; d = day + 1721014; julian = a - b + c + d; } // // send byte out serial // void sendbyte(unsigned char c) { // wait for transmit buffer empty while(txsta.1==0) { } txreg=c; } // // commands to slave // 0n decode: // // 0 low byte // 1 high byte // 2 set first day // 3 set month size // 4 set highlight // 5 do op 0=stop 1=blank 2=fill 3=count 3=seg test // // // void sendbytemsg(unsigned char v) { sendbyte(v&0x0f); // low nybble sendbyte(0x10|(v>>4)); // high nybble } rom char *st_jan="JANUARY"; rom char *st_feb="FEBRUARY"; rom char *st_mar="MARCH"; rom char *st_apr="APRIL"; rom char *st_may="MAY"; rom char *st_jun="JUNE"; rom char *st_jul="JULY"; rom char *st_aug="AUGUST"; rom char *st_sep="SEPTEMBER"; rom char *st_oct="OCTOBER"; rom char *st_nov="NOVEMBER"; rom char *st_dec="DECEMBER"; // month offsets rom unsigned char *mstart = { 1,0,2,2,3,2,2,1,0,1,0,0}; // alternate month offsets rom unsigned char *amstart = { 1,0,2,2,3,3,3,2,0,1,0,0}; // dystart rom unsigned char *dystart = { 9,9,8,8,7,7,7,8,10,9,9,9}; // // place month in line[] stating at offset // void placemonth(unsigned char moff) { rom unsigned char *rucptr; switch(month) { case 1: rucptr=st_jan; break; case 2: rucptr=st_feb; break; case 3: rucptr=st_mar; break; case 4: rucptr=st_apr; break; case 5: rucptr=st_may; break; case 6: rucptr=st_jun; break; case 7: rucptr=st_jul; break; case 8: rucptr=st_aug; break; case 9: rucptr=st_sep; break; case 10: rucptr=st_oct; break; case 11: rucptr=st_nov; break; case 12: rucptr=st_dec; break; } strcpy(line+moff,rucptr); } // // place 24 hour time at line[11] // place_24hrtime() { sprint2dig(line+11,cnt_hours); line[13]=':'; sprint2dig(line+14,cnt_minutes); } // // place 12 hour time at line[off] // place_12hrtime(unsigned char toff) { unsigned char hr; hr=cnt_hours%12; if(hr==0) hr=12; // hours if(hr>9) { sprint2dig(line+toff,hr); } else { line[toff]=' '; line[toff+1]=0x30|hr; } // colon line[toff+2]=':'; // minutes sprint2dig(line+toff+3,cnt_minutes); // AM or PM suffix if(cnt_hours<12) line[toff+5]='A'; else line[toff+5]='P'; line[toff+6]='M'; } // // place date string mm/dd/yyyy // // yyyy if flag true // void place_mmddyyyy(unsigned char flag) { unsigned char i; if(sprint2digblank(line,month)) i=1; else i=2; line[i++]='^'; // will display '/' character if(sprint2digblank(line+i,day)) i++; else { i++; i++; } line[i++]='^'; // will display '/' character if(flag) { // place yyyy sprint2dig(line+i,year/100); sprint2dig(line+i+2,year%100); } else { // place yy sprint2dig(line+i,year%100); } } //------------------------------------------------------------------------ // // Format top line according to dtype // // display types // 0 // 1 // 2 // 3 <24 hr time> // 4 <12 hr time> // 5 mm/dd/yyyy // 6 mm/dd/yyyy 24ht // 7 mm/dd/yy 12ht // void showtopline() { unsigned char hr; unsigned char moff; unsigned char mdisp; unsigned char ddisp; unsigned char ydisp; unsigned char madisp; unsigned char y_h; unsigned char y_l; unsigned char ldtype; moff=month-1; madisp=amstart[moff]; mdisp=mstart[moff]; ddisp=dystart[moff]; // compute year offset ydisp=ddisp+2; if(day>9) ydisp++; blankline(); y_h=year/100; y_l=year%100; // show month year if flipflag if(flipflag) ldtype=1; else ldtype=dtype; switch(ldtype) { case 0: // month dd yyyy placemonth(mdisp); sprint2digblank(line+ddisp,day); if((month==9)&&(day>9)) { // shorten year sprint2dig(line+ydisp,y_l); } else { // normal display sprint2dig(line+ydisp,y_h); sprint2dig(line+ydisp+2,y_l); } break; case 1: // month yyyy placemonth(mdisp+1); sprint2dig(line+ddisp+1,y_h); sprint2dig(line+ddisp+3,y_l); break; case 2: // month placemonth(mdisp+4); break; case 3: // month 24hr placemonth(madisp+1); place_24hrtime(); break; case 4: // month 12hr placemonth(madisp+0); hr=cnt_hours%12; if(hr==0) hr=12; if((month==9)&&(hr>9)) place_12hrtime(10); else place_12hrtime(9); break; case 5: // mm/dd/yyyy place_mmddyyyy(1); break; case 6: // mm/dd/yyyy 24hr place_mmddyyyy(1); place_24hrtime(); break; case 7: // mm/dd/yy 12hr place_mmddyyyy(0); place_12hrtime(9); break; break; } send_string(); } //**************************************************************** // void main() { unsigned char oldsec,oldmin; unsigned long old_julian; unsigned char oldsw1,oldsw2,oldsw3,oldsw0; unsigned char oldcap; unsigned int dis; unsigned char timer; unsigned char msize; unsigned char tc; rom char *st_setyear="SET YEAR"; rom char *st_setmonth="SET MONTH"; rom char *st_setday="SET DAY"; rom char *st_sethour="SET HOUR"; rom char *st_setmin="SET MINUTE"; rom char *st_preset="PRESET"; rom char *st_test="SELECT TEST"; rom char *st_kabtr="KABTRONICS"; rom char *st_count="0123456789ABCDEF"; // set port directions trisa = 0x30; // porta direction trisb = 0x78; // portb direction cmcon = 0x07; // turn off comparitors clear_bit( option_reg, 7 ); // turn on portb pullups // turn on serial transmiter spbrg = 25; // 2400 BAUD txsta = 0x20; // TXEN = 1, 8 bit, async rcsta = 0x80; // SPEN = 1 // clear time and state variables top_mode=TMODE_POWERUP; last_mode=TMODE_SETDAY; cnt_p125=0; cnt_seconds=0; cnt_minutes=20; cnt_hours=8; julian=2455044; // month=0; // will be set by julianunpack(); day=0; // will be set by julianunpack(); year=0; // will be set by julianunpack(); sw0=1; // switches go to 0 when pressed sw1=1; sw2=1; sw0cnt=0; // these are switch debounce filters used in interrupt sw1cnt=0; sw2cnt=0; oldsec=78; oldmin=0; timer=0; dis=0; old_julian=0; cap=0; capcnt=0; oldcap=0; flipflag=0; oldsw1=1; oldsw2=1; oldsw0=1; dtype=0; runflag=1; // enable time keeping // enable interrupts set_bit( intcon, T0IE ); //enable TMR0 overflow bit set_bit( intcon, GIE ); // start interrupts while( 1 ) { if(oldcap!=cap) // change in power state //if(0) { oldcap=cap; if(cap==1) // power loss, running on cap { // turn off RS232 // rcsta = 0x00; // SPEN = 0 // set outputs low to prevent driving a dead circuit // porta=0x30; // portb=0xf9; // RA0 (17) out SCL out // RA1 (18) out SDA1 out // RA2 (1) out SDA2 out // RA3 (2) out testbit out // RA4 (3) in 32KHz Clock in // RA5 (4) in power sense in // RA6 (15) open out // RA7 (16) open out // RB0 (6) open out // RB1 (7) out to MCLR of slave PIC out // RB2 (8) out to RX (pin-7) of slave PIC out // RB3 (9) in pushbutton SW0 UP out // RB4 (10) in pushbutton SW1 DOWN out // RB5 (11) in pushbutton SW2 ENTER out // RB6 (12) in pushbutton SW3 MODE out // RB7 (13) open out // data direction registers 1=input // trisa = 00110000 0x30 // trisb = 00000000 0x00 txsta = 0x00; // TXEN = 1, 8 bit, async trisa = 0x30; // porta direction trisb = 0x00; // portb direction porta = 0x30; portb = 0x00; } else // power restored { // restore RS232 txsta = 0x20; // TXEN = 1, 8 bit, async trisa = 0x30; // porta direction trisb = 0x78; // portb direction old_julian=0; // force an update top_mode=TMODE_POWERUP; // display power up last_mode=TMODE_SETDAY; // force powerup state } } if(cap==0) // power on { // unpack julian into global day,month,year if julian changed if (old_julian!=julian) { unsigned char fd; old_julian=julian; julianunpack(); switch(month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: msize=31; break; case 4: case 6: case 9: case 11: msize=30; break; case 2: // figure out size of this feb if(year&3) msize=28; else msize=29; break; } if(top_mode==TMODE_RUN) showtopline(); // calc offset fd= (julian-day)%7+2; fd=fd%7; sendbytemsg(msize); sendbyte(0x30); // set month size sendbytemsg(fd); sendbyte(0x20); // set first day 1-37 if ((top_mode==TMODE_RUN)&&(timer!=0)) // turn off highlight if flipping months sendbytemsg(0); else sendbytemsg(day); sendbyte(0x40); // set highlite if(top_mode==TMODE_RUN|| top_mode==TMODE_SETYEAR|| top_mode==TMODE_SETMONTH|| top_mode==TMODE_SETDAY) sendbyte(0x52); // fill } switch(top_mode) { case TMODE_POWERUP: if (last_mode!=top_mode) { timer=5; last_mode=top_mode; blankline(); strcpy(line+3,st_kabtr); send_string(); } break; case TMODE_RUN: if(!runflag) runflag=1; if (last_mode!=top_mode) { last_mode=top_mode; oldmin=65; sendbyte(0x52); showtopline(); } break; case TMODE_DTYPE: if(!runflag) runflag=1; if (last_mode!=top_mode) { if (flipflag) { julian=savejulian; flipflag=0; } timer=30; blankline(); last_mode=top_mode; strcpy(line,"SELECT FORMAT"); oldmin=65; // force update send_string(); sendbyte(0x52); } break; case TMODE_SETYEAR: if (last_mode!=top_mode) { timer=30; last_mode=top_mode; fill_line(st_setyear); sprint2dig(line+14,year%100); sprint2dig_send(line+12,year/100); } break; case TMODE_SETMONTH: if (last_mode!=top_mode) { timer=30; last_mode=top_mode; fill_line(st_setmonth); sprint2dig_send(line+14,month); } break; case TMODE_SETDAY: if (last_mode!=top_mode) { timer=30; last_mode=top_mode; fill_line(st_setday); sprint2dig_send(line+14,day); } break; case TMODE_SETHOUR: if (last_mode!=top_mode) { timer=30; runflag=0; // stop clock last_mode=top_mode; fill_line(st_sethour); sprint2dig_send(line+14,cnt_hours); } break; case TMODE_SETMINUTE: if (last_mode!=top_mode) { timer=30; runflag=0; // stop clock last_mode=top_mode; fill_line(st_setmin); sprint2dig_send(line+14,cnt_minutes); } break; case TMODE_PRESET: if (last_mode!=top_mode) { timer=30; last_mode=top_mode; fill_line_send(st_preset); } break; case TMODE_TEST: if (last_mode!=top_mode) { last_mode=top_mode; fill_line_send(st_test); } break; } // run the clock display if time is being shown if((top_mode==TMODE_RUN)&&((dtype==3)||(dtype==4)||(dtype==6)||(dtype==7))) { if(oldmin!=cnt_minutes) { oldmin=cnt_minutes; showtopline(); } } // check inactivity timer if (top_mode!=TMODE_TEST) { if((!sw0)||(!sw1)||(!sw2)) // if any switch pressed { if(timer) timer=30; } } if((timer>0)&&(top_mode!=TMODE_TEST)) { if (oldsec!=cnt_seconds) { oldsec=cnt_seconds; timer--; if(!timer) { if(flipflag) { // restore original date julian=savejulian; flipflag=0; } top_mode=TMODE_RUN; } } } // up switch if(oldsw0!=sw0) { oldsw0=sw0; if (!sw0) { unsigned long j; switch(top_mode) { case TMODE_PRESET: top_mode=TMODE_POWERUP; cnt_p125=0; cnt_seconds=0; cnt_minutes=0; cnt_hours=11; julian=2455039; // july 27 2009 break; case TMODE_SETDAY: day++; julianpack(); julianunpack(); sprint2dig_send(line+14,day); break; case TMODE_SETYEAR: year++; julianpack(); julianunpack(); sprint2dig(line+14,year%100); sprint2dig_send(line+12,year/100); break; case TMODE_SETMONTH: if(month<12) { month=month+1; if((month==2)&&(day>28)) day=28; julianpack(); julianunpack(); sprint2dig_send(line+14,month); } break; case TMODE_SETHOUR: cnt_hours++; if(cnt_hours>23) cnt_hours=0; sprint2dig_send(line+14,cnt_hours); break; case TMODE_SETMINUTE: cnt_minutes++; if(cnt_minutes>59) cnt_minutes=0; sprint2dig_send(line+14,cnt_minutes); break; case TMODE_DTYPE: if(dtype<7) dtype++; else dtype=0; showtopline(); break; case TMODE_RUN: // check if switching to flip page mode if (!flipflag) { flipflag=1; timer=30; // set countdown timeer savejulian=julian; // save this date day=1; // avoid month length problems } if(month<12) month++; else { month=1; year++; } julianpack(); julianunpack(); // showtopline(); break; case TMODE_TEST: sendbyte(0x53); strcpy(line,st_count); send_string(); break; default: break; } // switch } // if } // down switch if(oldsw1!=sw1) { oldsw1=sw1; if (sw1==0) { switch(top_mode) { case TMODE_SETDAY: if(day>1) { day--; julianpack(); julianunpack(); sprint2dig_send(line+14,day); } break; case TMODE_SETYEAR: if(year>2000) { year--; julianpack(); julianunpack(); sprint2dig(line+14,year%100); sprint2dig_send(line+12,year/100); } break; case TMODE_SETMONTH: if(month>1) { month--; if((month==2)&&(day>28)) day=28; julianpack(); julianunpack(); sprint2dig_send(line+14,month); } break; case TMODE_SETHOUR: if (cnt_hours==0) cnt_hours=23; else cnt_hours--; sprint2dig_send(line+14,cnt_hours); break; case TMODE_SETMINUTE: if (cnt_minutes==0) cnt_minutes=59; else cnt_minutes--; sprint2dig_send(line+14,cnt_minutes); break; case TMODE_DTYPE: if(dtype>0) dtype--; else dtype=7; showtopline(); break; case TMODE_RUN: // check if switching to flip page mode if (!flipflag) { flipflag=1; timer=30; // set countdown timer savejulian=julian; // save this date day=1; // avoid month length problems } if(month>1) month--; else { month=12; year--; } julianpack(); julianunpack(); // showtopline(); break; case TMODE_TEST: sendbyte(0x54); break; default: break; } // switch } // if } // MODE switch if(oldsw2!=sw2) { oldsw2=sw2; if (sw2==0) { top_mode++; if(top_mode>=TMODE_LAST) top_mode=TMODE_RUN; } } } delay_ms(50); } //endless while loop } // program end