บทความนี้สาธิตตัวอย่างการเขียนโค้ด MicroPython สำหรับบอร์ดไมโครคอนโทรลเลอร์ ESP32 เพื่อเชื่อมต่อกับโมดูลแสดงผลแบบ 8x8 LED Matrix ที่ใช้ชิป MAX7219 เป็นตัวควบคุมการทำงาน และใช้วิธีเชื่อมต่อสื่อสารข้อมูลระหว่างอุปกรณ์ด้วยบัส SPI
MAX7219 LED Driver
MAX7219 (Datasheet) เป็นไอซีสำหรับควบคุมการทำงานของ LED หลายดวง แบ่งเป็นสองโหมดตามลักษณะการใช้งานคือ ใช้ควบคุม 7-Segment Display และ LED Matrix
- ถ้าใช้กับ 7-Segment Display จะควบคุมได้ทั้งหมด 8 ชุด (8 หลัก)
- ถ้าใช้กับ 8x8 LED Matrix Display จะได้เพียง 1 ชุด
ไอซีมีขาสัญญาณ 16 เส้น ที่ใช้ควบคุมการทำงานของ LEDs แบ่งเป็น 2 กลุ่มคือ 8 SEGMENTS (SEG_A .. SEG_G, SEG_DP) และ 8 DIGITS (DIG0 .. DIG7) และมีการทำงานด้วยวิธี Time Multiplexing (เรียงไปตามลำดับ DIG0 .. DIG7 แล้ววนซ้ำใหม่)
การส่งข้อมูลจากไมโครคอนโทรลเลอร์ ไปยังไอซี MAX7219 จะใช้สัญญาณ 3 เส้น คือ CLK, DIN และ LOAD (/CS) โดยใช้วิธีเลื่อนบิตเข้าไปทีละบิต (Bit Shifting) แบบ MSB First ที่ขา DIN และออกที่ขา DOUT ตามจังหวะสัญญาณ CLK และข้อมูลมีขนาด 2 ไบต์ หรือ 16 บิต (D15 .. D0) สำหรับไอซี MAX7219 หนึ่งตัว
ถ้าต้องการควบคุมได้มากกว่าหนึ่งชุด (ใช้ไอซีหนึ่งตัว) ก็สามารถทำได้ โดยใช้ไอซี MAX7219 มากกว่าหนึ่งตัว นำมาต่อกันแบบ Daisy-Chain โดยให้ขา DOUT ของตัวแรกเชื่อมต่อกับขา DIN ตัวที่สอง ในลักษณะนี้ไปตามลำดับ
ตัวอย่างการใช้งานในลักษณะนี้และพบเห็นได้บ่อย เช่น การทำป้าย LED Matrix ที่มีความสูง 8 พิกเซล แต่มีความยาวมากกว่า 8 พิกเซล ถ้าต้องการขนาด 8x32 ก็ต้องใช้อุปกรณ์ทั้งหมด 4 ชุด เป็นต้น
การเขียนโปรแกรมไมโครคอนโทรลเลอร์ เพื่อเลื่อนบิตข้อมูลสำหรับ MAX7219 ทำได้ 2 วิธีคือ การทำคำสั่งเพื่อสร้างสัญญาณเอาต์พุต Clock (เรียกว่า Soft-SPI หรือ Software-based bit-bang SPI) และการใช้ Hardware SPI ซึ่งจะทำได้เร็วและใช้ความถี่ของ Clock ได้สูงกว่าวิธีแรก
บิตที่ D11 .. D8 ของข้อมูล 16 บิต (สำหรับ MAX7219 หนึ่งตัว) เป็นตัวระบุคำสั่งที่จะต้องทำ เช่น
- การไม่ทำคำสั่งใด ๆ (No-Op = No Operation)
- การกำหนดค่าขนาดหนึ่งไบต์ ให้รีจิสเตอร์ Digit 0 .. Digit 7 ซึ่งจะมีผลต่อสถานะติดหรือดับของ LEDs
- การกำหนดระดับความสว่าง (Intensity) ซึ่งมีทั้งหมด 16 ระดับ
- การเปิดหรือปิด LEDs (Display Shutdown)
- การเปิดหรือปิดโหมดการทดสอบ LEDs (Display Test) ที่ทำให้ LEDs ทุกดวงอยู่ในสถานะ ON
- การกำหนดค่า Scan-Limit (จำนวนหลักสูงสุดที่มี) ในกรณีที่ใช้กับ 7-Segment Display เป็นต้น
ตามเอกสาร Datasheet ของผู้ผลิต ไอซี MAX7219 จะใช้แรงดันไฟเลี้ยง (VCC) อยู่ในช่วง 4.0V ถึง 5.5V แต่ก็สามารถนำมาใช้กับ +3.3V ดังนั้นจึงต่อใช้งานร่วมกับ ESP32 ได้เช่นกัน
การสร้างคลาสสำหรับ MAX7219
ถัดไปเป็นตัวอย่างการเขียนโค้ด MicroPython เพื่อสร้างคลาส และนำไปทดลองใช้กับโมดูล MAX7219 8x8 LED Matrix จำนวน 1 ชุด และเลือกใช้วิธี Hardware SPI ของ ESP32 สำหรับการเลื่อนบิตข้อมูลเพื่อส่งไปยัง MAX7219
คำสั่ง write(…)
ต้องการพารามิเตอร์ reg
และ data
สำหรับเขียนข้อมูลไปยังรีจิสเตอร์ที่ต้องการ ถ้ามีโมดูล MAX7219 หนึ่งชุด ก็ใช้ข้อมูลหนึ่งไบต์ แต่ถ้ามีโมดูล MAX7219 ต่อกันแบบ Daisy-Chain มากกว่าหนึ่งชุด เราจะใช้ข้อมูลเป็นอาร์เรย์ ตามจำนวนโมดูลที่มี ข้อมูลไบต์เหล่านี้จะถูกเขียนไปที่รีจิสเตอร์เหมือนกัน แต่ละโมดูลขนาดหนึ่งไบต์ ตามลำดับในแถว
[reg][data_1] [reg][data_2] ... [reg][data_N]
คำสั่ง on()
และ off()
ใช้สำหรับเปิดหรือปิด LEDs ของโมดูล LED Matrix
คำสั่ง clear()
จะใช้สำหรับเคลียร์ข้อมูล ซึ่งจะทำให้ LEDs ทุกดวงของโมดูลอยู่ในสถานะ OFF
คำสั่ง flashing()
เป็นการเปิดและปิดโหมด Display Test โดยเว้นช่วงเวลาและทำตามจำนวนครั้งตามที่ระบุ
from micropython import const
from machine import Pin, SPI
import utime as timeclass MAX7219():
REG_DIGIT_BASE = const(0x1)
REG_DECODE_MODE = const(0x9)
REG_INTENSITY = const(0xA)
REG_SCAN_LIMIT = const(0xB)
REG_SHUTDOWN = const(0xC)
REG_DISP_TEST = const(0xF)
def __init__( self, spi, cs, n=1 ):
self._spi = spi # spi bus
self._cs = cs # cs pin
self._n = n # number of blocks
self.init()
def init( self ):
# decode mode: no decode for digits 0-7
self.write( REG_DECODE_MODE, self._n*[0] )
# set intensity: 0x7 = 15/32, 0xf = 31/32
self.write( REG_INTENSITY, self._n*[0xf] )
# scan limit: display digits 0-7
self.write( REG_SCAN_LIMIT, self._n*[7] )
# display test: normal (no display test)
self.write( REG_DISP_TEST, self._n*[0] )
# shutdown: normal operation (no shutdown)
self.write( REG_SHUTDOWN, self._n*[1] )
def write( self, reg, data ):
if isinstance(data, int):
data = [data]
n = len(data)
buf = []
for i in range(n):
buf += [reg, data[i]]
self._cs.value(0) # assert CS pin
self._spi.write( bytearray(buf) ) # write SPI data
self._cs.value(1) # deassert CS pin
def clear( self ):
for i in range(8):
self.write( REG_DIGIT_BASE+i, self._n*[0] )
def on( self ):
self.write( REG_SHUTDOWN, self._n*[1] )
def off( self ):
self.write( REG_SHUTDOWN, self._n*[0] )
def flashing( self, times, delay_ms=100 ):
for i in range(times):
self.write( REG_DISP_TEST, self._n*[1] )
time.sleep_ms( delay_ms )
self.write( REG_DISP_TEST, self._n*[0] )
time.sleep_ms( delay_ms )
def deinit( self ):
self._spi.deinit()
เมื่อได้สร้างคลาสแล้ว มาดูตัวอย่างการใช้งาน โดยจะให้แสดงรูปสัญลักษณ์ “หัวใจ” (Heart) บน 8x8 LED Matrix แล้วให้กระพริบ
# file: max7219_demo.py
from micropython import const
from machine import Pin, SPI
import utime as time
from max7219 import MAX7219SCK = const(14)
MOSI = const(13)
MISO = const(12)
CS = const(27)SPI(1).deinit()
spi = SPI(1, baudrate=1000000,
polarity=0, phase=0, bits=8,
firstbit=SPI.MSB, sck=Pin(SCK,Pin.OUT),
mosi=Pin(MOSI,Pin.OUT), miso=Pin(MISO,Pin.IN))
cs = Pin(CS, Pin.OUT, value=1) # chip-select pindisp = MAX7219(spi,cs,n=1)
disp.clear()heart = [ # bit patterns for heart symbol
0b00000000,
0b01100110,
0b11111111,
0b11111111,
0b01111110,
0b00111100,
0b00011000,
0b00000000, ]disp.on() # turn on the display
for i in range(8):
disp.write( MAX7219.REG_DIGIT_BASE+i, heart[7-i] )
time.sleep(2.0)disp.flashing(10,200) # flash the display
disp.off() # turn off the display
disp.deinit()
del disp
spi.deinit()
ในการต่อวงจรทดลอง จะใช้ขา GPIO14 สำหรับ SCK ซึ่งตรงกับขา CLK, GPIO13 สำหรับ MOSI ซึ่งตรงกับขา DIN, GPIO12 สำหรับ MISO (ไม่ได้ใช้สำหรับ MAX7219), และ GPIO27 สำหรับ CS ตามลำดับ
โดยสรุปเราได้เห็นตัวอย่างการสร้างคลาสในภาษา MicroPython เพื่อนำมาใช้งานร่วมกับโมดูล MAX7219 8x8 LED Matrix เพื่อแสดงรูปลักษณ์กราฟิก โดยใช้ SPI Bus เป็นรูปแบบการเชื่อมต่อ (การเลื่อนบิตข้อมูลไปยังโมดูล MAX7219)