TM1638
TM1638 เป็นไอซีที่ผลิตโดยบริษัท TITAN Micro Electronics ในประเทศจีน เหมาะสำหรับนำมาใช้ควบคุม LED Array / LED 7-Segment Display และสามารถต่อกับปุ่มกด (Push Buttons) หรือแบบแป้นกดคีย์ (Keypad) ได้
การเชื่อมต่อกับไมโครคอนโทรลเลอร์ใช้เพียงสัญญาณ 3 เส้นคือ CLK, DIO และ STB
- CLK ใช้สำหรับกำหนดจังหวะการส่งข้อมูล โดยใช้วิธีเลื่อนบิตตามขอบขาขึ้น
- DIO ใช้สำหรับเลื่อนบิต ทำงานได้สองทิศทาง เป็นเอาต์พุตหรืออินพุต การเลื่อนบิตจะเริ่มด้วย LSB First ในทิศทางอินพุตเป็นการรับข้อมูล และใช้ในกรณีที่อ่านค่าดูว่า มีการกดปุ่มหรือไม่ จากขั้นตอน Key Scan
- STB เป็นขา Strobe หรือ Chip Select ทำงานแบบ Active-Low (STB=Low เริ่มต้นการสื่อสารข้อมูล, STB=High จบการทำงาน) สถานะปรกติ (Idle) จะเป็น High
การควบคุมการทำงานของ TM1638 จะต้องใช้ชุดคำสั่ง (Instruction Set) ซึ่งประกอบด้วย 3 คำสั่งพื้นฐานดังนี้ (Datasheet)
- CMD1: data instruction set (
0x40
) สำหรับเริ่มต้นการเขียนหรืออ่านข้อมูล ถ้าเป็นการเขียนข้อมูล ก็จะเป็นการกำหนดค่าบิตให้ LEDs หรือ 7-Segment Display แต่ถ้าเป็นการอ่านข้อมูล จะใช้สำหรับตรวจสอบสถานะการกดปุ่มนอกจากนั้นยังระบุได้อีกว่า เมื่อมีการเขียนหรืออ่านข้อมูลหนึ่งไบต์แล้ว จะให้แอดเดรสเพิ่มโดยอัตโนมัติด้วยหรือไม่ (Auto Address Increment) เป็นต้น - CMD2: address instruction set (
0xC0
) สำหรับกำหนดแอดเดรส (Address) หรือตำแหน่ง (เริ่มต้น) ที่ข้อมูลไบต์จะถูกเขียนลงไป และมีแอดเดรสอยู่ในช่วง 00h .. 1Fh - CMD3: display instruction set (
0x80
) สำหรับกำหนดค่าความสว่าง (Brightness) หรือ เปิด/ปิดการแสดงผล (Display On/Off) เป็นต้น
การใช้คำสั่ง Data Instruction Set (0x40
) จะต้องมีการกำหนดค่า Flags ดังนี้
- Write data to register:
0x00
เพื่อเขียนข้อมูลไปยัง TM1638 ลงในรีจิสเตอร์ - Read key-scan data:
0x02
เพื่ออ่านข้อมูลที่ได้จากการสแกนอินพุต - Auto-address increment:
0x00
เลือกใช้โหมดเพิ่มแอดเดรสโดยอัตโนมัติ - Fixed-address:
0x04
ไม่ใช่โหมดเพิ่มแอดเดรส - Normal mode:
0x00
ใช้โหมดทำงานปรกติ - Test mode:
0x08
ใช้โหมดทดสอบ
ยกตัวอย่างเช่น ถ้าเขียนค่าให้คำสั่ง CMD1 เป็น (0x40 | 0x02
) ก็หมายถึง การอ่านค่าจาก Key-Scan Data เป็นต้น
การใช้คำสั่ง CMD1, CMD2 หรือ CMD3 แต่ละคำสั่ง เริ่มต้นจะต้องทำให้ขา STB เป็น LOW (Active) แล้วจึงส่งคำสั่งหรือข้อมูลออกไป และเมื่อส่งเสร็จแล้ว ให้ขา STB เป็น HIGH (Inactive)
ตามรูปตัวอย่างผังวงจร จะเห็นได้ว่า ตัวแสดงผล 7-Segment Display มีทั้งหมด 8 หลัก (Digits) แต่ละตัวจะใช้ขาสัญญาณ SEG1/KS1 .. SEG8/KS8 จาก TM1638 มากำหนดสถานะของ LED Segments (a,b,c,d,e,f,g และ dot หรือ DP)
ข้อสังเกต: ขา SEG1/KS1 .. SEG8/KS8 จะใช้สำหรับการอ่านสถานะของปุ่มกดด้วย (KeyScan Input) จำนวน 8 ปุ่ม
ขาสัญญาณ GRID1 .. GRID8 จะทำหน้าที่เป็นตัวควบคุมการทำงานของ 7-Segment แต่ละหลัก (ควบคุมการเปิดหรือปิดการไหลของกระแส) เรียงไปตามลำดับ แบ่งช่วงเวลากัน (Timing Multiplexing)
ขา SEG9 จะใช้ควบคุมการทำงานของ LEDs (Red) อีก 8 ดวง ในขณะที่ SEG10 ไม่ได้ต่อใช้งาน
เนื่องจาก มี SEG1 .. SEG10 ซึ่งหมายถึง จะต้องใช้ 10 บิต ในการการกำหนดสถานะลอจิก ถ้านับให้เป็นไบต์ จึงต้องใช้ข้อมูล 2 ไบต์ (High Byte และ Low Byte) และเนื่องจากมี 8 หลัก จึงมีแอดเดรสสำหรับข้อมูล 16 ตำแหน่ง
- ข้อมูลที่เขียนลงในแอดเดรสที่เป็นเลขคู่ เช่น
00h
,02h
, … จะใช้สำหรับ SEG9 และ SEG10 - ข้อมูลที่เขียนลงในแอดเดรสที่เป็นเลขคี่ เช่น
01h
,03h
, … จะใช้สำหรับกำหนดสถานะของ 7-Segment Display (SEG1 .. SEG8)
ขา K1, K2, K3 เป็นขาสำหรับการสแกนปุ่มกด (ใช้สำหรับ Push Buttons จำนวน 3 แถว ๆ ละ 8 ปุ่ม) แต่สำหรับตามผังวงจรของโมดูลที่ได้เลือกมาใช้งาน จะมีเพียงขา K3 เท่านั้นที่ต่อใช้งาน เนื่องจากมีปุ่มกดแถวเดียว
การตรวจสอบสถานะปุ่มกด จะต้องอ่านข้อมูล 4 ไบต์ และเนื่องจากว่า มีแถวเดียวซึ่งตรงกับ K3 ดังนั้นให้อ่านและตรวจสอบที่บิต B0 และบิตที่ B4 ถ้าบิตมีค่าเป็น 1 แสดงว่า มีการกดปุ่มในขณะนั้น
- ไบต์ที่ 1 (BYTE1) แสดงสถานะของปุ่มกด 2 ปุ่มที่ตรงกับ KS1 (B0) และ KS2 (B4)
- ไบต์ที่ 2 (BYTE2) แสดงสถานะของปุ่มกด 2 ปุ่มที่ตรงกับ KS3 (B0) และ KS4 (B4)
- ไบต์ที่ 3 (BYTE3) แสดงสถานะของปุ่มกด 2 ปุ่มที่ตรงกับ KS5 (B0) และ KS6 (B4)
- ไบต์ที่ 4 (BYTE4) แสดงสถานะของปุ่มกด 2 ปุ่มที่ตรงกับ KS7 (B0) และ KS8 (B4)
การคลาส MicroPython สำหรับ TM1638
มาดูตัวอย่างการเขียนโค้ด MicroPython เพื่อสร้างคลาส TM1638 สำหรับนำมาใช้งาน มีคำสั่งที่เรียกใช้ เช่น
on()
เปิดการทำงานของตัวแสดงผลoff()
ปิดการทำงานของตัวแสดงผลbrightness()
กำหนดระดับความสว่างของ LEDs เลือกได้ 0..7 (จากต่ำสุดถึงสูงสุด)write()
ใช้สำหรับเขียนคำสั่งและข้อมูลเพื่อกำหนดสถานะการทำงานของ LED หรือ 7-Segment ตามแอดเดรสที่ระบุled()
กำหนดสถานะ on/off ของ LED ตามตำแหน่งที่ระบุ (pos=0..7)segments()
กำหนดข้อมูลสำหรับแสดงสถานะของ 7-Segment Display ในตำแหน่งที่ระบุ (pos=0..7)read_buttons()
อ่านข้อมูลสถานะของปุ่มกดทั้ง 8 ปุ่ม ได้ค่ากลับคืนเป็นไบต์
# file: tm1638.py
from micropython import const
from machine import Pin
from time import sleep_us, sleep_msDIGITS = bytearray(b'\x3F\x06\x5B\x4F\x66\x6D\x7D\x07\x7F\x6F')class TM1638():
_CMD1 = const(0x40) # data command
_CMD2 = const(0xC0) # address command
_CMD3 = const(0x80) # display control command
_KEY_READ = const(0x02) # read key scan data flag for CMD1
_DISP_ON = const(0x08) # display on flag for CMD3 def __init__(self, stb, clk, dio, brightness=7):
self._stb = stb
self._clk = clk
self._dio = dio
self._brightness = brightness # 0..7
self._disp_on = _DISP_ON
self._clk.init( Pin.OUT, value=1 )
self._dio.init( Pin.OUT, value=0 )
self._stb.init( Pin.OUT, value=1 )
self.clear() def _write_byte(self, b):
for i in range(8):
self._clk(0)
self._dio((b >> i) & 1) # LSB first
self._clk(1) def _cmd1(self):
self._stb(0) # start
# write mode, auto-increment addressing, normal mode
self._write_byte(_CMD1)
self._stb(1) # stop def _cmd2(self, data, addr=0):
self._stb(0) # start
# set address start, followed by one data byte
self._write_byte( _CMD2 | (addr & 0xf) )
if isinstance(data,list):
for b in data:
self._write_byte( b )
sleep_us(1)
else:
self._write_byte( data )
self._stb(1) # stop def _cmd3(self):
self._stb(0) # start
# display command: display on, set brightness
self._write_byte( _CMD3 | self._disp_on | self._brightness )
self._stb(1) # stop def on(self):
self._disp_on = _DISP_ON
self._cmd3() def off(self):
self._disp_on = 0
self._cmd3() def brightness(self, val=7):
self._brightness = val & 0b111
self._cmd3() def clear(self):
self.write( 16*[0], 0 ) def write(self, data, addr=0):
self._cmd1()
self._cmd2( data, addr )
self._cmd3() def led(self, pos, value):
self._cmd1()
self._cmd2( value, (pos << 1) | 1 ) def segment(self, pos, value):
self._cmd1()
self._cmd2( value, (pos << 1) )
def read_buttons(self):
value = 0
self._stb(0)
self._write_byte( _CMD1 | _KEY_READ )
self._dio.init( Pin.IN, Pin.PULL_UP )
for j in range(4): # read 4 bytes
temp = 0
for i in range(4): # read nibble
self._clk(0)
if self._dio.value():
temp = 0x08
self._clk(1)
for i in range(4): # read nibble
self._clk(0)
if self._dio.value():
temp = 0x80
self._clk(1)
value = (value >> 1) | temp
self._dio.init( Pin.OUT, 0 )
self._stb(1)
return value
ตัวอย่าง: แสดงค่า Pi บน 7-Segment Display
ตัวอย่างแรกที่สาธิตการใช้คลาส TM1638 เป็นการแสดงตัวเลขของค่า Pi จำนวน 7 หลักหลังจุดทศนิยม (Decimal Point)
ในการต่อวงจรระหว่าง ESP32 กับ TM1638 ก็ใช้แรงดันไฟเลี้ยง 3.3V และ GND จากบอร์ด ESP32 และในตัวอย่างนี้ได้เลือกใช้ขา GPIO23=STB, GPIO22=CLK และ GPIO21=DIO ตามลำดับ
import tm1638
from machine import Pin
import utime as time
import mathtm = tm1638.TM1638(stb=Pin(23), clk=Pin(22), dio=Pin(21))
tm.clear()
tm.brightness(4)x = int(math.pi*10e6) # calculate Pi value (truncated)
for i in range(8):
value = tm1638.DIGITS[ x%10 ]
if i==7:
value |= 0x80 # show dot (DP)
tm.segment( 7-i, value )
x //= 10
time.sleep(3.0)
tm.off()
del tm
ตัวอย่าง: อ่านค่าปุ่มกดและแสดงค่าตัวนับในแต่ละหลักของ 7-Segment Display
ตัวอย่างที่สอง สาธิตการเปิดหรือปิด LED แต่ละดวงเรียงไปตามลำดับ ถัดไปทำให้ 7-Segment Display ทั้ง 8 ตำแหน่ง แสดงตัวเลขเริ่มต้นเป็น 0 ทุกตำแหน่ง
เมื่อมีการกดปุ่มใดปุ่มหนึ่ง จะทำให้ LED ที่ตรงกับตำแหน่งของปุ่มกดสว่างขึ้น แล้วจะเพิ่มค่าตัวเลขในตำแหน่งดังกล่าวทีละหนึ่ง ถ้ากดปุ่มค้าง จะทำให้ตัวเลขเพิ่มขึ้นต่อเนื่อง และถ้าเพิ่มให้ถึง 9 ถัดไปกลับไปเริ่มที่ 0 ใหม่
# file: tm1638_demo.py
import tm1638
from machine import Pin
import utime as timetm = tm1638.TM1638(stb=Pin(23), clk=Pin(22), dio=Pin(21))
tm.on()
tm.brightness(7)
tm.clear()for i in range(8): # 0,1,2...,7
tm.led(i, 1) # turn on LED at position i
time.sleep_ms(50)for i in range(7,-1,-1): # 7,6,...,0
tm.led(i, 0) # turn off LED at position i
time.sleep_ms(50)values = 8*[0]
try:
while True:
# read input buttons
input_bits = tm.read_buttons()
for i in range(8): # check input button
# if the button is pressed, increment the values[i]
if (input_bits&1) == 1:
values[i] = (values[i]+1) % 10
# update the LED status (turn on if pressed)
tm.led( i, (input_bits&1) )
# shift bits to the right
input_bits >>= 1
# update 7-segment status
tm.segment( i, tm1638.DIGITS[ values[i] ] )
time.sleep_ms(150)
except KeyboardInterrupt:
pass
finally:
tm.off()
print('Done')
โดยสรุป เราได้เรียนรู้หลักการทำงานของโมดูล TM1638 ในเบื้องต้น และได้เห็นตัวอย่างการสร้างคลาสในภาษา MicroPython และตัวอย่างสาธิตการใช้บอร์ด ESP32 ร่วมกับโมดูล TM1638 ที่มี LEDs / 7-Segments / Push Buttons ขนาด 8 บิต … หวังว่า จะเป็นประโยชน์ต่อผู้ที่สนใจเรียนรู้ภาษา Python แบบสัมผัสฮาร์ดแวร์นะครับ