ชื่อโปรเจกต์: Shift Registers - Tutorial 1, Absolute Addressing
ถ้าน้องหลงเข้ามาอ่านบทความนี้แบบงงๆ โดยไม่ได้เริ่มจากจุดเริ่มต้น บอกเลยว่าอาจจะมึนได้ เพราะนี่เป็น 1 ใน 6 บทเรียนที่จะช่วยให้น้องเข้าใจการใช้ Library ez_SIPO8_lib ในการควบคุม IC ประเภท Serial-in/Parallel-out (SIPO) shift registers อย่างเจ้า 74HC595 นั่นเอง
ถ้าอยากเริ่มตั้งแต่ตอนแรก ก็ลองไปหาอ่านใน Tutorial Start ดูนะ แต่ถ้าพร้อมลุยต่อจากตรงนี้ ก็อ่านต่อได้เลยวัยรุ่น...
บทเรียนนี้จะช่วยให้น้องเข้าใจการใช้งาน ez Serial-in/Parallel-out IC Library (
ez_SIPO8_lib) แบบเน้นๆ - บทเรียนที่ 1, การระบุตำแหน่งแบบสมบูรณ์ (Absolute Addressing) ถ้าใครอยากย้อนไปดูจุดเริ่มต้นของโปรเจกต์ก็ตามไปดูที่ Tutorial Start ได้เลย
พวกคู่มือ User Guide, Crib Sheet หรือบทความต้นฉบับของ
ez_SIPO8_libน้องสามารถไปหาโหลดได้ตามลิงก์พวกนี้เลย: -ez_SIPO8_libUser Guide -ez_SIPO8_libCrib Sheet - อ่านบทความez_SIPO8_libฉบับเต็ม
บทนำสู่บทเรียน
ในบทเรียนแรกนี้ เราจะมาลอง Config และขับ IC SIPO แบบ 8-bit ตัวเดียว นั่นคือเบอร์ 74HC595 ซึ่งจะทำให้เรามี Output เพิ่มมา 8 ขา เอาไว้ต่อ LED หล่อๆ ขาละดวงไปเลย
เป้าหมาย
เราจะสร้างสภาพแวดล้อม SIPO จำลองใน Software เพื่อลองใช้หลักการพื้นฐานแบบเริ่มจากจุดเล็กๆ ก่อน สิ่งที่น้องจะได้เรียนรู้คือ:
- วิธีต่อสาย (Wiring) IC 74HC595 (SIPO IC) เข้ากับ Microcontroller แบบไม่ให้แต๊ป
- โครงสร้างของ Arduino Sketch ที่เอาไว้คุม SIPO และ LED เช่น: a. การสร้าง SIPO8 Library Class Instance b. การสร้าง SIPO Bank จาก Array Pool ของ SIPO Output Pins เพื่อให้เราสั่งงานรายขาผ่าน Software ได้ง่ายๆ c. วิธีการระบุตำแหน่งขาออกแบบ Absolute (Absolute Addressing) ในระดับ Array
- ดูผลลัพธ์ของจริง – ไฟ LED วิ่งตามแพทเทิร์น และดูข้อมูล SIPO ผ่าน Serial Monitor
รายการของที่ต้องเตรียม (Check list กันหน่อย)
เตรียมของตามนี้เลยน้อง:
- 1 x Arduino UNO - จริงๆ จะใช้บอร์ดอะไรก็ได้ที่เป็นตระกูล Arduino หรือพวกบอร์ด Clone ขอแค่มี Pin พอสั่งงาน interface SIPO และจ่ายไฟได้พอเป็นอันใช้ได้
- 1 x Breadboard - เล็กหรือใหญ่ตามที่มีติดมือเลย
- 1 x 74HC595 IC - ตัวเอกของเรา IC SIPO 8-bit หรือเบอร์อื่นที่ขาเหมือนกันก็ได้
- 8 x LEDs - มีสีอะไรก็ขุดมาใช้ให้หมด
- 8 x Resistors 220 ohm - ตัวต้านทานเนี่ย ใส่ดักไว้ LED ละตัวนะน้อง (ใช้ 220 ohm นะ ส่วนในรูปวงจรที่บอก 180 ohm น่ะช่างมัน)
- สายจัมพ์ - จะสั้นจะยาว จัดมาให้พร้อม
การดูขา 74HC595 (Orientation and Pin Outs)
ฝั่งไหนหัวฝั่งไหนหาง? สังเกตนะน้อง เจ้า 74HC595 มันจะมีรอยบาก (Notch) อยู่ฝั่งหนึ่ง (ในรูปคือด้านบน) การนับขาจะเริ่มจากขา 1 ที่ซ้ายบน ไล่ลงมาทางซ้ายจนถึงข้างล่าง แล้ววนขึ้นไปทางขวาจนจบที่ขา 16 ฝั่งขวาบน:

การกำหนดขา Interface ระหว่าง Microcontroller กับ SIPO
ทุกๆ Bank ของ IC SIPO ที่น้องต่อกับบอร์ดเนี่ย ต้องใช้ Interface แบบ 3 สาย (3WI) เนื่องจากบทเรียนนี้เราใช้ IC แค่ตัวเดียว ก็เลยต้องใช้แค่ชุดเดียวพอ ตารางข้างล่างนี้คือการจับคู่ขาที่พี่แนะนำ แต่ถ้าอยากเปลี่ยนไปใช้ Digital Pin อื่นก็ได้นะ แต่ต้องไปแก้โค้ดในฟังก์ชัน create_bank ใน setup() ให้ตรงกันด้วยล่ะ
- UNO Pin 8 ไป SIPO Pin 14 - SIPO Data Pin
- UNO Pin 9 ไป SIPO Pin 12 - SIPO Latch Pin
- UNO Pin 10 ไป SIPO Pin 11 - SIPO Clock Pin
- UNO Pin +5v ไป SIPO Pin 10, 16 - จ่ายไฟเลี้ยงให้ IC
- UNO GND ไป SIPO Pin 8, 13 - ต่อกราวด์ (0v)
วิธีการต่อวงจร
จัดไปตามรูปด้านล่างเลยวัยรุ่น เช็คดีๆ อย่าสลับขา Input/Output นะ:

สังเกตนะว่าขา 9 ของ 74HC595 (ขา QH’) จะเป็นขาเดียวที่ว่างอยู่ เพราะมันเอาไว้ส่งข้อมูลต่อไปยังขา 14 (SER) ของ SIPO ตัวถัดไปเวลาเราจะพ่วงกัน (Cascade) เดี๋ยวพี่สอนในบทเรียนหน้าๆ นะ
ตัวอย่าง Code/Sketch
ต่อสายเสร็จแล้ว มาดูโค้ดง่ายๆ เอาไว้เล่นกับ 74HC595 กัน Sketch นี้จะสร้าง SIPO bank ขึ้นมา 1 ชุด โดยจะมีตำแหน่งเสมือน (Virtual Addresses) ตั้งแต่ 0 ถึง 7 หลังจากเราสั่ง create_bank
เปิด Arduino IDE ขึ้นมา สร้างไฟล์ใหม่แล้วจัดโค้ดนี้ลงไป:
//
// Tutorial 1 - การใช้งาน ez_SPI8 library
// การระบุตำแหน่งแบบ Absolute (Absolute addressing)
//
// Ron D Bentley, Stafford, UK
// แปลโดยรุ่นพี่สายช่าง
//
#include <ez_SIPO8_lib.h>
#define max_SIPOs 1 // บทเรียนนี้ใช้ SIPO ตัวเดียวพอ
#define max_timers 0 // ยังไม่ใช้ timer
// เริ่มประกาศ Class สำหรับจำนวน SIPO/Timer ที่ต้องการ
SIPO8 my_SIPOs(max_SIPOs, max_timers);
int my_LEDs; // เอาไว้เก็บ ID ของ SIPO bank
void setup() {
Serial.begin(9600);
// สร้าง Bank ขนาด 1 SIPO ด้วยฟังก์ชัน create_bank:
// (Data Pin, Clock Pin, Latch Pin, จำนวน SIPO ใน Bank นี้)
my_LEDs = my_SIPOs.create_bank(8, 10, 9, 1);
if (my_LEDs == create_bank_failure) {
Serial.println(F("\
สร้าง bank ไม่สำเร็จว่ะน้อง"));
Serial.flush();
exit(0);
}
// พิมพ์ข้อมูล Bank ออกมาดูหน่อยซิ
my_SIPOs.print_SIPO_data();
}
void loop() {
// เริ่มจากสั่งให้ Output ทุกขาเป็น LOW (ดับให้หมด)
my_SIPOs.set_all_array_pins(LOW);
my_SIPOs.xfer_array(LSBFIRST);
do {
//
// สร้าง Pattern 0b01010101 ลงใน Array
my_SIPOs.set_array_pin(0, HIGH);
my_SIPOs.set_array_pin(1, LOW);
my_SIPOs.set_array_pin(2, HIGH);
my_SIPOs.set_array_pin(3, LOW);
my_SIPOs.set_array_pin(4, HIGH);
my_SIPOs.set_array_pin(5, LOW);
my_SIPOs.set_array_pin(6, HIGH);
my_SIPOs.set_array_pin(7, LOW);
my_SIPOs.xfer_array(MSBFIRST); // ส่งค่าจาก Array ไปที่ IC ตัวจริงเพื่อให้ LED ติด
delay(500);
// สลับ Pattern เป็น 0b10101010 ลงใน Array
my_SIPOs.set_array_pin(0, LOW);
my_SIPOs.set_array_pin(1, HIGH);
my_SIPOs.set_array_pin(2, LOW);
my_SIPOs.set_array_pin(3, HIGH);
my_SIPOs.set_array_pin(4, LOW);
my_SIPOs.set_array_pin(5, HIGH);
my_SIPOs.set_array_pin(6, LOW);
my_SIPOs.set_array_pin(7, HIGH);
my_SIPOs.xfer_array(MSBFIRST); // ส่งค่าไปที่ IC อีกรอบ
delay(500);
} while (true);
}
Compile แล้ว Upload เลยน้อง! น้องจะเห็น LED มันกระพริบสลับไปสลับมาแบบ "ม้ากระดก" พร้อม Delay นิดๆ:

Sketch นี้ใช้การระบุตำแหน่งแบบ Absolute โดยใช้ฟังก์ชัน set_array_pin และ xfer_array โดยฟังก์ชันแรกใช้กำหนดว่าขาไหนใน Array จะเป็น HIGH หรือ LOW และฟังก์ชันหลังใช้ส่งข้อมูลทั้งหมดไปอัปเดตที่ตัว IC ของจริง (Physical Bank) หลังจากเราแก้ค่าใน Software เสร็จแล้ว
ตำแหน่งขา (Address) ที่ใช้ใน set_array_pin จะเริ่มที่ 0 เสมอ ขา Output ทุกตัวที่กำหนดไว้สามารถอ้างอิงผ่าน Absolute Address นี้ได้เลย แต่จำไว้นะน้อง ขา Virtual Output พวกนี้จะใช้งานได้ก็ต่อเมื่อมันถูกสั่ง create_bank มาแล้วเท่านั้น (มาเป็นชุด ชุดละ 8 ขา) ประเด็นสำคัญคือ Array Pool ของเราจะสั่งงานไม่ได้เลยถ้ายังไม่ Setup ให้มันเป็น SIPO Bank เสียก่อน
โน้ตไว้หน่อย:
การระบุตำแหน่งแบบ Absolute จะต่างกับการระบุแบบ Relative (สัมพัทธ์) ซึ่งเดี๋ยวพี่จะสอนใน Tutorial 2 ลองสังเกตพารามิเตอร์
MSBFIRSTในฟังก์ชันxferดูนะว่ามันทำให้ผลลัพธ์ออกมาเป็นยังไง ลองเปลี่ยนเป็นLSBFIRSTดูสิ แล้วจะเห็นความต่างว่าไฟมันจะสลับฝั่งกัน!
สุดท้าย ลองเช็ค Serial Monitor ดู มันควรจะขึ้นประมาณนี้:
SIPOglobal values:
pins_per_SIPO = 8
max_SIPOs = 1
bank_SIPO_count= 1
num_active_pins= 8
num_pin_status_bytes= 1
next_freebank = all SIPOs used
Number
Bank
bank
num SIPOs = 1
latch_pin = 9 clock_pin = 10 data_pin = 8
low_pin = 0 high_pin = 7
เห็นไหมว่าฟังก์ชัน print_SIPO_data() มันมีประโยชน์มากตอนเรากำลังไล่ Code หรือ Debug งาน
ลองเล่นดูนะน้อง ลองเขียน Loop มาคุมขา LED แทนการสั่งทีละบรรทัดดู หรือจะสุ่มลำดับการติดดับก็ได้ ลองไปเรื่อยๆ เดี๋ยวก็เก่ง!
จบบทเรียนที่ 1 แล้วนะวัยรุ่น เวอร์ชั่น PDF ไปโหลดเก็บไว้ได้ที่ github เลย
ถ้าพร้อมลุยต่อแล้วก็ตามพี่ไปที่ [Tutorial 2, Relative Addressing] ได้เลย หรือถ้าจะกลับไปอ่านจุดเริ่มต้นก็ไปที่ [Tutorial Start] จัดไป!
รายละเอียดทางเทคนิคเพิ่มเติม (เผื่ออยากเป็นเทพ)
การขยาย Output โดยใช้ Pin น้อยๆ
บทเรียนนี้พาเจาะลึก 74HC595 Shift Register ซึ่งเป็นหัวใจสำคัญเวลาเราอยากคุม Output เยอะๆ (เช่น LED หรือ Relay เป็นสิบๆ ตัว) โดยใช้ขา Arduino แค่ 3 ขา
- Serial-to-Parallel Pipeline: Arduino จะส่งข้อมูลแบบ 8-bit ต่อเนื่องกันผ่านฟังก์ชัน
shiftOut()ตัว IC จะเก็บข้อมูลไว้ข้างในก่อน แล้วพอเราสั่ง "Latch" มันก็จะปล่อยข้อมูลออกขา Output พร้อมกันทีเดียว วิธีนี้จะทำให้ไฟไม่กระพริบมั่วตอนส่งข้อมูล - Absolute Bit-Addressing: คือการใช้ Logic ในการเลือกบิต (เช่น
1 << n) เพื่อสั่งงาน Output ขาเดียว โดยไม่ไปยุ่งกับสถานะของอีก 7 ขาที่เหลือใน IC ตัวเดียวกัน
ความสามารถในการขยายระบบ (Scalability)
- Daisy-Chaining Method: น้องสามารถเอาชิป 74HC595 มาต่อพ่วงกันได้เรื่อยๆ โดยเอาขา "Serial Out" ของตัวแรก ไปเข้า "Serial In" ของตัวถัดไป วิธีนี้จะทำให้น้องคุม Output ได้ 16, 32 หรือแม้แต่ 128 ช่อง โดยใช้ขา Arduino แค่ 3 ขาเท่าเดิม... หล่อเท่เลยงานนี้!