ไลบรารีกราฟิกสี (Colour Graphics Library)
นี่คือไลบรารีกราฟิกสีขนาดเล็กสำหรับจอแสดงผล OLED Colour SPI 96×64 ที่ใช้ ชิปไดรเวอร์ SD1331 ซึ่งช่วยให้คุณสามารถพล็อตจุดเส้นเติมสี่เหลี่ยมและเปิดและข้อความที่มีอักขระขนาดเล็กหรือใหญ่:
การใช้งานจอ OLED Display SSD1331 ด้วย ATtiny85
OLED Display SSD1331 โมดูลนี้ จะแตกต่างจากไลบรารีการแสดงผล SPI OLED อื่น ๆ ซึ่งส่วนใหญ่ ไม่จำเป็นต้องมีบัฟเฟอร์หน่วยความจำทำให้สามารถรันบนโปรเซสเซอร์ใดก็ได้ รวมทั้ง ATtiny85 โดยใช้เพียง 3 ขาในการให้จอแสดงผลทำงาน โดยมี 2 ขา ของ ATtiny85 ที่เหลือเพื่อเชื่อมต่อกับอุปกรณ์อื่น ๆ เช่นเซ็นเซอร์ I2C
OLED Display SSD1331 Module
การแสดงผลนี้ใช้ชิปไดรเวอร์ SD1331 ซึ่งมีเอกลักษณ์เฉพาะในการมีคำสั่งตัวเร่งกราฟิกที่ช่วยให้คุณสามารถลากเส้นและสี่เหลี่ยมได้โดยไม่ต้องเขียนลงในหน่วยความจำข้อมูลกราฟิก คำสั่งตัวเร่งกราฟิกนั้นเร็วมาก วิธีปกติในการล้างหน้าจอคือการเขียนเลขศูนย์ลงในหน่วยความจำข้อมูลกราฟิกทั้งหมดและขั้นตอนการทดสอบที่ฉันเขียนเพื่อทำสิ่งนี้ใช้เวลา 91 มิลลิวินาที การใช้คำสั่ง Clear Window graphics Accelerator ใช้เวลาน้อยกว่าหนึ่งมิลลิวินาทีซึ่งเร็วกว่า 100 เท่า!
ด้วยคำสั่งตัวเร่งกราฟิกทำให้สามารถสร้างไลบรารีกราฟิกที่ไม่จำเป็นต้องเขียนข้อมูลโดยตรงไปยังหน่วยความจำแสดงผลโดยตรง นอกเหนือจากความรวดเร็วแล้วยังมีข้อได้เปรียบเพิ่มเติมในการเพิ่มขา DC ซึ่งสามารถผูกไว้ต่ำอย่างถาวรได้ ตอนนี้ ATtiny85 มีขาว่าง 2 ขา ซึ่งเพียงพอที่จะให้อินเทอร์เฟซ I2C เพื่อเชื่อมต่อเซ็นเซอร์และอุปกรณ์อื่น ๆ
ขั้นตอนการทํางาน
1 : ทำเครื่องโปรแกรม AVR เพื่อใช้อัพโหลดโปรแกรม
ขั้นตอนการใช้บอร์ด Arduino UNO เป็น เครื่องเขียนโปรแกรม ตามลิงค์ด้านล่าง
2 : อัพโหลดโปรแกรมให้กับ ATtiny85
เปิดโปรแกรม Arduino IDE เขียนโปรแกรมและอัพโหลดโค้ดด้านล่างนี้ ไปที่ ATtiny85
// ATtiny85 Pins
int const data = 1;
int const cs = 3;
int const clk = 4;
// Character set for text - stored in program memory
const uint8_t CharMap[96][6] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 },
{ 0x00, 0x07, 0x00, 0x07, 0x00, 0x00 },
{ 0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00 },
{ 0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00 },
{ 0x23, 0x13, 0x08, 0x64, 0x62, 0x00 },
{ 0x36, 0x49, 0x56, 0x20, 0x50, 0x00 },
{ 0x00, 0x08, 0x07, 0x03, 0x00, 0x00 },
{ 0x00, 0x1C, 0x22, 0x41, 0x00, 0x00 },
{ 0x00, 0x41, 0x22, 0x1C, 0x00, 0x00 },
{ 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00 },
{ 0x08, 0x08, 0x3E, 0x08, 0x08, 0x00 },
{ 0x00, 0x80, 0x70, 0x30, 0x00, 0x00 },
{ 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 },
{ 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 },
{ 0x20, 0x10, 0x08, 0x04, 0x02, 0x00 },
{ 0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00 },
{ 0x00, 0x42, 0x7F, 0x40, 0x00, 0x00 },
{ 0x72, 0x49, 0x49, 0x49, 0x46, 0x00 },
{ 0x21, 0x41, 0x49, 0x4D, 0x33, 0x00 },
{ 0x18, 0x14, 0x12, 0x7F, 0x10, 0x00 },
{ 0x27, 0x45, 0x45, 0x45, 0x39, 0x00 },
{ 0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00 },
{ 0x41, 0x21, 0x11, 0x09, 0x07, 0x00 },
{ 0x36, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x46, 0x49, 0x49, 0x29, 0x1E, 0x00 },
{ 0x00, 0x00, 0x14, 0x00, 0x00, 0x00 },
{ 0x00, 0x40, 0x34, 0x00, 0x00, 0x00 },
{ 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x14, 0x14, 0x14, 0x14, 0x14, 0x00 },
{ 0x00, 0x41, 0x22, 0x14, 0x08, 0x00 },
{ 0x02, 0x01, 0x59, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00 },
{ 0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x36, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x22, 0x00 },
{ 0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x49, 0x49, 0x49, 0x41, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x01, 0x00 },
{ 0x3E, 0x41, 0x41, 0x51, 0x73, 0x00 },
{ 0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00 },
{ 0x00, 0x41, 0x7F, 0x41, 0x00, 0x00 },
{ 0x20, 0x40, 0x41, 0x3F, 0x01, 0x00 },
{ 0x7F, 0x08, 0x14, 0x22, 0x41, 0x00 },
{ 0x7F, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00 },
{ 0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00 },
{ 0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00 },
{ 0x7F, 0x09, 0x09, 0x09, 0x06, 0x00 },
{ 0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00 },
{ 0x7F, 0x09, 0x19, 0x29, 0x46, 0x00 },
{ 0x26, 0x49, 0x49, 0x49, 0x32, 0x00 },
{ 0x03, 0x01, 0x7F, 0x01, 0x03, 0x00 },
{ 0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00 },
{ 0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00 },
{ 0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00 },
{ 0x63, 0x14, 0x08, 0x14, 0x63, 0x00 },
{ 0x03, 0x04, 0x78, 0x04, 0x03, 0x00 },
{ 0x61, 0x59, 0x49, 0x4D, 0x43, 0x00 },
{ 0x00, 0x7F, 0x41, 0x41, 0x41, 0x00 },
{ 0x02, 0x04, 0x08, 0x10, 0x20, 0x00 },
{ 0x00, 0x41, 0x41, 0x41, 0x7F, 0x00 },
{ 0x04, 0x02, 0x01, 0x02, 0x04, 0x00 },
{ 0x40, 0x40, 0x40, 0x40, 0x40, 0x00 },
{ 0x00, 0x03, 0x07, 0x08, 0x00, 0x00 },
{ 0x20, 0x54, 0x54, 0x78, 0x40, 0x00 },
{ 0x7F, 0x28, 0x44, 0x44, 0x38, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x28, 0x00 },
{ 0x38, 0x44, 0x44, 0x28, 0x7F, 0x00 },
{ 0x38, 0x54, 0x54, 0x54, 0x18, 0x00 },
{ 0x00, 0x08, 0x7E, 0x09, 0x02, 0x00 },
{ 0x18, 0xA4, 0xA4, 0x9C, 0x78, 0x00 },
{ 0x7F, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x00, 0x44, 0x7D, 0x40, 0x00, 0x00 },
{ 0x20, 0x40, 0x40, 0x3D, 0x00, 0x00 },
{ 0x7F, 0x10, 0x28, 0x44, 0x00, 0x00 },
{ 0x00, 0x41, 0x7F, 0x40, 0x00, 0x00 },
{ 0x7C, 0x04, 0x78, 0x04, 0x78, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x78, 0x00 },
{ 0x38, 0x44, 0x44, 0x44, 0x38, 0x00 },
{ 0xFC, 0x18, 0x24, 0x24, 0x18, 0x00 },
{ 0x18, 0x24, 0x24, 0x18, 0xFC, 0x00 },
{ 0x7C, 0x08, 0x04, 0x04, 0x08, 0x00 },
{ 0x48, 0x54, 0x54, 0x54, 0x24, 0x00 },
{ 0x04, 0x04, 0x3F, 0x44, 0x24, 0x00 },
{ 0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00 },
{ 0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00 },
{ 0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00 },
{ 0x44, 0x28, 0x10, 0x28, 0x44, 0x00 },
{ 0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00 },
{ 0x44, 0x64, 0x54, 0x4C, 0x44, 0x00 },
{ 0x00, 0x08, 0x36, 0x41, 0x00, 0x00 },
{ 0x00, 0x00, 0x77, 0x00, 0x00, 0x00 },
{ 0x00, 0x41, 0x36, 0x08, 0x00, 0x00 },
{ 0x02, 0x01, 0x02, 0x04, 0x02, 0x00 },
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 },
};
// OLED 96x64 colour display **********************************************
// Initialisation sequence for OLED module
int const InitLen = 6;
const unsigned char Init[InitLen] PROGMEM = {
0xA0, // Driver remap and colour depth
0x22, // COM split, flip horizontal
0xA8, 0x3F, // Multiplex
0xAD, 0x8E, // External supply
};
// Send a byte to the display
void Send (uint8_t d) {
for (uint8_t bit = 0x80; bit; bit >>= 1) {
PINB = 1<<clk; // clk low
if (d & bit) PORTB = PORTB | (1<<data); else PORTB = PORTB & ~(1<<data);
PINB = 1<<clk; // clk high
}
}
void InitDisplay () {
PINB = 1<<cs; // cs low
for (uint8_t c=0; c<InitLen; c++) Send(pgm_read_byte(&Init[c]));
PINB = 1<<cs; // cs high
}
// Display off = 0, on = 1
void DisplayOn (uint8_t on) {
PINB = 1<<cs; // cs low
Send(0xAE + on);
PINB = 1<<cs; // cs high
}
// Graphics **********************************************
// Global plot parameters
uint8_t x0 = 0;
uint8_t y0 = 0;
uint8_t ForeR = 0x3F, ForeG = 0x3F, ForeB = 0x3F;
uint8_t BackR = 0x00, BackG = 0x00, BackB = 0x00;
uint8_t Scale = 1; // Text size - 2 for big characters
// Clear display
void ClearDisplay () {
PINB = 1<<cs; // cs low
Send(0x25); // Clear Window
Send(0); Send(0); Send(95); Send(63);
PINB = 1<<cs; // cs high
delay(1);
}
void MoveTo (uint8_t x, uint8_t y) {
x0 = x; y0 = y;
}
// Draw line to (x,y) in foreground colour
void DrawTo (uint8_t x, uint8_t y) {
PINB = 1<<cs; // cs low
Send(0x21); // Draw Line
Send(x0); Send(y0); Send(x); Send(y);
Send(ForeR); Send(ForeG); Send(ForeB);
PINB = 1<<cs; // cs high
x0 = x; y0 = x;
}
// Plot a point at (x,y)
void PlotPoint (uint8_t x, uint8_t y) {
MoveTo(x, y);
DrawTo(x, y);
}
// Draw a rectangle in foreground colour optionally filled with background colour
void DrawRect (boolean filled, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
PINB = 1<<cs; // cs low
Send(0x26); Send(filled); // Enable fill
Send(0x22); // Draw rectangle
Send(x1); Send(y1); Send(x2); Send(y2);
Send(ForeR); Send(ForeG); Send(ForeB);
Send(BackR); Send(BackG); Send(BackB);
PINB = 1<<cs; // cs high
delay(1);
}
// Plot character in foreground colour
void PlotChar (uint8_t ch) {
PINB = 1<<cs; // cs low
for (uint8_t c = 0 ; c < 6; c++) { // Column range
uint8_t bits = pgm_read_byte(&CharMap[ch-32][c]);
uint8_t r = 0;
while (bits) {
while ((bits & 1) == 0) {r++; bits = bits>>1; }
uint8_t on = (7-r)*Scale;
while ((bits & 1) != 0) {r++; bits = bits>>1; }
uint8_t off = (7-r)*Scale+1;
for (int i=0; i<Scale; i++) {
uint8_t h = x0+c*Scale+i;
Send(0x21); // Draw line
Send(h); Send(y0+on); Send(h); Send(y0+off);
Send(ForeR); Send(ForeG); Send(ForeB);
}
}
}
PINB = 1<<cs; // cs high
x0 = x0+6*Scale;
}
// Plot text from program memory
void PlotText(PGM_P p) {
while (1) {
char c = pgm_read_byte(p++);
if (c == 0) return;
PlotChar(c);
}
}
// Setup **********************************************
void setup() {
// Define pins
DDRB = 1<<clk | 1<<cs | 1<<data; // All outputs
PORTB = 1<<clk | 1<<cs; // clk and cs high
InitDisplay();
ClearDisplay();
DisplayOn(1);
}
// Demo display
void loop () {
MoveTo(1, 56);
ForeR=ForeG=ForeB=0x3F; // White
PlotText(PSTR("Graphics Display"));
for (int x=-48; x<48; x++) {
for (int y=-26; y<26; y++) {
int fun = (x * (x + y) + y * y)/8;
ForeB = abs((fun & 0x3F)-32);
ForeG = abs(((fun + 12) & 0x3F)-32);
ForeR = abs(((fun + 24) & 0x3F)-32);
PlotPoint(x+48, y+26);
}
}
for(;;);
}
3 : อธิบายโค้ด การเขียนลงจอแสดงผล
ATtiny85 และโปรเซสเซอร์ AVR อื่น ๆ รองรับการสลับบิตอย่างน้อยหนึ่งบิตในพอร์ตดังนั้นหากคุณตั้งค่าขาทั้งหมดเป็นสถานะปิดใช้งานเมื่อเริ่มต้นเพื่อความเร็วในการเข้าถึงการแสดงผลสามารถสลับขาที่เหมาะสมเพื่อเปิดหรือปิดใช้งานได้
ฟังก์ชั่น Send () จะส่งไบต์ไปยังจอแสดงผลโดยการสลับขา clock , clk สำหรับแต่ละบิตบนขา data:
void Send (uint8_t d) {
for (uint8_t bit = 0x80; bit; bit >>= 1) {
PINB = 1<<clk; // clk low
if (d & bit) PORTB = PORTB | (1<<data); else PORTB = PORTB & ~(1<<data);
PINB = 1<<clk; // clk high
}
}
ก่อนและหลังเข้าถึงจอแสดงผลคุณต้องสลับพินเลือกชิป cs ด้วยคำสั่ง:
PINB = 1<<cs;
การล้างการแสดงผล
ในการล้างการแสดงผลเราใช้คำสั่ง Clear Window ของตัวเร่งกราฟิก (graphics accelerator):
void ClearDisplay () {
PINB = 1<<cs; // cs low
Send(0x25); // Clear Window
Send(0); Send(0); Send(95); Send(63);
PINB = 1<<cs; // cs high
delay(1);
}
โปรดสังเกตว่าคำสั่งนี้และคำสั่งอื่น ๆ บางคำสั่งมีการหน่วงเวลา 1ms เพื่อให้คำสั่งดำเนินการ แม้ว่าจะไม่พบสิ่งนี้ที่กล่าวถึงใน datasheet แต่ก็พบว่ามันจำเป็นในทางปฏิบัติ
graphics accelerator เป็นอุปกรณ์อิเลคโทรนิคส์ขนาดเล็ก ซึ่งให้โปรแกรมคอมพิวเตอร์สามารถ off load การส่งและ refresh ภาพไปที่จอภาพ และคำนวณการใช้ Special effect จาก 2 มิติ เป็น 3 มิติ graphics accelerator จะเพิ่มความเร็วในการแสดงภาพบนจอ เช่น การแสดงภาพขนาดใหญ่ หรือเกมส์ แบบ inter active ซึ่งต้องการภาพที่ตอบสนองต่อผู้ใช้ได้เร็ว
สี
องค์ประกอบสีแดงสีน้ำเงินและสีเขียวของสีพื้นหน้าและพื้นหลังถูกกำหนดโดยตัวแปร (global variables) ที่ประกาศไว้ภายนอกฟังก์ชันหลัก 6 ตัวแปร ในขั้นต้นจะตั้งค่าเป็น 0x3F สีขาวและ 0x00 สีดำตามลำดับ:
uint8_t ForeR = 0x3F, ForeG = 0x3F, ForeB = 0x3F;
uint8_t BackR = 0x00, BackG = 0x00, BackB = 0x00;
วาดเส้นและพล็อตจุด
เขียนกราฟิกพื้นฐานสำหรับการพล็อตจุดและวาดเส้น สิ่งเหล่านี้ทำงานบนระบบพิกัดแบบเดิมโดยมีจุดเริ่มต้นที่ด้านล่างซ้าย:
ตำแหน่งการวาดปัจจุบันถูกเก็บไว้ในตัวแปรส่วนกลาง x0 และ y0 คุณสามารถเปลี่ยนแปลงได้ด้วยคำสั่ง MoveTo () :
void MoveTo (uint8_t x, uint8_t y) {
x0 = x; y0 = y;
}
การลากเส้นเพียงแค่เรียกตัวเร่งกราฟิกคำสั่ง Draw Line:
void DrawTo (uint8_t x, uint8_t y) {
PINB = 1<<cs; // cs low
Send(0x21); // Draw Line
Send(x0); Send(y0); Send(x); Send(y);
Send(ForeR); Send(ForeG); Send(ForeB);
PINB = 1<<cs; // cs high
x0 = x; y0 = x;
}
คำสั่งตัวเร่งกราฟิกไม่มีคำสั่งที่ชัดเจนในการพล็อตจุด แต่คุณสามารถทำได้โดยลากเส้นยาวหนึ่งพิกเซล:
void PlotPoint (uint8_t x, uint8_t y) {
MoveTo(x, y);
DrawTo(x, y);
}
การวาดรูปสี่เหลี่ยม
ฟังก์ชั่น DrawRect () ใช้วาดรูปสี่เหลี่ยมที่เติมเต็มหรือจัดเค้าร่างโดยใช้คำสั่ง Draw Rectangle ของตัวเร่งกราฟิก:
void DrawRect (boolean filled, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
PINB = 1<<cs; // cs low
Send(0x26); Send(filled); // Enable fill
Send(0x22); // Draw rectangle
Send(x1); Send(y1); Send(x2); Send(y2);
Send(ForeR); Send(ForeG); Send(ForeB);
Send(BackR); Send(BackG); Send(BackB);
PINB = 1<<cs; // cs high
delay(1);
}
ตั้งค่าให้เต็มเป็น 0 สำหรับเส้นสี่เหลี่ยมผืนผ้า หรือ 1 สำหรับสี่เหลี่ยมผืนผ้าที่เต็มไปด้วยสีพื้นหลัง
อักขระและข้อความ
ชุดอักขระถูกกำหนดโดยข้อมูลที่เก็บไว้ในหน่วยความจำโปรแกรม แผนผังอักขระแบบย่อมีดังนี้:
const uint8_t CharMap[96][6] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00 },
...
{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }
};
แถวแรกกำหนดรูปแบบบิตสำหรับอักขระ ASCII 32 ช่องว่างและอื่น ๆ สูงสุดถึงอักขระ 127
PlotChar () แปลงประจำตัวอักษรเป็นชุดของเส้นที่สอดคล้องกับคอลัมน์ของพิกเซลที่ต่อเนื่องกันในบิตแมปตัวละครที่ ด้วยการเพิ่มประสิทธิภาพนี้ฉันพบว่าการพล็อตอักขระนั้นเร็วกว่าวิธีการเขียนไบต์ตามปกติในหน่วยความจำข้อมูลกราฟิก:
void PlotChar (uint8_t ch) {
PINB = 1<<cs; // cs low
for (uint8_t c = 0 ; c < 6; c++) { // Column range
uint8_t bits = pgm_read_byte(&CharMap[ch-32][c]);
uint8_t r = 0;
while (bits) {
while ((bits & 1) == 0) {r++; bits = bits>>1; }
uint8_t on = (7-r)*Scale;
while ((bits & 1) != 0) {r++; bits = bits>>1; }
uint8_t off = (7-r)*Scale+1;
for (int i=0; i<Scale; i++) {
uint8_t h = x0+c*Scale+i;
Send(0x21); // Draw line
Send(h); Send(y0+on); Send(h); Send(y0+off);
Send(ForeR); Send(ForeG); Send(ForeB);
}
}
}
PINB = 1<<cs; // cs high
x0 = x0+6*Scale;
}
การตั้งค่ามาตราส่วนเป็น 2 พล็อตอักขระขนาดสองเท่า
สุดท้าย PlotText () ให้คุณพล็อตข้อความจากสตริงในหน่วยความจำโปรแกรม:
void PlotText(PGM_P p) {
while (1) {
char c = pgm_read_byte(p++);
if (c == 0) return;
PlotChar(c);
}
}
ในการกำหนดข้อความที่จะพล็อตว่าอยู่ในหน่วยความจำโปรแกรมให้ใช้มาโคร PSTR () (สำหรับโปรแกรมสตริง) ตัวอย่างเช่น:
PlotText(PSTR("Graphics Display"));
4 : เชื่อมต่ออุปกรณ์เข้ากับ ATtiny85 ตามวงจรด้านล่าง
5 : ผลลัพธ์การทำงาน
6 : อุปกรณ์ที่ใช้ในโปรเจค
- 1. ATtiny85 ATTINY85-20PU 8-bit AVR
- 2. Jumper (M2M) 20cm Male to Male
- 3. OLED Display 0.95 inch 96×64 SSD1331 Module
- 4. รีซิสเตอร์ 33K Ohm 1/4W
- 5. Breadboard 830 Point MB-102
- 6. 100NF 0.1UF Film Capacitor จำนวน 2 ชิ้น
- 7. CR2025 CR2032 3V Battery Socket Holder
- 8. CR2025 3V Lithium Button Coin Battery
credit : http://www.technoblogy.com/show?2EA7