Fix day of week calculation, remove leading zeros
authorNick Downing <nick@ndcode.org>
Thu, 24 Mar 2022 15:43:28 +0000 (02:43 +1100)
committerNick Downing <nick@ndcode.org>
Thu, 24 Mar 2022 15:43:28 +0000 (02:43 +1100)
examples/board_clock_7seg/atmega168_clock_7seg.c
examples/board_clock_7seg/clock_7seg.c

index 6348fee..04b0a11 100644 (file)
 #include <util/delay.h>
 #include <avr/sleep.h>
 #include <stdbool.h>
+#include <string.h>
 #include "atmega168_clock_7seg.h"
 
 // for linker, emulator, and programmer's sake
 #include "avr_mcu_section.h"
 AVR_MCU(F_CPU, "atmega168");
 
-#define N_DIGITS 17
-#define USE_17SEG 1
-#if USE_17SEG
-#define BYTES_PER_DIGIT 3
-#else
-#define BYTES_PER_DIGIT 1
-#endif
+#define N_DIGIT 14
+#define N_ALPHA 3
+#define N_BYTES (N_DIGIT + N_ALPHA * 3)
+#define DIGIT_SEG_DP 0b10000000
+#define ALPHA_SEG_DP 0b10000000000000000L
 
 PIN_DEFINE(SRESET, D, PD4, 1);
 //PIN_DEFINE(SOE, D, PD6, 1);    // pwm AIN0/OC0A
@@ -125,11 +124,7 @@ enum EState {
 } ;
 
 uint8_t state = state_ShowTime | state_IncrementTime;
-#if USE_17SEG
-uint32_t digits[N_DIGITS];
-#else
-uint8_t digits[N_DIGITS];
-#endif
+uint8_t data[N_BYTES];
 
 enum EDecimal {
   D_SECOND = 0, D_MINUTE, D_HOUR, D_DAY, D_MONTH, D_YEAR, D_MAX
@@ -213,18 +208,23 @@ uint8_t dayMax(uint8_t month, uint8_t year) {
 }
 
 uint8_t weekDay(uint8_t day, uint8_t month, uint8_t year) {
+  uint8_t y0 = year & 3;
+  year >>= 3;
+  uint8_t y1 = year % 25;
+  year /= 25;
   return (
     day +
       month_weekday[month] +
-      (month >= 2 && isLeap(year)) +
-      (year >> 2) -
-      year / 100
+      (365 % 7) * y0 +
+      ((365 * 4 + 1) % 7) * y1 +
+      (uint8_t)((365L * 100 + 24) % 7) * year +
+      (y1 && (y0 || month >= 2))
   ) % 7;
 }
 
 void decimalInc()
 {
-#if 1 // for testing day/month/year increments
+#if 0 // for testing day/month/year increments
   for (uint8_t in = D_DAY; in < D_MAX; in++)
 #else
   for (uint8_t in = 0; in < D_MAX; in++)
@@ -245,13 +245,13 @@ void decimalInc()
   }
 }
 
-#if USE_17SEG
+#if 0 // not used anymore
 //   A1 A2
 // F H J K B
 //   G1 G2
 // E N M L C
 //   D1 D2   DP
-const uint16_t digit_to_segments[10] = {
+const uint16_t digit_to_data[10] = {
   //NMLKJHGGFEDDCBAA
   //      21  21  21
   0b0000000011111111, // 0
@@ -265,15 +265,13 @@ const uint16_t digit_to_segments[10] = {
   0b0000001111111111, // 8
   0b0000001110001111, // 9
 };
-#define SEG_DP 0b10000000000000000L
-#define SEG_h 0b0000001111001000
 #else
 //   A
 // F   B
 //   G
 // E   C
 //   D   DP
-const uint8_t digit_to_segments[10] = {
+const uint8_t digit_to_data[10] = {
   // GFEDCBA
   0b00111111, // 0
   0b00000110, // 1
@@ -286,8 +284,6 @@ const uint8_t digit_to_segments[10] = {
   0b01111111, // 8
   0b01100111, // 9
 };
-#define SEG_DP 0b10000000
-#define SEG_h 0b01110100
 #endif
 
 //   A1 A2
@@ -296,55 +292,54 @@ const uint8_t digit_to_segments[10] = {
 // E N M L C
 //   D1 D2   DP
 // note: table starts with Saturday for 1/1/2000
-const uint16_t weekday_to_segments[7][3] = {
+const uint8_t weekday_to_data[7][3][3] = {
   //  NMLKJHGGFEDDCBAA
   //        21  21  21
   {
-    0b0000001110111011, // S
-    0b0000001111001111, // A
-    0b0100100000000011, // T
+    {0b00000000, 0b00000011, 0b10111011}, // S
+    {0b00000000, 0b00000011, 0b11001111}, // A
+    {0b00000000, 0b01001000, 0b00000011}, // T
   },
   {
-    0b0000001110111011, // S
-    0b0000000011111100, // U
-    0b0010010011001100, // N
+    {0b00000000, 0b00000011, 0b10111011}, // S
+    {0b00000000, 0b00000000, 0b11111100}, // U
+    {0b00000000, 0b00100100, 0b11001100}, // N
   },
   {
-    0b0001010011001100, // M
-    0b0000000011111111, // O
-    0b0010010011001100, // N
+    {0b00000000, 0b00010100, 0b11001100}, // M
+    {0b00000000, 0b00000000, 0b11111111}, // O
+    {0b00000000, 0b00100100, 0b11001100}, // N
   },
   {
-    0b0100100000000011, // T
-    0b0000000011111100, // U
-    0b0000001111110011, // E
+    {0b00000000, 0b01001000, 0b00000011}, // T
+    {0b00000000, 0b00000000, 0b11111100}, // U
+    {0b00000000, 0b00000011, 0b11110011}, // E
   },
   {
-    0b1010000011001100, // W
-    0b0000001111110011, // E
-    0b0100100000111111, // D
+    {0b00000000, 0b10100000, 0b11001100}, // W
+    {0b00000000, 0b00000011, 0b11110011}, // E
+    {0b00000000, 0b01001000, 0b00111111}, // D
   },
   {
-    0b0100100000000011, // T
-    0b0000001111001100, // H
-    0b0000000011111100, // U
+    {0b00000000, 0b01001000, 0b00000011}, // T
+    {0b00000000, 0b00000011, 0b11001100}, // H
+    {0b00000000, 0b00000000, 0b11111100}, // U
   },
   {
-    0b0000001111000011, // F
-    0b0010001111000111, // R
-    0b0100100000110011, // I
+    {0b00000000, 0b00000011, 0b11000011}, // F
+    {0b00000000, 0b00100011, 0b11000111}, // R
+    {0b00000000, 0b01001000, 0b00110011}, // I
   },
 };
 
 struct {
-  uint8_t b[N_DIGITS * BYTES_PER_DIGIT];
-  uint8_t in;
-  uint8_t out;  
+  uint8_t b[N_BYTES];
+  uint8_t ptr;
 } spi;
 
 void spi_init()
 {
-  spi.in = spi.out = 0;
+  spi.ptr = 0;
     
   SPCR =   (1 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | 
       (0 << CPOL) | (0 << CPHA) | (0 << SPR0);
@@ -354,8 +349,8 @@ void spi_init()
 void spi_start()
 {
   uint8_t b;
-  if (spi.in != spi.out) {
-    b = spi.b[spi.in++];
+  if (spi.ptr != N_BYTES) {
+    b = spi.b[spi.ptr++];
     SPDR = b;
   }    
 }
@@ -376,8 +371,8 @@ void spi_start()
 ISR(SPI_STC_vect)
 {
   uint8_t b;
-  if (spi.in != spi.out) {
-    b = spi.b[spi.in++];
+  if (spi.ptr != N_BYTES) {
+    b = spi.b[spi.ptr++];
     SPDR = b;
   } else {
     // fifo is empty, tell the 74hc595 to latch the shift register
@@ -458,27 +453,15 @@ void updateTimer()
   if (!(state & state_IncrementTime) || timer[delay_Second].delay <= 2) {
     switch (state & ~state_IncrementTime) {
       case state_ShowTime:
-        digits[0] |= SEG_DP; // mapped to colon
+        data[N_ALPHA * 3] |= DIGIT_SEG_DP; // mapped to colon
         break;
     }
   }       
   cli();
   // interupts are stopped here, so there is no race condition
-  //int restart = spi.out == spi.in;
-  spi.in = 0;
-  spi.out = 0;
-  for (uint8_t bi = 0; bi < N_DIGITS; bi++)
-#if USE_17SEG
-  {
-    spi.b[spi.out++] = (uint8_t)(digits[bi] >> 16);
-    spi.b[spi.out++] = (uint8_t)(digits[bi] >> 8);
-    spi.b[spi.out++] = (uint8_t)digits[bi];
-  }
-#else
-    spi.b[spi.out++] = digits[bi];
-#endif
-  //if (restart)
-    spi_start();
+  spi.ptr = 0;
+  memcpy(spi.b, data, N_BYTES);
+  spi_start();
   sei();
 }
 
@@ -486,37 +469,43 @@ void updateTimerDisplay()
 {
   switch (state & ~state_IncrementTime) {
     case state_ShowTime: {
+      uint8_t weekday =
+        weekDay(decimal[D_DAY], decimal[D_MONTH], decimal[D_YEAR]);
+      for (uint8_t i = 0; i < N_ALPHA; ++i)
+        for (uint8_t j = 0; j < 3; ++j)
+          data[i * 3 + j] = weekday_to_data[weekday][N_ALPHA - 1 - i][j];
+
       uint16_t year = decimal[D_YEAR] + 2000;
-      digits[0] = digit_to_segments[year % 10];
+      data[N_ALPHA * 3] = digit_to_data[year % 10];
       year /= 10;
-      digits[1] = digit_to_segments[year % 10];
+      data[N_ALPHA * 3 + 1] = digit_to_data[year % 10];
       year /= 10;
-      digits[2] = digit_to_segments[year % 10];
-      year /= 10;
-      digits[3] = digit_to_segments[year];
+      data[N_ALPHA * 3 + 2] = digit_to_data[year % 10];
+      data[N_ALPHA * 3 + 3] = digit_to_data[year / 10];
+
+      uint8_t month = decimal[D_MONTH] + 1;
+      data[N_ALPHA * 3 + 4] = digit_to_data[month % 10] | DIGIT_SEG_DP;
+      month /= 10;
+      data[N_ALPHA * 3 + 5] = month ? digit_to_data[month / 10] : 0;
 
-      uint8_t temp = decimal[D_MONTH] + 1;
-      digits[4] = digit_to_segments[temp % 10] | SEG_DP;
-      digits[5] = digit_to_segments[temp / 10];
+      uint8_t day = decimal[D_DAY] + 1;
+      data[N_ALPHA * 3 + 6] = digit_to_data[day % 10] | DIGIT_SEG_DP;
+      day /= 10;
+      data[N_ALPHA * 3 + 7] = day ? digit_to_data[day] : 0;
 
-      /*uint8_t*/ temp = decimal[D_DAY] + 1;
-      digits[6] = digit_to_segments[temp % 10] | SEG_DP;
-      digits[7] = digit_to_segments[temp / 10];
+      data[N_ALPHA * 3 + 8] = digit_to_data[decimal[D_SECOND] % 10];
+      data[N_ALPHA * 3 + 9] = digit_to_data[decimal[D_SECOND] / 10];
 
-      temp = weekDay(decimal[D_DAY], decimal[D_MONTH], decimal[D_YEAR]);
-      digits[8] = weekday_to_segments[temp][2];
-      digits[9] = weekday_to_segments[temp][1];
-      digits[10] = weekday_to_segments[temp][0];
+      data[N_ALPHA * 3 + 10] = digit_to_data[decimal[D_MINUTE] % 10];
+      data[N_ALPHA * 3 + 11] = digit_to_data[decimal[D_MINUTE] / 10];
 
-      digits[11] = digit_to_segments[decimal[D_SECOND] % 10];
-      digits[12] = digit_to_segments[decimal[D_SECOND] / 10];
-      digits[13] = digit_to_segments[decimal[D_MINUTE] % 10];
-      digits[14] = digit_to_segments[decimal[D_MINUTE] / 10];
-      digits[15] = digit_to_segments[decimal[D_HOUR] % 10];
-      digits[16] = digit_to_segments[decimal[D_HOUR] / 10];
+      uint8_t hour = decimal[D_HOUR];
+      data[N_ALPHA * 3 + 12] = digit_to_data[hour % 10];
+      hour /= 10;
+      data[N_ALPHA * 3 + 13] = hour ? digit_to_data[hour] : 0;
 
       if (!(state & state_IncrementTime))
-        digits[0] |= SEG_DP; // mapped to colon
+        data[N_ALPHA * 3] |= DIGIT_SEG_DP; // mapped to colon
     }  break;
     //case state_Sleep: {
     //  /* nothing to do */
index 8b2f233..be8b6d5 100644 (file)
@@ -42,7 +42,9 @@
 #include "button.h"
 #include "hc595.h"
 
-#define N_DIGITS 17
+#define N_DIGIT 14
+#define N_ALPHA 3
+#define N_BYTES (N_DIGIT + N_ALPHA * 3)
 #define ORIGIN_X 50.f
 #define ORIGIN_Y 50.f
 #define DIGIT_WIDTH 320.f
 #define WINDOW_X (ORIGIN_X + 5.5f * DIGIT_WIDTH + .5f * COLON_WIDTH)
 #define WINDOW_Y (ORIGIN_Y + 1.5f * LINE_HEIGHT)
 
-#define USE_17SEG 1
-#if USE_17SEG
-#define BYTES_PER_DIGIT 3
-#define SEGMENTS_PER_DIGIT 17
-#define SEG_DP 0x10000
-#else
-#define BYTES_PER_DIGIT 1
-#define SEGMENTS_PER_DIGIT 8
-#define SEG_DP 0x80
-#endif
+#define DIGIT_SEG_DP 0x80
+#define DIGIT_N_SEG 8
+
+#define ALPHA_SEG_DP 0x10000
+#define ALPHA_N_SEG 17
 
 enum {
   B_START = 0, B_STOP, B_RESET,
@@ -73,10 +70,9 @@ button_t button[B_MAX]; // Start/Stop/Reset
 volatile int do_button_press[B_MAX] = {0};
 avr_t * avr = NULL;
 avr_vcd_t vcd_file;
-#define N_SHIFTERS (N_DIGITS * BYTES_PER_DIGIT)
-hc595_t shifters[N_SHIFTERS];
+hc595_t shifters[N_BYTES];
 
-const float digit_pos[N_DIGITS][3] = {
+const float digit_pos[N_DIGIT][3] = {
   // first row
   {ORIGIN_X, ORIGIN_Y + .6f * LINE_HEIGHT, 1.f},
   {ORIGIN_X + DIGIT_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, 1.f},
@@ -85,9 +81,6 @@ const float digit_pos[N_DIGITS][3] = {
   {ORIGIN_X + 4.f * DIGIT_WIDTH + 1.5f * COLON_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, .5f},
   {ORIGIN_X + 4.5f * DIGIT_WIDTH + 1.5f * COLON_WIDTH, ORIGIN_Y + .6f * LINE_HEIGHT, .5f},
   // second row
-  {ORIGIN_X, ORIGIN_Y, .5f},
-  {ORIGIN_X + .5f * DIGIT_WIDTH, ORIGIN_Y, .5f},
-  {ORIGIN_X + 1.f * DIGIT_WIDTH, ORIGIN_Y, .5f},
   {ORIGIN_X + 1.5f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
   {ORIGIN_X + 2.f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
   {ORIGIN_X + 2.5f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
@@ -98,8 +91,15 @@ const float digit_pos[N_DIGITS][3] = {
   {ORIGIN_X + 5.f * DIGIT_WIDTH + .5f * COLON_WIDTH, ORIGIN_Y, .5f},
 };
 
+const float alpha_pos[N_ALPHA][3] = {
+  // second row
+  {ORIGIN_X, ORIGIN_Y, .5f},
+  {ORIGIN_X + .5f * DIGIT_WIDTH, ORIGIN_Y, .5f},
+  {ORIGIN_X + 1.f * DIGIT_WIDTH, ORIGIN_Y, .5f},
+};
+
 int display_flag = 0;
-volatile uint32_t display_bits[N_DIGITS];
+volatile uint8_t display_data[N_BYTES];
 volatile uint8_t display_pwm = 0;
 
 int window;
@@ -113,20 +113,8 @@ int window;
  */
 void hc595_changed_hook(struct avr_irq_t * irq, uint32_t value, void * param)
 {
-#if 0
- printf("shifters:\n");
- for (int i = 0; i < N_SHIFTERS; ++i)
-  printf("%02x: %08x\n", i, shifters[i].value);
- printf("\n");
-#endif
-  for (int i = 0; i < N_DIGITS; ++i)
-    display_bits[i] = shifters[i * BYTES_PER_DIGIT].value;
-#if 0
- printf("digits:\n");
- for (int i = 0; i < N_DIGITS; ++i)
-  printf("%02x: %08x\n", i, display_bits[i]);
- printf("\n");
-#endif
+  for (int i = 0; i < N_BYTES; ++i)
+    display_data[i] = shifters[i].value;
   display_flag++;
 }
 
@@ -159,34 +147,28 @@ void displayCB(void)    /* function called whenever redisplay needed */
     color_on = color_off;
 
   uint32_t bits;
-  for (int di = 0; di < N_DIGITS; di++) {
-    bits = display_bits[di];
+  for (int di = 0; di < N_DIGIT; di++) {
+    bits = display_data[di];
 
     float x = digit_pos[di][0];
     float y = digit_pos[di][1];
     float scale = digit_pos[di][2];
 
-    for (int i = 0; i < SEGMENTS_PER_DIGIT; i++) {
-      bool segment = (bits & (1 << i)) != 0;
-      if (di == N_DIGITS - 1 && i == SEGMENTS_PER_DIGIT - 1)
-        segment = false; // mapped to colon instead (but still shown dark)
-      glColor3f(0.f, segment ? color_on : color_off, 0.f);
+    for (int i = 0; i < DIGIT_N_SEG; i++) {
+      bool bit = (bits & (1 << i)) != 0;
+      if (di == N_DIGIT - 1 && i == DIGIT_N_SEG - 1)
+        bit = false; // mapped to colon instead (but still shown dark)
+      glColor3f(0.f, bit ? color_on : color_off, 0.f);
       glBegin(GL_POLYGON); //GL_LINE_STRIP);
-#if USE_17SEG
-      int end = led_17seg_ptr[i + 1];
-      for (int j = led_17seg_ptr[i]; j < end; ++j)
-        glVertex2f(x + led_17seg[j][0] * scale, y + led_17seg[j][1] * scale);
-#else
       int end = led_8seg_ptr[i + 1];
       for (int j = led_8seg_ptr[i]; j < end; ++j)
         glVertex2f(x + led_8seg[j][0] * scale, y + led_8seg[j][1] * scale);
-#endif
       glEnd();
     }
   }
 
   // colon
-  glColor3f(0.f, bits & SEG_DP ? color_on : color_off, 0.f);
+  glColor3f(0.f, bits & DIGIT_SEG_DP ? color_on : color_off, 0.f);
   for (int i = 0; i < 2; ++i) {
     glBegin(GL_POLYGON); //GL_LINE_STRIP);
     int end = led_colon_ptr[i + 1];
@@ -195,6 +177,27 @@ void displayCB(void)    /* function called whenever redisplay needed */
     glEnd();
   }
 
+  for (int di = 0; di < N_ALPHA; di++) {
+    bits =
+      (uint32_t)display_data[N_DIGIT + di * 3] |
+      ((uint32_t)display_data[N_DIGIT + di * 3 + 1] << 8) +
+      ((uint32_t)display_data[N_DIGIT + di * 3 + 2] << 16);
+
+    float x = alpha_pos[di][0];
+    float y = alpha_pos[di][1];
+    float scale = alpha_pos[di][2];
+
+    for (int i = 0; i < ALPHA_N_SEG; i++) {
+      bool bit = (bits & (1 << i)) != 0;
+      glColor3f(0.f, bit ? color_on : color_off, 0.f);
+      glBegin(GL_POLYGON); //GL_LINE_STRIP);
+      int end = led_17seg_ptr[i + 1];
+      for (int j = led_17seg_ptr[i]; j < end; ++j)
+        glVertex2f(x + led_17seg[j][0] * scale, y + led_17seg[j][1] * scale);
+      glEnd();
+    }
+  }
+
   glutSwapBuffers();
   //glFlush();        /* Complete any pending operations */
 }
@@ -279,7 +282,7 @@ int main(int argc, char *argv[])
   //
   // initialize our 'peripherals'
   //
-  for (int i = 0; i < N_SHIFTERS; ++i)
+  for (int i = 0; i < N_BYTES; ++i)
     hc595_init(avr, shifters + i);
   
   button_init(avr, &button[B_START], "button.start");
@@ -300,7 +303,7 @@ int main(int argc, char *argv[])
       * i_reset = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 4),
       * i_latch = avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 7);
   avr_irq_t * i_data = i_mosi;
-  for (int i = 0; i < N_SHIFTERS; ++i) {
+  for (int i = 0; i < N_BYTES; ++i) {
     avr_connect_irq(i_data, shifters[i].irq + IRQ_HC595_SPI_BYTE_IN);
     avr_connect_irq(i_reset, shifters[i].irq + IRQ_HC595_IN_RESET);
     avr_connect_irq(i_latch, shifters[i].irq + IRQ_HC595_IN_LATCH);