MicroPython Programming for ESP32 [6]

<rawat.s>
5 min readApr 24, 2020

--

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

บทความนี้แนะนำการเขียนโค้ด MicroPython สำหรับ ESP32 เพื่อใช้งานโมดูล LED Matrix ขนาด 16x8 ที่ใช้ชิป TM1640 [Datasheet] เป็นตัวควบคุมการทำงาน

โมดูลแสดงผลแบบ 16x8 LED Matrix

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

โมดูลที่ได้เลือกมาลองใช้งานคือ TTGO 16x8 Blue LED Matrix ที่ใช้ชิป TTGO TM1640 Driver (ตัวอย่าง Datasheet) เป็นตัวควบคุมการทำงานของแผง SMD LED (สูง 8 ยาว 16 พิกเซล)

การเชื่อมต่ออุปกรณ์นี้กับบอร์ดไมโครคอนโทรลเลอร์ เช่น ESP32 ก็ใช้สายไฟเพียง 4 เส้น คือ VCC, GND, DATA, SCK ตามลำดับ และสามารถใช้แรงดันไฟเลี้ยงที่ +3.3V หรือ +5V ได้

ตัวอย่างอุปกรณ์ (มุมมองจากด้านหน้า)
ตัวอย่างอุปกรณ์ (มุมมองจากด้านหลัง)
แผนผังแสดงตำแหน่งขาของโมดูล TTGO TM1640 16x8 LED Matrix
แผนผังแสดงตำแหน่งขา (Pinout) ของบอร์ด ESP32 ที่ได้เลือกมาใช้งาน

การเขียนคำสั่งและข้อมูลสำหรับ TM1640

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

การสื่อสารข้อมูลกับ TM1640 จะใช้สายสัญญาณ 2 เส้น คือ SCK (SCLK) และ DATA (DIN) สัญญาณ SCK เป็นตัวกำหนดจังหวะการอ่านข้อมูลขาเข้าที่ถูกส่งไปยัง TM1640 ที่ขา DATA ทีละบิต ด้วยวิธีการเลื่อนบิต ตามลำดับแบบ LSB First

การเริ่มต้นส่งข้อมูล จะต้องเริ่มด้วยการส่งสัญญาณ START Condition ซึ่งก็คือ เมื่อสัญญาณ SCK เป็น HIGH และ DATA มีการเปลี่ยนจาก HIGH เป็น LOW จากนั้น SCK จึงเปลี่ยนจาก HIGH เป็น LOW

เมื่อส่งข้อมูลครบหนึ่งไบต์จะจบด้วยการส่งสัญญาณ STOP Condition ซึ่งก็คือ SCK เปลี่ยนจาก LOW เป็น HIGH แล้วตามด้วย DATA เปลี่ยนจาก LOW เป็น HIGH

รูปคลื่นสัญญาณ SCK และ DATA (DIN) เมื่อส่งข้อมูลหนึ่งไบต์ (LSB First)

นอกจากนั้นยังมีการแบ่งข้อมูลไบต์เป็น 2 ประเภท คือ Command และ Data การส่งข้อมูลจะต้องเริ่มต้นด้วย Command ก่อน แล้วตามด้วยข้อมูลไบต์สำหรับ Data

ข้อมูลไบต์ที่เป็น Command เช่น

  • Data command setting (CMD1) สำหรับกำหนดว่า จะเลือกโหมดการทำงาน เช่น Address Auto-Increment (default) หรือ Fixed Address เป็นต้น
  • Address command setting (CMD2) สำหรับกำหนดแอดเดรสเริ่มต้น (Start Address) ขนาด 4 บิต (0x00 .. 0x0F) เพื่อใช้ในการเขียนข้อมูลลงใน SRAM และนำไปใช้ในการแสดงผล
  • Display control command setting (CMD3) เช่น สำหรับเปิดหรือปิดจอแสดงผล (Display On/Off) และกำหนดระดับความสว่าง (Brightness Level) มี 8 ระดับ (0..7)

ลำดับการเขียนข้อมูล Command และ Data เป็นดังนี้

[CMD1] [CMD2] [DATA_1] [DATA_2] ... [DATA_N] [CMD3]

เนื่องจาก TM1640 ถูกนำมาใช้กับ 16x8 LED Matrix ดังนั้น ข้อมูลที่ถูกเขียนลงในหน่วยความจำ SRAM ของไอซี จะมีทั้งหมด 16 ไบต์ แต่ละไบต์จะถูกนำไปใช้แสดงผลในแนวตั้ง (คอลัมน์) ขนาด 8 บิต (8 พิกเซล)

การสร้างคลาส TM1640_LED_Matrix ในภาษา MicroPython

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

ลองมาดูตัวอย่างการเขียนโค้ดสร้างคลาสชื่อ TM1640_LED_Matrix ดังนี้ ซึ่งมีคำสั่ง เช่น การเปิดหรือปิดจอแสดงผล การกำหนดระดับความสว่าง 0..7 และการเขียนข้อมูลแบบอาร์เรย์ เพื่อนำไปใช้แสดงผล

import machine
from machine import Pin
import utime as time
from micropython import const
class TM1640_LED_Matrix():
# list of three commands of TM1640
_CMD1 = const(0x40) # data command
_CMD2 = const(0xC0) # address command
_CMD3 = const(0x80) # display control command
_DSP_ON = const(0x08) # display on (flag)
def __init__( self, sck, dio ):
self._sck = sck
self._dio = dio
self._brightness = 3 # value range: 0..7
self._disp_on = _DSP_ON
self._vertical_invert = True
self._sck(1)
self._dio(1)

def _send_dio( self, b ):
self._dio(b)
time.sleep_us(10)

def _send_sck( self, b ):
self._sck(b)
time.sleep_us(10)

def _start( self ): # send start condition
self._send_dio(0)
self._send_sck(0)

def _stop( self ): # send stop condition
self._send_dio(0)
self._send_sck(1)
self._send_dio(1)

def _write_byte(self, data, reverse=False):
for i in range(8):
if reverse:
self._send_dio( (data >> (7-i)) & 1 )
else:
self._send_dio( (data >> i) & 1 )
self._send_sck(1)
self._send_sck(0)

def _cmd_data( self ):
self._start()
self._write_byte( _CMD1 )
self._stop()
def _disp_ctrl( self ):
self._start()
data = _CMD3 | self._disp_on | self._brightness
self._write_byte( data )
self._stop()

def on( self ): # turn on display
self._disp_on = _DSP_ON
self._disp_ctrl()

def off( self ): # turn off display
self._disp_on = 0
self._disp_ctrl()

def clear( self ): # clear display
self.write( 16*[0] )

def vertical_invert( self, b ):
self._vertical_invert = b
def brightness( self, value=7 ): # set display brightness
# brightness 0 = 1/16th pulse width
# brightness 7 = 14/16th pulse width
if 0 <= value <= 7:
self._brightness = value
self._cmd_data()
self._disp_ctrl()

def write( self, data, pos=0 ): # write display data
if isinstance(data,int):
data = [data]
self._cmd_data()
self._start()
self._write_byte( _CMD2 | pos )
for b in data:
self._write_byte(b, self._vertical_invert)
self._stop()
self._disp_ctrl()

เมื่อสร้างคลาสและบันทึกลงไฟล์ชื่อ tm1640.py ได้แล้ว ก็มาดูตัวอย่างการนำไปใช้

โค้ดตัวอย่างนี้ สาธิตการเชื่อมต่อ WiFi ในขั้นตอนแรก ในขั้นตอนที่สอง จะเชื่อมต่อกับ NTP Server เพื่ออ่านข้อมูลที่ระบุวันเวลาปัจจุบัน ตั้งค่าให้วงจร RTC (Real-Time Clock) ของ ESP32

เมื่อตั้งค่าให้ RTC เป็นเวลาปัจจุบัน (UTC) ได้แล้ว จึงทำการอ่านค่าตัวเลขสำหรับชั่วโมงและนาทีในขณะนั้น (GMT+7 สำหรับประเทศไทย) แล้วนำไปแสดงผลเป็นตัวเลขบน 16x8 LED Matrix แล้วเว้นระยะเวลาก่อนทำซ้ำ

# file: tm1640_demo.py
from machine import Pin, RTC
from micropython import const
import utime as time
import ujson as json
import network
import ntptime
from tm1640 import TM1640_LED_Matrix
#----------------------------------------------------------
# Step 1: connect WiFi
wifi_config = None
try:
# read json file 'wifi_config.json' for WiFi configuration:
# { "ssid": "XXXXX", "password": "XXXXXXXX" }
with open( 'wifi_config.json' ) as f:
wifi_config = json.load(f)
except OSError:
print('Cannot open configuration file')
def connect_wifi( wifi_cfg, retries=10 ):
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect( wifi_cfg['ssid'], wifi_cfg['password'] )
while not wlan.isconnected():
retries -= 1
if retries < 0:
return None
time.sleep_ms(1000)
return wlan
wifi = connect_wifi( wifi_config )
if wifi is None:
print('WiFi connection failed...')
while True:
pass
#----------------------------------------------------------
# Step 2: connect NTP server and synchronize RTC with NTP
while True:
try:
# synchronize RTC with NTP server
ntptime.settime()
break
except OSError:
print('NTP server: connection timeout...')
# create an RTC object
rtc = RTC()
#----------------------------------------------------------
# step 3: display clock (hours and minutes)
DIGITS = [ # font characters (3x8 pixels) for digits 0-9
[0x7f,0x41,0x7f], # 0
[0x21,0x7f,0x01], # 1
[0x4f,0x49,0x79], # 2
[0x49,0x49,0x7f], # 3
[0x78,0x08,0x7f], # 4
[0x79,0x49,0x4f], # 5
[0x7f,0x49,0x4f], # 6
[0x40,0x40,0x7f], # 7
[0x7f,0x49,0x7f], # 8
[0x79,0x49,0x7f] # 9
]
DIO = const(0)
SCK = const(4)
sck_pin = Pin( SCK, Pin.OUT, value=0 )
dio_pin = Pin( DIO, Pin.OUT, value=0 )
disp = TM1640_LED_Matrix(sck_pin, dio_pin)
disp.brightness(7)
try:
while True:
# read current datetime from RTC
tm = rtc.datetime()
tz_offset = +7
hour, minute = (tm[4]+tz_offset) % 24, tm[5]
disp.write( DIGITS[hour//10], 0 )
disp.write( DIGITS[hour%10], 4 )
disp.write( [0x14], 7 ) # show colon
disp.write( DIGITS[minute//10], 9 )
disp.write( DIGITS[minute%10], 13 )
time.sleep_ms(500)
disp.write( [0x00], 7 ) # clear colon
time.sleep_ms(500)

except KeyboardInterrupt:
pass
finally:
disp.clear()
print('Done')
ตัวอย่างการต่อวงจรทดลอง
การแสดงตัวเลขที่เป็นชั่วโมงและนาทีแบบดิจิทัลด้วย 16x8 LED Matrix

โดยสรุป เราได้เห็นตัวอย่างการเขียนโค้ด MicroPython เพื่อสร้างคลาสที่นำมาใช้กับ TM1640 16x8 LED Matrix และสาธิตการสร้าง Digital Clock ที่เชื่อมต่อกับ NTP Server ในการตั้งเวลาปัจจุบัน แล้วนำมาแสดงผลบน 16x8 LED Matrix

--

--

<rawat.s>
<rawat.s>

Written by <rawat.s>

I'm Thai and working in Bangkok/Thailand.

No responses yet