// 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://wokwi.com/arduino/projects/318868939929027156
#define CLK 13
#define DIN 11
#define CS 10
#define X_SEGMENTS 4 //x 排幾個 "8x8" (列)
#define Y_SEGMENTS 4 //y 排幾個 "8x8" (行)
#define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS) //總數共幾個 "8x8"
// a framebuffer to hold the state of the entire matrix of LEDs
// laid out in raster order, with (0, 0) at the top-left
// 保存整個 LED 矩陣狀態的幀緩衝區
// 按光柵順序排列,(0, 0) 在左上角
// fb[X] : X= 矩陣總點數 / 8
byte fb[8 * NUM_SEGMENTS]; // 1byte = 8bit ,
byte Hr[]={17,1,
/*-- 圖像來源 81SC Hr.bmp --*/
/*-- 寬度x高度18x16 --*/
0xFE,0xFE,0x80,0x80,0x80,0x80,0xFE,0xFE,0x00,0x00,0x60,0xE0,0x80,0x60,0x60,0x60,
0xE0,0xC0,0xFF,0xFF,0x01,0x01,0x01,0x01,0xFF,0xFF,0x00,0x00,0xC0,0xFF,0xC1,0x00,
0x00,0x00,0x01,0x01
};
//MAX7219 DIN傳送方向 --> D0,D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15 -->
//D15,D14,D13,D12 : 未使用
//D11,D10,D09,D08 : address
//D07,D06,D05,D04 : HSB Data
//D03,D02,D01,D00 : LSB Data
void MAX72XX_Int(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 設定 MAX7219
MAX72XX_Int(0x0c, 0x01); //shutdown register - normal operation 關機寄存器-正常操作
MAX72XX_Int(0x09, 0x00); //decode mode register - No decode 解碼模式寄存器 - 無解碼
MAX72XX_Int(0x0a, 0x0f); //intensity register - max brightness 強度寄存器 - 最大亮度
MAX72XX_Int(0x0b, 0x07); //scan limit register - display digits 0 thru 7 掃描限制寄存器 - 顯示數字 0 到 7
MAX72XX_Int(0x0f, 0x00); //display test register - test mode off 顯示測試寄存器 - 測試模式關閉
clear();
}
void loop() {
/*
static int16_t sx1 = 8<<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; //y 平方和
yroot = int(sqrtf(ysumsquares)); //y 平方根
ynextsquare = yroot*yroot; //y 下一個平方根
//---------------------------------------------------------
// Quadrant II (top-left) //第二象限 (左上)
screeny = Y_SEGMENTS * 8; //屏幕點 y
while (y < 0 && screeny) { //y 小於0 以及 screeny>0
x = x_offset;
screenx = X_SEGMENTS * 8; //屏幕點 x
xsumsquares = ysumsquares; //x 平方和
xroot = yroot; // x平方根
if (x < 0) { //如果 x小於0
xnextsquare = xroot * xroot; //x 下一個平方根
while (x < 0 && screenx) { //x 小於0 以及 screenx>0
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--;
}
//----------------------------------------------
*/
byte *dst = Hr;
byte output = 0;
/*for (byte i = 0; i < 32; i++) //1 * NUM_SEGMENTS
{ *dst++ = output;
output++;
}*/
GP_Engine(Hr, 0, 2, 0);
//set_pixel(1, 0, 0xdf);
while(1)
{ show();
delay(10000);}
}
/*
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 set_pixel(uint8_t x, uint8_t y, uint8_t mode) {
byte *addr = &fb[x / 8 + y * X_SEGMENTS];
byte mask = 128 >> (x % 8);
//byte mask = 128 >> 0;
byte i,c,rows;
//column=*mode; ++mode;
//row=*ms; ++ms;
/* for (i=0; i<=row; i++)
{
CSFlag=0;
Disp_Position(x1,y1);
for (j=0; j<=column; j++)
{
if (Inverse!=1) c=*ms; else c=~*ms;
if (x1<61) WriteLeft(1,c);
else{if (CSFlag==0) {Disp_Position(x1,y1);CSFlag=1;} WriteRight(1,c);}
++ms;++x1;
}
y1++;
x1=x;
}*/
c=mode;
rows=0x01; Serial.println(c, BIN);
for(byte i=0;i<8;i++)
{
Serial.println(rows, BIN);
byte *addr = &fb[x / 8 + (y+i) * X_SEGMENTS];
if(c & rows) *addr |= mask;
rows=rows<<1;
}
switch (10) {
case 0: // clear pixel
*addr &= ~mask;
break;
case 1: // plot pixel
*addr |= mask;
byte *addr = &fb[x / 8 + (y+1) * X_SEGMENTS];
*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);
}*/
void GP_Engine(unsigned char *ms, char x, char y, char Inverse)
{
unsigned char CSFlag,i,j,c,row,column,x1,y1;
x1=x;y1=y;
column=*ms; ++ms;
row=*ms; ++ms;
for (i=0; i<=row; i++)
{
CSFlag=0;
for (j=0; j<=column; j++)
{
if (Inverse!=1) c=*ms; else c=~*ms;
if (x1<61) set_pixel(x1, y1, c);
//else{if (CSFlag==0) {CSFlag=1;} set_pixel(x1, y1, c);}
++ms;++x1;
}
y1+=8;
x1=x;
}
}
// turn off every LED in the framebuffer
void clear() {
byte *addr = fb;
for (byte i = 0; i < 8 * NUM_SEGMENTS; i++)
*addr++ = 0;
for (byte row = 0; row < 8; row++) { // 行: (y軸)
digitalWrite(CS, LOW);
byte segment = NUM_SEGMENTS; // NUM_SEGMENTS=16
while (segment--) {
byte x = segment % X_SEGMENTS; // X_SEGMENTS=4 ,x =0
byte y = segment / X_SEGMENTS * 8; // y=32
byte addr = (row + y) * X_SEGMENTS; //addr=0+32 *4 = 128
if (segment & X_SEGMENTS) { // odd rows of segments 奇數行段 15,14,13,12 : 7,6,5,4
shiftOut(DIN, CLK, MSBFIRST, 8 - row); //傳到 MAX72XX的 addres
shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]); //傳到 MAX72XX的 data
} else { // even rows of segments 偶數行段 11,10,9,8 : 3,2,1,0
shiftOut(DIN, CLK, MSBFIRST, 1 + row); //傳到 MAX72XX的 addres
shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]); //傳到 MAX72XX的 data
}
}
digitalWrite(CS, HIGH);
}
}
// send the raster order framebuffer in the correct order
// for the boustrophedon layout of daisy-chained MAX7219s
// 以正確的順序發送光柵順序幀緩衝區
// 對於菊花鏈 MAX7219s 的 boustrophedon 佈局
// boustrophedon : 不斷地由左向右,由右向左返複書寫的方式
void show() {
for (byte row = 0; row < 8; row++) { // 行: (y軸)
digitalWrite(CS, LOW);
byte segment = NUM_SEGMENTS; // NUM_SEGMENTS=16
while (segment--) {
byte x = segment % X_SEGMENTS; // X_SEGMENTS=4 ,x =0
byte y = segment / X_SEGMENTS * 8; // y=32
byte addr = (row + y) * X_SEGMENTS; //addr=0+32 *4 = 128
//digitalWrite(CS, LOW);
if (segment & X_SEGMENTS) { // odd rows of segments 奇數行段 15,14,13,12 : 7,6,5,4
shiftOut(DIN, CLK, MSBFIRST, 8 - row); //傳到 MAX72XX的 addres
shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]); //傳到 MAX72XX的 data
} else { // even rows of segments 偶數行段 11,10,9,8 : 3,2,1,0
shiftOut(DIN, CLK, MSBFIRST, 1 + row); //傳到 MAX72XX的 addres
shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]); //傳到 MAX72XX的 data
}
//digitalWrite(CS, HIGH);
// delay(2000);
}
digitalWrite(CS, HIGH);
}
}