[TH] ESP8266 and OLED

บทความนี้เป็นการเชื่อมต่อ ESP8266 เข้ากับโอแอลอีดี หรือ OLED ซึ่งเป็นแอลอีดีกราฟิกแบบ 2 สี คือ สี 0 แทนไม่แสดงจุดสี และ 1 แทนการแสดงจุดสี โดยเชื่อมต่อกับไมโครคอนโทรลเลอร์ผ่านบัส I2C โดยกล่าวถึงวิธีการใช้และฟังก์ชันสำหรับใช้งานเพื่อเป็นแนวทางและเนื้อหาอ้างอิงในการนำไปใช้ต่อไป

ภาพที่ 1 ตัวอย่างการใช้งาน OLED

ตัวควบคุมการแสดงผล

โอแอลอีดีที่ผู้เขียนใช้งานพบว่ามีตัวควบคุมการแสดงผล 2 ประเภท คือ ใช้ไอซี sh1106 หรือ ssd1306 ซึ่งโมดูลแอลอีดีมักไม่ได้ระบุไว้ และผู้ใช้งานไม่สามารถมองเห็นได้เนื่องจากถูกโมดูลแอลอีดีบังไว้ โดย OLED (มีสีฟ้า และสีขาว หรือบางรุ่นมีการกำหนดให้บางแถวเป็นสีหนึ่งและบางแถวเป็นอีกสีหนึ่ง) ที่เลือกใช้ในบทความนี้เป็นแบบ I2C ดังภาพที่ 2 และเชื่อมต่อกับขาของ esp8266 ดังภาพที่ 3

ภาพที่ 2 โมดูล OLED แบบ I2C
ภาพที่ 3 การเชื่อมต่อเข้ากับขา SDA และ SCL ของ esp8266

ไลบรารีที่ต้องใช้

import sh1106

หรือ

import ssd1306

ในการเรียกใช้ต้องทดลองว่าผลลัพธ์เป็นอย่างไร ถ้าออกมาผิดพลาดให้กลับไปเลือกอีกตัวหนึ่ง

เตรียมการ i2c

from machine import I2C, Pin
i2c = I2C(sda=Pin(4), scl=Pin(5))
oled_addr = const(0x3c)
oled = sh1106.SH1106_I2C(128,64,i2c,None,oled_addr)

หลังจากเรียกใช้ไลบรารีสำหรับตัวควบคุมแอลอีดี ขั้นตอนต่อมาคือเปิดการใช้งาน บัส I2C และสร้างตัวแปรสำหรับชี้ไปยังโมดูลแอลอีดีแบบโอแอลอีดี

แสดงข้อความ

oled.text("ข้อความ", x, y, c=1)

โดย
c คือ สีของจุด ซึ่ง 1 แทนสีสว่าง และ 0 แทนสีดำ
x,y คือ พิกัดมุมซ้ายบนของข้อความที่เริ่มต้นแสดงผล

สั่งแสดงข้อมูลที่จอแสดงผล

oled.show()

การสั่ง show( ) เป็นสั่งให้ตัวควบคุมโมดูลแอลอีดีนำข้อมูลจากบัฟเฟอร์ทั้งหมดเขียนลงโมดูลแอลอีดี ทำให้มองเห็นผลลัพธ์คำสั่งที่สั่งให้กับตัวควบคุม

สั่งเติมสี

oled.fill( 1 )		# เติมสีสว่าง
oled.fill( 0 )		# เติมสีดำ

การเติมสี เป็นการกำหนดให้สีฉากหลังของโมดูลแอลอีดีทั้งหมดเป็นสี 0 หรือ 1 เปรียบเสมือนการล้างค่าหน้าจอด้วยสี 0 หรือ 1

สั่งลงพิกเซลที่ตำแหน่ง (x,y)

oled.pixel( x, y, c )

โดย
x,y คือ พิกัดของพิกเซลซึ่งค่า x อยู่ในช่วง [0, 127] และ y อยู่ในช่วง [0, 63]
c คือ ค่าสีของพิกเซล ซึ่งมีค่าเป็น 0 หรือ 1

สั่งให้กลับสี

oled.invert( True )
oled.invert( False )

การสั่งกลับสีทำให้จุดสีถูกเปลี่ยนเป็นสีตรงกันข้าม คือ เดิมที่เป็น 0 จะเปลี่ยนเป็น 1 และจาก 1 กลายเป็น 0 ดังนั้น เมื่อนำเทคนิคการกลับสีมาใช้กับการกะพริบหน้าจอ 5 ครั้ง ในเวลา 1 วินาที จะเขียนโค้ดได้ดังนี้

for counter in range(5):
		oled.invert(True)
		time.sleep_ms(100)
		old.invert(False)
		time.sleep_ms(100)

สั่งอ่านค่าสีที่ตำแหน่ง (x,y)

c = oled.pixel( x, y )

โดย c คือ ค่าสีที่อ่านได้จากพิกัด (x,y)

สั่งวาดเส้นตรงในแนวนอน

oled.hline( x, y, w, c=1 )

โดย
x,y คือ ตำแหน่งเริ่มต้น
w คือ ความยาวของเส้น
c คือ สี

สั่งวาดเส้นตรงในแนวตั้ง

oled.vline( x, y, h, c=1 )

โดย
x,y คือ ตำแหน่งเริ่มต้น
h คือ ความยาวของเส้น
c คือ สี

สั่งวาดเส้นตรง

oled.line( x1, y1, x2, y2, c=1 )

โดย
x1,y1 คือ พิกัดเริ่มต้นของเส้นตรง
x2,y2 คือ พิกัดสิ้นสุดของเส้นตรง
c คือ สี

สั่งวาดสี่เหลี่ยม

oled.rect( x, y, w, h, c )

โดย
x,y คือ พิกัดมุมซ้ายบนของสี่เหลี่ยม
w คือ ความกว้างของสี่เหลี่ยม
h คือ ความสูงของสี่เหลี่ยม
c คือ สี

สั่งวาดสี่เหลี่ยมทึบ

oled.fill_rect( x, y, w, h, c )

โดย
x,y คือ พิกัดมุมซ้ายบนของสี่เหลี่ยม
w คือ ความกว้างของสี่เหลี่ยม
h คือ ความสูงของสี่เหลี่ยม
c คือ สี

สั่งเลื่อนหน้าจอในแกน x และ y

oled.scroll( x, y )

โดย
x คือ ตำแหน่งการเลื่อนในแกน x
y คือ ตำแหน่งการเลื่อนในแกน y
เช่น ต้องการเลื่อนหน้าจอลง 4 จุด พร้อมทั้งเลื่อนไปทางซ้าย 8 จุด สามารถสั่งงานได้เป็น

oled.scroll( -8, -4 )

การวาดภาพที่สร้างเองด้วยการลงพิกเซล

การวาดโดยใช้ข้อมูล 1 ตัวต่อ 1 พิกเซล

ขั้นตอนที่ 1 สร้างตัวแปรเก็บค่ารูปภาพ เช่น ต้องการแสดง “ก”

korkai = [
	[ 0, 0, 1, 1, 1, 1, 1, 0 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ],
	[ 0, 0, 1, 0, 0, 0, 0, 1 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ],
	[ 0, 1, 0, 0, 0, 0, 0, 1 ]
]

ขั้นตอนที่ 2 สั่งลงพิกเซล เช่น

for ch_row in range(8):
	for ch_col in range(8):
		oled.pixel( ch_col, ch_row, korkai[ch_row][ch_col] )

ขั้นตอนที่ 3 สั่งแสดงผล

oled.show( )

การวาดโดยใช้ข้อมูล 1 บิตต่อ 1 พิกเซล

ขั้นตอนที่ 1 สร้างตัวแปรเก็บค่ารูปภาพ เช่น ต้องการแสดง “ก”

korkai = [
	0b00111110,
	0b01000001,
	0b00100001,
	0b01000001,
	0b01000001,
	0b01000001,
	0b01000001,
	0b01000001
]

ขั้นตอนที่ 2 สั่งลงพิกเซล เช่น

for ch_row in range(8):
	bit = 0x80
	for ch_col in range(8):
		cl = korkai[ch_row]&bit
		oled.pixel( ch_col, ch_row, cl)
		bit >>= 1

ขั้นตอนที่ 3 สั่งแสดงผล

oled.show( )

การวาดแบบบิตและให้ตัวหนา

ให้ปรับแต่งขั้นตอนที่ 2 เพื่อสั่งวาดพิกเซล 2 จุดติดกันแทนการวาดเพียงจุดเดียว

for ch_row in range(8):
	bit = 0x80
	for ch_col in range(8):
		cl = korkai[ch_row]&bit
		oled.pixel( ch_col*2, ch_row, cl)
		oled.pixel( ch_col*2+1, ch_row, cl)
		bit >>= 1

การวาดแบบบิตและให้ตัวใหญ่ 2 เท่า

ให้ปรับแต่งขั้นตอนที่ 2 เพื่อสั่งวาดสี่เหลี่ยมแบบเติมสีขนาด 2×2 แทนการใช้พิกเซล

for ch_row in range(8):
	bit = 0x80
	for ch_col in range(8):
		cl = korkai[ch_row]&bit
		oled.fill_rect( ch_col*2, ch_row*2, 2, 2, cl)
		bit >>= 1

การวาดแบบโปร่งใส

การวาดแบบโปร่งใสหรือโปร่งแสงเป็นการตรวจสอบข้อมูลสีในการวาด คือ ถ้าเป็น 1 จึงจะลงจุดสี แต่ถ้าเป็น 0 จะไม่ลงจุดสี ซึ่งการไม่ลงจุดสีนี้มีผลทำให้ข้อมูลสีที่ลงไว้ก่อนหน้าไม่ถูกทับด้วยสี 0 ตัวอย่าง การตรวจสอบและการวาดแบบโปร่งแสงเป็นดังนี้

for ch_row in range(8):
	bit = 0x80
	for ch_col in range(8):
		cl = korkai[ch_row]&bit
		if cl:
			oled.pixel( ch_col, ch_row, 1)
		bit >>= 1

จัดเก็บบิตแม็พแบบ bytearray

ขั้นตอนที่ 1 สร้างตัวแปรเก็บค่ารูปภาพ เช่น ต้องการแสดง “ก” ซึ่งวิธีการนี้เป็นการรับประกันขนาดของข้อมูลแต่ละชุกมีขนาด 1 ไบต์

korkai = bytearray(
	[0b00111110,
	0b01000001,
	0b00100001,
	0b01000001,
	0b01000001,
	0b01000001,
	0b01000001,
	0b01000001]
)

ขั้นตอนที่ 2 สั่งลงพิกเซล เช่น

for ch_row in range(8):
	bit = 0x80
	for ch_col in range(8):
		cl = korkai[ch_row]&bit
		oled.pixel( ch_col, ch_row, cl)
		bit >>= 1

ขั้นตอนที่ 3 สั่งแสดงผล

oled.show( )

สั่งปรับความสว่าง

oled.contrast( cn )

โดย cn คือ ระดับความสว่างมีค่าอยู่ในช่วง 0 ถึง 255

การบลิต

การบลิต (blit) เป็นเทคนิคของการส่งบัฟเฟอร์ข้อมูลขนาด WxH ไปยังบัฟเฟอร์แสดงผล ทำให้ประสิทธิภาพในการส่งข้อมูลดีกว่าการสั่งแสดงพิกเซลจำนวน WxH พิกเซลด้วยการวนรอบ W*H ครั้ง

รูปแบบของข้อมูลที่นำไปใช้กับการบลิตต้องเป็นข้อมูลประเภท bytearray และรูปแบบของคำสั่งใช้งานเป็นดังนี้

oled.blit( buf, x, y )

โดย
buf คือ ข้อมูลประเภท FrameBuffer ที่เก็บข้อมูลภาพ
x,y คือ พิกัดมุมบนซ้ายของโมดูลแอลอีดีที่ใช้เริ่มต้นบลิตภาพ

การสร้างข้อมูลแบบ framebuffer มีขั้นตอนการทำดังนี้

import  framebuf
data = bytearray([ข้อมูล])
buf = framebuf.FrameBuffer( data, width, height, framebuf.MONO_HLSB)

ตัวอย่างการวาดภาพ “ก” ด้วยการบลิต

ขั้นตอนที่ 1 สร้างตัวแปรเก็บค่ารูปภาพ เช่น ต้องการแสดง “ก”

korkai = bytearray(
	[0b00111110,
	 0b01000001,
	 0b00100001,
	 0b01000001,
	 0b01000001,
	 0b01000001,
	 0b01000001,
	 0b01000001]
)

ขั้นตอนที่ 2 สร้าง FrameBuffer

buf = framebuf.FrameBuffer( korkai, 8, 8, framebuf.MONO_HLSB)

ขั้นตอนที่ 3 สั่งบลิตภาพที่ตำแหน่ง (x, y)

oled.blit(buf, x, y )

ขั้นตอนที่ 4 สั่งแสดงผล

oled.show( )

สรุป

จากบทความนี้จะพบว่า เราสามารถสั่งงานแสดงผลโมดูล OLED ผ่านบัส I2C โดยใช้สายสัญญาณเพียง 2 เส้น คือ sda และ scl พร้อมทั้งได้เรียนรู้คำสั่ง และตัวอย่างวิธีการใช้งาน สุดท้ายหวังว่าบทความนี้คงเป็นประโยชน์บ้างไม่มากก็น้อยและขอให้สนุกกับการเขียนโปรแกรมครับ

อ้างอิง

  1. SH1106 โดย robert-hh
  2. ssd1306 โดย randomnerdtutorials.com

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-06-11, 2021-06-28, 2021-09-27