From: Pat Thoyts Date: Sun, 7 Dec 2014 12:54:21 +0000 (+0000) Subject: Working version. X-Git-Url: https://privyetmir.co.uk/gitweb.cgi?a=commitdiff_plain;h=bb38d56b5686f1df53931e3b2d3ef47d87cc059d;p=vetinari_clock Working version. Implemented both randomised ticking with skipped ticks. Can skip 1 or 2 ticks and catches them up on the next tick. Tick offset is up to half a second. Works out quite nicely irregular with the skipped ticks catching the attention quite well. --- diff --git a/main.c b/main.c index b18e3f8..34c5e8e 100644 --- a/main.c +++ b/main.c @@ -1,17 +1,39 @@ +/* vetinari's clock + * + * This is an accurate time-keeping clock which has irregular second + * hand ticks. + * This is achieved by counting seconds properly using an external + * 32.768 kHz crystal and calling an interrupt every 1/512 of a second + * We further separate this into 1/32 second intervals and offset the + * actual movement of the second hand by between 0 and 15 1/32s. + * Also we then occasionally skip 1 or 2 ticks and catch them up later + * my moving the hand the necessary additional number of ticks as part + * of the next tick performed. + */ + #include #include #include #include -//#define LED0 BIT0 /* P1.0 */ #define CLKP BIT6 /* P1.6 */ #define CLKN BIT7 /* P1.7 */ +static unsigned long next = 0; +static void my_srand(unsigned long seed) +{ + next = seed; +} +static unsigned int +my_rand() +{ + next = next * 1103515245 + 12345; + return (unsigned int)next; +} + static void setup(void) { - //P1DIR |= LED0 | CLKP | CLKN; /* set P1.0,P1.1,P1.2 as output */ - //P1OUT |= LED0 | CLKP | CLKN; /* set P1.0,P1.1,P1.2 low */ P1DIR = 0xff; /* set P1.* to output for reduced power consumption */ P1OUT = CLKP | CLKN; @@ -29,17 +51,18 @@ main(void) { /* disable the watchdog */ WDTCTL = WDTPW + WDTHOLD; - + /* external 32.768kHz crystal */ BCSCTL1 |= DIVA_3; /* ACLK/8 */ BCSCTL3 |= XCAP_3; /* enable 12.5pF internal capacitance */ - - srand(0xf00d); + + srand(2); + my_srand(0xdeadbeef); setup(); /* enable global interrupts */ eint(); - + while (1) { /* do nothing forever, timer interrupts drive the leds */ /* enter low power mode 3 with interrupts enabled) */ @@ -47,12 +70,28 @@ main(void) } } -enum State {State_Wait, State_Delay, State_Driving}; +static void +energize_coil() +{ + static int coil_mode = 0; + P1OUT |= (coil_mode ? CLKP : CLKN); + P1OUT &= ~(coil_mode ? CLKN : CLKP); + coil_mode = !coil_mode; +} + +static void +deenergize_coil() +{ + P1OUT &= ~(CLKP | CLKN); +} + +enum State { + State_Wait, State_BeginTick, State_EndTick, + State_SkipTick, State_BeginDouble, State_NextDouble, + State_SkipTwo, State_BeginTriple, State_NextTriple, +}; enum State state = State_Wait; -static uint8_t count = 0; -static int8_t offset = 0; -static uint8_t pin_pos = CLKP; -static uint8_t pin_neg = CLKN; +static uint8_t count = 0, offset = 0; interrupt(TIMER0_A0_VECTOR) TIMERA0_ISR(void) @@ -61,27 +100,62 @@ TIMERA0_ISR(void) TACCTL0 &= ~CCIFG; ++count; - /* if driving the stepper coil, stop after 32ms (1 interrupt) */ - if (state == State_Driving) { - state = State_Wait; - P1OUT &= ~(CLKP | CLKN); - } - if (count == 32) { count = 0; - offset = 1 + (rand() & 0x0f); - state = State_Delay; + int skip = ((my_rand() % 3) == 0) ? 1 : 0; + switch (state) { + case State_SkipTwo: + state = State_BeginTriple; + break; + case State_SkipTick: + state = skip ? State_SkipTwo : State_BeginDouble; + break; + default: + offset = 1 + (my_rand() % 15); + state = skip ? State_SkipTick : State_BeginTick; + break; + } } - if (state == State_Delay) { - --offset; - if (offset == 0) { - state = State_Driving; - P1OUT |= pin_pos; - P1OUT &= ~pin_neg; - /* swap the pins for the next tick */ - uint8_t t = pin_pos; - pin_pos = pin_neg; - pin_neg = t; + /* if driving the stepper coil, stop after 32ms (1 interrupt) */ + switch (state) { + case State_SkipTick: + case State_SkipTwo: { + break; + } + case State_BeginTriple: { + energize_coil(); + state = State_NextTriple; + break; + } + case State_NextTriple: { + deenergize_coil(); + state = State_BeginDouble; + break; + } + case State_BeginDouble: { + energize_coil(); + state = State_NextDouble; + break; + } + case State_NextDouble: { + deenergize_coil(); + state = State_BeginTick; + break; + } + case State_BeginTick: { + --offset; + if (offset == 0) { + energize_coil(); + state = State_EndTick; + } + break; + } + case State_EndTick: { + deenergize_coil(); + state = State_Wait; + break; } + case State_Wait: + break; } }