-// SilentTimer Action Figure software, v1.5
+// SilentTimer Action Figure software, v2.1
// main.c
// The main c file.
//
-// 03.05.2020
+// 27.06.2020
// Copyright (C) 2014-2017, 2020 Balthasar Szczepański
//
// This program is free software: you can redistribute it and/or modify
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+ // #define NEW_DISPLAY
// #define OLD_HARDWARE
// #define DEBAG
#include "msp430.h"
unsigned char changed; //changed value during edit
unsigned char run; //switch used in some states
unsigned char cont; //continued calculation
+ unsigned char buzzmode=0; //buzzer, 0-normal, 1-mute, 2-always on.
//for RS232 receiving
volatile unsigned char rxbyte=0;
unsigned char rxdata[RXDATASIZE];
unsigned char rxcmd;
+ volatile unsigned char txbyte;
+ volatile unsigned char txcount=0;
+ volatile unsigned char txindW=0;
+ volatile unsigned char txindR=0;
+ volatile unsigned char txpin=1;
+ volatile unsigned char txbuf[TXBUFSIZE];
+ volatile unsigned char txbuzz=0;
+
volatile unsigned char event=0;
+ unsigned char eventmask=0;
const unsigned char symbol[16] ={
SYMB_0,
void leave(void);
void showvalue(void);
+ void send(unsigned char data);
+ void sendhex(unsigned char data);
+ void sendevent(unsigned char data);
+
void display(
unsigned char *data);
void spi(
unsigned short n);
int main( void );
-
+
+ void send(unsigned char data)
+ {
+ if (data == '\n')
+ send ('\r');
+
+ while (((txindW - txindR) & TXBUFMASK) == TXBUFMASK) {} //wait for free buffer
+
+ //put byte to output buffer
+ txbuf[txindW] = data;
+ ++txindW;
+ txindW &= TXBUFMASK;
+
+ if (!(TACCTL0 & CCIE))
+ {
+ TACCTL0 &= ~CCIFG;
+ TACCTL0 |= CCIE;
+ }
+ }
+
+ void sendhex (unsigned char data)
+ {
+ unsigned char i,j;
+
+ for (i=0; i<2; ++i)
+ {
+ j = i? (data & 0x0f) : (data>>4);
+
+ if (j>9)
+ j += 87;
+ else
+ j += 48;
+
+ send(j);
+ }
+ }
+
+ void sendevent (unsigned char data)
+ {
+ if (data & eventmask)
+ {
+ send('O');
+ sendhex(data);
+ send('\n');
+ }
+ }
+
void display(unsigned char *data)
{
- //lsd
- P1OUT =data[0];
- P3OUT |=0x80; //74hc373 latch enable
- P3OUT &=0x0f;
+ unsigned char i,j;
- P1OUT =data[1];
- P3OUT |=0x40;
- P3OUT &=0x0f;
+ for(i=0,j=0x80; i<4; ++i, j>>=1)
+ // for(i=0,j=0x80; i<2; ++i, j>>=1)
+ {
+ P1OUT = data[i];
+ P3OUT |= j;
+ P3OUT &= ~j;
+ }
+ // //lsd
+ // P1OUT =data[0];
+ // P3OUT |=0x80; //74hc373 latch enable
+ // P3OUT &=0x0f;
+
+ // P1OUT =data[1];
+ // P3OUT |=0x40;
+ // P3OUT &=0x0f;
- P1OUT =data[2];
- P3OUT |=0x20;
- P3OUT &=0x0f;
+ // P1OUT =data[2];
+ // P3OUT |=0x20;
+ // P3OUT &=0x0f;
- //msd
- P1OUT =data[3];
- P3OUT |=0x10;
- P3OUT &=0x0f;
+ // //msd
+ // P1OUT =data[3];
+ // P3OUT |=0x10;
+ // P3OUT &=0x0f;
}
void spi(
#pragma vector=TIMERA0_VECTOR
__interrupt void TA0_ISR()
{
+ // P3OUT |=0x10;
+
rxpin = P2IN & 0x10; //quickly capture state of P2.4
- TACCTL0 &= ~CCIFG;
+ if(txpin)
+ P2OUT |= 0x04;
+ else
+ P2OUT &= ~0x04;
- ++rxcount;
+ TACCTL0 &= ~CCIFG;
- if (!(rxcount & 0x01)) //only every second count
+ if (rxcount) // receive mode
{
- if (rxcount == 2) //start bit
- {
- if (rxpin) //start fail
- {
- rxcount = 0;
- TACCTL0 &= ~CCIE; //abort
- }
- }
- else if (rxcount >= 20) //stop bit
- {
- if (rxpin) //correct stop bit
+ ++rxcount;
+
+ // if (!(rxcount & 0x01)) //only every second count
+ // {
+ if (rxcount == 2) //start bit
{
- if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame
+ if (rxpin) //start fail
{
- if(rxind)
- {
- rxind = 0;
- event |= EVENT_RS; //signal
- }
+ rxcount = 0;
+ txcount = 0;
+ txindR = txindW;
+ P2OUT |= 0x04;
+ TACCTL0 &= ~CCIE; //abort
}
- else
+ }
+ else if (rxcount >= 11) //stop bit
+ {
+ if (rxpin) //correct stop bit
{
- if (rxbyte >= 'g' && rxbyte <= 'z') //new command
+ if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame
{
- rxind=0;
+ if(rxind)
+ {
+ rxind = 0;
+ event |= EVENT_RS; //signal
+ }
}
- if (rxind < RXBUFSIZE) //still place in buffer
+ else
{
- rxbuf[rxind] = rxbyte; //put byte to buffer
- ++rxind;
+ if ((rxbyte >= 'g' && rxbyte <= 'z') || (rxbyte >= 'G' && rxbyte <= 'Z')) //new command
+ {
+ rxind=0;
+ }
+ if (rxind < RXBUFSIZE) //still place in buffer
+ {
+ rxbuf[rxind] = rxbyte; //put byte to buffer
+ ++rxind;
+ }
}
}
+ rxcount = 0;
+ txcount = 0;
+ txindR = txindW;
+ P2OUT |= 0x04;
+ TACCTL0 &= ~CCIE; //stop receiving
}
- rxcount = 0;
- TACCTL0 &= ~CCIE; //stop receiving
- }
- else //receive single bit
+ else //receive single bit
+ {
+ rxbyte >>= 1;
+ rxbyte |= rxpin ? 0x80 : 0x00;
+ }
+ // }
+ if(event)
+ _BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0);
+ }
+
+ else if ((txindR != txindW) || txcount) //transmit mode
+ {
+ if(txcount)
+ --txcount;
+
+ if (!txcount) //reached end of byte
{
- rxbyte >>= 1;
- rxbyte |= rxpin ? 0x80 : 0x00;
+ if (txindR != txindW) //bytes to send available
+ {
+ txbyte=txbuf[txindR];
+ ++txindR; //next byte
+ txindR &= TXBUFMASK;
+ txcount = 10;
+ }
+
+ else if (txbuzz) //buzzer should be done
+ {
+ txbyte = 0x55;
+ txcount = 10;
+ }
}
+
+ // if (!(txcount & 0x01)) //every second count
+ // {
+ if ((txcount == 1) || (txcount == 0)) //stop bit
+ txpin = 1;
+ else if (txcount == 10) //start bit
+ txpin = 0;
+ else if (txcount < 10) //data bits
+ {
+ txpin = txbyte & 0x01;
+ txbyte >>= 1;
+ }
+ else //before start
+ txpin = 1;
+ // }
}
- if(event)
- _BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0);
+
+ else if (txbuzz) //buzzer should be done
+ {
+ txcount = 2; //start buzzer from stop bit
+ }
+
+
+ else //nothing left to do
+ {
+ txpin = 1;
+ TACCTL0 &= ~CCIE;
+ }
+
+ // P3OUT &= ~0x10;
return;
}
}
else if(P2IFG&0x10) // RS232
{
+ // P3OUT |= 0x10;
P2IFG &= ~0x10;
if(!rxcount) //start bit detected
{
- TACTL |= TACLR; //reset timer
+ // TACTL |= TACLR; //reset timer
+ TACTL &= ~MC_3; //stop timer
+ TAR = BAUDHALF; //set timer to half count
+ TACTL |= MC_1; //start timer
TACCTL0 &= ~CCIFG; //clear any waiting timer interrupt
TACCTL0 |= CCIE; //enable timer interrupts
rxcount = 1;
rxbyte = 0;
+
+ txcount = 0; //cancel transmission
+ // txindW = 0;
+ txindR = txindW;
+ txpin = 1;
}
+ // P3OUT &= ~0x10;
}
else
P2IFG=0;
mode=MODE_ALARM;
alarm[0]=0; //alarm removed after activated
spi(RTC_WRITE,0x20,inbuf,alarm,1);
+ sendevent(EVENT_ALARM);
}
else
{
alarm[0]=0;
- spi(RTC_WRITE,0x20,inbuf,outbuf,1);
+ spi(RTC_WRITE,0x20,inbuf,alarm,1);
}
mode=MODE_TIME;
break;
event |= EVENT_RTC;
break;
case MODE_DOWN:
- if(run && (settime[1] | settime[0]))
+ if(run && (settime[1] || settime[0]))
{
if(settime[0])
settime[0]=bcd_add_byte(settime[0],0x99);
settime[0]=0x59;
settime[1]=bcd_add_byte(settime[1],0x99);
}
+ if (!(settime[1] || settime[0]))
+ sendevent(EVENT_0);
}
else
run=0;
break;
case MODE_VER:
dispvalue[4] = SYMB_NUL;
- dispvalue[5] = SYMB_0;
+ dispvalue[5] = SYMB_1;
dispvalue[6] = SYMB_2;
dispvalue[7] = SYMB_NUL;
dot |= 0x02; //.
if(dot & (1<<i))
dispvalue[i] &= SYMB_DOT;
}
- if (dot & 0x80)
- P2SEL ^= 0x04;
- else
- P2SEL &= ~0x04;
+ if (buzzmode & 0x01) //force mute
+ txbuzz = 0;
+ else if (buzzmode & 0x02) //force buzzer
+ txbuzz = 1;
+ else if (dot & 0x80) //beep
+ txbuzz = !txbuzz;
+ else //no action
+ txbuzz = 0;
+ if (txbuzz && !(TACCTL0 & CCIE))
+ {
+ TACCTL0 &= ~CCIFG;
+ TACCTL0 |= CCIE;
+ }
}
int main( void )
{
unsigned char i,j;
+ unsigned char *p;
//watchdog:
WDTCTL = WDTPW + WDTHOLD;
+ //rs232 output
+ P2OUT |= 0x04;
+ P2SEL &= ~0x04;
+ P2DIR |= 0x04;
+
//init 7 segment display
P1OUT =0xff; //display data on p1
}
//init timer:
- TACCR0 = 625-1; //6MHz/625 = 9600Hz (buzz. 4.8kHz)
+ TACCR0 = BAUDCOUNT - 1;
TACCTL0= //also, compare, not capture
// CCIE| //enable interupt
OUTMOD_4; //toggle
MC_1| //up mode
TACLR; //reset
// P2SEL|=0x04; //P2.2 timer output.
- P2OUT &= ~0x04;
- P2SEL &= ~0x04;
- P2DIR |= 0x04;
// Init interrupts
P2IE=
mode=MODE_CALIB;
else if(!(P2IN&0x01)) //button B pressed at start?
{
- calcdata[0] = 0x00;
- calcdata[1] = 0x00;
- calcdata[2] = 0x00;
- calcdata[3] = 0x00;
- calcdata[4] = 0x00;
- calcdata[5] = 0x00;
- calcdata[6] = 0x00;
- calcdata[7] = 0x00;
+ for (i=0; i<8; ++i)
+ calcdata[i] = 0x00;
mode=MODE_CALC;
}
else if(!(P2IN&0x20)) //button C pressed at start?
if (event & EVENT_A)
{
event &= ~ EVENT_A;
+ sendevent(EVENT_A);
if (mode & MODE_EDIT)
{
case MODE_CALC:
if (calcdata[7] || calcdata[1] || calcdata[0]) //if error on non-0
{
- calcdata[0]=0x00;
- calcdata[1]=0x00;
- calcdata[2]=0x00;
- calcdata[3]=0x00;
- calcdata[4]=0x00;
- calcdata[5]=0x00;
- calcdata[6]=0x00;
- calcdata[7]=0x00;
+ for (j=0; j<8; ++j)
+ calcdata[j] = 0x00;
}
else
mode = MODE_TIME;
else if (event & EVENT_B)
{
event &= ~ EVENT_B;
+ sendevent(EVENT_B);
if (mode & MODE_EDIT)
{
case MODE_CALC:
if(calcdata[7])
{
- calcdata[0]=0x00;
- calcdata[1]=0x00;
- calcdata[2]=0x00;
- calcdata[3]=0x00;
- calcdata[4]=0x00;
- calcdata[5]=0x00;
- calcdata[6]=0x00;
- calcdata[7]=0x00;
+ for (j=0; j<8; ++j)
+ calcdata[j] = 0x00;
}
else
{
else if (event & EVENT_C)
{
event &= ~ EVENT_C;
+ sendevent(EVENT_C);
if (mode & MODE_EDIT)
{
case MODE_CALC:
if(calcdata[7])
{
- calcdata[0]=0x00;
- calcdata[1]=0x00;
- calcdata[2]=0x00;
- calcdata[3]=0x00;
- calcdata[4]=0x00;
- calcdata[5]=0x00;
- calcdata[6]=0x00;
- calcdata[7]=0x00;
+ for (j=0; j<8; ++j)
+ calcdata[j] = 0x00;
}
else
{
rxdata[i>>1] = j<<4;
}
- switch (rxcmd)
+ if(rxcmd & 0x20) //lowercase
{
- case 'g': //force display value
- forcedisp[0]=rxdata[0];
- forcedisp[1]=rxdata[1];
- forcedisp[2]=rxdata[2];
- forcedisp[3]=rxdata[3];
- forcedisp[4]=1;
- break;
- case 'h': //free display value
- forcedisp[4]=0;
- break;
- case 'i': //trigger event
- event |= rxdata[0];
- break;
- case 'j': //go to mode
- mode = rxdata[0];
- enter();
- break;
- case 'k': //select digit
- digit = rxdata[0];
- break;
- case 'l': //value under digit
- i = digit >> 1;
- j = settime[i];
- if (digit & 0x01)
- {
- j &= 0x0f;
- j |= rxdata[0]<<4;
- }
- else
+ switch (rxcmd)
{
- j &= 0xf0;
- j |= rxdata[0]&0x0f;
+ case 'g': //force display value
+ for (i=0; i<4; ++i)
+ forcedisp[i]=rxdata[i];
+ forcedisp[4]=1;
+ break;
+ case 'h': //free display value
+ forcedisp[4]=0;
+ break;
+ case 'i': //trigger event
+ event |= rxdata[0];
+ break;
+ case 'j': //go to mode
+ mode = rxdata[0];
+ enter();
+ break;
+ case 'k': //select digit
+ digit = rxdata[0];
+ break;
+ case 'l': //value under digit
+ i = digit >> 1;
+ j = settime[i];
+ if (digit & 0x01)
+ {
+ j &= 0x0f;
+ j |= rxdata[0]<<4;
+ }
+ else
+ {
+ j &= 0xf0;
+ j |= rxdata[0]&0x0f;
+ }
+ settime[i] = j;
+ break;
+ case 'm': //confirm editing
+ changed=1;
+ leave();
+ enter();
+ break;
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v': //enter values
+ changed = 1;
+ settime[0] = rxdata[0];
+ settime[1] = rxdata[1];
+ settime[2] = rxdata[2];
+ switch (rxcmd)
+ {
+ case 'n': //set time
+ mode = MODE_EDIT | MODE_SETTIME;
+ break;
+ case 'o': //set alarm
+ mode = MODE_EDIT | MODE_SETALARM;
+ if(settime[0]==0xff && settime[1]==0xff)
+ {
+ changed=0;
+ alarm[0]=ALARMVALUE;
+ }
+ break;
+ case 'p': //set date
+ mode = MODE_EDIT | MODE_SETDATE;
+ break;
+ case 'q': //set year
+ mode = MODE_EDIT | MODE_SETYEAR;
+ break;
+ case 'r': //set countdown
+ mode = MODE_EDIT | MODE_SETDOWN;
+ run=0;
+ break;
+ case 's': //set calibration
+ mode = MODE_EDIT | MODE_SETCALIB;
+ break;
+ case 't': //set debug address
+ mode = MODE_EDIT | MODE_SETDEBUGADDR;
+ break;
+ case 'u': //set debug value
+ mode = MODE_EDIT | MODE_SETDEBUGVAL;
+ break;
+ case 'v': //perform calculation
+ calcdata[0]=0x00;
+ calcdata[1]=0x00;
+ for (i=0; i<5; ++i)
+ calcdata[i+2]=rxdata[i];
+ // calcdata[3]=rxdata[1];
+ // calcdata[4]=rxdata[2];
+ // calcdata[5]=rxdata[3];
+ // calcdata[6]=rxdata[4];
+ calcdata[7]=0;
+ run = 1;
+ cont = 0xFF;
+ mode = MODE_EDIT | MODE_SETCALCNUM;
+ }
+ leave();
+ break;
+ case 'w': //set value
+ settime[0]=rxdata[0];
+ settime[1]=rxdata[1];
+ settime[2]=rxdata[2];
+ break;
+ case 'x': //set run/pause
+ run = rxdata[0];
+ break;
+ case 'y': //set buzzer mode
+ buzzmode = rxdata[0];
+ break;
+ case 'z': //set memory
+ p = (unsigned char*)(*((unsigned short*)rxdata));
+ *p = rxdata[2];
+ break;
}
- settime[i] = j;
- break;
- case 'm': //confirm editing
- changed=1;
- leave();
- enter();
- break;
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'r':
- case 's':
- case 't':
- case 'u':
- case 'v': //enter values
- changed = 1;
- settime[0] = rxdata[0];
- settime[1] = rxdata[1];
- settime[2] = rxdata[2];
+ }
+ else //uppercase
+ {
+ send(rxcmd);
switch (rxcmd)
{
- case 'n': //set time
- mode = MODE_EDIT | MODE_SETTIME;
+ case 'G': //get time
+ gettime();
+ for (i=0; i<8; ++i)
+ {
+ if (i != 4)
+ sendhex(time[i]); //hs
+ }
+ sendhex(lastyear[4]); //yL
break;
- case 'o': //set alarm
- mode = MODE_EDIT | MODE_SETALARM;
- if(settime[0]==0xff && settime[1]==0xff)
- changed=0;
+ case 'H': //get state
+ sendhex(mode);
break;
- case 'p': //set date
- mode = MODE_EDIT | MODE_SETDATE;
+ case 'I': //get display
+ for (i=0; i<4; ++i)
+ sendhex(dispvalue[i]);
break;
- case 'q': //set year
- mode = MODE_EDIT | MODE_SETYEAR;
+ case 'J': //get value
+ sendhex(settime[0]);
+ sendhex(settime[1]);
+ sendhex(settime[2]);
break;
- case 'r': //set countdown
- mode = MODE_EDIT | MODE_SETDOWN;
- run=0;
+ case 'K': //get calculation
+ for (i=0; i<8; ++i)
+ sendhex(calcdata[i]);
break;
- case 's': //set calibration
- mode = MODE_EDIT | MODE_SETCALIB;
+ case 'L': //get run state
+ sendhex(run);
break;
- case 't': //set debug address
- mode = MODE_EDIT | MODE_SETDEBUGADDR;
+ case 'M': //get version
+ sendhex(1);
+ sendhex(2);
break;
- case 'u': //set debug value
- mode = MODE_EDIT | MODE_SETDEBUGVAL;
+ case 'N': //get pinout
+ sendhex(PIN_AB);
+ sendhex(PIN_CD);
+ sendhex(PIN_EF);
+ sendhex(PIN_GH);
+ break;
+ case 'O': //subscribe for events
+ eventmask = rxdata[0];
+ sendhex(0);
+ break;
+ case 'P': //get alarm
+ if(alarm[0])
+ {
+ sendhex(alarm[1]);
+ sendhex(alarm[2]);
+ }
+ else
+ {
+ sendhex(0xFF);
+ sendhex(0xFF);
+ }
+ break;
+ case 'Q': //get diit
+ sendhex(digit);
+ break;
+ case 'R': //set memory
+ p = (unsigned char*)(*((unsigned short*)rxdata));
+ sendhex(*p);
break;
- case 'v': //perform calculation
- calcdata[0]=0x00;
- calcdata[1]=0x00;
- calcdata[2]=rxdata[0];
- calcdata[3]=rxdata[1];
- calcdata[4]=rxdata[2];
- calcdata[5]=rxdata[3];
- calcdata[6]=rxdata[4];
- calcdata[7]=0;
- run = 1;
- cont = 0xFF;
- mode = MODE_EDIT | MODE_SETCALCNUM;
}
- leave();
- break;
+ send('\n');
}
}
else if (event & EVENT_RTC)
{
event &= ~ EVENT_RTC;
+ sendevent(EVENT_RTC);
gettime();
exec();
}
showvalue();
-
display(forcedisp[4]?forcedisp:dispvalue);
}
else //go to low power mode if nothing's going on