กลับไปหน้ารวมไฟล์
shift-registers-tutorial-3-using-timers-e4d02a.md

ถ้าน้องบังเอิญหลงมาอ่านบทความนี้โดยไม่ได้เริ่มจากจุดเริ่มต้นของซีรี่ส์ มันอาจจะดูงงๆ หน่อยนะ เพราะบทความนี้เป็นหนึ่งในหกบทเรียนที่ช่วยให้เข้าใจการใช้ไลบรารี ez_SIPO8_lib ในการจัดการและควบคุม IC แบบ Serial-in/Parallel-out (SIPO) หรือที่เรียกกันว่า shift registers อย่างเช่นชิป 74HC595 นั่นเอง

ถ้าอยากเริ่มอ่านตั้งแต่ต้นซีรี่ส์ ก็กดไปที่ลิงก์นี้เลย (จุดเริ่มต้นบทเรียน) ไม่งั้นก็อ่านต่อเลยละกัน...

บทเรียนนี้เป็นบทที่ 3 จากซีรี่ส์สอนการใช้ไลบรารี ez Serial-in/Parallel-out IC (ez_SIPO8_lib) โดยจะเน้นเรื่องการใช้ Timers ถ้าอยากกลับไปอ่านบทเริ่มต้นก็กดที่ลิงก์นี้: จุดเริ่มต้นบทเรียน.
น้องสามารถดาวน์โหลดคู่มือผู้ใช้ (User Guide), เอกสารสรุป (Crib Sheet) และอ่านบทความต้นฉบับของ ez_SIPO8_lib ได้จากลิงก์ด้านล่างนี้:
- ez_SIPO8_lib คู่มือผู้ใช้
- ez_SIPO8_lib เอกสารสรุป
- อ่านบทความเต็มของ ez_SIPO8_lib ได้ที่นี่

มุมมองของโปรเจกต์

Shift Registers - บทที่ 3, การใช้ Timers เป็นการเจาะลึกเทคโนโลยีดิจิทัลและการทำงานแบบอะซิงโครนัสอย่างลงตัว โดยเน้นไปที่โครงสร้างพื้นฐานสำคัญ—นั่นคือ สถาปัตยกรรมการเก็บข้อมูลแบบอนุกรมสู่ขนานของ 74HC595 และ ซอฟต์แวร์ไทเมอร์แบบไม่บล็อกหลายช่อง—น้องจะได้เรียนรู้วิธีสื่อสารและประสานงานงานลอจิกต่างๆ โดยใช้ไลบรารีเฉพาะทางและการตั้งค่าด้วยมือที่มั่นคง

แนะนำบทเรียน

ในบทเรียนที่ 3 นี้ เราจะต่อยอดจากประสบการณ์ในบทที่ 1 และ 2 โดยมาดูกันว่าเราจะใช้ฟีเจอร์ไทเมอร์ของไลบรารี SIPO8 ควบคุมสถานะของพินเอาต์พุตบน IC SIPO ได้ยังไง เราจะใช้วงจร IC SIPO ตัวเดิมที่ตั้งไว้ในบทเรียนที่ 1 นะ

บทเรียนนี้จะตั้งค่าไทเมอร์ SIPO8 จำนวนแปดตัว โดยแต่ละตัวจะควบคุมพินเอาต์พุตของ SIPO หนึ่งพิน ใช้ควบคุมอัตราการกะพริบของ LED ที่ต่ออยู่ให้เปิด/ปิดตามที่เราต้องการ วิธีนี้มีความยืดหยุ่นสูง ทำให้เราปรับอัตรากะพริบและลำดับของพินเอาต์พุตได้ง่ายๆ จัดไปวัยรุ่น!

เป้าหมาย

เราจะมาสร้างสภาพแวดล้อม SIPO เสมือนกัน เพื่อประยุกต์หลักการพื้นฐานเพิ่มเติม โดยเฉพาะเราจะเรียนรู้:

1. วิธีการต่อสายและเชื่อมต่อ IC 74HC595 ตัวเดียว (SIPO) เข้ากับไมโครคอนโทรลเลอร์ (ดู Tutorial 1 ถ้ายังไม่ได้ทำ)

2. วิธีการใช้ฟังก์ชันตัวจับเวลา (timer) ในไลบรารี SIPO8 เพื่อควบคุมและขับเอาต์พุต SIPO จริงๆ

3. การใช้งานฟังก์ชันของไลบรารี SIPO8 เพิ่มเติม

4. มองเห็นผลลัพธ์จากสเก็ตช์ – LED ที่กะพริบแบบแปรผันและข้อมูล SIPO บน Serial Monitor

ถ้าน้องทำ Tutorial 1 และ 2 มาจนจบ และยังตั้งชิ้นส่วนไว้เหมือนเดิม ก็ข้ามไปที่ส่วน The Code/Sketch ได้เลย ไม่ก็ทำตามขั้นตอนด้านล่างนี้ต่อ

การลงมือทำจริง: ตรรกะแบบอะซิงโครนัสและตัวจับเวลาพื้นหลัง

โปรเจคนี้จะเผยให้เห็นเลเยอร์ที่ซ่อนอยู่ของปฏิสัมพันธ์ระหว่างข้อมูลกับเวลา:

  • เลเยอร์ระบุตัวตน: รีจิสเตอร์ 74HC595 ทำหน้าที่เป็นหน่วยความจำดิจิทัลความละเอียดสูง คอยวัดการมาถึงของแต่ละบิตสตรีมผ่านอินพุตแบบอนุกรม
  • เลเยอร์แปลงสัญญาณ: ระบบใช้พินดิจิทัลความเร็วสูง (Data, Clock, Latch) เพื่อรับพัลส์ไบนารีความเร็วสูง สำหรับประสานงานงานเซนซิ่งที่สำคัญ
  • เลเยอร์อินเทอร์เฟซด้านเวลา: ตัวจับเวลาของไลบรารี ez_SIPO8 ให้ฟีดแบ็คภาพและเวลาความละเอียดสูงสำหรับการตรวจสอบสถานะของแต่ละงาน (เช่น การสลับ LED เทียบกับรอบลูป)
  • เลเยอร์อินเทอร์เฟซการสื่อสาร: Serial Terminal ความเร็วสูง ให้อินเทอร์เฟซภาพที่ชัดเจนและน่าเชื่อถือสำหรับแต่ละจุดของบันทึกข้อมูลระยะไกล
  • ตรรกะการประมวลผล: โค้ด Arduino ใช้กลยุทธ์ "การส่งงานแบบอะซิงโครนัส" (หรือส่งงานด้วยตัวจับเวลา): มันตีความช่วงเวลาที่เฉพาะเจาะจงกับงาน และจับคู่สถานะของพิน เพื่อให้การทำงานดิจิทัลที่ปลอดภัยและเป็นจังหวะ โดยไม่ใช้ delay()
  • ลูปการสื่อสาร: รหัสจับเวลาถูกส่งเป็นจังหวะไปยัง Serial Monitor ในระหว่างการปรับเทียบเริ่มต้น เพื่อประสานสถานะ

โครงสร้างพื้นฐานฮาร์ดแวร์-รีจิสเตอร์

  • Arduino Uno: "สมอง" ของโปรเจค จัดการพัลส์ข้อมูลอนุกรมหลายทิศทาง และประสานการซิงค์ของรีจิสเตอร์และตัวจับเวลา
  • IC 74HC595: ให้ "ลิงก์ดิจิทัล" ที่ชัดเจนและน่าเชื่อถือสำหรับแต่ละจุดของวงจรลอจิก
  • แถว LED (8 ดวง): ให้อินเทอร์เฟซทางกายภาพที่มีความจุสูงและน่าเชื่อถือสำหรับแต่ละจุดของภารกิจ
  • เบรดบอร์ด: วิธีที่สะดวกสำหรับการทำวงจรอิเล็กทรอนิกส์-ลอจิกต้นแบบแรก และเชื่อมต่อชิ้นส่วนทั้งหมดโดยไม่ต้องบัดกรี
  • ไลบรารี ez_SIPO8: สำคัญมากสำหรับการให้แพลตฟอร์มการเขียนโปรแกรมที่ชัดเจนและประหยัดพลังงาน สำหรับแต่ละจุดของลอจิกรีจิสเตอร์
  • สาย Micro-USB: ใช้สำหรับโปรแกรม Arduino และเป็นอินเทอร์เฟซหลักสำหรับตัวควบคุมระบบ

รายการอุปกรณ์

จัดเตรียมชิ้นส่วนต่อไปนี้ให้พร้อม:

  • 1 x Arduino UNO - ดีไซน์นี้ใช้ Arduino UNO แต่ไมโครคอนโทรลเลอร์ตัวไหนที่เหมาะสม (Arduino หรือของโคลน) ก็ใช้ได้ ตราบใดที่มันรองรับความต้องการพินสำหรับขับอินเทอร์เฟซ SIPO และความต้องการพลังงาน
  • 1 x เบรดบอร์ด - เล็กหรือใหญ่ อันไหนที่หยิบได้ใกล้มือก็ใช้เลย
  • 1 x IC 74HC595 - IC SIPO 8 บิต หรือของโคลนอื่นๆ ที่ "เข้ากันได้จริงๆ" แบบเสียบแล้วใช้ได้
  • 8 x LED - อันไหนที่มีอยู่รอบตัวก็เอามาใช้
  • 8 x ตัวต้านทาน (Resistor), 220 โอห์ม - หนึ่งตัวต่อ LED หนึ่งดวง ใช้ตัวต้านทาน 220 โอห์มนะ ห้ามใช้ 180 โอห์มตามที่แผนภาพต่อสายบางอันแนะนำ มันช็อตแน่ๆ ตัวนี้!
  • สายต่อ - สั้น/ยาว หรือสายสำหรับเบรดบอร์ด อันไหนที่เหมาะกับงานก็ใช้เลย

74HC595 วางยังไง? ไหนด้านไหน?

จะรู้ได้ไงว่าด้านไหนเป็นด้านไหน? ง่ายนิดเดียวครับน้อง! ดูที่รอยบาก (notch) ของไอซี 74HC595 สิ มันจะอยู่ด้านบนของแผนภาพนี่แหละ การนับขา (Pin numbering) จะเริ่มที่ขา 1 ที่มุมซ้ายบน แล้วไล่ลงมาตามด้านซ้าย วนไปที่ด้านล่างของไอซี แล้วขึ้นมาที่มุมขวาบนจนถึงขา 16:

Pin Outs 1 - 74HC595

วิธีต่อกับไมโครคอนโทรลเลอร์ (Microcontroller/SIPO Interface Pin Configuration)

ทุกๆ กลุ่ม (bank) ของไอซี SIPO ที่เราจะต่อกับไมโครคอนโทรลเลอร์เนี่ย ต้องใช้การเชื่อมต่อแบบดิจิตอล 3 สาย (3WI) เนื่องจากบทสอนนี้ใช้ SIPO แค่ตัวเดียว เราก็เลยต้องการแค่ 3WI หนึ่งชุดเท่านั้น ตารางด้านล่างนี้เป็นตัวอย่างการจับคู่ขาระหว่างไมโครคอนโทรลเลอร์กับไอซี SIPO สำหรับบทสอนนี้ แต่จริงๆ แล้วน้องเลือกใช้ขาไหนของไมโครคอนโทรลเลอร์ก็ได้ตามใจชอบเลย ถ้าน้องเลือกขาไม่เหมือนตัวอย่าง ก็อย่าลืมไปแก้ไขการเรียกฟังก์ชัน create_bank ใน setup() ด้วยล่ะ

  • UNO ขา 8 ไปที่ SIPO ขา 14 - ขาข้อมูลของ SIPO (SIPO Data Pin)
  • UNO ขา 9 ไปที่ SIPO ขา 12 - ขาล็อคของ SIPO (SIPO Latch Pin)
  • UNO ขา 10 ไปที่ SIPO ขา 11 - ขานาฬิกาของ SIPO (SIPO Clock Pin)
  • UNO ขา +5v ไปที่ SIPO ขา 10, 16 - จ่ายไฟให้ SIPO
  • UNO ขา GND ไปที่ SIPO ขา 8, 13 - กราวด์ (0v)

เอาหล่ะ มาจัดการต่อสายให้ครบกันเถอะ!

ใช้แผนภาพด้านล่างนี้เป็นไกด์ ต่อสายให้ครบทุกส่วน ระวังเรื่องขาเข้า-ขาออกให้ดีๆ หน่อยนะ ผิดนิดเดียวไฟไม่ติด!

Wiring Scheme 1- Single SIPO IC, 8 outputs

สังเกตดีๆ นะ จะเห็นว่ามีขาเดียวของไอซี 74HC595 ที่เราไม่ได้ต่ออะไรเลย นั่นคือขา 9 (QH’) ขานี้เอาไว้ใช้เป็นขาออกแบบอนุกรม (serial output) เพื่อต่อเข้ากับขาเข้าแบบอนุกรม (14SER) ของไอซี SIPO 74HC595 ตัวต่อไป เวลาเราต่อแบบเรียงลำดับ (cascade) ไงล่ะ

ขั้นตอนการทำงานแบบอัตโนมัติและโต้ตอบกับ Timing Hub

กระบวนการทำงานของ shift-register ออกแบบมาให้มีประสิทธิภาพสูงสุด:

  1. เตรียมพื้นที่ทำงาน (Initialize Workspace): วางไอซี 74HC595 และ LED ลงบนเบรดบอร์ดให้ถูกต้อง แล้วต่อสายเข้ากับขาของ Arduino ตามแผนภาพการต่อสายด้านบนให้เป๊ะ
  2. ตั้งค่าการซิงค์เอาต์พุต (Setup Output Sync): ในสเก็ตช์ Arduino ให้เริ่มต้นด้วย my_SIPOs.begin() และกำหนดช่วงเวลาของตัวจับเวลา (timer intervals) (เช่น 500ms) ในฟังก์ชัน setup()
  3. ลูปการทำงานภายใน (Internal Dialogue Loop): สถานีจะทำการวนลูปดิจิตอลประสิทธิภาพสูงอย่างต่อเนื่อง และอัปเดตสถานะของขาแบบเรียลไทม์ตามการตั้งค่าที่เรากำหนดไว้เบื้องหลัง
  4. การผสานข้อมูลและการตอบรับภาพ (Visual and Data Feedback Integration): ดูแแดชบอร์ด LED ของเรากลายเป็นสัญญาณสถานะที่มีจังหวะไปเองอัตโนมัติ กะพริบเป็นจังหวะและทำตามการตั้งค่าตรรกะของเราจากระยะไกลได้เลย สุดยอดไปเลยมั้ยล่ะ! จัดไปวัยรุ่น!

โค้ด/สเก็ตช์

เอาล่ะ หลังจากตั้งค่าเสร็จสรรพ มาดูสเก็ตช์ที่ใช้ตัวจับเวลา (timers) ควบคุมให้ LED กะพริบแบบแปรผันกันดีกว่า โหลดโค้ดไปเลย แล้วก็คอมไพล์ อัพโหลดลงบอร์ดซะ

//
// Tutorial 3 - use of ez_SIPO8 library,
// 1x physical SIPO, and use of SIPO8 timers to control SIPO outputs with time
//
// Ron D Bentley, Stafford, UK
// April 2021
//
// This example and code is in the public domain and
// may be used without restriction and without warranty.
//
#include <ez_SIPO8_lib.h>
#define Max_SIPOs 1 // one virtual SIPO for this tutorial
#define Max_timers 8 // 8 timers required to map a complete 8bit SIPO
// initiate the class for Max SIPOs/timers required
SIPO8 my_SIPOs(Max_SIPOs, Max_timers);
int bank0_id; // used to keep the SIPO bank id
//
// setup pin/LED flash data
uint8_t timer;
uint32_t timer_intervals[Max_timers] = {
300, 400, 500, 600, 700, 800, 900, 1000 // millisecond elapse timer values
};
uint8_t timer_pins[Max_timers] = {
0, 1, 2, 3, 4, 5, 6, 7 // SIPO output pin absolute addresses
};
void setup() {
Serial.begin(9600);
// create bank, params are:
// data pin, clock pin, latch pin, number of SIPOs this bank
bank0_id = my_SIPOs.create_bank(8, 10, 9, 1);
if (bank0_id == create_bank_failure) {
Serial.println(F("\
failed to create bank"));
Serial.flush();
exit(0);
}
// print the bank data for confirmation/inspection
my_SIPOs.print_SIPO_data();
}
void loop() {
// start by setting all SIPO outputs to low (off)
my_SIPOs.set_all_array_pins(LOW);// set all declared virtual output pins LOW/off
my_SIPOs.xfer_array(LSBFIRST); // move virtual pin statuses to real SIPO output pins
//
// start all timers
for (timer = 0; timer < Max_timers; timer++) {
my_SIPOs.SIPO8_start_timer(timer);
}
timer = 0; // start checking at first timer
do {
// check each timer for elapse and, if elapsed, invert the timer's output pin
// and reset the timer
if (my_SIPOs.SIPO8_timer_elapsed(timer, timer_intervals[timer]) == elapsed) {
my_SIPOs.invert_array_pin(timer_pins[timer]); // invert the pin associated with this timer
my_SIPOs.xfer_array(MSBFIRST);// update physical SIPO outputs
my_SIPOs.SIPO8_start_timer(timer);// reset/restart the current timer
}
timer++; // move on to next timer
if (timer >= Max_timers) timer = 0; // wrap around to beginning
} while (true);
}

จุดที่ต้องสังเกต (จัดไปวัยรุ่น):

1. เราได้ตั้งค่าตัวจับเวลา (timers) ทั้ง 8 ตัวที่เราต้องการ (หนึ่งตัวต่อพอร์ตเอาต์พุต/LED) อัตโนมัติไปแล้วตอนสร้างอ็อบเจ็กต์ของคลาส SIPO8 (พารามิเตอร์ตัวที่สอง ตรงนี้คือ 8) จริงๆ แล้วเราสร้างได้สูงสุดถึง 255 ตัวเลยนะ ถ้าอยาก...แต่เยอะเวอร์! 555

2. เราได้ประกาศและตั้งค่าเริ่มต้นให้อาร์เรย์สองตัว เพื่อกำหนดช่วงเวลากะพริบ (หน่วยมิลลิวินาที) และเลขพินเอาต์พุตแบบ absolute ที่เราอยากควบคุม นั่นคือ:

uint32_t timer_intervals[Max_timers], และ

uint8_t timer_pins[Max_timers]

อาร์เรย์พวกนี้ทำให้เราปรับความเร็วการกะพริบและสลับลำดับพินเอาต์พุตได้ตามใจชอบง่ายๆ เลย

3. มีฟังก์ชันในไลบรารี SIPO8 อยู่ 3 ตัวที่ช่วยให้เราใช้งานและควบคุมตัวจับเวลาได้ นั่นคือ:

  • SIPO8_start_timer (timer)
  • SIPO8_timer_elapsed(timer, timer_intervals[timer]) และ
  • SIPO8_stop_timer (timer)

ฟังก์ชันตัวจับเวลาแต่ละตัวรับพารามิเตอร์แรกเป็นหมายเลขตัวจับเวลาที่เราอ้างอิงถึง แต่อย่างในกรณีของ SIPO8_timer_elapsed ฟังก์ชันนี้จะมีพารามิเตอร์ที่สองเพิ่มมา ซึ่งคือช่วงเวลาที่เราอยากตรวจสอบว่าหมดแล้วหรือยัง (หน่วยมิลลิวินาที) ตรงนี้ก็คือช่วงเวลาที่ตัวจับเวลาจะรันก่อนหมดอายุไงล่ะ ระวังให้ดี พารามิเตอร์ที่สองนี่เป็นตัวแปรแบบ unsigned 32 บิตนะ อย่าลืมเช็คการกำหนดค่าในสเก็ตช์ด้วยล่ะ.

สเก็ตช์นี้ไม่ได้ใช้ฟังก์ชัน SIPO8_stop_timer แต่รายละเอียดเต็มๆ มีอยู่ในคู่มือผู้ใช้ (User Guide) อยู่แล้ว ไปหาอ่านเพิ่มเติมได้

ข้อมูล Frontmatter ดั้งเดิม

title: "งานง่ายแต่หล่อ! มาปล่อย Shift Register ให้สุดด้วย Timers - Tutorial 3"
description: "มาแกะกล่องความสามารถ "เทพๆ" ของ ez_SIPO8_lib กัน คราวนี้จัดเต็มเรื่อง Timer และ Interrupt ให้งานของเราทำงานได้ตึงๆ แบบไม่ต้องมานั่งรอ!"
author: "ronbentley1"
category: "Lab Stuff"
tags:
  - "tutorials"
  - "sipo"
  - "74hc595"
  - "shift registers"
  - "timers"
views: 474
likes: 0
price: 299
difficulty: "Intermediate"
components:
  - "8x Resistor 220 ohm"
  - "1x Breadboard (generic)"
  - "1x Arduino UNO"
  - "1x Shift Register- Serial to Parallel"
  - "8x LED (generic)"
tools: []
apps:
  - "1x Arduino IDE"
downloadableFiles:
  - "https://projects.arduinocontent.cc/5b7e3579-0933-4a34-87a9-cc027d42a5db.ino"
  - "https://projects.arduinocontent.cc/5b7e3579-0933-4a34-87a9-cc027d42a5db.ino"
documentationLinks: []
passwordHash: "efba31563485bbea51266692a877fd540455efd142a5f2a375b4d75e7d945b8b"
encryptedPayload: "U2FsdGVkX1/q7lC9Fz7iXejq6qFuJLr+B47HLlXKm5Li0NLdMYZhzSwQe1brjwc6+1SfFMdr3gaqAV5zrrXyJgz7nl59cqc7uoLBf8GMvT0="
seoDescription: "Learn to use ez_SIPO8_lib timer functions for Shift Registers in this Arduino Tutorial 3. Explore library capabilities and features."
videoLinks: []
heroImage: "https://cdn.jsdelivr.net/gh/bigboxthailand/arduino-assets@main/images/projects/shift-registers-tutorial-3-using-timers-e4d02a_cover.jpg"
lang: "en"