ขั้นตอนที่ 1: ต่อสายบนเบรดบอร์ด & จับมือ I2C ให้มั่น
เจ้า DoodlePi เนี่ย มันทำงานเหมือนเป็นผืนผ้าใบดิจิทัลแบบแยกส่วนเลยว่ะ แปลงสถานะอินพุตแบบไบนารี่ตรงๆ ไปลงบนจอ SH1106 ที่ใช้ I2C โปรโตคอลหลักจะเชื่อมจอ OLED เข้ากับชิป RP2040 ของ Raspberry Pi Pico แบบเนทีฟเลย พร้อมกับตั้งค่าพูลอัพให้การสื่อสารนิ่งๆ ไม่มีสะดุด

- VCC → VSYS (ขา Pico หมายเลข 39)
- GND → GND (ขา Pico หมายเลข 38)
- SDA → GP4 (ขา Pico หมายเลข 6)
- SCL → GP5 (ขา Pico หมายเลข 7)
ขั้นตอนที่ 2: ประกอบปุ่มบนเพิร์ฟบอร์ด (ถ้าอยากจัดเต็ม) & รวมร่างเมทริกซ์ปุ่ม
เราจะเอาเมทริกซ์สวิตช์กลไกมาติดบนเพิร์ฟบอร์ด เพื่อแปลงการกดปุ่มให้เป็นสถานะลอจิก การจัดวางจะจับคู่กับเวกเตอร์คาร์ทีเซียนมาตรฐานบนแกน X-Y (ขึ้น, ลง, ซ้าย, ขวา) ส่วนปุ่มเสริมจะใช้ควบคุมสถานะปากกา (ยกขึ้น/ลง) และโหมดลบแบบบูลีน วงจรกราวด์จะต่อตรงกลับไปที่เฮดเดอร์ GPIO ผ่านสายจัมเปอร์ธรรมดา

จัดวางปุ่มทั้งหกปุ่มให้จับถนัดมือ เหมือนจอยเกมนั่นแหละ
ใช้สี่ปุ่มสำหรับ ขึ้น, ลง, ซ้าย, ขวา อีกปุ่มสำหรับสลับปากกา (ยกขึ้น/ลง) และปุ่มสุดท้ายสำหรับโหมดล้าง/ยางลบ
บัดกรีปุ่มแต่ละปุ่มลงบนเพิร์ฟบอร์ด แล้วต่อสายจัมเปอร์ไปหา Pico ตามแผนภาพวงจรที่บอกไปก่อนหน้า
พี่บัดกรีปุ่มให้มันใช้งานคล้ายๆ โมดูลคีย์แพดเลย ใช้ง่ายดี
หมายเหตุ: ขั้นตอนนี้เป็นตัวเลือกเสริมนะน้อง ถ้าไม่อยากยุ่งยากก็ต่อปุ่มบนเบรดบอร์ดไปเลยง่ายกว่า
ขั้นตอนที่ 3: อัพโหลดโค้ด & จัดสรรพื้นที่ในหน่วยความจำ
ใช้ Arduino IDE เป็นที่ทำงานหลัก โดยใช้ลอจิกจากไลบรารี Adafruit GFX มาช่วยแปลงการวาดพิกเซลดิบๆ ให้เป็นคำสั่งระดับสูง สเก็ตช์ C++ ที่เตรียมไว้จะเริ่มต้นด้วยตัวแปรบูลีนชื่อ penDown เพื่อติดตามสถานะปากกา และคอยอัพเดทข้อมูลใน RAM ท้องถิ่นด้วยอาร์เรย์ที่เรียงลำดับตามการจัดวางของหน้าจอ
ใช้ Arduino IDE ในการอัพโหลดโค้ด C++ ที่ให้ไว้
อย่าลืมติดตั้ง Earle Philhower's Pico Core และไลบรารีที่จำเป็นด้วยนะ ไม่งั้นจะอัพโหลดไม่ได้ ศึกษาวิธีติดตั้งได้จากบทความสอนใช้งานทั่วไปเกี่ยวกับ Pico ใน Arduino IDE
ไลบรารีที่ต้องมี:
- Adafruit GFX Library
- Adafruit SH110X Library
- Earle Philhower's Pico Core
โค้ด:
/*
* Project Name: DoodlePi
* Designed For: Raspberry Pi Pico/Pico W
*
*
* License: GPL3+
* This project is licensed under the GNU General Public License v3.0 or later.
* You are free to use, modify, and distribute this software under the terms
* of the GPL, as long as you preserve the original license and credit the original
* author. For more details, see <https://www.gnu.org/licenses/gpl-3.0.en.html>.
*
* Copyright (C) 2025 Ameya Angadi
*
* Code Created And Maintained By: Ameya Angadi
* Last Modified On: August 15, 2025
* Version: 1.0.0
*
*/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#define OLED_I2C_ADDRESS 0x3C
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define OLED_RESET -1
Adafruit_SH1106G display = Adafruit_SH1106G(DISPLAY_WIDTH, DISPLAY_HEIGHT, &Wire, OLED_RESET);
const unsigned char Splash_Screen [] PROGMEM = {
// "DoodlePi", 128x64px
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0xf8, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xfc, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0xfd, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1c, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0x1d, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1c, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0x1d, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1c, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x07, 0x1c, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1c, 0xfc, 0x3f, 0x0f, 0xe7, 0x1f, 0x87, 0x1d, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xfe, 0x7f, 0x9f, 0xe7, 0x3f, 0xc7, 0x1d, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x39, 0xc7, 0xfd, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x39, 0xc7, 0xfd, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x39, 0xc7, 0xf9, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x3f, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x3f, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x38, 0x07, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0x1d, 0xce, 0x73, 0x9c, 0xe7, 0x39, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xfd, 0xce, 0x73, 0x9c, 0xe7, 0x39, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xfd, 0xfe, 0x7f, 0x9f, 0xe7, 0x3f, 0xc7, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x07, 0xf8, 0xfc, 0x3f, 0x0e, 0xe7, 0x1f, 0x87, 0x01, 0xc0, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x04, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x7a, 0xc4, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x4b, 0x44, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x7a, 0x04, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x42, 0x04, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x7a, 0x0e, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0
เฮ้ย น้อง! ดูโค้ดนี้สิ มันคือการสร้างรูปภาพแบบ Bitmap (บิตแมป) ด้วยการเขียนค่า Hex (เฮกซ์) ลงไปตรงๆ เลย งานแบบนี้แหละที่เรียกว่า "Low-level" จัดไปวัยรุ่น! หลักการมันก็คือ แต่ละคู่ของเลขฐานสิบหก (เช่น 0x80) จะแทนค่าสีหรือสถานะของพิกเซล (Pixel) หนึ่งจุดบนหน้าจอแบบโมโนโครม (Monochrome) หรือจอเล็กๆ พวกนี้แหละ
สังเกตดีๆ นะ ว่ามันมี pattern (แพทเทิร์น) ซ้ำๆ อยู่ ตรงนี้แหละคือศิลปะของการโปรแกรมมิ่งฮาร์ดแวร์ (Hardware Programming) บางทีก็เอาไปใช้กับจอ OLED เล็กๆ หรือพวกกราฟิกบนอุปกรณ์ฝังตัว (Embedded Device) ได้เลย
เคล็ดลับจากรุ่นพี่:
- การจะอ่านโค้ดแบบนี้ให้ออก ต้องนึกภาพเป็นตาราง หรือไม่ก็ใช้เครื่องมือช่วยแปลงเป็นภาพดู จะได้เห็นเลยว่ามันวาดอะไรอยู่ (บางทีอาจเป็นโลโก้ หรือไอคอนกวนๆ ก็ได้นะ 555)
- เวลาเขียนเอง ระวังเรื่อง Endianness (เอนเดียนเนส) ด้วยนะตัวนี้! ระบบบางตัวอาจจะอ่านไบต์สลับกัน ห้ามช็อตนะ!
- ฝึกอ่าน Hex ให้คล่อง มันมีประโยชน์เวลาดีบัก (Debug) ข้อมูลดิบ หรือทำงานกับ Protocol (โปรโตคอล) ต่างๆ
ลองเอาโค้ดนี้ไปรันในเครื่องจำลอง หรือบนบอร์ดจริงๆ ดูสิ น้องจะได้เห็นของจริง! สู้งานนะน้อง