Working version.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Sun, 7 Dec 2014 12:54:21 +0000 (12:54 +0000)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Sun, 7 Dec 2014 12:54:21 +0000 (12:54 +0000)
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.

main.c

diff --git a/main.c b/main.c
index b18e3f8a42b25de36e1614bf241dcb323b551534..34c5e8ea6e5911221ed9cf4d78a91c68257fb8e2 100644 (file)
--- 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 <msp430.h>
 #include <legacymsp430.h>
 #include <stdint.h>
 #include <stdlib.h>
 
-//#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;
     }
 }