← Back to list

MicroPython Programming for ESP32 [9]

—  ตัวอย่างเขียนโค้ด MicroPython สำหรับ ESP32

<rawat.s> · 2020-04-30 02:46 · 2 claps · 5.1 min read
#embedded-systems #micropython #esp32 #tm1638
Open on Medium ↗
Wiki topics: 💻 · Programming

MicroPython Programming for ESP32 [9]

‍‍‍‍‍‍ ‍‍ ‍‍‍‍‍‍ ‍‍‍‍‍‍ ‍‍

บทความนี้กล่าวถึง การสร้างคลาสในภาษา MicroPython เพื่อนำมาใช้กับโมดูลที่ใช้ชิป TM1638 ควบคุมการทำงานของ LED จำนวน 8 ดวง ตัวแสดงผลแบบ 7-Segment จำนวน 8 หลักและปุ่มกด Push Button จำนวน 8 ตำแหน่ง

TM1638

‍‍‍‍‍‍ ‍‍ ‍‍‍‍‍‍ ‍‍‍‍‍‍ ‍‍

TM1638 เป็นไอซีที่ผลิตโดยบริษัท TITAN Micro Electronics ในประเทศจีน เหมาะสำหรับนำมาใช้ควบคุม LED Array / LED 7-Segment Display และสามารถต่อกับปุ่มกด (Push Buttons) หรือแบบแป้นกดคีย์ (Keypad) ได้

รูปแสดงตำแหน่งขาของไอซี TM1637

รูปแสดงตำแหน่งขาของไอซี TM1637

ตัวอย่างโมดูล 8-Digit 7-Segment Display / 8-bit Push Buttons & LEDs

ตัวอย่างโมดูล 8-Digit 7-Segment Display / 8-bit Push Buttons & LEDs

การเชื่อมต่อกับไมโครคอนโทรลเลอร์ใช้เพียงสัญญาณ 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)

ตัวอย่างลำดับการส่งคำสั่งและข้อมูลไปยัง TM1638 (Datasheet)

ตัวอย่างลำดับการส่งคำสั่งและข้อมูลไปยัง TM1638 (Datasheet)

ตัวอย่างผังวงจร (Schematic)

ตัวอย่างผังวงจร (Schematic)

ตามรูปตัวอย่างผังวงจร จะเห็นได้ว่า ตัวแสดงผล 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)

ตารางแสดงลำดับการอ่านข้อมูลจาก TM1638 เพื่อตรวจสอบสถานะปุ่มกด

ตารางแสดงลำดับการอ่านข้อมูลจาก TM1638 เพื่อตรวจสอบสถานะปุ่มกด

การคลาส 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_ms
DIGITS = 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 math
tm = 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 time
tm = 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 แบบสัมผัสฮาร์ดแวร์นะครับ


메타데이터
post_id
eecbc1df9994
slug
micropython-programming-for-esp32-9-eecbc1df9994
url
https://medium.com/@rawats/micropython-programming-for-esp32-9-eecbc1df9994
canonical_url
https://medium.com/@rawats/micropython-programming-for-esp32-9-eecbc1df9994
author_url
https://medium.com/@rawats
status
ok
fetched_at
2026-07-29 03:27:06