หน้าแรก ดูโปรเจกต์ทั้งหมด
Easy

โปรเจกต์ LED Cube 4x4x4 พร้อม code ที่ง่ายมากโดยใช้ shift registers

วิธีการสร้าง patterns หลากหลายรูปแบบสำหรับ LED Cube 4x4x4 ด้วยการใช้ shift registers

โปรเจกต์ LED Cube 4x4x4 พร้อม code ที่ง่ายมากโดยใช้ shift registers

วิดีโอสาธิต

Video

▶ กดเพื่อดูวิดีโอสาธิตโปรเจกต์

26,868 การดู
7 ถูกใจ

รายการอุปกรณ์และเครื่องมือ

1x Materia 101
-
1x Pushbutton Switch, Momentary
🛒 สั่งซื้อ
2x Shift Register 75HC595
-

รายละเอียดและวิธีทำ

ตอนที่ผมเริ่มใช้งาน Arduino ผมรู้สึกหลงใหลใน LED Cube มาก แต่การสร้างมันขึ้นมาเองนั้นยากสำหรับผม หลังจากผ่านไปสักพัก ผมก็ได้พบว่ามันสามารถทำได้ง่ายมาก

ในบทความนี้ ผมจะเน้นไปที่ Code ที่เข้าใจง่ายสำหรับ LED Cube 4x4x4 ที่ใช้ shift registers และวิธีการสร้าง patterns ต่างๆ สำหรับลูกบาศก์นี้ ผมไม่ค่อยชอบ Code ที่เคยเห็นในโปรเจกต์ทำนองนี้ ผมเลยต้องสร้างมันขึ้นมาในแบบของตัวเอง

การสร้าง LED Cube

ผมจะไม่อธิบายวิธีการต่อ LED เพื่อสร้างลูกบาศก์ 4x4x4 เพราะมีวิดีโอมากมายบน YouTube ที่สอนวิธีสร้างอยู่แล้ว ตัวอย่างเช่น: https://www.youtube.com/watch?v=hjrfa04KPYI

เมื่อคุณสร้างเสร็จแล้วด้วยความใจเย็นและความอดทน คุณจะได้ลูกบาศก์ที่มี 16 ขา และ 4 แถว เรามาเรียกแถวเหล่านี้ว่า layers วิธีที่ง่ายที่สุดในการต่อขาทั้ง 16 ขานี้เข้ากับ Arduino โดยไม่ให้ใช้ pins จนหมดคือการใช้ shift register 75HC595

Shift register 75HC595

ผมต่อ 8 ขาแรก (1-8) ของลูกบาศก์เข้ากับ shift register ตัวแรก (pins Q0-Q7) และอีก 8 ขาที่เหลือ (9-16) เข้ากับอีกตัวหนึ่ง ตามที่แสดงในตารางจากมุมมองด้านบน:

ขาของลูกบาศก์จากมุมมองด้านบน

ขั้นตอนต่อไปคือการเชื่อมต่อ pins ของ shift registers เข้ากับ Arduino ดังนี้:

  • PIN 8 (ของ shift registers ทั้งสองตัว / GND) ต่อกับ GROUND pin ของ Arduino
  • PIN 9 (Q7´) ของ shift register ตัวแรก ต่อกับ PIN 14 (DATA) ของ shift register ตัวที่สอง
  • PIN 10 (ของ shift registers ทั้งสองตัว / RESET) ต่อกับ PIN 8 ของ Arduino
  • PIN 11 (ของ shift registers ทั้งสองตัว / CLOCK) ต่อกับ PIN 9 ของ Arduino
  • PIN 12 (ของ shift registers ทั้งสองตัว / LATCH) ต่อกับ PIN 10 ของ Arduino
  • PIN 14 (ของ shift register ตัวแรก / DATA) ต่อกับ PIN 11 ของ Arduino
  • PIN 16 (ของ shift registers ทั้งสองตัว / VCC) ต่อกับ 5V pin ของ Arduino

ขั้นตอนสุดท้ายคือการเชื่อมต่อ layers ของลูกบาศก์เข้ากับ Arduino:

  • PIN 4 - Layer 0 (ผ่าน 100ohm resistor)
  • PIN 5 - Layer 1 (ผ่าน 100ohm resistor)
  • PIN 6 - Layer 2 (ผ่าน 100ohm resistor)
  • PIN 7 - Layer 3 (ผ่าน 100ohm resistor)
ด้านล่างของลูกบาศก์ที่ดูวุ่นวายเล็กน้อย

วิธีการควบคุม LED

หัวใจสำคัญของโปรเจกต์นี้คือการทำความเข้าใจว่าเราจะควบคุม LED แต่ละดวงในลูกบาศก์แยกจากกันได้อย่างไร ในหนึ่ง layer จะมี LED 16 ดวง ซึ่งทำให้เราได้ไอเดียในการตั้งค่า 16 bits ของ unsigned int สรุปสั้นๆ คือ LED แต่ละดวงในหนึ่ง layer จะถูกแทนที่ด้วยตัวเลขดังที่แสดงในตารางนี้:

ค่าของ LED เพื่อสั่งให้เปิดใช้งาน

ดังนั้นถ้าเราต้องการเปิด LED ดวงที่สองในแถวที่สองของ layer เราจะตั้งค่า layer = 32 หากต้องการเปิด LED 2 ดวงแรก จะเป็น layer = 1 + 2 = 3 และหากต้องการเปิด LED แถวแรกทั้งหมด จะเป็น layer = 1 + 2 + 4 + 8 = 15

หากเราต้องการให้แสงเคลื่อนที่วนซ้ำ (loop) ผ่าน LED ทุกดวงใน layer ขั้นตอนแรกเราจะตั้งค่า layer = B0000000000000001 = 1 จากนั้นใน loop เราจะทำการ shift bit นี้โดยตั้งค่า layer = layer << 1 หรือเราจะตั้งค่า layer = (1 << count) และเพิ่มค่า "count" ภายใน loop สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าและการ shifting bits ใน C++ สามารถค้นหาได้จาก Google

LOOP หลัก

เมื่อเราทราบวิธีตั้งค่า LED ในหนึ่ง layer แล้ว ต่อไปเราจะควบคุมทั้ง 4 layers เนื่องจากเราสามารถส่งข้อมูลไปยัง shift registers ทั้ง 2 ตัวได้ทีละ 1 layer เท่านั้น เราจึงใช้ main loop ของ Arduino ในการเปิดและปิดแต่ละ layer สลับกันอย่างรวดเร็ว จนดวงตาของเรามองว่าพวกมันเปลี่ยนไปพร้อมๆ กัน Code ในการแสดงผลค่าของ layers นั้นง่ายมาก:

 SetShiftReg(layer[k]);    //ส่งข้อมูล layer ไปยัง shift registers
bitClear(PORTD, 4 + k); //เปิด (ON) layer k
delay(1); //สำคัญมากต่อความสว่างของ LED
PORTD |= B11110000; //ปิด (OFF) layers
k++; if (k > 3) k = 0; //เลือก layer ถัดไปใน loop

ในโปรเจกต์ของผม ผมใช้ปุ่มกด (เชื่อมต่อกับ Ground และ pin 2 ของ Arduino) เพื่อเปลี่ยน patterns ที่ผมสร้างขึ้น การกดปุ่มจะเป็นการตั้งค่า boolean "start" ซึ่งจะไปเริ่มและกำหนดค่าเริ่มต้นให้กับ pattern ถัดไป

จากนั้น loop จะเรียกใช้งาน pattern ที่เลือกไว้ตามระยะเวลาหน่วยมิลลิวินาที (milliseconds) ที่กำหนดไว้ในค่า "speedTime"

Tab เกี่ยวกับ main loop และปุ่มกด:

#define buttonPin 2
unsigned int layer[4] = {0, 0, 0, 0}; //65535 สำหรับเต็ม layer
byte k = 0;
bool start = true;
unsigned long delayTime;
int speedTime = 0;
int count;
void setup() {
InitializeShiftReg();
InitializeMyLedCube();
}
void InitializeMyLedCube() {
DDRD = B11110000; //pins D0-D3 เป็น INPUTS, D4-D7 เป็น OUTPUTS
PORTD |= B11110000; //ปิด layers
pinMode(buttonPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
delayTime = millis();
}
byte patternNum = 28;
byte pattern = patternNum - 1;
void loop() {
if (start) {
detachInterrupt(digitalPinToInterrupt(buttonPin));
delay(500); //รอให้ปล่อยปุ่มกด
pattern++;
if (pattern > patternNum) pattern = 1;
attachInterrupt(digitalPinToInterrupt(buttonPin), PushButton, FALLING);
count = 0;
}
if (((millis() - delayTime) > speedTime) || start) {
switch (pattern) {
case 1: LayersUpDown(); break;
case 2: FallingDot(); break;
case 3: Rain(); break;
case 4: AllCube(); break;
case 5: Cut(); break;
case 6: Cube(); break;
case 7: Diagonal(); break;
case 8: Mixer(); break;
case 9: Random(); break;
case 10: FallingLayer(); break;
case 11: LayerCut(); break;
case 12: Circle(); break;
case 13: RandomWay(); break;
case 14: SmallCube(); break;
case 15: RandomWayCube(); break;
case 16: GrowingCube(); break;
case 17: FallingLayers(); break;
case 18: GrowingLine(); break;
case 19: CircleEdges(); break;
case 20: CircleSide(); break;
case 21: RandomWayLine(); break;
case 22: RandomWaySide(); break;
case 23: DJCube(); break;
case 24: FillingCube(); break;
case 25: NanoBuilding(); break;
case 26: Curve(); break;
case 27: Snake(); break;
case 28: Julka(); break;
default: break;
}
delayTime = millis();
}
//ส่วนนี้ใช้แสดงผล layers ตามที่ตั้งค่าไว้ใน functions
SetShiftReg(layer[k]); //ส่งข้อมูล layer ไปยัง shift registers
bitClear(PORTD, 4 + k); //เปิด layer k
delay(1); //สำคัญมากต่อความสว่างของ LED
PORTD |= B11110000; //ปิด layers
k++; if (k > 3) k = 0; //เลือก layer ถัดไปใน loop
}
void PushButton() {
start = true;
}

Tab "ShiftRegister":

#define latchPin 10   //PORT B2
#define clockPin 9 //PORT B1
#define dataPin 11 //PORT B3
#define resetPin 8 //PORT B0
void InitializeShiftReg() {
DDRB |= B1111; //pins D8-D11 เป็น OUTPUTS
PORTB |= B0001; //ตั้ง resetPin เป็น HIGH
}
void SetShiftReg(unsigned int value) {
bitClear(PORTB, 2); //digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, MSBFIRST, value >> 8);
shiftOut(dataPin, clockPin, MSBFIRST, value);
bitSet(PORTB, 2); //digitalWrite(latchPin, HIGH);
}

การสร้าง patterns

การสร้าง patterns นั้นง่ายมาก และลูกบาศก์นี้ก็กลายเป็นเรื่องสนุกในการคิดค้นท่าทางใหม่ๆ และหาวิธีสร้างมันขึ้นมา อย่างที่คุณเห็น Code ของแต่ละ pattern มักจะเรียบง่ายมาก

เราแค่ต้องเข้าใจว่า main loop ของ Arduino จะเรียกใช้งาน pattern ที่เลือกไว้ตามเวลาที่เรากำหนดไว้ในช่วงเริ่มต้นของ pattern ในตัวแปร "speedTime" หรือพูดอีกอย่างคือ Function ของ pattern จะเปลี่ยนค่า layers เพียงครั้งเดียว แต่ main loop จะทำการแสดงผลซ้ำไปเรื่อยๆ

มาดูตัวอย่าง pattern Rain() กันครับ:

void Rain() {
if (start) {
start = false; speedTime = 200;
ClearLayers();
}
layer[0] = layer[1];
layer[1] = layer[2];
layer[2] = layer[3];
layer[3] = 1 << random(16);
}

ส่วนของ "start" จะทำงานเพียงครั้งเดียวเมื่อเราเริ่มเปิด pattern นั้น มันจะตั้งค่า speedTime และปิด LED ทุกดวง จากนั้นเราจะสุ่มเปิด LED 1 ดวงจาก 16 ดวงใน layer บนสุด และภายใน loop เราจะเคลื่อนย้ายมันลงไปยัง layers ด้านล่าง

ด้านล่างนี้คุณสามารถดู Code สำหรับ patterns ต่างๆ ที่ผมสร้างขึ้น และมีตัวอย่างบางส่วนในวิดีโอ ขอให้สนุกนะครับ!

Tab "Patterns":

bool direct;
unsigned int actualValue;
byte lay, xVal, yVal;
byte place;
void SetLayers(unsigned int value) { //function ช่วยในการตั้งค่า
layer[0] = value; layer[1] = value; layer[2] = value; layer[3] = value;
}
void InversLayers() { //function ช่วยในการกลับค่า
layer[0] = 65535 - layer[0];
layer[1] = 65535 - layer[1];
layer[2] = 65535 - layer[2];
layer[3] = 65535 - layer[3];
}
void ClearLayers() { //function ช่วยในการล้างค่า
SetLayers(0);
}
void LayersUpDown() {
if (start) {
start = false; speedTime = 500;
direct = true;
}
ClearLayers();
layer[count] = 65535;
if (direct) {
count++;
if (count > 3) {
direct = false;
count = 2;
}
} else {
count--; if (count < 1) direct = true;
}
}
void FallingDot() {
if (start) {
start = false; speedTime = 100;
count = 4;
actualValue = 1;
direct = true;
}
count--;
ClearLayers();
layer[count] = actualValue;
if (count == 0) {
count = 4;
actualValue = actualValue << 1;
if (actualValue == 0) actualValue = 1;
}
}
void Rain() {
if (start) {
start = false; speedTime = 200;
ClearLayers();
}
layer[0] = layer[1];
layer[1] = layer[2];
layer[2] = layer[3];
layer[3] = 1 << random(16);
}
void Random() {
if (start) {
start = false; speedTime = 200;
}
layer[0] = random(65536);
layer[1] = random(65536);
layer[2] = random(65536);
layer[3] = random(65536);
}
void AllCube() {
if (start) {
start = false; speedTime = 2000;
}
ClearLayers();
switch (count) {
case 0:
SetLayers(65535);
break;
case 1:
layer[1] = 1632;
layer[2] = 1632;
break;
}
count++; if (count > 1) count = 0;
}
void Cut() {
if (start) {
start = false; speedTime = 2000;
layer[0] = 4369;
layer[1] = 13107;
layer[2] = 30583;
layer[3] = 65535;
}
InversLayers();
}
void Cube() {
if (start) {
start = false; speedTime = 2000;
layer[0] = 15+16+128+256+2048+4096+8192+16384+32768;
layer[1] = 1+8+4096+32768;
layer[2] = layer[1];
layer[3] = layer[0];
}
InversLayers();
}
void Diagonal() {
if (start) {
start = false; speedTime = 2000;
layer[0] = 33825;
layer[1] = 33825;
layer[2] = 33825;
layer[3] = 33825;
}
InversLayers();
}
void Mixer() {
if (start) {
start = false; speedTime = 100;
}
switch (count) {
case 0: actualValue = 33825; break;
case 1: actualValue = 17442; break;
case 2: actualValue = 8772; break;
case 3: actualValue = 4680; break;
case 4: actualValue = 960; break;
case 5: actualValue = 3120; break;
}
SetLayers(actualValue);
count++;
if (count > 5) count = 0;
}
void FallingLayer() {
if (start) {
start = false; speedTime = 100;
actualValue = 0;
direct = false;
}
if (actualValue == 0) {
actualValue = 1;
ClearLayers();
direct = !direct;
layer[3 - (direct? 0:3)] = 65535;
}
switch (count) {
case 0:
layer[3 - (direct? 0:3)] -= actualValue;
layer[2 - (direct? 0:1)] = actualValue;
break;
case 1:
layer[1 + (direct? 0:1)] = layer[2 - (direct? 0:1)];
layer[2 - (direct? 0:1)] = 0;
break;
case 2:
layer[0 + (direct? 0:3)] += layer[1 + (direct? 0:1)];
layer[1 + (direct? 0:1)] = 0;
actualValue = actualValue << 1;
break;
}
count++; if (count > 2) count = 0;
}
void LayerCut() {
if (start) {
start = false; speedTime = 100;
}
if (count) layer[0] = layer[0] << 1;
else layer[0] = 4369;
SetLayers(layer[0]);
count++;
if (count > 20) count = 0;
}
void Circle() {
if (start) {
start = false; speedTime = 100;
lay = 3;
}
switch (count) {
case 0: ClearLayers(); layer[lay] = 1; break;
case 1: layer[lay] = 2; break;
case 2: layer[lay] = 4; break;
case 3: layer[lay] = 8; break;
case 4: layer[lay] = 128; break;
case 5: layer[lay] = 2048; break;
case 6: layer[lay] = 32768; break;
case 7: layer[lay] = 16384; break;
case 8: layer[lay] = 8192; break;
case 9: layer[lay] = 4096; break;
case 10: layer[lay] = 256; break;
case 11: layer[lay] = 16; break;
case 12: layer[lay] = 1; break;
}
count++;
if (count > 12) {
count = 0;
if (lay == 0) lay = 3;
else lay--;
}
}
void RandomWay() {
if (start) {
start = false; speedTime = 200;
lay = random(4);
xVal = random(4);
yVal = random(4);
}
switch (random(7)) {
case 0: if ((lay + 1) <= 3) lay++; break;
case 1: if ((lay - 1) >= 0) lay--; break;
case 2: if ((xVal + 1) <= 3) xVal++; break;
case 3: if ((xVal - 1) >= 0) xVal--; break;
case 4: if ((yVal + 1) <= 3) yVal++; break;
case 5: if ((yVal - 1) >= 0) yVal--; break;
default: break;
}
ClearLayers();
layer[lay] = (1 << xVal) << (4 * yVal);
}
void SmallCube() {
if (start) {
start = false; speedTime = 200;
}
switch (count) {
case 0: lay = random(3); ClearLayers(); actualValue = 51; break;
case 1: actualValue = actualValue << 1; break;
case 2: actualValue = actualValue << 1; break;
case 3: actualValue = actualValue << 4; break;
case 4: actualValue = actualValue << 4; break;
case 5: actualValue = actualValue >> 1; break;
case 6: actualValue = actualValue >> 1; break;
case 7: actualValue = actualValue >> 4; break;
case 8: actualValue = actualValue >> 4; break;
}
layer[lay] = actualValue;
layer[lay+1] = actualValue;
count++; if (count > 8) count = 0;
}
void RandomWayCube() {
if (start) {
start = false; speedTime = 200;
lay = random(3);
xVal = random(3);
yVal = random(3);
}
switch (random(7)) {
case 0: if ((lay + 1) < 3) lay++; break;
case 1: if ((lay - 1) >= 0) lay--; break;
case 2: if ((xVal + 1) < 3) xVal++; break;
case 3: if ((xVal - 1) >= 0) xVal--; break;
case 4: if ((yVal + 1) < 3) yVal++; break;
case 5: if ((yVal - 1) >= 0) yVal--; break;
default: break;
}
ClearLayers();
layer[lay] = (51 << xVal) << (4 * yVal);
layer[lay+1] = layer[lay];
}
void GrowingCube() {
if (start) {
start = false; speedTime = 1000;
}
switch (count) {
case 0: ClearLayers(); layer[0] = 1; break;
case 1: layer[0] = 51; layer[1] = 51; break;
case 2: layer[0] = 1911; layer[1] = 1911; layer[2] = 1911; break;
case 3: SetLayers(65535); break;
default: break;
}
count++; if (count > 4) count = 0;
}
void FallingLayers() {
if (start) {
start = false; speedTime = 200;
actualValue = 0;
lay = 4;
}
if (actualValue == 0) {
lay--; if (lay < 1) lay = 3;
actualValue = 1;
ClearLayers();
layer[lay] = 65535;
}
layer[lay] -= actualValue;
layer[lay-1] += actualValue;
actualValue = actualValue << 1;
}
void GrowingLine() {
if (start) {
start = false; speedTime = 100;
}
switch (count) {
case 0:
ClearLayers();
layer[0] = 1;
lay = 0; xVal = 0; yVal = 0;
while ((lay == 0) && (xVal == 0) && (yVal == 0)) {
lay = random(2);
xVal = random(2);
yVal = random(2);
}
break;
case 1: layer[lay] += ((xVal==0)?1:2) << (4 * yVal); break;
case 2: layer[2 * lay] += ((xVal==0)?1:4) << (8 * yVal); break;
case 3: layer[3 * lay] += ((xVal==0)?1:8) << (12 * yVal); break;
case 4: layer[3 * lay] -= ((xVal==0)?1:8) << (12 * yVal); break;
case 5: layer[2 * lay] -= ((xVal==0)?1:4) << (8 * yVal); break;
default: break;
}
count++; if (count > 5) count = 0;
}
void CircleEdges() {
if (start) {
start = false; speedTime = 100;
lay = 3;
ClearLayers();
}
switch (count) {
case 0: layer[lay] = 1; break;
case 1: layer[lay] += 2; break;
case 2: layer[lay] += 4; break;
case 3: layer[lay] += 8; break;
case 4: layer[lay] += 128; break;
case 5: layer[lay] += 2048; break;
case 6: layer[lay] += 32768; break;
case 7: layer[lay] += 16384; break;
case 8: layer[lay] += 8192; break;
case 9: layer[lay] += 4096; break;
case 10: layer[lay]+= 256; break;
case 11: layer[lay] += 16; break;
default: break;
}
count++;
if (count > 12) {
count = 0;
if (lay == 0) {
lay = 3;
ClearLayers();
}
else lay--;
}
}
void CircleSide() {
if (start) {
start = false; speedTime = 1000;
}
switch (count) {
case 0: SetLayers(15); break;
case 1: SetLayers(34952); break;
case 2: SetLayers(61440); break;
case 3: SetLayers(4369); break;
case 4: ClearLayers(); layer[0] = 65535; break;
case 5: SetLayers(34952); break;
case 6: ClearLayers(); layer[3] = 65535; break;
case 7: SetLayers(4369); break;
}
count++;
if (count > 7) count = 0;
}
void RandomWayLine() {
if (start) {
start = false; speedTime = 200;
lay = random(3);
yVal = random(3);
}
switch (random(5)) {
case 0: if ((lay + 1) <= 3) lay++; break;
case 1: if ((lay - 1) >= 0) lay--; break;
case 2: if ((yVal + 1) <= 3) yVal++; break;
case 3: if ((yVal - 1) >= 0) yVal--; break;
default: break;
}
ClearLayers();
layer[lay] = 15 << (4 * yVal);
}
void RandomWaySide() {
if (start) {
start = false; speedTime = 200;
xVal = random(3);
}
switch (random(3)) {
case 0: if ((xVal + 1) <= 3) xVal++; break;
case 1: if ((xVal - 1) >= 0) xVal--; break;
default: break;
}
ClearLayers();
actualValue = 4369 << xVal;
switch (random(2)) {
case 0: SetLayers(actualValue); break;
case 1: layer[1] = actualValue; layer[2] = actualValue; break;
}
}
void DJCube() {
if (start) {
start = false; speedTime = 200;
xVal = random(3);
}
switch (random(3)) {
case 0: if ((xVal + 1) <= 3) xVal++; break;
case 1: if ((xVal - 1) >= 0) xVal--; break;
default: break;
}
switch (xVal) {
case 0: SetLayers(4369); break;
case 1: SetLayers(13107); break;
case 2: SetLayers(30583); break;
case 3: SetLayers(65535); break;
}
}
void FillingCube() {
if (start) {
start = false; speedTime = 200;
count = 4;
actualValue = 1;
}
if ((count == 4) && (actualValue == 1)) ClearLayers();
count--;
layer[count] += actualValue;
if (count == 0) {
count = 4;
actualValue = actualValue << 1;
if (actualValue == 0) actualValue = 1;
}
}
void NanoBuilding() {
if (start) {
start = false; speedTime = 150;
actualValue = 0;
place = 1;
direct = true;
}
if (direct) {
direct = false;
while ((actualValue < place) && (place < 64)) {
lay = random(4);
xVal = random(4);
yVal = random(4);
actualValue = xVal + (yVal * 4) + (lay * 16);
}
}
actualValue = 0;
int xValP = xVal;
int yValP = yVal;
int layP = lay;
while ((actualValue < place) && (place < 64)) {
xVal = xValP;
yVal = yValP;
lay = layP;
switch (random(7)) {
case 0: if ((lay + 1) <= 3) lay++; break;
case 1: if ((lay - 1) >= 0) lay--; break;
case 2: if ((xVal + 1) <= 3) xVal++; break;
case 3: if ((xVal - 1) >= 0) xVal--; break;
case 4: if ((yVal + 1) <= 3) yVal++; break;
case 5: if ((yVal - 1) >= 0) yVal--; break;
default: break;
}
actualValue = xVal + (yVal * 4) + (lay * 16);
}
if (actualValue == place) {
place++;
direct = true;
}
ClearLayers();
if (place < 16) layer[0] = (1 << place) - 1;
else {
if (place < 32) {
layer[1] = (1 << (place - 16)) - 1;
layer[0] = 65535;
} else {
if (place < 48) {
layer[2] = (1 << (place - 32)) - 1;
layer[0] = 65535;
layer[1] = 65535;
} else {
if (place < 64) {
SetLayers(65535);
layer[3] = (1 << (place - 48)) - 1;
} else place = 1;
}
}
}
layer[lay] |= ((1 << xVal) << (4 * yVal));
}
void Curve() {
int line[4] = {4369, 8738, 17476, 34952};
byte pos[12] = {0, 1, 2, 3, 3, 2, 1, 0, 0, 1, 2, 3};
if (start) {
start = false; speedTime = 100;
}
layer[0] = ((pos[count] == 0) ? line[0]: 0) + ((pos[count+1] == 0) ? line[1]: 0) + ((pos[count+2] == 0) ? line[2]: 0) + ((pos[count+3] == 0) ? line[3]: 0);
layer[1] = ((pos[count] == 1) ? line[0]: 0) + ((pos[count+1] == 1) ? line[1]: 0) + ((pos[count+2] == 1) ? line[2]: 0) + ((pos[count+3] == 1) ? line[3]: 0);
layer[2] = ((pos[count] == 2) ? line[0]: 0) + ((pos[count+1] == 2) ? line[1]: 0) + ((pos[count+2] == 2) ? line[2]: 0) + ((pos[count+3] == 2) ? line[3]: 0);
layer[3] = ((pos[count] == 3) ? line[0]: 0) + ((pos[count+1] == 3) ? line[1]: 0) + ((pos[count+2] == 3) ? line[2]: 0) + ((pos[count+3] == 3) ? line[3]: 0);
count++; if (count > 7) count = 0;
}
struct snake {
byte x, y, z;
} obj[7];
void Snake() {
int k;
byte c = 7;
if (start) {
start = false; speedTime = 200;
for (k = 0; k < c; k++) {
obj[k].x = 0;
obj[k].y = 0;
obj[k].z = 0;
}
lay = 0;
xVal = 0;
yVal = 0;
}
int xValP = xVal;
int yValP = yVal;
int layP = lay;
direct = true;
while (direct) {
xVal = xValP;
yVal = yValP;
lay = layP;
switch (random(6)) {
case 0: if ((lay + 1) <= 3) lay++; break;
case 1: if ((lay - 1) >= 0) lay--; break;
case 2: if ((xVal + 1) <= 3) xVal++; break;
case 3: if ((xVal - 1) >= 0) xVal--; break;
case 4: if ((yVal + 1) <= 3) yVal++; break;
case 5: if ((yVal - 1) >= 0) yVal--; break;
default: break;
}
direct = false;
for (k = 0; k < c; k++) {
if ((xVal == obj[k].x) && (yVal == obj[k].y) && (lay == obj[k].z)) direct = true;
}
}
for (k = c-2; k >= 0; k--) {
obj[k+1].x = obj[k].x;
obj[k+1].y = obj[k].y;
obj[k+1].z = obj[k].z;
}
obj[0].x = xVal;
obj[0].y = yVal;
obj[0].z = lay;
ClearLayers();
for (k = 0; k < c; k++) {
layer[obj[k].z] += (1 << obj[k].x) << (4 * obj[k].y);
}
}
void Julka() {
int letters[5] = {59556, 43694, 8750, 58446, 60138};
if (start) {
start = false; speedTime = 1000;
ClearLayers();
}
layer[3] = letters[count];
count++;
if (count == 5) count = 0;
}
ตัวอย่างของ patterns ต่างๆ

Code

🔒 ปลดล็อก Code

สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้

รหัสอ้างอิงโปรเจกต์: led-cube-4x4x4-very-easy-code-with-shift-registers-044b6f
2450 บาท
PromptPay QR Code