โปรเจกต์ Arduino GUI Library
ต้องการ GUI ง่ายๆ สำหรับโปรเจกต์ Arduino ของคุณใช่ไหม? ลองดูนี่เลย!
ต้องการ GUI ง่ายๆ สำหรับโปรเจกต์ Arduino ของคุณใช่ไหม? ลองดูนี่เลย!
RTT-GUI คือ GUI framework แบบ open source สำหรับ embedded system โปรเจกต์นี้แยก (forked) มาจาก RT-Thread Package -- GUI Engine และได้รับการปรับโครงสร้างใหม่ (refactored) ขนานใหญ่สำหรับ Arduino

RTT-GUI ถูกสร้างขึ้นบน Arduino RT-Thread library โดย library ตัวหลังจะทำหน้าที่เตรียม low-level device drivers ให้กับตัวแรกผ่านทางการจัดการอุปกรณ์พื้นฐานและกราฟิก
/* common device operations (RT-Thread: "rtdef.h") */
struct rt_device_ops {
rt_err_t (*init)(rt_device_t dev);
rt_err_t (*open)(rt_device_t dev, rt_uint16_t oflag);
rt_err_t (*close)(rt_device_t dev);
rt_size_t (*read)(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
rt_size_t (*write)(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
rt_err_t (*control)(rt_device_t dev, int cmd, void *args);
};
/* graphic device operations (RTT-GUI: "driver.h") */
struct rtgui_graphic_driver_ops {
void (*set_pixel)(rtgui_color_t *c, int x, int y);
void (*get_pixel)(rtgui_color_t *c, int x, int y);
void (*draw_hline)(rtgui_color_t *c, int x1, int x2, int y);
void (*draw_vline)(rtgui_color_t *c, int x , int y1, int y2);
void (*draw_raw_hline)(rt_uint8_t *pixels, int x1, int x2, int y);
};
RTT-GUI มาพร้อมกับชุดฟังก์ชันกราฟิกพื้นฐาน
/* graphic functions (RTT-GUI: "dc.h") */
void rtgui_dc_draw_point(rtgui_dc_t *dc, int x, int y);
void rtgui_dc_draw_vline(rtgui_dc_t *dc, int x, int y1, int y2);
void rtgui_dc_draw_hline(rtgui_dc_t *dc, int x1, int x2, int y);
void rtgui_dc_draw_line(rtgui_dc_t *dc, int x1, int y1, int x2, int y2);
void rtgui_dc_draw_rect(rtgui_dc_t *dc, rtgui_rect_t *rect);
void rtgui_dc_fill_rect(rtgui_dc_t *dc, rtgui_rect_t *rect);
void rtgui_dc_draw_round_rect(rtgui_dc_t *dc, rtgui_rect_t *rect, int r);
void rtgui_dc_fill_round_rect(rtgui_dc_t *dc, rtgui_rect_t *rect, int r);
void rtgui_dc_draw_annulus(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r1, rt_int16_t r2, rt_int16_t start, rt_int16_t end);
void rtgui_dc_draw_pie(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r, rt_int16_t start, rt_int16_t end);
void rtgui_dc_fill_pie(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r, rt_int16_t start, rt_int16_t end);
void rtgui_dc_draw_polygon(rtgui_dc_t *dc, const int *vx, const int *vy, int count);
void rtgui_dc_fill_polygon(rtgui_dc_t *dc, const int *vx, const int *vy, int count);
void rtgui_dc_draw_circle(rtgui_dc_t *dc, int x, int y, int r);
void rtgui_dc_fill_circle(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r);
void rtgui_dc_draw_arc(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t r, rt_int16_t start, rt_int16_t end);
void rtgui_dc_draw_ellipse(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t rx, rt_int16_t ry);
void rtgui_dc_fill_ellipse(rtgui_dc_t *dc, rt_int16_t x, rt_int16_t y, rt_int16_t rx, rt_int16_t ry);
พารามิเตอร์ตัวแรกของฟังก์ชันเหล่านี้เรียกว่า device context pointer ซึ่งสามารถเรียกใช้ได้ผ่านการเรียก rtgui_dc_begin_drawing()
สีในการวาดสามารถตั้งค่าได้ด้วย RTGUI_DC_FC() ซึ่งจะเป็นการเปลี่ยนสีพื้นหน้า (foreground color) ของ widget เป้าหมาย
RTGUI_DC_FC(dc) = GREEN;
เมื่อวาดเสร็จแล้ว ควรเรียกใช้ rtgui_dc_end_drawing() เพื่อคืนค่า device context และเริ่มกระบวนการ rendering
/* device context functions (RTT-GUI: "dc.h") */
rtgui_dc_t *rtgui_dc_begin_drawing(rtgui_widget_t *owner);
void rtgui_dc_end_drawing(rtgui_dc_t *dc, rt_bool_t update);
พารามิเตอร์ของ rtgui_dc_begin_drawing():
พารามิเตอร์ของ rtgui_dc_end_drawing():
โปรดดูตัวอย่างการใช้งานในส่วน CODE
ปัจจุบัน RTT-GUI รองรับการแสดงผลตัวอักษร ASCII และตัวอักษรจีนตัวย่อ (Unicode) โดยมีขนาดฟอนต์ให้เลือก 2 ขนาด คือ 12 และ 16 พิกเซล สำหรับชุดตัวอักษรแต่ละแบบ (asc12, asc16, hz12 และ hz16)
หากมี SD card driver แนะนำให้เก็บข้อมูลฟอนต์ (ดูได้ที่นี่) ไว้ใน SD card เพื่อประหยัดพื้นที่ (ตั้งค่า CONFIG_USING_FONT_FILE == 1) โดยปกติ RTT-GUI จะตรวจสอบไดเรกทอรี /font/ เพื่อหาฟอนต์
/* font config (RTT-GUI: "guiconfig.h") */
#define CONFIG_USING_FONT_12 (0)
#define CONFIG_USING_FONT_16 (1)
#define CONFIG_USING_FONT_HZ (0)
#define CONFIG_USING_FONT_FILE (1)
/* text function (RTT-GUI: "dc.h") */
void rtgui_dc_draw_text(rtgui_dc_t *dc, const char *text, rtgui_rect_t *rect);
โปรดดูตัวอย่างการใช้งานในส่วน CODE
ปัจจุบัน RTT-GUI รองรับการถอดรหัสรูปภาพในรูปแบบดังต่อไปนี้:
ตัวถอดรหัส (decoder) ทั้งหมดเป็นทางเลือกและสามารถตั้งค่าได้
/* image decoder config (RTT-GUI: "guiconfig.h") */
#define CONFIG_USING_IMAGE_XPM (1)
#define CONFIG_USING_IMAGE_BMP (1)
#define CONFIG_USING_IMAGE_JPEG (1)
#define CONFIG_USING_IMAGE_PNG (0)
/* image functions (RTT-GUI: "image.h") */
rtgui_image_t *rtgui_image_create_from_file(const char *type, const char *fn, rt_int32_t scale, rt_bool_t load);
rtgui_image_t *rtgui_image_create_from_mem(const char *type, const rt_uint8_t *data, rt_size_t size, rt_int32_t scale, rt_bool_t load);
void rtgui_image_destroy(rtgui_image_t *image);
void rtgui_image_get_rect(rtgui_image_t *image, rtgui_rect_t *rect);
void rtgui_image_blit(rtgui_image_t *image, rtgui_dc_t *dc, rtgui_rect_t *rect);
โปรดดูตัวอย่างการใช้งานในส่วน CODE
ฟังก์ชันที่น่าสนใจที่สุดอยู่ตรงนี้! RTT-GUI เป็น framework รูปแบบ client-server โดย server thread จะเริ่มทำงานโดยอัตโนมัติเพื่อส่งกระจาย events ไปยัง clients ส่วน clients ก็คือ widgets ต่างๆ ที่ทำหน้าที่จัดการ event นั้นๆ
เช่นเดียวกับกลไกลการส่งต่อ event อื่นๆ event ของ RTT-GUI จะถูกส่งต่อจาก widget ชั้นบนสุด (Window หลัก) ไปยัง widget ชั้นในสุด และการส่งต่อจะหยุดลงเมื่อ event นั้นถูกจัดการแล้ว
มาเจาะลึกที่โค้ดกัน ขั้นตอนแรกคือการสร้าง RTT-GUI application
CREATE_APP_INSTANCE(app, RT_NULL, "Demo App");
พารามิเตอร์ของ CREATE_APP_INSTANCE():
RT_NULL ได้ทุกๆ RTT-GUI application จะต้องเชื่อมโยงกับ thread และแต่ละ thread สามารถเชื่อมโยงได้เพียงหนึ่ง RTT-GUI application เท่านั้น ดังนั้นเมื่อเรียกใช้ CREATE_APP_INSTANCE() แอปพลิเคชันใหม่จะเชื่อมโยงกับ thread ที่สร้างมันขึ้นมา หากมีแอปพลิเคชันอื่นเชื่อมโยงอยู่แล้ว CREATE_APP_INSTANCE() จะล้มเหลว (ในกรณีนี้ app == RT_NULL)
ขั้นตอนต่อไปคือการสร้าง Window หลักเพื่อบรรจุ widgets อื่นๆ ทั้งหมด
main_win = CREATE_MAIN_WIN(win_event_handler, "Demo Window",
RTGUI_WIN_STYLE_DEFAULT);
พารามิเตอร์ของ CREATE_MAIN_WIN():
ภายในฟังก์ชันจัดการ event เรายังสามารถเรียกใช้ตัวจัดการ event เริ่มต้นของ Window (โดยใช้ DEFAULT_HANDLER(obj)()) และจัดการเฉพาะ event ที่เราสนใจเป็นพิเศษได้ (เช่น PAINT)
rt_bool_t win_event_handler(void *obj, rtgui_evt_generic_t *evt) {
rt_bool_t done = RT_FALSE;
if (DEFAULT_HANDLER(obj)) {
done = DEFAULT_HANDLER(obj)(obj, evt);
}
if (IS_EVENT_TYPE(evt, PAINT)) {
done = show_demo(TO_WIN(obj));
}
return done;
}
การเตรียมการเสร็จสิ้นแล้ว ต่อไปลองเพิ่ม widgets กัน
label = CREATE_LABEL_INSTANCE(main_win, RT_NULL, RT_NULL, "Label Demo");
WIDGET_TEXTALIGN_SET(label, CENTER_HORIZONTAL);
btn = CREATE_BUTTON_INSTANCE(main_win, RT_NULL, NORMAL, "Button Demo");
พารามิเตอร์ของ CREATE_LABEL_INSTANCE():
rtgui_rect_t)พารามิเตอร์ของ CREATE_BUTTON_INSTANCE():
ปกติแล้วคุณสมบัติการจัดวางข้อความของ widget จะเป็น LEFT และ CENTER_VERTICAL ซึ่งสามารถเปลี่ยนได้โดยใช้ WIDGET_TEXTALIGN_SET()
CREATE_BUTTON_INSTANCE() ไม่ได้มีพารามิเตอร์สำหรับตั้งค่าตำแหน่งและขนาด อย่างไรก็ตาม สำหรับ widget ใดๆ ก็ตาม สามารถเปลี่ยนค่าเหล่านั้นได้โดยใช้ rtgui_widget_set_rect()
อะไรนะ? คุณกำลังบอกว่าการตั้งค่าตำแหน่งและขนาดด้วยตัวเองให้ทุก widget มันยุ่งยากเกินไปใช่ไหม?
ข่าวดีคือเราสามารถใช้ sizer (Box) เพื่อจัดการให้โดยอัตโนมัติได้
sizer = CREATE_BOX_INSTANCE(main_win, RTGUI_HORIZONTAL, 0);
WIDGET_ALIGN_SET(label, STRETCH);
WIDGET_ALIGN_SET(btn, STRETCH);
rtgui_box_layout(sizer);
พารามิเตอร์ของ CREATE_BOX_INSTANCE():
Container หรือ widget ที่ "สืบทอด" มาจาก Container (เช่น Window)RTGUI_HORIZONTAL หรือ RTGUI_VERTICALเมื่อสร้างเสร็จแล้ว sizer จะถูกแนบเข้ากับ widget แม่ โดย rtgui_box_layout() จะกระตุ้นให้เกิดการจัดเรียงตำแหน่งและขนาดของ widget ลูกภายใต้ widget แม่นั้นใหม่
ในการระบุว่า widget สามารถปรับเปลี่ยนตาม sizer ได้ ให้ตั้งค่าบิต STRETCH (ในทิศทางตาม sizer) และ EXPAND (ในทิศทางตรงข้าม sizer) ในคุณสมบัติการจัดวาง
ในตัวอย่างข้างต้น มีการตั้งค่าเพียง STRETCH เท่านั้น เหตุผลคือสำหรับ Label และ Button จะมีค่าเริ่มต้นสำหรับความสูงและความกว้างขั้นต่ำอยู่แล้ว สำหรับ widget อื่นๆ จำเป็นต้องตั้งค่าบิต EXPAND หรือความสูงขั้นต่ำ (โดยใช้ WIDGET_SETTER(min_height)()) เพื่อให้ทำงานได้อย่างถูกต้อง
ขั้นตอนสุดท้ายคือการแสดง Window หลักและเริ่มการทำงานของ RTT-GUI application
rtgui_win_show(main_win, RT_FALSE);
rtgui_app_run(app);
DELETE_WIN_INSTANCE(main_win);
rtgui_app_uninit(app);
พารามิเตอร์ของ rtgui_win_show():
WindowWindow หรือไม่พารามิเตอร์ของ rtgui_app_run():
rtgui_app_run() จะเรียกใช้งาน ตัวจัดการ event ของแอปพลิเคชัน และจะไม่คืนค่ากลับมาจนกว่า Window หลักจะถูกปิดลง จากนั้น DELETE_WIN_INSTANCE() และ rtgui_app_uninit() จะทำหน้าที่ทำลาย widget ลูกและคืนทรัพยากร
นอกจากการออกแบบผ่านโค้ดโปรแกรมแล้ว ยังมีการตั้งค่า GUI แบบข้อความที่มีลักษณะคล้าย JSON ให้ใช้งานด้วย การออกแบบเดียวกันกับในหัวข้อที่แล้วสามารถเปลี่ยนเป็นสคริปต์ได้ดังนี้
APP: {
PARAM: {
// name, handler
"Demo App", NULL,
},
MWIN: {
PARAM: {
// title, handler
"Demo Window", hdl,
},
BOX: {
PARAM: {
// orient, border size
// orient: 1, HORIZONTAL; 2, VERTICAL
1, 0,
},
ID: 0,
},
LABEL: {
PARAM: {
// size, handler, text
NULL, NULL, "Label Demo",
},
// CENTER_HORIZONTAL
TEXTALIGN: 0x01,
// RTGUI_ALIGN_STRETCH
ALIGN: 0x20,
},
BUTTON: {
PARAM: {
// handler, type, text
// type: 0x00, NORMAL; 0x10, PUSH
NULL, 0, "Button Demo",
},
// RTGUI_ALIGN_STRETCH
ALIGN: 0x20,
},
},
}
APP คือตัวแทนของ RTT-GUI application และจะเป็น element ราก (root) ของสคริปต์การออกแบบเสมอ
ในตัวอย่างด้านบน มี sub-elements สองตัวภายใน APP คือ PARAM และ MWIN
PARAM คือ element สำหรับกำหนดคุณสมบัติที่ใช้เป็นพารามิเตอร์ส่งไปยัง constructor ของ widget ซึ่งต้องเป็น sub-element แรกของ element แม่เสมอ
ข้อความใดๆ ระหว่าง "//" ถึง "\n" (การขึ้นบรรทัดใหม่) คือ comment ซึ่ง parser จะข้ามส่วนนี้ไป
MWIN คือ Window หลัก ส่วน element WIN จะใช้สำหรับ Window ทั่วไป โดย RTT-GUI application หนึ่งชุดสามารถมี Window ทั่วไปได้หลายอัน แต่มี Window หลักได้เพียงอันเดียว
ภายใน MWIN ประกอบด้วย BOX, LABEL และ BUTTON ส่วนที่เหลือคือ element กำหนดคุณสมบัติ ซึ่งต้องวางไว้หลัง PARAM และก่อนหน้า element ของ widget ใดๆ
TEXTALIGN และ ALIGN คือการกำหนดการจัดวางข้อความและการจัดวาง widget (พฤติกรรมของ sizer)
ID เป็น element คุณสมบัติพิเศษ หากต้องการอ้างอิง widget ที่กำหนดในสคริปต์ (เช่น BOX) จากโค้ด sketch เราต้องแจ้งให้ parser ทราบโดยใช้ ID โดยค่าของ ID ต้องไม่ซ้ำกันและเริ่มจาก 0
สคริปต์การออกแบบทั้งหมดสามารถเก็บไว้ในตัวแปรแบบ string ในโค้ด sketch หรือเก็บเป็นไฟล์ข้อความใน SD card ก็ได้ (มีตัวอย่างให้ดูทั้งสองแบบ)
ในฝั่งโค้ด sketch ขั้นตอนแรกคือเรียกใช้ rtgui_design_init() เพื่อตั้งค่า parser
design_contex_t ctx;
const hdl_tbl_entr_t hdl_tbl[] = {
{ "hdl", (void *)win_event_handler },
{ RT_NULL, RT_NULL },
};
obj_tbl_entr_t obj_tbl[1];
rtgui_design_init(&ctx, design_read, hdl_tbl, obj_tbl, 1));
พารามิเตอร์ของ rtgui_design_init():
ฟังก์ชันสำหรับอ่านแบบร่าง (Design reading function) เป็นฟังก์ชันที่ผู้ใช้กำหนดขึ้น เพื่อให้ parser ใช้อ่านสคริปต์ เมื่อสคริปต์ถูกเก็บไว้ในตัวแปร string ฟังก์ชันอาจถูกกำหนดไว้ดังนี้
char design[] = "\\
APP: {\
\\
PARAM: {\
\\
// name, handler\
\\
\\"Demo App\\", NULL,\
\\
},\
\\
\
\\
...
}\
\\
";
uint32_t offset = 0;
rt_err_t design_read(char **buf, rt_uint32_t *sz) {
if (offset >= sizeof(design)) {
*sz = 0;
return -RT_EEMPTY;
}
*buf = design;
*sz = sizeof(design);
offset += *sz;
return RT_EOK;
}
พารามิเตอร์ของ design_read():
เมื่อสคริปต์ถูกเก็บไว้เป็นไฟล์ข้อความ ฟังก์ชันอาจถูกกำหนดไว้ดังนี้
#define DESIGN_FILE "/design/demo.gui"
char buf[512];
rt_err_t design_read(char **_buf, rt_uint32_t *sz) {
*sz = (rt_uint32_t)read(designFile, buf, sizeof(buf));
*_buf = buf;
return RT_EOK;
}
ตารางฟังก์ชันจัดการ (Handler function table) ต้องรวมฟังก์ชันจัดการทั้งหมดที่อ้างถึงในสคริปต์ ในแต่ละแถว รายการแรกคือชื่อ handler (ตามที่ระบุในสคริปต์) และรายการที่สองคือ pointer ของฟังก์ชันจัดการนั้น โปรดทราบว่าตารางนี้ต้องลงท้ายด้วย NULL หรืออีกนัยหนึ่งคือแถวสุดท้ายต้องเป็น { RT_NULL, RT_NULL }
ตารางวัตถุ (Object table) ถูกใช้งานโดย parser เพื่อเก็บ pointer ของ widgets ที่มีคุณสมบัติ ID ตัวอย่างเช่น ถ้าค่า ID คือ 1 pointer ของ widget นั้นจะถูกเก็บไว้ในช่องที่สองของ object table
ขั้นตอนต่อไปคือการประมวลผลการออกแบบโดยใช้ rtgui_design_parse() ตัวอย่างต่อไปนี้สมมติว่าสคริปต์ถูกเก็บไว้เป็นไฟล์ข้อความ
int designFile = -1;
designFile = open(DESIGN_FILE, O_RDONLY);
rtgui_design_parse(&ctx);
close(designFile);
เมื่อประมวลผลเสร็จสิ้น สามารถเข้าถึง pointer ของ widget ที่ต้องการได้จาก object table
sizer = (rtgui_box_t *)obj_tbl[0];
rtgui_box_layout(sizer);
Pointer ของ RTT-GUI application และ Window หลัก จะมีให้ใช้งานใน parser context
rtgui_win_show(ctx.win, RT_FALSE);
rtgui_app_run(ctx.app);
DELETE_WIN_INSTANCE(ctx.win);
rtgui_app_uninit(ctx.app);
คุณอาจสังเกตเห็นความแตกต่างของการแสดงผลหลังจากรันทั้งสองตัวอย่าง: สำหรับตัวอย่างการออกแบบแบบไดนามิก จะไม่มีแถบหัวเรื่อง (title bar) บน Window หลัก เหตุผลคือเมื่อสร้าง Window หลัก parser จะใช้รูปแบบเริ่มต้นคือ RTGUI_WIN_STYLE_MAINWIN อย่างไรก็ตาม ในอีกตัวอย่างหนึ่ง เราได้กำหนดรูปแบบอย่างชัดเจนว่าเป็น RTGUI_WIN_STYLE_DEFAULT (เพื่อให้แสดง Window หลักเหมือนเป็น Window ปกติ)
เมื่อเปิดใช้งานการรองรับ BMP (ตั้งค่า CONFIG_USING_IMAGE_BMP == 1) จะมีฟังก์ชันจับภาพหน้าจอ screenshot() เพื่อบันทึกสิ่งที่แสดงผลอยู่บนอุปกรณ์กราฟิกในขณะนั้นลงใน SD card นอกจากนี้ยังสามารถเรียกใช้งานผ่าน FinSH (screenshot) หรือ MSH (prtscn) ได้โดยการพิมพ์คำสั่งต่อไปนี้
msh />prtscn demo.bmp
รูปภาพด้านล่างถูกบันทึกด้วยตัวอย่างแรกในส่วน CODE
ฮาร์ดแวร์ต่อไปนี้ได้รับการรองรับพร้อมใช้งานโดย Arduino RT-Thread (v0.7.8) และ RTT-GUI (v0.7.1):
Adafruit 2.8" TFT Touch Shield v2
Module OLED ทั่วไปขนาด 0.96"
/* hardware config (RT-Thread: "rtconfig.h") */
// #define CONFIG_USING_ADAFRUIT_TFT_CAPACITIVE
// #define CONFIG_USING_TINYSCREEN
// #define CONFIG_USING_SSD1306_SPI4
/* RT-Thread device name (RTT-GUI: "guiconfig.h") */
#define CONFIG_GUI_DEVICE_NAME "ILI9341" // RGB565
#define CONFIG_TOUCH_DEVICE_NAME "FT6206"
// #define CONFIG_GUI_DEVICE_NAME "SSD1331" // RGB565
// #define CONFIG_KEY_DEVICE_NAME "BTN"
// #define CONFIG_GUI_DEVICE_NAME "SSD1306" // MONO
/* color */
#define CONFIG_USING_MONO (0)
#define CONFIG_USING_RGB565 (1)
#define CONFIG_USING_RGB565P (0)
#define CONFIG_USING_RGB888 (0)
เราสามารถเปิดใช้งานการรองรับฮาร์ดแวร์ได้ดังนี้
Adafruit 2.8" TFT Touch Shield v2
/* hardware config (RT-Thread: "rtconfig.h") */
#define CONFIG_USING_ADAFRUIT_TFT_CAPACITIVE
/* RT-Thread device name (RTT-GUI: "guiconfig.h") */
#define CONFIG_GUI_DEVICE_NAME "ILI9341"
#define CONFIG_TOUCH_DEVICE_NAME "FT6206"
/* color */
#define CONFIG_USING_MONO (0)
#define CONFIG_USING_RGB565 (1)
#define CONFIG_USING_RGB565P (0)
#define CONFIG_USING_RGB888 (0)
/* hardware config (RT-Thread: "rtconfig.h") */
#define CONFIG_USING_TINYSCREEN
/* RT-Thread device name (RTT-GUI: "guiconfig.h") */
#define CONFIG_GUI_DEVICE_NAME "SSD1331"
#define CONFIG_KEY_DEVICE_NAME "BTN"
/* color */
#define CONFIG_USING_MONO (0)
#define CONFIG_USING_RGB565 (1)
#define CONFIG_USING_RGB565P (0)
#define CONFIG_USING_RGB888 (0)
Module OLED ทั่วไปขนาด 0.96"
/* hardware config (RT-Thread: "rtconfig.h") */
#define CONFIG_USING_SSD1306_SPI4
/* RT-Thread device name (RTT-GUI: "guiconfig.h") */
#define CONFIG_GUI_DEVICE_NAME "SSD1306"
/* color */
#define CONFIG_USING_MONO (1)
#define CONFIG_USING_RGB565 (0)
#define CONFIG_USING_RGB565P (0)
#define CONFIG_USING_RGB888 (0)



นอกจากตัวอย่างที่กล่าวมาข้างต้นแล้ว ยังมี sketch ตัวอย่าง "Pic Show" และ "File Browser" ให้เลือกใช้ทั้งแบบเขียนโปรแกรมโดยตรงและแบบ dynamic design เชิญทดลองเล่นตัวอย่างเหล่านี้และขอให้สนุกครับ!
(GIF ต่อไปนี้ถูกบันทึกจาก RTT-GUI เวอร์ชันเก่า ซึ่งในเวอร์ชันล่าสุดจะมีรูปลักษณ์ใหม่ที่เปลี่ยนไป)


สนับสนุนเพื่อรับ Source Code หรือแอปพลิเคชันสำหรับโปรเจกต์นี้