fork download
  1. // This version uses bit-banged SPI.
  2. // If you see tearing (jagged edges on the circles) try the version
  3. // which uses AVR's hardware SPI peripheral:
  4. // https://w...content-available-to-author-only...i.com/arduino/projects/318868939929027156
  5.  
  6. #define CLK 13
  7. #define DIN 11
  8. #define CS 10
  9. #define X_SEGMENTS 4
  10. #define Y_SEGMENTS 4
  11. #define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS)
  12.  
  13. // a framebuffer to hold the state of the entire matrix of LEDs
  14. // laid out in raster order, with (0, 0) at the top-left
  15. byte fb[8 * NUM_SEGMENTS];
  16.  
  17.  
  18. void shiftAll(byte send_to_address, byte send_this_data)
  19. {
  20. digitalWrite(CS, LOW);
  21. for (int i = 0; i < NUM_SEGMENTS; i++) {
  22. shiftOut(DIN, CLK, MSBFIRST, send_to_address);
  23. shiftOut(DIN, CLK, MSBFIRST, send_this_data);
  24. }
  25. digitalWrite(CS, HIGH);
  26. }
  27.  
  28.  
  29. void setup() {
  30. Serial.begin(115200);
  31. pinMode(CLK, OUTPUT);
  32. pinMode(DIN, OUTPUT);
  33. pinMode(CS, OUTPUT);
  34.  
  35. // Setup each MAX7219
  36. shiftAll(0x0f, 0x00); //display test register - test mode off
  37. shiftAll(0x0b, 0x07); //scan limit register - display digits 0 thru 7
  38. shiftAll(0x0c, 0x01); //shutdown register - normal operation
  39. shiftAll(0x0a, 0x0f); //intensity register - max brightness
  40. shiftAll(0x09, 0x00); //decode mode register - No decode
  41. }
  42.  
  43.  
  44. void loop() {
  45. static int16_t sx1 = 15 << 8, sx2 = sx1, sy1, sy2;
  46. sx1 = sx1 - (sy1 >> 6);
  47. sy1 = sy1 + (sx1 >> 6);
  48. sx2 = sx2 - (sy2 >> 5);
  49. sy2 = sy2 + (sx2 >> 5);
  50.  
  51. static byte travel = 0;
  52. travel--;
  53. byte *dst = fb;
  54. byte output = 0;
  55. int8_t x_offset = (sx1 >> 8) - X_SEGMENTS * 4;
  56. int8_t y_offset = (sx2 >> 8) - Y_SEGMENTS * 4;
  57.  
  58. uint8_t screenx, screeny, xroot, yroot;
  59. uint16_t xsumsquares, ysumsquares, xnextsquare, ynextsquare;
  60. int8_t x, y;
  61.  
  62. // offset the origin in screen space
  63. x = x_offset;
  64. y = y_offset;
  65. ysumsquares = x_offset * x_offset + y * y;
  66. yroot = int(sqrtf(ysumsquares));
  67. ynextsquare = yroot*yroot;
  68.  
  69. // Quadrant II (top-left)
  70. screeny = Y_SEGMENTS * 8;
  71. while (y < 0 && screeny) {
  72. x = x_offset;
  73. screenx = X_SEGMENTS * 8;
  74. xsumsquares = ysumsquares;
  75. xroot = yroot;
  76. if (x < 0) {
  77. xnextsquare = xroot * xroot;
  78. while (x < 0 && screenx) {
  79. screenx--;
  80. output <<= 1;
  81. output |= ((xroot + travel) & 8) >> 3;
  82. if (!(screenx & 7))
  83. *dst++ = output;
  84. xsumsquares += 2 * x++ + 1;
  85. if (xsumsquares < xnextsquare)
  86. xnextsquare -= 2 * xroot-- - 1;
  87. }
  88. }
  89. // Quadrant I (top right)
  90. if (screenx) {
  91. xnextsquare = (xroot + 1) * (xroot + 1);
  92. while (screenx) {
  93. screenx--;
  94. output <<= 1;
  95. output |= ((xroot + travel) & 8) >> 3;
  96. if (!(screenx & 7))
  97. *dst++ = output;
  98. xsumsquares += 2 * x++ + 1;
  99. if (xsumsquares >= xnextsquare)
  100. xnextsquare += 2 * ++xroot + 1;
  101. }
  102. }
  103. ysumsquares += 2 * y++ + 1;
  104. if (ysumsquares < ynextsquare)
  105. ynextsquare -= 2 * yroot-- - 1;
  106. screeny--;
  107. }
  108. // Quadrant III (bottom left)
  109. ynextsquare = (yroot + 1) * (yroot + 1);
  110. while (screeny) {
  111. x = x_offset;
  112. screenx = X_SEGMENTS * 8;
  113. xsumsquares = ysumsquares;
  114. xroot = yroot;
  115. if (x < 0) {
  116. xnextsquare = xroot * xroot;
  117. while (x < 0 && screenx) {
  118. screenx--;
  119. output <<= 1;
  120. output |= ((xroot + travel) & 8) >> 3;
  121. if (!(screenx & 7))
  122. *dst++ = output;
  123. xsumsquares += 2 * x++ + 1;
  124. if (xsumsquares < xnextsquare)
  125. xnextsquare -= 2 * xroot-- - 1;
  126. }
  127. }
  128. // Quadrant IV (bottom right)
  129. if (screenx) {
  130. xnextsquare = (xroot + 1) * (xroot + 1);
  131. while (screenx--) {
  132. output <<= 1;
  133. output |= ((xroot + travel) & 8) >> 3;
  134. if (!(screenx & 7))
  135. *dst++ = output;
  136. xsumsquares += 2 * x++ + 1;
  137. if (xsumsquares >= xnextsquare)
  138. xnextsquare += 2 * ++xroot + 1;
  139. }
  140. }
  141. ysumsquares += 2 * y++ + 1;
  142. if (ysumsquares >= ynextsquare)
  143. ynextsquare += 2 * ++yroot + 1;
  144. screeny--;
  145. }
  146.  
  147. show();
  148. }
  149.  
  150.  
  151. void set_pixel(uint8_t x, uint8_t y, uint8_t mode) {
  152. byte *addr = &fb[x / 8 + y * X_SEGMENTS];
  153. byte mask = 128 >> (x % 8);
  154. switch (mode) {
  155. case 0: // clear pixel
  156. *addr &= ~mask;
  157. break;
  158. case 1: // plot pixel
  159. *addr |= mask;
  160. break;
  161. case 2: // XOR pixel
  162. *addr ^= mask;
  163. break;
  164. }
  165. }
  166.  
  167.  
  168. void safe_pixel(uint8_t x, uint8_t y, uint8_t mode) {
  169. if ((x >= X_SEGMENTS * 8) || (y >= Y_SEGMENTS * 8))
  170. return;
  171. set_pixel(x, y, mode);
  172. }
  173.  
  174.  
  175. // turn off every LED in the framebuffer
  176. void clear() {
  177. byte *addr = fb;
  178. for (byte i = 0; i < 8 * NUM_SEGMENTS; i++)
  179. *addr++ = 0;
  180. }
  181.  
  182.  
  183. // send the raster order framebuffer in the correct order
  184. // for the boustrophedon layout of daisy-chained MAX7219s
  185. void show() {
  186. for (byte row = 0; row < 8; row++) {
  187. digitalWrite(CS, LOW);
  188. byte segment = NUM_SEGMENTS;
  189. while (segment--) {
  190. byte x = segment % X_SEGMENTS;
  191. byte y = segment / X_SEGMENTS * 8;
  192. byte addr = (row + y) * X_SEGMENTS;
  193.  
  194. if (segment & X_SEGMENTS) { // odd rows of segments
  195. shiftOut(DIN, CLK, MSBFIRST, 8 - row);
  196. shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]);
  197. } else { // even rows of segments
  198. shiftOut(DIN, CLK, MSBFIRST, 1 + row);
  199. shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]);
  200. }
  201. }
  202. digitalWrite(CS, HIGH);
  203. }
  204. }
Success #stdin #stdout 0.04s 25300KB
stdin
Standard input is empty
stdout
// This version uses bit-banged SPI.
// If you see tearing (jagged edges on the circles) try the version
// which uses AVR's hardware SPI peripheral:
// https://w...content-available-to-author-only...i.com/arduino/projects/318868939929027156

#define CLK 13
#define DIN 11
#define CS  10
#define X_SEGMENTS   4
#define Y_SEGMENTS   4
#define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS)

// a framebuffer to hold the state of the entire matrix of LEDs
// laid out in raster order, with (0, 0) at the top-left
byte fb[8 * NUM_SEGMENTS];


void shiftAll(byte send_to_address, byte send_this_data)
{
  digitalWrite(CS, LOW);
  for (int i = 0; i < NUM_SEGMENTS; i++) {
    shiftOut(DIN, CLK, MSBFIRST, send_to_address);
    shiftOut(DIN, CLK, MSBFIRST, send_this_data);
  }
  digitalWrite(CS, HIGH);
}


void setup() {
  Serial.begin(115200);
  pinMode(CLK, OUTPUT);
  pinMode(DIN, OUTPUT);
  pinMode(CS, OUTPUT);

  // Setup each MAX7219
  shiftAll(0x0f, 0x00); //display test register - test mode off
  shiftAll(0x0b, 0x07); //scan limit register - display digits 0 thru 7
  shiftAll(0x0c, 0x01); //shutdown register - normal operation
  shiftAll(0x0a, 0x0f); //intensity register - max brightness
  shiftAll(0x09, 0x00); //decode mode register - No decode
}


void loop() {
  static int16_t sx1 = 15 << 8, sx2 = sx1, sy1, sy2;
  sx1 = sx1 - (sy1 >> 6);
  sy1 = sy1 + (sx1 >> 6);
  sx2 = sx2 - (sy2 >> 5);
  sy2 = sy2 + (sx2 >> 5);

  static byte travel = 0;
  travel--;
  byte *dst = fb;
  byte output = 0;
  int8_t x_offset = (sx1 >> 8) - X_SEGMENTS * 4;
  int8_t y_offset = (sx2 >> 8) - Y_SEGMENTS * 4;

  uint8_t  screenx, screeny, xroot, yroot;
  uint16_t xsumsquares, ysumsquares, xnextsquare, ynextsquare;
  int8_t   x, y;

  // offset the origin in screen space
  x = x_offset;
  y = y_offset;
  ysumsquares = x_offset * x_offset + y * y;
  yroot = int(sqrtf(ysumsquares));
  ynextsquare = yroot*yroot;

  // Quadrant II (top-left)
  screeny = Y_SEGMENTS * 8;
  while (y < 0 && screeny) {
    x = x_offset;
    screenx = X_SEGMENTS * 8;
    xsumsquares = ysumsquares;
    xroot = yroot;
    if (x < 0) {
      xnextsquare = xroot * xroot;
      while (x < 0 && screenx) {
        screenx--;
        output <<= 1;
        output |= ((xroot + travel) & 8) >> 3;
        if (!(screenx & 7))
          *dst++ = output;
        xsumsquares += 2 * x++ + 1;
        if (xsumsquares < xnextsquare)
          xnextsquare -= 2 * xroot-- - 1;
      }
    }
    // Quadrant I (top right)
    if (screenx) {
      xnextsquare = (xroot + 1) * (xroot + 1);
      while (screenx) {
        screenx--;
        output <<= 1;
        output |= ((xroot + travel) & 8) >> 3;
        if (!(screenx & 7))
          *dst++ = output;
        xsumsquares += 2 * x++ + 1;
        if (xsumsquares >= xnextsquare)
          xnextsquare += 2 * ++xroot + 1;
      }
    }
    ysumsquares += 2 * y++ + 1;
    if (ysumsquares < ynextsquare)
      ynextsquare -= 2 * yroot-- - 1;
    screeny--;
  }
  // Quadrant III (bottom left)
  ynextsquare = (yroot + 1) * (yroot + 1);
  while (screeny) {
    x = x_offset;
    screenx = X_SEGMENTS * 8;
    xsumsquares = ysumsquares;
    xroot = yroot;
    if (x < 0) {
      xnextsquare = xroot * xroot;
      while (x < 0 && screenx) {
        screenx--;
        output <<= 1;
        output |= ((xroot + travel) & 8) >> 3;
        if (!(screenx & 7))
          *dst++ = output;
        xsumsquares += 2 * x++ + 1;
        if (xsumsquares < xnextsquare)
          xnextsquare -= 2 * xroot-- - 1;
      }
    }
    // Quadrant IV (bottom right)
    if (screenx) {
      xnextsquare = (xroot + 1) * (xroot + 1);
      while (screenx--) {
        output <<= 1;
        output |= ((xroot + travel) & 8) >> 3;
        if (!(screenx & 7))
          *dst++ = output;
        xsumsquares += 2 * x++ + 1;
        if (xsumsquares >= xnextsquare)
          xnextsquare += 2 * ++xroot + 1;
      }
    }
    ysumsquares += 2 * y++ + 1;
    if (ysumsquares >= ynextsquare)
      ynextsquare += 2 * ++yroot + 1;
    screeny--;
  }

  show();
}


void set_pixel(uint8_t x, uint8_t y, uint8_t mode) {
  byte *addr = &fb[x / 8 + y * X_SEGMENTS];
  byte mask = 128 >> (x % 8);
  switch (mode) {
    case 0: // clear pixel
      *addr &= ~mask;
      break;
    case 1: // plot pixel
      *addr |= mask;
      break;
    case 2: // XOR pixel
      *addr ^= mask;
      break;
  }
}


void safe_pixel(uint8_t x, uint8_t y, uint8_t mode) {
  if ((x >= X_SEGMENTS * 8) || (y >= Y_SEGMENTS * 8))
    return;
  set_pixel(x, y, mode);
}


// turn off every LED in the framebuffer
void clear() {
  byte *addr = fb;
  for (byte i = 0; i < 8 * NUM_SEGMENTS; i++)
    *addr++ = 0;
}


// send the raster order framebuffer in the correct order
// for the boustrophedon layout of daisy-chained MAX7219s
void show() {
  for (byte row = 0; row < 8; row++) {
    digitalWrite(CS, LOW);
    byte segment = NUM_SEGMENTS;
    while (segment--) {
      byte x = segment % X_SEGMENTS;
      byte y = segment / X_SEGMENTS * 8;
      byte addr = (row + y) * X_SEGMENTS;

      if (segment & X_SEGMENTS) { // odd rows of segments
        shiftOut(DIN, CLK, MSBFIRST, 8 - row);
        shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]);
      } else { // even rows of segments
        shiftOut(DIN, CLK, MSBFIRST, 1 + row);
        shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]);
      }
    }
    digitalWrite(CS, HIGH);
  }
}