-#include "msp430.h"\r
-#include "definitions.h"\r
+// SilentTimer Action Figure software, v1.4\r
+// main.c\r
+// The main c file.\r
+// \r
+// Copyright (C) 2014-2016 Balthasar Szczepański\r
+// \r
+// This program is free software: you can redistribute it and/or modify\r
+// it under the terms of the GNU General Public License as published by\r
+// the Free Software Foundation, either version 3 of the License, or\r
+// (at your option) any later version.\r
+// \r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+// \r
+// You should have received a copy of the GNU General Public License\r
+// along with this program. If not, see <http://www.gnu.org/licenses/>.\r
\r
-unsigned char inbuf[8];\r
-unsigned char outbuf[8];\r
-unsigned char dispvalue[4];\r
-unsigned char time[8];\r
-unsigned char leap;\r
-unsigned char settime[3];\r
-unsigned char mode;\r
-unsigned char alarm[3];\r
-unsigned char lastcdn[2];\r
-unsigned char lastyear[5];\r
-unsigned char digit;\r
-unsigned char changed;\r
-unsigned char run;\r
-unsigned char symbol[16] ={\r
- SYMB_0,\r
- SYMB_1,\r
- SYMB_2,\r
- SYMB_3,\r
- SYMB_4,\r
- SYMB_5,\r
- SYMB_6,\r
- SYMB_7,\r
- SYMB_8,\r
- SYMB_9,\r
- SYMB_A,\r
- SYMB_B,\r
- SYMB_C,\r
- SYMB_D,\r
- SYMB_E,\r
- SYMB_F};\r
+ #include "msp430.h"\r
+ #include "definitions.h"\r
\r
-__interrupt void P2_ISR();\r
-void display(\r
- unsigned char *data);\r
-void spi(\r
- unsigned char command,\r
- unsigned char addr,\r
- unsigned char *inbuf,\r
- unsigned char *outbuf,\r
- unsigned short n);\r
-int main( void );\r
+ unsigned char inbuf[8];\r
+ unsigned char outbuf[8];\r
+ unsigned char dispvalue[4];\r
+ unsigned char time[8];\r
+ unsigned char leap;\r
+ unsigned char settime[3];\r
+ unsigned char mode;\r
+ unsigned char alarm[3];\r
+ unsigned char lastcdn[2];\r
+ unsigned char lastyear[5];\r
+ unsigned char digit;\r
+ unsigned char changed;\r
+ unsigned char run;\r
+ unsigned char symbol[16] ={\r
+ SYMB_0,\r
+ SYMB_1,\r
+ SYMB_2,\r
+ SYMB_3,\r
+ SYMB_4,\r
+ SYMB_5,\r
+ SYMB_6,\r
+ SYMB_7,\r
+ SYMB_8,\r
+ SYMB_9,\r
+ SYMB_A,\r
+ SYMB_B,\r
+ SYMB_C,\r
+ SYMB_D,\r
+ SYMB_E,\r
+ SYMB_F};\r
\r
-void display(unsigned char *data)\r
-{\r
- //lsd\r
- P1OUT =data[0];\r
- P3OUT |=0x80; //74hc373 latch enable\r
- P3OUT &=0x0f;\r
- \r
- P1OUT =data[1];\r
- P3OUT |=0x40;\r
- P3OUT &=0x0f;\r
- \r
- P1OUT =data[2];\r
- P3OUT |=0x20;\r
- P3OUT &=0x0f;\r
- \r
- //msd\r
- P1OUT =data[3];\r
- P3OUT |=0x10;\r
- P3OUT &=0x0f;\r
-}\r
+ __interrupt void P2_ISR();\r
+ void display(\r
+ unsigned char *data);\r
+ void spi(\r
+ unsigned char command,\r
+ unsigned char addr,\r
+ unsigned char *inbuf,\r
+ unsigned char *outbuf,\r
+ unsigned short n);\r
+ int main( void );\r
\r
-void spi(\r
- unsigned char command,\r
- unsigned char addr,\r
- unsigned char *inbuf,\r
- unsigned char *outbuf,\r
- unsigned short n)\r
-{\r
- unsigned short i;\r
- unsigned char nul;\r
- unsigned char flags;\r
- \r
- switch (command)\r
- {\r
- case RTC_EEREAD:\r
- case RTC_IDREAD:\r
- case RTC_READ:\r
- flags= ADDRFLAG|READFLAG;\r
- break;\r
- \r
- case RTC_EEWRITE:\r
- case RTC_IDWRITE:\r
- n=(n>8)?8:n;\r
- case RTC_WRITE:\r
- flags= ADDRFLAG|WRITEFLAG;\r
- break;\r
- \r
- case RTC_EEWREN:\r
- case RTC_EEWRDI:\r
- flags=0;\r
- break;\r
- \r
- case RTC_SRREAD:\r
- n=(n>1)?1:n;\r
- flags=READFLAG;\r
- break;\r
- \r
- case RTC_SRWRITE: //1\r
- case RTC_CLRRAM: //data ignored but has to be\r
- case RTC_UNLOCK: //1\r
- n=(n>1)?1:n;\r
- flags=WRITEFLAG;\r
- break;\r
- default:\r
- return;\r
- }\r
- \r
- P3OUT&=0xfe; //chip select down\r
- \r
- while((IFG2&UTXIFG0)==0); // wait until can be sent\r
- U0TXBUF=command; // send command\r
- while((IFG2&UTXIFG0)==0); // wait until received\r
- nul=U0RXBUF; //pretend to read "data"\r
- \r
- if(flags&ADDRFLAG)\r
- {\r
- while((IFG2&UTXIFG0)==0); // wait until can be sent\r
- U0TXBUF=addr; // send address\r
- while((IFG2&UTXIFG0)==0); // wait until received\r
- nul=U0RXBUF; //pretend to read "data"\r
- }\r
- if(flags&(READFLAG|WRITEFLAG))\r
- {\r
- for(i=0;i<n;++i)\r
- {\r
- while((IFG2&UTXIFG0)==0); // wait until can be sent\r
- U0TXBUF=(flags&WRITEFLAG)?outbuf[i]:0xff; // send data\r
- while((IFG2&UTXIFG0)==0); // wait until received\r
- if(flags&READFLAG)\r
- inbuf[i]=U0RXBUF; //read data\r
- else\r
- nul=U0RXBUF;\r
- }\r
- }\r
- P3OUT|=0x01; //chip select up\r
- for(i=0;i<255;++i); //looks like the RTC might not like another SPI transmission exactly before the previous one, sometimes.\r
-}\r
+ void display(unsigned char *data)\r
+ {\r
+ //lsd\r
+ P1OUT =data[0];\r
+ P3OUT |=0x80; //74hc373 latch enable\r
+ P3OUT &=0x0f;\r
+ \r
+ P1OUT =data[1];\r
+ P3OUT |=0x40;\r
+ P3OUT &=0x0f;\r
+ \r
+ P1OUT =data[2];\r
+ P3OUT |=0x20;\r
+ P3OUT &=0x0f;\r
+ \r
+ //msd\r
+ P1OUT =data[3];\r
+ P3OUT |=0x10;\r
+ P3OUT &=0x0f;\r
+ }\r
\r
-#pragma vector=PORT2_VECTOR\r
-__interrupt void P2_ISR()\r
-{\r
- if(P2IFG&0x08) // RTC\r
- {\r
- P2IFG &= ~0x08;\r
- spi(RTC_READ,0x00,inbuf,outbuf,8);\r
- \r
- time[0]=inbuf[0]; //1/100 s\r
- time[1]=inbuf[1]&0x7f; //seconds\r
- time[2]=inbuf[2]&0x7f; //minutes\r
- time[3]=inbuf[3]&0x3f; //hours\r
- time[4]=inbuf[4]&0x07; //dow\r
- time[5]=inbuf[5]&0x3f; //dom\r
- time[6]=inbuf[6]&0x1f; //mon\r
- time[7]=inbuf[7];//year\r
- leap=inbuf[6]&0x20;\r
- \r
- spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?)\r
- if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0])\r
- {\r
- mode=MODE_ALARM;\r
- alarm[0]=0; //alarm removed after activated\r
- spi(RTC_WRITE,0x20,inbuf,alarm,1);\r
- }\r
- \r
- if(mode==MODE_COUNTUP && run)\r
- {\r
- if(settime[1]<0x59)\r
- settime[1]=__bcd_add_short(settime[1],0x01);\r
- else\r
- {\r
- settime[1]=0x00;\r
- settime[2]=__bcd_add_short(settime[2],0x01);\r
- }\r
- }\r
- else if(mode==MODE_COUNTDOWN && run && (settime[1]|settime[2]))\r
- {\r
- if(settime[1])\r
- settime[1]=__bcd_add_short(settime[1],0x99);\r
- else\r
- {\r
- settime[1]=0x59;\r
- settime[2]=__bcd_add_short(settime[2],0x99);\r
- }\r
- }\r
- \r
- if (mode==MODE_ALARM || (mode==MODE_COUNTDOWN && !(settime[1]|settime[2])))\r
- {\r
- TACTL^=MC_1;\r
- //P2DIR^=0x40;\r
- //P2SEL^=0x40;\r
- }\r
- else if(TACTL & MC_3)\r
- {\r
- TACTL&= ~MC_3;\r
- //P2DIR&= ~0x40;\r
- //P2SEL&= ~0x40;\r
- }\r
- \r
- lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?__bcd_add_short(lastyear[1],0x01):lastyear[1];\r
- if (time[7]!=lastyear[0])\r
- {\r
- if(time[7]==lastyear[2])\r
- ++(lastyear[3]);\r
- else\r
- lastyear[3]=0;\r
- \r
- lastyear[2]=time[7];\r
- \r
- if(lastyear[3]>55)\r
- {\r
- lastyear[3]=0;\r
- \r
- if(time[7]==0x00 && lastyear[0]==0x99)\r
- lastyear[1]=__bcd_add_short(lastyear[1],0x01);\r
- \r
- lastyear[0]=time[7];\r
- \r
- outbuf[0]=ALARMVALUE;\r
- outbuf[1]=lastyear[0];\r
- outbuf[2]=lastyear[1];\r
- spi(RTC_WRITE,0x26,inbuf,outbuf,3);\r
- } \r
- }\r
- \r
- \r
- if(mode==MODE_DEBUG && changed)\r
- spi(RTC_READ,settime[1],settime,outbuf,1);\r
- }\r
- else if(P2IFG&0x02) // button A\r
- {\r
- P2IFG &= ~0x02;\r
- switch(mode)\r
- {\r
- case MODE_TIME:\r
- case MODE_SETDATE:\r
- case MODE_SETYEAR:\r
- mode=MODE_DATE;\r
- break;\r
- case MODE_DATE:\r
- mode=MODE_COUNTUP;\r
- settime[1]=0x00;\r
- settime[2]=0x00;\r
- run=0;\r
- break;\r
- case MODE_COUNTUP:\r
- if(run)\r
- {\r
- settime[1]=0x00;\r
- settime[2]=0x00;\r
- run=0;\r
- }\r
- else\r
- {\r
- mode=MODE_SETCOUNTDOWN;\r
- settime[1]=lastcdn[0];\r
- settime[2]=lastcdn[1];\r
- changed=0;\r
- digit=3;\r
- }\r
- break;\r
- case MODE_DEBUGADDR:\r
- case MODE_DEBUGVAL:\r
- mode=MODE_DEBUG;\r
- break;\r
- case MODE_SETCOUNTDOWN:\r
- case MODE_COUNTDOWN:\r
- if(changed || mode==MODE_COUNTDOWN)\r
- {\r
- mode=MODE_SETCOUNTDOWN;\r
- settime[1]=lastcdn[0];\r
- settime[2]=lastcdn[1];\r
- changed=0;\r
- digit=3;\r
- break;\r
- }\r
- //case MODE_SETTIME:\r
- //case MODE_SETALARM:\r
- //case MODE_ALARM:\r
- //case MODE_CALIBRATE:\r
- //case MODE_DEBUG:\r
- default:\r
- mode=MODE_TIME;\r
- break;\r
- }\r
- }\r
- else if(P2IFG&0x01) // button B\r
- {\r
- P2IFG &= ~0x01;\r
- \r
- switch(mode)\r
- {\r
- case MODE_TIME:\r
- mode=MODE_SETTIME;\r
- digit=3;\r
- changed=0;\r
- settime[0]=0;\r
- settime[1]=time[2];\r
- settime[2]=time[3];\r
- break;\r
- case MODE_DATE:\r
- mode=MODE_SETDATE;\r
- digit=2;\r
- changed=0;\r
- settime[0]=time[5];\r
- settime[1]=time[6];\r
- break;\r
- case MODE_COUNTUP:\r
- case MODE_COUNTDOWN:\r
- run=!run;\r
- break;\r
- case MODE_SETCOUNTDOWN:\r
- if(digit)\r
- {\r
- --digit;\r
- changed=1;\r
- }\r
- else\r
- {\r
- lastcdn[0]=settime[1];\r
- lastcdn[1]=settime[2];\r
- \r
- outbuf[0]=ALARMVALUE;\r
- outbuf[1]=settime[1];\r
- outbuf[2]=settime[2];\r
- spi(RTC_WRITE,0x23,inbuf,outbuf,3);\r
+ void spi(\r
+ unsigned char command,\r
+ unsigned char addr,\r
+ unsigned char *inbuf,\r
+ unsigned char *outbuf,\r
+ unsigned short n)\r
+ {\r
+ unsigned short i;\r
+ unsigned char nul;\r
+ unsigned char flags;\r
+ \r
+ switch (command)\r
+ {\r
+ case RTC_EEREAD:\r
+ case RTC_IDREAD:\r
+ case RTC_READ:\r
+ flags= ADDRFLAG|READFLAG;\r
+ break;\r
+ \r
+ case RTC_EEWRITE:\r
+ case RTC_IDWRITE:\r
+ n=(n>8)?8:n;\r
+ case RTC_WRITE:\r
+ flags= ADDRFLAG|WRITEFLAG;\r
+ break;\r
+ \r
+ case RTC_EEWREN:\r
+ case RTC_EEWRDI:\r
+ flags=0;\r
+ break;\r
+ \r
+ case RTC_SRREAD:\r
+ n=(n>1)?1:n;\r
+ flags=READFLAG;\r
+ break;\r
+ \r
+ case RTC_SRWRITE: //1\r
+ case RTC_CLRRAM: //data ignored but has to be\r
+ case RTC_UNLOCK: //1\r
+ n=(n>1)?1:n;\r
+ flags=WRITEFLAG;\r
+ break;\r
+ default:\r
+ return;\r
+ }\r
+ \r
+ P3OUT&=0xfe; //chip select down\r
+ \r
+ while((IFG2&UTXIFG0)==0); // wait until can be sent\r
+ U0TXBUF=command; // send command\r
+ while((IFG2&UTXIFG0)==0); // wait until received\r
+ nul=U0RXBUF; //pretend to read "data"\r
+ \r
+ if(flags&ADDRFLAG)\r
+ {\r
+ while((IFG2&UTXIFG0)==0); // wait until can be sent\r
+ U0TXBUF=addr; // send address\r
+ while((IFG2&UTXIFG0)==0); // wait until received\r
+ nul=U0RXBUF; //pretend to read "data"\r
+ }\r
+ if(flags&(READFLAG|WRITEFLAG))\r
+ {\r
+ for(i=0;i<n;++i)\r
+ {\r
+ while((IFG2&UTXIFG0)==0); // wait until can be sent\r
+ U0TXBUF=(flags&WRITEFLAG)?outbuf[i]:0xff; // send data\r
+ while((IFG2&UTXIFG0)==0); // wait until received\r
+ if(flags&READFLAG)\r
+ inbuf[i]=U0RXBUF; //read data\r
+ else\r
+ nul=U0RXBUF;\r
+ }\r
+ }\r
+ P3OUT|=0x01; //chip select up\r
+ for(i=0;i<255;++i); //looks like the RTC might not like another SPI transmission exactly before the previous one, sometimes.\r
+ }\r
\r
- mode=MODE_COUNTDOWN;\r
- run=0;\r
- }\r
- break;\r
- case MODE_CALIBRATE:\r
- if(digit)\r
- --digit;\r
- else\r
- {\r
- spi(RTC_WRITE,0x09,inbuf,settime,1);\r
- outbuf[0]=time[3]|settime[1];\r
- spi(RTC_WRITE,0x03,inbuf,outbuf,1);\r
- digit=3;\r
- }\r
- break;\r
- case MODE_DEBUGADDR:\r
- if(digit)\r
- --digit;\r
- else\r
- {\r
- spi(RTC_READ,settime[1],settime,outbuf,1);\r
- mode=MODE_DEBUG;\r
- changed=1;\r
- }\r
- break;\r
- case MODE_DEBUGVAL:\r
- if(digit)\r
- --digit;\r
- else\r
- {\r
- spi(RTC_WRITE,settime[1],inbuf,settime,1);\r
- mode=MODE_DEBUG;\r
- }\r
- break;\r
- case MODE_SETTIME:\r
- if(digit)\r
- {\r
- if(digit==3&&settime[2]>0x23)\r
- settime[2]&=0xf0;\r
- --digit;\r
- }\r
- else\r
- {\r
- if(changed)\r
- {\r
- outbuf[0]=0x00;\r
- outbuf[1]=0x00;\r
- outbuf[2]=settime[1]&0x7f;\r
- outbuf[3]=settime[2]&0x3f;\r
- \r
- spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc.\r
- spi(RTC_READ,0x03,inbuf,outbuf,1);\r
- outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit.\r
- \r
- spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time\r
- \r
- outbuf[0]=0x80;\r
- spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc;\r
- \r
- time[1]=0;\r
- time[2]=settime[1];\r
- time[3]=settime[2];\r
- }\r
- mode=MODE_TIME;\r
- }\r
- break;\r
- case MODE_SETYEAR:\r
- if(digit)\r
- --digit;\r
- else\r
- {\r
- if(changed)\r
- {\r
- time[7]=settime[1];\r
- spi(RTC_WRITE,0x07,inbuf,settime+1,1);\r
- \r
- lastyear[0]=settime[1];\r
- lastyear[1]=settime[2];\r
- settime[0]=ALARMVALUE;\r
- \r
- spi(RTC_WRITE,0x26,inbuf,settime,3);\r
- }\r
- mode=MODE_DATE; \r
- }\r
- break;\r
- case MODE_SETDATE:\r
- if(digit)\r
- {\r
- --digit;\r
- if(settime[0]>((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30)))\r
- settime[0]&=(digit?0x00:0xf0);\r
- if(settime[0]==0x00)\r
- settime[0]=0x01;\r
- }\r
- else\r
- {\r
- if (changed)\r
- {\r
- time[5]=settime[0];\r
- time[6]=settime[1];\r
- settime[2]=time[7];\r
- spi(RTC_WRITE,0x06,inbuf,settime+1,2);\r
- spi(RTC_WRITE,0x05,inbuf,settime,1);\r
- }\r
- mode=MODE_DATE;\r
- }\r
- \r
- break;\r
- case MODE_SETALARM:\r
- if(digit)\r
- {\r
- if(digit==3&&settime[2]>0x23)\r
- settime[2]&=0xf0;\r
- --digit;\r
- }\r
- else\r
- {\r
- if(changed|| !alarm[0])\r
- {\r
- alarm[0]=ALARMVALUE;\r
- alarm[1]=settime[1];\r
- alarm[2]=settime[2];\r
- \r
- spi(RTC_WRITE,0x20,inbuf,alarm,3);\r
- }\r
- else\r
- {\r
- alarm[0]=0;\r
- spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
- }\r
- mode=MODE_TIME;\r
- }\r
- break;\r
- case MODE_ALARM:\r
- alarm[0]=0;\r
- spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
- mode=MODE_TIME;\r
- break;\r
- case MODE_DEBUG:\r
- //changed=1;\r
- digit=1;\r
- mode=MODE_DEBUGADDR;\r
- break; \r
- default:\r
- break;\r
- }\r
- }\r
- else if(P2IFG&0x20) // button C\r
- {\r
- P2IFG &= ~0x20;\r
- \r
- switch(mode)\r
- {\r
- case MODE_COUNTUP:\r
- settime[1]=0x00;\r
- settime[2]=0x00;\r
- break;\r
- case MODE_COUNTDOWN:\r
- settime[1]=lastcdn[0];\r
- settime[2]=lastcdn[1];\r
- changed=0;\r
- mode=MODE_SETCOUNTDOWN;\r
- digit=3;\r
- break;\r
- case MODE_CALIBRATE:\r
- if(digit==2)\r
- settime[1]^=0x80;\r
- if(digit>=2)\r
- break;\r
- case MODE_DEBUGADDR:\r
- case MODE_DEBUGVAL:\r
- settime[(mode==MODE_DEBUGADDR)?1:0]+=(digit==1?0x10:(((settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f)==0x0f)?0xf1:0x01));\r
- break;\r
- case MODE_SETTIME:\r
- case MODE_SETALARM:\r
- case MODE_SETYEAR:\r
- case MODE_SETCOUNTDOWN:\r
- changed=1;\r
- //these 4 lines replaced a larger switch structure\r
- if((settime[digit&0x02?2:1]&((digit&0x01)?0xf0:0x0f))<(digit==1?((mode==MODE_SETYEAR)?0x90:0x50):(digit==3?((mode==MODE_SETCOUNTDOWN||mode==MODE_SETYEAR)?0x90:0x20):((mode!=MODE_SETCOUNTDOWN&&mode!=MODE_SETYEAR&&digit==2&&settime[2]>0x19)?0x03:0x09))))\r
- settime[digit&0x02?2:1]+=((digit&0x01)?0x10:0x01);\r
- else\r
- settime[digit&0x02?2:1]&=((digit&0x01)?0x0f:0xf0);\r
- break;\r
- case MODE_SETDATE:\r
- changed=1;\r
- switch (digit)\r
- {\r
- case 2:\r
- if(settime[1]<0x12)\r
- settime[1]=__bcd_add_short(settime[1],0x01);\r
- else\r
- settime[1]=0x01;\r
- break;\r
- case 1:\r
- if((settime[0]&0xf0)<((settime[1]==0x02)?0x20:0x30))\r
- settime[0]+=0x10;\r
- else\r
- settime[0]&=0x0f;\r
- break;\r
- \r
- case 0:\r
- if((settime[0]<((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30))) && (settime[0]&0x0f)<0x09)\r
- ++settime[0];\r
- else\r
- settime[0]&=0xf0;\r
- if(settime[0]==0x00)\r
- settime[0]=0x01;\r
- break;\r
- }\r
- break;\r
- case MODE_DATE:\r
- mode=MODE_SETYEAR;\r
- digit=3;\r
- changed=0;\r
- \r
- settime[1]=time[7];\r
- settime[2]=lastyear[1];\r
- break;\r
- case MODE_TIME:\r
- mode=MODE_SETALARM;\r
- digit=3;\r
- changed=0;\r
- \r
- settime[0]=0;\r
- settime[1]=alarm[1]; //get last alarm time\r
- if(settime[1]>0x59 || (settime[1]&0x0f)>0x09)\r
- settime[1]=0x00;\r
- settime[2]=alarm[2];\r
- if(settime[2]>0x23 || (settime[2]&0x0f)>0x09)\r
- settime[2]=0x00;\r
- break;\r
- case MODE_ALARM:\r
- alarm[0]=0;\r
- spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
- mode=MODE_TIME;\r
- break;\r
- case MODE_DEBUG:\r
- if(changed)\r
- {\r
- digit=1;\r
- mode=MODE_DEBUGVAL;\r
- }\r
- break;\r
- default:\r
- break;\r
- }\r
- }\r
- else\r
- P2IFG=0;\r
- \r
- switch(mode)\r
- {\r
- case MODE_SETTIME:\r
- case MODE_SETALARM:\r
- case MODE_SETCOUNTDOWN:\r
- case MODE_SETYEAR:\r
- dispvalue[0]=(symbol[settime[1]&0x0f] | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((((((time[1]+0x01)&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);\r
- dispvalue[1]=(symbol[(settime[1]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & (((((time[1]&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);\r
- dispvalue[2]=(symbol[settime[2]&0x0f] | ((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) ;\r
- dispvalue[3]=(symbol[(settime[2]&0xf0)>>4] | ((digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((mode!=MODE_SETALARM && alarm[0] || mode==MODE_SETALARM && !(time[1]&0x01))?SYMB_DOT:SYMB_NUL);\r
- break;\r
- case MODE_DEBUGADDR:\r
- case MODE_DEBUGVAL:\r
- dispvalue[0]=(symbol[settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f] | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;\r
- dispvalue[1]=(symbol[(settime[(mode==MODE_DEBUGADDR)?1:0]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;\r
- dispvalue[2]=(mode==MODE_DEBUGADDR)?SYMB_A:SYMB_NUL; \r
- dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
- break;\r
- case MODE_SETDATE:\r
- dispvalue[0]=(symbol[settime[1]&0x0f]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8));\r
- dispvalue[1]=(symbol[(settime[1]&0xf0)>>4]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&SYMB_DOT;\r
- dispvalue[2]=(symbol[settime[0]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8));\r
- dispvalue[3]=(symbol[(settime[0]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- break;\r
- case MODE_CALIBRATE:\r
- dispvalue[0]=symbol[settime[0]&0x0f]|((digit!=0 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
- dispvalue[1]=symbol[(settime[0]&0xf0)>>4]|((digit!=1 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
- dispvalue[2]=(settime[1]?SYMB_MIN:SYMB_NUL)|((digit!=2 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
- dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
- break;\r
- case MODE_DATE:\r
- if((time[1]&0x03)==((time[1]&0x10)?0x01:0x03))\r
- {\r
- dispvalue[0]=symbol[time[7]&0x0f];\r
- dispvalue[1]=symbol[(time[7]&0xf0)>>4];\r
- dispvalue[2]=symbol[lastyear[4]&0x0f];\r
- dispvalue[3]=symbol[(lastyear[4]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- }\r
- else\r
- {\r
- dispvalue[0]=symbol[time[6]&0x0f];\r
- dispvalue[1]=symbol[(time[6]&0xf0)>>4]&SYMB_DOT;\r
- dispvalue[2]=symbol[time[5]&0x0f];\r
- dispvalue[3]=((time[5]&0xf0)?symbol[(time[5]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- }\r
- break;\r
- case MODE_COUNTDOWN:\r
- if(!(settime[1]|settime[2]))\r
- {\r
- if(!run)\r
- {\r
- dispvalue[0]=SYMB_g&SYMB_DOT;\r
- dispvalue[1]=SYMB_n&SYMB_DOT;\r
- dispvalue[2]=SYMB_o;\r
- dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
- break;\r
- }\r
- run=0;\r
- }\r
- case MODE_COUNTUP:\r
- dispvalue[0]=symbol[settime[1]&0x0f]&SYMB_DOT;\r
- dispvalue[1]=symbol[(settime[1]&0xf0)>>4]&SYMB_DOT;\r
- dispvalue[2]=symbol[settime[2]&0x0f];\r
- dispvalue[3]=((settime[2]&0xf0)?symbol[(settime[2]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- break;\r
- case MODE_DEBUG:\r
- if(changed)\r
- {\r
- dispvalue[0]=symbol[settime[0]&0x0f]&SYMB_DOT;\r
- dispvalue[1]=symbol[(settime[0]&0xf0)>>4]&SYMB_DOT;\r
- dispvalue[2]=symbol[settime[1]&0x0f];\r
- dispvalue[3]=symbol[(settime[1]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- }\r
- else\r
- {\r
- dispvalue[0]=SYMB_NUL;\r
- dispvalue[1]=SYMB_4&SYMB_DOT;\r
- dispvalue[2]=SYMB_1;\r
- dispvalue[3]=SYMB_NUL&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
- }\r
- break;\r
- case MODE_ALARM:\r
- case MODE_TIME:\r
- if(((time[1]&0x01) && mode==MODE_ALARM) || (time[3]==0x04 && time[2]==0x33 && time[1]==0x00))\r
- {\r
- dispvalue[0]=SYMB_g;\r
- dispvalue[1]=SYMB_n;\r
- dispvalue[2]=SYMB_o;\r
- dispvalue[3]=SYMB_DOT;\r
- break;\r
- }\r
- default:\r
- dispvalue[0]=symbol[time[2]&0x0f]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);\r
- dispvalue[1]=symbol[(time[2]&0xf0)>>4]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);\r
- dispvalue[2]=symbol[time[3]&0x0f];\r
- dispvalue[3]=((time[3]&0xf0)?symbol[(time[3]&0xf0)>>4]:SYMB_NUL)&((alarm[0] || mode==MODE_ALARM)?SYMB_DOT:SYMB_NUL);\r
- break;\r
- }\r
- \r
- display(dispvalue);\r
- \r
- \r
- return;\r
-}\r
+ #pragma vector=PORT2_VECTOR\r
+ __interrupt void P2_ISR()\r
+ {\r
+ if(P2IFG&0x08) // RTC\r
+ {\r
+ P2IFG &= ~0x08;\r
+ spi(RTC_READ,0x00,inbuf,outbuf,8);\r
+ \r
+ time[0]=inbuf[0]; //1/100 s\r
+ time[1]=inbuf[1]&0x7f; //seconds\r
+ time[2]=inbuf[2]&0x7f; //minutes\r
+ time[3]=inbuf[3]&0x3f; //hours\r
+ time[4]=inbuf[4]&0x07; //dow\r
+ time[5]=inbuf[5]&0x3f; //dom\r
+ time[6]=inbuf[6]&0x1f; //mon\r
+ time[7]=inbuf[7];//year\r
+ leap=inbuf[6]&0x20;\r
+ \r
+ spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?)\r
+ if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0])\r
+ {\r
+ mode=MODE_ALARM;\r
+ alarm[0]=0; //alarm removed after activated\r
+ spi(RTC_WRITE,0x20,inbuf,alarm,1);\r
+ }\r
+ \r
+ if(mode==MODE_COUNTUP && run)\r
+ {\r
+ if(settime[1]<0x59)\r
+ settime[1]=bcd_add_byte(settime[1],0x01);\r
+ else\r
+ {\r
+ settime[1]=0x00;\r
+ settime[2]=bcd_add_byte(settime[2],0x01);\r
+ }\r
+ }\r
+ else if(mode==MODE_COUNTDOWN && run && (settime[1]|settime[2]))\r
+ {\r
+ if(settime[1])\r
+ settime[1]=bcd_add_byte(settime[1],0x99);\r
+ else\r
+ {\r
+ settime[1]=0x59;\r
+ settime[2]=bcd_add_byte(settime[2],0x99);\r
+ }\r
+ }\r
+ \r
+ if (mode==MODE_ALARM || (mode==MODE_COUNTDOWN && !(settime[1]|settime[2])))\r
+ {\r
+ TACTL^=MC_1;\r
+ //P2DIR^=0x40;\r
+ //P2SEL^=0x40;\r
+ }\r
+ else if(TACTL & MC_3)\r
+ {\r
+ TACTL&= ~MC_3;\r
+ //P2DIR&= ~0x40;\r
+ //P2SEL&= ~0x40;\r
+ }\r
+ \r
+ lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?bcd_add_byte(lastyear[1],0x01):lastyear[1];\r
+ if (time[7]!=lastyear[0])\r
+ {\r
+ if(time[7]==lastyear[2])\r
+ ++(lastyear[3]);\r
+ else\r
+ lastyear[3]=0;\r
+ \r
+ lastyear[2]=time[7];\r
+ \r
+ if(lastyear[3]>55)\r
+ {\r
+ lastyear[3]=0;\r
+ \r
+ if(time[7]==0x00 && lastyear[0]==0x99)\r
+ lastyear[1]=bcd_add_byte(lastyear[1],0x01);\r
+ \r
+ lastyear[0]=time[7];\r
+ \r
+ outbuf[0]=ALARMVALUE;\r
+ outbuf[1]=lastyear[0];\r
+ outbuf[2]=lastyear[1];\r
+ spi(RTC_WRITE,0x26,inbuf,outbuf,3);\r
+ } \r
+ }\r
+ \r
+ \r
+ if(mode==MODE_DEBUG && changed)\r
+ spi(RTC_READ,settime[1],settime,outbuf,1);\r
+ }\r
+ else if(P2IFG&0x02) // button A\r
+ {\r
+ P2IFG &= ~0x02;\r
+ switch(mode)\r
+ {\r
+ case MODE_TIME:\r
+ case MODE_SETDATE:\r
+ case MODE_SETYEAR:\r
+ mode=MODE_DATE;\r
+ break;\r
+ case MODE_DATE:\r
+ mode=MODE_COUNTUP;\r
+ settime[1]=0x00;\r
+ settime[2]=0x00;\r
+ run=0;\r
+ break;\r
+ case MODE_COUNTUP:\r
+ if(run)\r
+ {\r
+ settime[1]=0x00;\r
+ settime[2]=0x00;\r
+ run=0;\r
+ }\r
+ else\r
+ {\r
+ mode=MODE_SETCOUNTDOWN;\r
+ settime[1]=lastcdn[0];\r
+ settime[2]=lastcdn[1];\r
+ changed=0;\r
+ digit=3;\r
+ }\r
+ break;\r
+ case MODE_DEBUGADDR:\r
+ case MODE_DEBUGVAL:\r
+ mode=MODE_DEBUG;\r
+ break;\r
+ case MODE_SETCOUNTDOWN:\r
+ case MODE_COUNTDOWN:\r
+ if(changed || mode==MODE_COUNTDOWN)\r
+ {\r
+ mode=MODE_SETCOUNTDOWN;\r
+ settime[1]=lastcdn[0];\r
+ settime[2]=lastcdn[1];\r
+ changed=0;\r
+ digit=3;\r
+ break;\r
+ }\r
+ //case MODE_SETTIME:\r
+ //case MODE_SETALARM:\r
+ //case MODE_ALARM:\r
+ //case MODE_CALIBRATE:\r
+ //case MODE_DEBUG:\r
+ default:\r
+ mode=MODE_TIME;\r
+ break;\r
+ }\r
+ }\r
+ else if(P2IFG&0x01) // button B\r
+ {\r
+ P2IFG &= ~0x01;\r
+ \r
+ switch(mode)\r
+ {\r
+ case MODE_TIME:\r
+ mode=MODE_SETTIME;\r
+ digit=3;\r
+ changed=0;\r
+ settime[0]=0;\r
+ settime[1]=time[2];\r
+ settime[2]=time[3];\r
+ break;\r
+ case MODE_DATE:\r
+ mode=MODE_SETDATE;\r
+ digit=2;\r
+ changed=0;\r
+ settime[0]=time[5];\r
+ settime[1]=time[6];\r
+ break;\r
+ case MODE_COUNTUP:\r
+ case MODE_COUNTDOWN:\r
+ run=!run;\r
+ break;\r
+ case MODE_SETCOUNTDOWN:\r
+ if(digit)\r
+ {\r
+ --digit;\r
+ changed=1;\r
+ }\r
+ else\r
+ {\r
+ lastcdn[0]=settime[1];\r
+ lastcdn[1]=settime[2];\r
+ \r
+ outbuf[0]=ALARMVALUE;\r
+ outbuf[1]=settime[1];\r
+ outbuf[2]=settime[2];\r
+ spi(RTC_WRITE,0x23,inbuf,outbuf,3);\r
\r
-int main( void )\r
-{\r
- unsigned char delay;\r
- \r
- //watchdog:\r
- WDTCTL = WDTPW + WDTHOLD;\r
- \r
- mode=MODE_INIT;\r
- \r
- //init 7 segment display\r
- \r
- P1OUT =0xff; //display data on p1\r
- P1DIR =0xff;\r
- \r
- P3OUT &=0x0f; //display control on p3.4-7\r
- P3DIR |=0xf0; \r
- \r
- dispvalue[0]=SYMB_NUL;\r
- dispvalue[1]=SYMB_o;\r
- dispvalue[2]=SYMB_o;\r
- dispvalue[3]=SYMB_NUL;\r
- \r
- display(dispvalue); \r
- \r
- //clocking:\r
- \r
- BCSCTL2 |= DIVM_3; //errata sheet recommends this here \r
- \r
- DCOCTL =0x00;\r
- BCSCTL1 =\r
- RSEL2| //in the\r
- XTS| //hi freq\r
- DIVA_1; //ACLK = 6/2 MHz\r
- \r
- do\r
- {\r
- IFG1 &= ~OFIFG;\r
- for (delay = 0xFF; delay > 0; --delay);\r
- }\r
- while ((IFG1 & OFIFG)); \r
- \r
- BCSCTL2 =\r
- SELM_2| //MCLK from XT2\r
- DIVM_1| //MCLK = 6/2 MHz\r
- SELS| //SMCLK from XT2\r
- DIVS_0; //SMCLK = 6/1 MHz\r
- \r
- //init SPI\r
- \r
- P3SEL =0x0e; // SPI on p3.1, 3.2, 3.3\r
- P3OUT |=0x01;\r
- P3DIR |=0x01; //RTC CS on p3.0\r
- \r
- U0CTL =\r
- SWRST| //reset\r
- MM| //master\r
- SYNC| //SPI mode\r
- CHAR; //8 bit data\r
- U0TCTL=\r
- CKPH| //polarity and phase\r
- SSEL0|SSEL1| //SMCLK\r
- STC; //3 pin mode\r
- U0BR1=0x00;\r
- U0BR0=0x02; //baudrate = SMCLK/2 = 3MHz\r
- U0MCTL=0x00;\r
- ME2|=USPIE0;\r
- U0CTL &= ~SWRST;\r
- \r
- \r
- //init RTC\r
- \r
- //Looks like sometimes the first SPI reads rom the RTC may be incorrect.\r
- //To be sure, let's do a few redundant reads before starting the real work\r
- \r
- for (delay = 0xFF; delay > 0; --delay)\r
- spi(RTC_READ,0x00,inbuf,outbuf,1);\r
- \r
- //set 24 hour mode\r
- spi(RTC_READ,0x03,inbuf,outbuf,1);\r
- if(inbuf[0]&0x40)\r
- {\r
- outbuf[0]=inbuf[0]&(~0x40);\r
- spi(RTC_WRITE,0x03,inbuf,outbuf,1);\r
- }\r
- \r
- //enable battery\r
- spi(RTC_READ,0x04,inbuf,outbuf,1);\r
- if(!(inbuf[0]&0x08))\r
- {\r
- outbuf[0]=inbuf[0]|0x08; //enable battery\r
- spi(RTC_WRITE,0x04,inbuf,outbuf,1);\r
- }\r
- \r
- //set control register\r
- //spi(RTC_READ,0x08,inbuf,outbuf,1);\r
- outbuf[0]=\r
- 0x40| //squarewave enable\r
- 0x04; //1Hz\r
- //no hardware alarms :(\r
- spi(RTC_WRITE,0x08,inbuf,outbuf,1);\r
- \r
- //get (soft) alarm from RTC SRAM\r
- spi(RTC_READ,0x20,inbuf,outbuf,3);\r
- \r
- alarm[0]=(inbuf[0]==ALARMVALUE)?ALARMVALUE:0;\r
- alarm[1]=inbuf[1];\r
- alarm[2]=inbuf[2];\r
- \r
- spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)\r
- \r
- //get last countdown value from RTC SRAM\r
- spi(RTC_READ,0x23,inbuf,outbuf,3);\r
- if(inbuf[0]==ALARMVALUE)\r
- {\r
- lastcdn[0]=inbuf[1];\r
- lastcdn[1]=inbuf[2];\r
- }\r
- else\r
- {\r
- lastcdn[0]=0;\r
- lastcdn[1]=0;\r
- }\r
- \r
- spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)\r
- \r
- //get last year value from RTC SRAM\r
- spi(RTC_READ,0x26,inbuf,outbuf,3);\r
- if(inbuf[0]==ALARMVALUE)\r
- {\r
- lastyear[0]=inbuf[1];\r
- lastyear[1]=inbuf[2];\r
- }\r
- else\r
- {\r
- lastyear[0]=0x00;\r
- lastyear[1]=0x20;\r
- }\r
- lastyear[3]=0;\r
- \r
- //start oscillator\r
- spi(RTC_READ,0x01,inbuf,outbuf,1);\r
- if(!(inbuf[0]&0x80))\r
- {\r
- outbuf[0]=inbuf[0]|0x80;\r
- spi(RTC_WRITE,0x01,inbuf,outbuf,1);\r
- }\r
- \r
- //init timer:\r
- TACCR0 = 375-1; //3MHz/375/2=4kHz\r
- TACCTL0= //also, compare, not capture\r
- OUTMOD_4; //toggle\r
- TACTL=\r
- TASSEL_1| //ACLK, 3MHz\r
- ID_0| //3MHz/1\r
- //MC_1| //up mode\r
- TACLR; //reset\r
- P2SEL|=0x04; //P2.2 timer output.\r
- P2DIR|=0x04;\r
- \r
- // Init interrupts\r
- P2IE=\r
- 0x08| //p2.3 - int. from RTC\r
- 0x02| //p2.1 - int. from button A\r
- 0x01| //p2.0 - int. from button B\r
- 0x20; //p2.5 - int. from button C\r
- P2IES|=0x01|0x02|0x20; //button int. on falling edge\r
- P2IES&= ~0x08; //RTC int. on rising edge\r
- P2IFG=0x00;\r
- \r
- if(!(P2IN&0x02)) //button A pressed at start?\r
- {\r
- mode=MODE_CALIBRATE;\r
- spi(RTC_READ,0x03,inbuf,outbuf,1);\r
- settime[1]=inbuf[0]&0x80;\r
- spi(RTC_READ,0x09,inbuf,outbuf,1);\r
- settime[0]=inbuf[0];\r
- digit=3;\r
- }\r
- else if(!(P2IN&0x20)) //button C pressed at start?\r
- {\r
- mode=MODE_DEBUG;\r
- settime[1]=0x00;\r
- changed=0;\r
- }\r
- else\r
- mode=MODE_TIME;\r
- \r
- __enable_interrupt();\r
- \r
- \r
- while(1)\r
- {\r
- __low_power_mode_3();\r
- }\r
-}\r
+ mode=MODE_COUNTDOWN;\r
+ run=0;\r
+ }\r
+ break;\r
+ case MODE_CALIBRATE:\r
+ if(digit)\r
+ --digit;\r
+ else\r
+ {\r
+ spi(RTC_WRITE,0x09,inbuf,settime,1);\r
+ outbuf[0]=time[3]|settime[1];\r
+ spi(RTC_WRITE,0x03,inbuf,outbuf,1);\r
+ digit=3;\r
+ }\r
+ break;\r
+ case MODE_DEBUGADDR:\r
+ if(digit)\r
+ --digit;\r
+ else\r
+ {\r
+ spi(RTC_READ,settime[1],settime,outbuf,1);\r
+ mode=MODE_DEBUG;\r
+ changed=1;\r
+ }\r
+ break;\r
+ case MODE_DEBUGVAL:\r
+ if(digit)\r
+ --digit;\r
+ else\r
+ {\r
+ spi(RTC_WRITE,settime[1],inbuf,settime,1);\r
+ mode=MODE_DEBUG;\r
+ }\r
+ break;\r
+ case MODE_SETTIME:\r
+ if(digit)\r
+ {\r
+ if(digit==3&&settime[2]>0x23)\r
+ settime[2]&=0xf0;\r
+ --digit;\r
+ }\r
+ else\r
+ {\r
+ if(changed)\r
+ {\r
+ outbuf[0]=0x00;\r
+ outbuf[1]=0x00;\r
+ outbuf[2]=settime[1]&0x7f;\r
+ outbuf[3]=settime[2]&0x3f;\r
+ \r
+ spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc.\r
+ spi(RTC_READ,0x03,inbuf,outbuf,1);\r
+ outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit.\r
+ \r
+ spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time\r
+ \r
+ outbuf[0]=0x80;\r
+ spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc;\r
+ \r
+ time[1]=0;\r
+ time[2]=settime[1];\r
+ time[3]=settime[2];\r
+ }\r
+ mode=MODE_TIME;\r
+ }\r
+ break;\r
+ case MODE_SETYEAR:\r
+ if(digit)\r
+ --digit;\r
+ else\r
+ {\r
+ if(changed)\r
+ {\r
+ time[7]=settime[1];\r
+ spi(RTC_WRITE,0x07,inbuf,settime+1,1);\r
+ \r
+ lastyear[0]=settime[1];\r
+ lastyear[1]=settime[2];\r
+ settime[0]=ALARMVALUE;\r
+ \r
+ spi(RTC_WRITE,0x26,inbuf,settime,3);\r
+ }\r
+ mode=MODE_DATE; \r
+ }\r
+ break;\r
+ case MODE_SETDATE:\r
+ if(digit)\r
+ {\r
+ --digit;\r
+ if(settime[0]>((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30)))\r
+ settime[0]&=(digit?0x00:0xf0);\r
+ if(settime[0]==0x00)\r
+ settime[0]=0x01;\r
+ }\r
+ else\r
+ {\r
+ if (changed)\r
+ {\r
+ time[5]=settime[0];\r
+ time[6]=settime[1];\r
+ settime[2]=time[7];\r
+ spi(RTC_WRITE,0x06,inbuf,settime+1,2);\r
+ spi(RTC_WRITE,0x05,inbuf,settime,1);\r
+ }\r
+ mode=MODE_DATE;\r
+ }\r
+ \r
+ break;\r
+ case MODE_SETALARM:\r
+ if(digit)\r
+ {\r
+ if(digit==3&&settime[2]>0x23)\r
+ settime[2]&=0xf0;\r
+ --digit;\r
+ }\r
+ else\r
+ {\r
+ if(changed|| !alarm[0])\r
+ {\r
+ alarm[0]=ALARMVALUE;\r
+ alarm[1]=settime[1];\r
+ alarm[2]=settime[2];\r
+ \r
+ spi(RTC_WRITE,0x20,inbuf,alarm,3);\r
+ }\r
+ else\r
+ {\r
+ alarm[0]=0;\r
+ spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
+ }\r
+ mode=MODE_TIME;\r
+ }\r
+ break;\r
+ case MODE_ALARM:\r
+ alarm[0]=0;\r
+ spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
+ mode=MODE_TIME;\r
+ break;\r
+ case MODE_DEBUG:\r
+ //changed=1;\r
+ digit=1;\r
+ mode=MODE_DEBUGADDR;\r
+ break; \r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ else if(P2IFG&0x20) // button C\r
+ {\r
+ P2IFG &= ~0x20;\r
+ \r
+ switch(mode)\r
+ {\r
+ case MODE_COUNTUP:\r
+ settime[1]=0x00;\r
+ settime[2]=0x00;\r
+ break;\r
+ case MODE_COUNTDOWN:\r
+ settime[1]=lastcdn[0];\r
+ settime[2]=lastcdn[1];\r
+ changed=0;\r
+ mode=MODE_SETCOUNTDOWN;\r
+ digit=3;\r
+ break;\r
+ case MODE_CALIBRATE:\r
+ if(digit==2)\r
+ settime[1]^=0x80;\r
+ if(digit>=2)\r
+ break;\r
+ case MODE_DEBUGADDR:\r
+ case MODE_DEBUGVAL:\r
+ settime[(mode==MODE_DEBUGADDR)?1:0]+=(digit==1?0x10:(((settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f)==0x0f)?0xf1:0x01));\r
+ break;\r
+ case MODE_SETTIME:\r
+ case MODE_SETALARM:\r
+ case MODE_SETYEAR:\r
+ case MODE_SETCOUNTDOWN:\r
+ changed=1;\r
+ //these 4 lines replaced a larger switch structure\r
+ if((settime[digit&0x02?2:1]&((digit&0x01)?0xf0:0x0f))<(digit==1?((mode==MODE_SETYEAR)?0x90:0x50):(digit==3?((mode==MODE_SETCOUNTDOWN||mode==MODE_SETYEAR)?0x90:0x20):((mode!=MODE_SETCOUNTDOWN&&mode!=MODE_SETYEAR&&digit==2&&settime[2]>0x19)?0x03:0x09))))\r
+ settime[digit&0x02?2:1]+=((digit&0x01)?0x10:0x01);\r
+ else\r
+ settime[digit&0x02?2:1]&=((digit&0x01)?0x0f:0xf0);\r
+ break;\r
+ case MODE_SETDATE:\r
+ changed=1;\r
+ switch (digit)\r
+ {\r
+ case 2:\r
+ if(settime[1]<0x12)\r
+ settime[1]=bcd_add_byte(settime[1],0x01);\r
+ else\r
+ settime[1]=0x01;\r
+ break;\r
+ case 1:\r
+ if((settime[0]&0xf0)<((settime[1]==0x02)?0x20:0x30))\r
+ settime[0]+=0x10;\r
+ else\r
+ settime[0]&=0x0f;\r
+ break;\r
+ \r
+ case 0:\r
+ if((settime[0]<((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30))) && (settime[0]&0x0f)<0x09)\r
+ ++settime[0];\r
+ else\r
+ settime[0]&=0xf0;\r
+ if(settime[0]==0x00)\r
+ settime[0]=0x01;\r
+ break;\r
+ }\r
+ break;\r
+ case MODE_DATE:\r
+ mode=MODE_SETYEAR;\r
+ digit=3;\r
+ changed=0;\r
+ \r
+ settime[1]=time[7];\r
+ settime[2]=lastyear[1];\r
+ break;\r
+ case MODE_TIME:\r
+ mode=MODE_SETALARM;\r
+ digit=3;\r
+ changed=0;\r
+ \r
+ settime[0]=0;\r
+ settime[1]=alarm[1]; //get last alarm time\r
+ if(settime[1]>0x59 || (settime[1]&0x0f)>0x09)\r
+ settime[1]=0x00;\r
+ settime[2]=alarm[2];\r
+ if(settime[2]>0x23 || (settime[2]&0x0f)>0x09)\r
+ settime[2]=0x00;\r
+ break;\r
+ case MODE_ALARM:\r
+ alarm[0]=0;\r
+ spi(RTC_WRITE,0x20,inbuf,outbuf,1);\r
+ mode=MODE_TIME;\r
+ break;\r
+ case MODE_DEBUG:\r
+ if(changed)\r
+ {\r
+ digit=1;\r
+ mode=MODE_DEBUGVAL;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ else\r
+ P2IFG=0;\r
+ \r
+ switch(mode)\r
+ {\r
+ case MODE_SETTIME:\r
+ case MODE_SETALARM:\r
+ case MODE_SETCOUNTDOWN:\r
+ case MODE_SETYEAR:\r
+ dispvalue[0]=(symbol[settime[1]&0x0f] | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((((((time[1]+0x01)&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);\r
+ dispvalue[1]=(symbol[(settime[1]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & (((((time[1]&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);\r
+ dispvalue[2]=(symbol[settime[2]&0x0f] | ((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) ;\r
+ dispvalue[3]=(symbol[(settime[2]&0xf0)>>4] | ((digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((mode!=MODE_SETALARM && alarm[0] || mode==MODE_SETALARM && !(time[1]&0x01))?SYMB_DOT:SYMB_NUL);\r
+ break;\r
+ case MODE_DEBUGADDR:\r
+ case MODE_DEBUGVAL:\r
+ dispvalue[0]=(symbol[settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f] | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;\r
+ dispvalue[1]=(symbol[(settime[(mode==MODE_DEBUGADDR)?1:0]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;\r
+ dispvalue[2]=(mode==MODE_DEBUGADDR)?SYMB_A:SYMB_NUL; \r
+ dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
+ break;\r
+ case MODE_SETDATE:\r
+ dispvalue[0]=(symbol[settime[1]&0x0f]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8));\r
+ dispvalue[1]=(symbol[(settime[1]&0xf0)>>4]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&SYMB_DOT;\r
+ dispvalue[2]=(symbol[settime[0]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8));\r
+ dispvalue[3]=(symbol[(settime[0]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ break;\r
+ case MODE_CALIBRATE:\r
+ dispvalue[0]=symbol[settime[0]&0x0f]|((digit!=0 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
+ dispvalue[1]=symbol[(settime[0]&0xf0)>>4]|((digit!=1 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
+ dispvalue[2]=(settime[1]?SYMB_MIN:SYMB_NUL)|((digit!=2 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);\r
+ dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
+ break;\r
+ case MODE_DATE:\r
+ if((time[1]&0x03)==((time[1]&0x10)?0x01:0x03))\r
+ {\r
+ dispvalue[0]=symbol[time[7]&0x0f];\r
+ dispvalue[1]=symbol[(time[7]&0xf0)>>4];\r
+ dispvalue[2]=symbol[lastyear[4]&0x0f];\r
+ dispvalue[3]=symbol[(lastyear[4]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ }\r
+ else\r
+ {\r
+ dispvalue[0]=symbol[time[6]&0x0f];\r
+ dispvalue[1]=symbol[(time[6]&0xf0)>>4]&SYMB_DOT;\r
+ dispvalue[2]=symbol[time[5]&0x0f];\r
+ dispvalue[3]=((time[5]&0xf0)?symbol[(time[5]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ }\r
+ break;\r
+ case MODE_COUNTDOWN:\r
+ if(!(settime[1]|settime[2]))\r
+ {\r
+ if(!run)\r
+ {\r
+ dispvalue[0]=SYMB_g&SYMB_DOT;\r
+ dispvalue[1]=SYMB_n&SYMB_DOT;\r
+ dispvalue[2]=SYMB_o;\r
+ dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;\r
+ break;\r
+ }\r
+ run=0;\r
+ }\r
+ case MODE_COUNTUP:\r
+ dispvalue[0]=symbol[settime[1]&0x0f]&SYMB_DOT;\r
+ dispvalue[1]=symbol[(settime[1]&0xf0)>>4]&SYMB_DOT;\r
+ dispvalue[2]=symbol[settime[2]&0x0f];\r
+ dispvalue[3]=((settime[2]&0xf0)?symbol[(settime[2]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ break;\r
+ case MODE_DEBUG:\r
+ if(changed)\r
+ {\r
+ dispvalue[0]=symbol[settime[0]&0x0f]&SYMB_DOT;\r
+ dispvalue[1]=symbol[(settime[0]&0xf0)>>4]&SYMB_DOT;\r
+ dispvalue[2]=symbol[settime[1]&0x0f];\r
+ dispvalue[3]=symbol[(settime[1]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ }\r
+ else\r
+ {\r
+ dispvalue[0]=SYMB_NUL;\r
+ dispvalue[1]=SYMB_4&SYMB_DOT;\r
+ dispvalue[2]=SYMB_1;\r
+ dispvalue[3]=SYMB_NUL&(alarm[0]?SYMB_DOT:SYMB_NUL);\r
+ }\r
+ break;\r
+ case MODE_ALARM:\r
+ case MODE_TIME:\r
+ if(((time[1]&0x01) && mode==MODE_ALARM) || (time[3]==0x04 && time[2]==0x33 && time[1]==0x00))\r
+ {\r
+ dispvalue[0]=SYMB_g;\r
+ dispvalue[1]=SYMB_n;\r
+ dispvalue[2]=SYMB_o;\r
+ dispvalue[3]=SYMB_DOT;\r
+ break;\r
+ }\r
+ default:\r
+ dispvalue[0]=symbol[time[2]&0x0f]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);\r
+ dispvalue[1]=symbol[(time[2]&0xf0)>>4]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);\r
+ dispvalue[2]=symbol[time[3]&0x0f];\r
+ dispvalue[3]=((time[3]&0xf0)?symbol[(time[3]&0xf0)>>4]:SYMB_NUL)&((alarm[0] || mode==MODE_ALARM)?SYMB_DOT:SYMB_NUL);\r
+ break;\r
+ }\r
+ \r
+ display(dispvalue);\r
+ \r
+ \r
+ return;\r
+ }\r
+\r
+ int main( void )\r
+ {\r
+ unsigned char delay;\r
+ \r
+ //watchdog:\r
+ WDTCTL = WDTPW + WDTHOLD;\r
+ \r
+ mode=MODE_INIT;\r
+ \r
+ //init 7 segment display\r
+ \r
+ P1OUT =0xff; //display data on p1\r
+ P1DIR =0xff;\r
+ \r
+ P3OUT &=0x0f; //display control on p3.4-7\r
+ P3DIR |=0xf0; \r
+ \r
+ dispvalue[0]=SYMB_NUL;\r
+ dispvalue[1]=SYMB_o;\r
+ dispvalue[2]=SYMB_o;\r
+ dispvalue[3]=SYMB_NUL;\r
+ \r
+ display(dispvalue); \r
+ \r
+ //clocking:\r
+ \r
+ BCSCTL2 |= DIVM_3; //errata sheet recommends this here \r
+ \r
+ DCOCTL =0x00;\r
+ BCSCTL1 =\r
+ RSEL2| //in the\r
+ XTS| //hi freq\r
+ DIVA_1; //ACLK = 6/2 MHz\r
+ \r
+ do\r
+ {\r
+ IFG1 &= ~OFIFG;\r
+ for (delay = 0xFF; delay > 0; --delay);\r
+ }\r
+ while ((IFG1 & OFIFG)); \r
+ \r
+ BCSCTL2 =\r
+ SELM_2| //MCLK from XT2\r
+ DIVM_1| //MCLK = 6/2 MHz\r
+ SELS| //SMCLK from XT2\r
+ DIVS_0; //SMCLK = 6/1 MHz\r
+ \r
+ //init SPI\r
+ \r
+ P3SEL =0x0e; // SPI on p3.1, 3.2, 3.3\r
+ P3OUT |=0x01;\r
+ P3DIR |=0x01; //RTC CS on p3.0\r
+ \r
+ U0CTL =\r
+ SWRST| //reset\r
+ MM| //master\r
+ SYNC| //SPI mode\r
+ CHAR; //8 bit data\r
+ U0TCTL=\r
+ CKPH| //polarity and phase\r
+ SSEL0|SSEL1| //SMCLK\r
+ STC; //3 pin mode\r
+ U0BR1=0x00;\r
+ U0BR0=0x02; //baudrate = SMCLK/2 = 3MHz\r
+ U0MCTL=0x00;\r
+ ME2|=USPIE0;\r
+ U0CTL &= ~SWRST;\r
+ \r
+ \r
+ //init RTC\r
+ \r
+ //Looks like sometimes the first SPI reads rom the RTC may be incorrect.\r
+ //To be sure, let's do a few redundant reads before starting the real work\r
+ \r
+ for (delay = 0xFF; delay > 0; --delay)\r
+ spi(RTC_READ,0x00,inbuf,outbuf,1);\r
+ \r
+ //set 24 hour mode\r
+ spi(RTC_READ,0x03,inbuf,outbuf,1);\r
+ if(inbuf[0]&0x40)\r
+ {\r
+ outbuf[0]=inbuf[0]&(~0x40);\r
+ spi(RTC_WRITE,0x03,inbuf,outbuf,1);\r
+ }\r
+ \r
+ //enable battery\r
+ spi(RTC_READ,0x04,inbuf,outbuf,1);\r
+ if(!(inbuf[0]&0x08))\r
+ {\r
+ outbuf[0]=inbuf[0]|0x08; //enable battery\r
+ spi(RTC_WRITE,0x04,inbuf,outbuf,1);\r
+ }\r
+ \r
+ //set control register\r
+ //spi(RTC_READ,0x08,inbuf,outbuf,1);\r
+ outbuf[0]=\r
+ 0x40| //squarewave enable\r
+ 0x04; //1Hz\r
+ //no hardware alarms :(\r
+ spi(RTC_WRITE,0x08,inbuf,outbuf,1);\r
+ \r
+ //get (soft) alarm from RTC SRAM\r
+ spi(RTC_READ,0x20,inbuf,outbuf,3);\r
+ \r
+ alarm[0]=(inbuf[0]==ALARMVALUE)?ALARMVALUE:0;\r
+ alarm[1]=inbuf[1];\r
+ alarm[2]=inbuf[2];\r
+ \r
+ spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)\r
+ \r
+ //get last countdown value from RTC SRAM\r
+ spi(RTC_READ,0x23,inbuf,outbuf,3);\r
+ if(inbuf[0]==ALARMVALUE)\r
+ {\r
+ lastcdn[0]=inbuf[1];\r
+ lastcdn[1]=inbuf[2];\r
+ }\r
+ else\r
+ {\r
+ lastcdn[0]=0;\r
+ lastcdn[1]=0;\r
+ }\r
+ \r
+ spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)\r
+ \r
+ //get last year value from RTC SRAM\r
+ spi(RTC_READ,0x26,inbuf,outbuf,3);\r
+ if(inbuf[0]==ALARMVALUE)\r
+ {\r
+ lastyear[0]=inbuf[1];\r
+ lastyear[1]=inbuf[2];\r
+ }\r
+ else\r
+ {\r
+ lastyear[0]=0x00;\r
+ lastyear[1]=0x20;\r
+ }\r
+ lastyear[3]=0;\r
+ \r
+ //start oscillator\r
+ spi(RTC_READ,0x01,inbuf,outbuf,1);\r
+ if(!(inbuf[0]&0x80))\r
+ {\r
+ outbuf[0]=inbuf[0]|0x80;\r
+ spi(RTC_WRITE,0x01,inbuf,outbuf,1);\r
+ }\r
+ \r
+ //init timer:\r
+ TACCR0 = 375-1; //3MHz/375/2=4kHz\r
+ TACCTL0= //also, compare, not capture\r
+ OUTMOD_4; //toggle\r
+ TACTL=\r
+ TASSEL_1| //ACLK, 3MHz\r
+ ID_0| //3MHz/1\r
+ //MC_1| //up mode\r
+ TACLR; //reset\r
+ P2SEL|=0x04; //P2.2 timer output.\r
+ P2DIR|=0x04;\r
+ \r
+ // Init interrupts\r
+ P2IE=\r
+ 0x08| //p2.3 - int. from RTC\r
+ 0x02| //p2.1 - int. from button A\r
+ 0x01| //p2.0 - int. from button B\r
+ 0x20; //p2.5 - int. from button C\r
+ P2IES|=0x01|0x02|0x20; //button int. on falling edge\r
+ P2IES&= ~0x08; //RTC int. on rising edge\r
+ P2IFG=0x00;\r
+ \r
+ if(!(P2IN&0x02)) //button A pressed at start?\r
+ {\r
+ mode=MODE_CALIBRATE;\r
+ spi(RTC_READ,0x03,inbuf,outbuf,1);\r
+ settime[1]=inbuf[0]&0x80;\r
+ spi(RTC_READ,0x09,inbuf,outbuf,1);\r
+ settime[0]=inbuf[0];\r
+ digit=3;\r
+ }\r
+ else if(!(P2IN&0x20)) //button C pressed at start?\r
+ {\r
+ mode=MODE_DEBUG;\r
+ settime[1]=0x00;\r
+ changed=0;\r
+ }\r
+ else\r
+ mode=MODE_TIME;\r
+ \r
+ __enable_interrupt();\r
+ \r
+ \r
+ while(1)\r
+ {\r
+ lpm3();\r
+ }\r
+ }\r