หน้าแรก ดูโปรเจกต์ทั้งหมด
Intermediate

โปรเจกต์ เริ่มต้นใช้งาน OLED Displays

OLED คือ Diode ประเภทหนึ่งที่ประกอบด้วย Organic compound ซึ่งจะส่องสว่างเมื่อมี Current ไหลผ่าน

โปรเจกต์ เริ่มต้นใช้งาน OLED Displays

วิดีโอสาธิต

Video

▶ กดเพื่อดูวิดีโอสาธิตโปรเจกต์

รายละเอียดและวิธีทำ

OLED คืออะไร?

OLED คือไดโอดชนิดหนึ่งที่ประกอบด้วยสารประกอบอินทรีย์ที่สามารถส่องสว่างได้เมื่อมีกระแสไฟฟ้าไหลผ่าน

OLED สื่อสารกับ Arduino อย่างไร?

วิธีที่ OLED สื่อสารกับ Arduino คือผ่านทาง Inter-Integrated Circuit (I2C) อย่างไรก็ตาม ยังสามารถสื่อสารผ่าน Serial Peripheral Interface (SPI) ได้เช่นกัน สำหรับบทเรียนนี้ เราจะเน้นไปที่การสื่อสารแบบ I2C ซึ่งการสื่อสารประเภทนี้ช่วยให้ Slave หลายตัวสามารถสื่อสารกับ Master ตัวเดียวได้ ในกรณีนี้ เราจะทำงานกับ Slave เพียงตัวเดียวคือชิป SSD1306 โดยมี Master คือ Arduino UNO

SSD1306 เป็นชิปเดี่ยว CMOS OLED/PLED driver พร้อมคอนโทรลเลอร์สำหรับระบบแสดงผลกราฟิก dot-matrix ของไดโอดเปล่งแสงแบบสารประกอบอินทรีย์/โพลิเมอร์ พูดง่ายๆ ก็คือมันเป็นอุปกรณ์ที่ทำหน้าที่ควบคุมหน้าจอโดยสั่งการให้หน้าจอทำงานต่างๆ ในการสร้างการสื่อสารแบบ I2C ระหว่าง Master และ Slave จำเป็นต้องใช้เพียงสองช่องทางคือ SDA และ CLK อย่างไรก็ตาม เรายังต้องคำนึงถึง VCC และ Ground สำหรับการจ่ายแรงดันไฟฟ้า และในกรณีนี้มี RST สำหรับการเริ่มต้นระบบ (initialization) ด้วย ภาพด้านล่างแสดงการต่อสายไฟสำหรับ OLED ของเรา:

SDA ทำหน้าที่ในการส่งข้อมูลและตรงกับ Pin A4 ใน Arduino ส่วน CLK ทำหน้าที่กำหนดสัญญาณนาฬิกาเพื่อการซิงโครไนซ์ และตรงกับ Pin A5 ใน Arduino อย่างไรก็ตาม Pin เหล่านี้จะเปลี่ยนไปหากคุณไม่ได้ใช้ Arduino UNO หรือ Ethernet สามารถดูลิงก์ด้านล่างเพื่อตรวจสอบ I2C Pins สำหรับ Arduino รุ่นต่างๆ: https://www.arduino.cc/en/Reference/Wire

RST ใช้เพื่อรีเซ็ตอุปกรณ์กลับไปเป็นค่าเริ่มต้น และสามารถต่อเข้ากับ Digital Input ช่องใดก็ได้ใน Arduino ในกรณีนี้เราใช้ Pin 10 เมื่อกำหนดช่องทางสำหรับการสื่อสารเรียบร้อยแล้ว ก็จะสามารถส่งข้อมูลไปยังอุปกรณ์ของเราได้ รูปที่ 1 แสดงวิธีการดำเนินการดังกล่าว

สิ่งแรกที่เราต้องการคือ Slave address เลขเจ็ดหลักนี้จะระบุตัวตนของอุปกรณ์เฉพาะอย่าง เพื่อให้ Master รู้ว่าต้องการสื่อสารกับ Slave ตัวไหน จาก datasheet ของ SSD1306 ค่า Slave address สำหรับไดรเวอร์นี้อาจเป็น “0111100” หรือ “0111101” ขึ้นอยู่กับ SA0 (ว่าเป็น high หรือ low) โดยค่าเริ่มต้นจะเป็น high แต่ถ้าคุณต้องการเปลี่ยน Slave address คุณสามารถต่อสาย SA0 เข้ากับ Digital Pin ใดก็ได้ใน Arduino และตั้งค่าเป็นศูนย์ ในบทเรียนนี้ เราตัดสินใจที่จะไม่เปลี่ยน SA0 ดังนั้น Address ของ Slave ของเราคือ 0x3D เนื่องจาก OLED จะอยู่ในโหมดเขียนเสมอ Bit R/W# (read/write bit) จึงถูกตั้งค่าเป็น “0”

สิ่งต่อไปที่เราต้องการคือ Control byte ซึ่งกำหนดโดย Co (continuation bit) และ D/C# (data/command selection bit) ตามด้วย “0” จำนวนหกตัว Co จะกำหนดว่า Byte ถัดไปจะเป็น Byte เดียวหรือเป็น Stream ของข้อมูล ในขณะที่ D/C# จะกำหนดว่า Byte นั้นจะถูกจัดการในฐานะข้อมูล (Data) หรือคำสั่ง (Command) ดังนั้นเราจึงมี Control byte ที่เป็นไปได้สี่แบบ ดังนี้:

  • 0x40: Data stream
  • 0xC0: Single Data Byte
  • 0x80: Single Command byte
  • 0x00: Command Stream

คุณสามารถดูรายการคำสั่งทั้งหมดได้ในตารางที่ 9-1 ใน datasheet ของ SSD1306

ข้อมูลแสดงผลอย่างไร?

OLED ประกอบด้วย 128 คอลัมน์ (SEG) และ 8 หน้า (Page) ซึ่งแต่ละหน้าประกอบด้วย 8 แถว (COM) ดังที่แสดงในรูปที่ 2

ในขณะที่คำสั่งถูกใช้เพื่อกำหนดค่าหน้าจอและปรับแต่งผ่านการใช้ Registers แต่ข้อมูล (Data) จะถูกใช้เพื่อแสดงผลข้อมูลใดก็ตามที่เก็บไว้ใน GDDRAM (Graphic Display Data RAM) หากเราเขียน Byte “00000001” Pixel แรกที่อยู่มุมบนซ้าย หรือที่ Page 0 คอลัมน์ 0 จะสว่างขึ้น สาเหตุที่ Byte ถูกเขียนในลำดับย้อนกลับเป็นเพราะ OLED ใช้การกำหนดค่าต่อไปนี้ในการแสดงผลข้อมูล:

ด้วยการใช้ Pointer ข้อมูลจะเริ่มเติมลงในคอลัมน์ตั้งแต่ Least significant bit ไปจนถึง Most significant bit เมื่อ Pointer ไปถึงจุดสิ้นสุดของคอลัมน์ มันจะเลื่อนไปยังคอลัมน์ถัดไปโดยอัตโนมัติในโหมด Horizontal addressing หรือไปยังหน้าถัดไปในโหมด Vertical addressing (อ้างอิงจาก datasheet ของ SSD1306 สำหรับโหมดการระบุตำแหน่ง)

วิธีวาด Pixel?

ตอนนี้เราทราบวิธีทำงานของ OLED แล้ว เราสามารถสร้างโปรแกรมที่ให้ผู้ใช้สั่งเปิด Pixel เฉพาะจุดบนหน้าจอได้

#include<Wire.h> //Include Wire library for I2C communication
#define HEIGHT 64
#define WIDTH 128
const int RST = 10; //Assign pin 10 for Reset  
int i; //Set variable i as integer
static unsigned char array[1024]; //buffer array/>
 
void setup() {
  pin_init(); //Initialize pins
  initialize_OLED(); //Initialize screen
  memset(array, 0, sizeof(array)); //Clear array
  draw_pixel(63,31); //Store pixel at (x,y) location
  Flush(); //Send data
}
 
void loop() {
  //Nothing happens here
}
 
void pin_init(){
  Serial.begin(9600); //Set baud for serial transmission
  pinMode(RST, OUTPUT); //Set RST as output
}
 
void initialize_OLED(){
  Wire.begin(); //Initialize I2C interface
  digitalWrite(RST, LOW); //Set reset pin low (active)
  delay(10); //Wait 100 ms
  digitalWrite(RST, HIGH); //Set reset pin high (inactive)  
  Wire.beginTransmission(0x3D); // Start communication with slave
  Wire.write(0x00); //Command stream
  Wire.write(0xAE); //Set display Off
  Wire.write(0xD5); //Set display clock divide ratio/oscillator frequency
  Wire.write(0x80);
  Wire.write(0xA8); //Set multiplex ratio
  Wire.write(0x3F);
  Wire.write(0xD3); //Set display offset
  Wire.write(0x00);
  Wire.write(0x40); //Set display start line
  Wire.write(0x8D); //Set charge pump
  Wire.write(0x14); //VCC generated by internal DC/DC circuit
  Wire.write(0xA1); //Set segment re-map 
  Wire.write(0xC0); //Set COM output scan direction
  Wire.write(0xDA); //Set COM pins hardware configuration
  Wire.write(0x12);
  Wire.write(0x81); //Set contrast control
  Wire.write(0xCF);
  Wire.write(0xD9); //Set pre-changed period
  Wire.write(0xF1);
  Wire.write(0xDB); //Set VCOMH Deselected level
  Wire.write(0x40);
  Wire.write(0xA4); //Set entire display on/off
  Wire.write(0xA6); //Set normal display 
  Wire.write(0x20); //Set memory address mode
  Wire.write(0x00); //Horizontal
  Wire.write(0xAF); //Set display on
  Wire.endTransmission(); //End communicaiton with slave
}
 
void draw_pixel(int x, int y)
  if((x<0) || (x>=WIDTH) || (y<0) || (y>=HEIGHT)){ //Check for boundaries
    return;
  }
  else{
    array[x+(y/8)*WIDTH] |= _BV((y%8)); //Store pixel in array
  }
}
 
void Flush(){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x00); //Command stream
 Wire.write(0x00); //Set lower column start address for page addressing mode
 Wire.write(0x10); //Set higher column start address for page addressing mode
 Wire.write(0x40); //Set display start line
 Wire.endTransmission(); //End communication with slave
 
 unsigned char twbrbackup = TWBR; //Two wire bit rate register
 TWBR = 12; //Set to 400 kHz
 
 for(unsigned short q=0; q<(WIDTH*HEIGHT/8); q++){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x40); //Data stream
 for(unsigned char w=0; w<16; w++){
    Wire.write(array[q]); //Transmit data to be displayed
    q++;
 }
 q--;
  Wire.endTransmission(); //End communication with slave
}
TWBR = twbrbackup;
}

Library Wire ช่วยให้ Arduino สามารถสื่อสารกับอุปกรณ์ I2C ได้ ในส่วนแรกของโค้ด เรากำหนด Digital Pin ที่กล่าวไปแล้วให้กับ RST และสร้าง Array เพื่อพักข้อมูล (buffer) ที่เราต้องการแสดงผล จากนั้น Pin RST จะถูกกำหนดค่าเริ่มต้นให้เป็น Output ต่อมา OLED จะถูกกำหนดค่าเริ่มต้นโดยทำตามตัวอย่างที่แสดงใน datasheet ของหน้าจอในหน้า 15 แนะนำให้คุณรีเซ็ตอุปกรณ์หนึ่งครั้งก่อนเริ่มใช้งาน โดยการตั้งค่า RST เป็น low ชั่วขณะหนึ่งแล้วจึงตั้งเป็น high เนื่องจาก Pin นี้ทำงานแบบ active low จึงต้องมีสถานะเป็น high ในระหว่างการทำงานปกติ

จากนั้นฟังก์ชัน “pixel” จะถูกสร้างขึ้นเพื่อเก็บ Pixel ไว้ในตำแหน่งเฉพาะใน Array buffer ฟังก์ชันนี้รับพารามิเตอร์สองตัวคือ x และ y เพื่อระบุพิกัดที่แม่นยำของจุดที่เราต้องการให้ Pixel แสดงผล โดย x สามารถมีค่าได้ตั้งแต่ 0-127 และ y มีค่าได้ตั้งแต่ 0-63 พิกัด (0,0) จะอยู่ที่ด้านล่างซ้ายของหน้าจอ หากพิกัดอยู่นอกช่วง โปรแกรมจะไม่แสดงผลใดๆ สุดท้าย ฟังก์ชัน “Flush” จะถูกใช้เพื่อแสดงผลองค์ประกอบใน Array buffer โดยส่งข้อมูลแบบ 16 byte burst transfers ในขณะที่โปรแกรมวิ่งผ่าน Buffer ทั้งหมด ภายในฟังก์ชันนี้ TWBR (Two wire bit rate register) ถูกตั้งค่าเป็น 12 เพื่อเพิ่มความถี่ของสัญญาณนาฬิกา Arduino (SCL) จาก 100kHz เป็น 400kHz วิธีนี้จะทำให้การส่งข้อมูลเร็วขึ้น ด้านล่างนี้คือวิธีการคำนวณค่า 12: โดยที่:

  • CPUFrequency = 16MHz
  • TWIFrequency = 400kHz
  • TWI = Two Wire Interface

สำหรับบทเรียนนี้ เราเลือกพิกัด (63,31) เพื่อเปิด Pixel ที่อยู่ตรงกลางหน้าจอดังที่แสดงในภาพด้านล่าง:

วิธีวาดเส้นตรง?

เมื่อเรามีฟังก์ชัน Pixel แล้ว เราสามารถใช้มันเพื่อวาดเส้นตรงที่กำหนดโดยจุดเริ่มต้นและจุดสิ้นสุดบนแกน x และ y บนหน้าจอได้

#include<Wire.h> //Include Wire library for I2C communication
#define HEIGHT 64
#define WIDTH 128
const int RST = 10; //Assign pin 10 for Reset  
int i; //Set variable i as integer
static unsigned char array[1024]; //Buffer array
 
void setup() {
  pin_init(); //Initialize pins
  initialize_OLED(); //Initialize screen
  memset(array, 0, sizeof(array)); //Initialize array with 0s
  line(0,63,0,31); //Draw line
  Flush(); //Send data
}
 
void loop() { 
}
 
void pin_init(){
  Serial.begin(9600); //Set baud for serial transmission
  pinMode(RST, OUTPUT); //Set RST as output
}
 
void initialize_OLED(){
  Wire.begin(); //Initialize I2C interface
  digitalWrite(RST, LOW); //Set RST pin low
  delay(100); //Wait 100 ms
  digitalWrite(RST, HIGH); //Set RST pin high
  Wire.beginTransmission(0x3D); // Start communication with slave
  Wire.write(0x00); //Command stream
  Wire.write(0xAE); //Set display Off
  Wire.write(0xD5); //Set display clock divide ratio/oscillator frequency
  Wire.write(0x80);
  Wire.write(0xA8); //Set multiplex ratio
  Wire.write(0x3F);
  Wire.write(0xD3); //Set display offset
  Wire.write(0x00);
  Wire.write(0x40); //Set display start line
  Wire.write(0x8D); //Set charge pump
  Wire.write(0x14); //VCC generated by internal DC/DC circuit
  Wire.write(0xA1); //Set segment re-map 
  Wire.write(0xC0); //Set COM output scan direction
  Wire.write(0xDA); //Set COM pins hardware configuration
  Wire.write(0x12);
  Wire.write(0x81); //Set contrast control
  Wire.write(0xCF);
  Wire.write(0xD9); //Set pre-changed period
  Wire.write(0xF1);
  Wire.write(0xDB); //Set VCOMH Deselected level
  Wire.write(0x40);
  Wire.write(0xA4); //Set entire display on/off
  Wire.write(0xA6); //Set normal/inverse display 
  Wire.write(0x20); //Set memory address mode
  Wire.write(0x00); //Horizontal
  Wire.write(0xAF); //Set display on
  Wire.endTransmission(); //End communicaiton with slave
}
 
/*Bresenham's line drawing algorithm*/
 
void line(int x1, int x2, int y1, int y2){
  int cx = x1;
  int cy = y1;
 
  int dx = x2-cx;
  int dy = y2-cy;
 
  if(dx<0){
   dx = 0-dx;
  }
  if(dy<0){
    dy = 0-dy;
  }
 
  int sx = 0;
  int sy = 0; 
  if(cx<x2){
   sx = 1; 
  }
  else{
   sx = -1;
  }
  if(cy<y2){
   sy = 1;
  }
  else{
   sy = -1;
  }
  int err = dx-dy;
 
  for(int n=0; n<1000; n++){
   draw_pixel(cx,cy);
  if((cx==x2) && (cy==y2)){ 
   return;
  }
  int e2 =2*err;
  if(e2>(0-dy)){
   err = err-dy;
   cx = cx+sx;
  }
  if(e2<dx){ 
   err = err+dx;
   cy = cy+sy;
   }
  }
 }
 
void draw_pixel(int x, int y){
  if((x<0) || (x>=WIDTH) || (y<0) || (y>=HEIGHT)){ //Check for boundaries
    return;
  }
  else{
    array[x+(y/8)*WIDTH] |= _BV((y%8)); //Store pixel in array
  }
}
 
void Flush(){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x00); //Command stream
 Wire.write(0x00);  //Set lower column start address for page addressing mode
 Wire.write(0x10); //Set higher column start address for page addressing mode
 Wire.write(0x40); //Set display start line
 Wire.endTransmission(); //End communication with slave
 
 unsigned char twbrbackup = TWBR; //Two wire bit rate register
 TWBR = 12; //Set to 400 kHz
 
 for(unsigned short q=0; q<(WIDTH*HEIGHT/8); q++){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x40); //Data stream
 for(unsigned char w=0; w<16; w++){
    Wire.write(array[q]); //Transmit data to be displayed
    q++;
 }
 q--;
  Wire.endTransmission(); //End communication with slave
}
TWBR = twbrbackup;
}

ฟังก์ชันวาดเส้นตรงอ้างอิงจาก Bresenham's Line Drawing Algorithm ที่ใช้สำหรับวาดเส้นด้วย Pixel โปรแกรมของเราได้นำอัลกอริทึมนี้มาใช้งานโดยใช้ Pseudo code ต่อไปนี้: http://41j.com/blog/2012/09/bresenhams-line-drawing-algorithm-implemetations-in-go-and-c/

อัลกอริทึมนี้พื้นฐานแล้วจะเติม Pixel ระหว่าง (x0,y0) และ (x1,y1) โดยตัดสินใจว่าควรจะเปิด Pixel ใดเป็นลำดับถัดไปตามค่า Error สามารถดูข้อมูลเพิ่มเติมเกี่ยวกับอัลกอริทึมได้ที่ลิงก์ต่อไปนี้:

ฟังก์ชัน Pixel ถูกใช้เพื่อเก็บแต่ละจุดของเส้นไว้ใน Array buffer ณ ตำแหน่งที่ระบุทุกครั้งที่ถูกเรียกใช้ในโปรแกรม ด้วยวิธีนี้ Array buffer จะถูกเติมเต็มด้วย Pixel ทั้งหมดที่จำเป็นในการวาดเส้นของเรา เมื่อ Buffer ถูกโหลดด้วยข้อมูลที่จำเป็นแล้ว ฟังก์ชัน Flush จะถูกใช้เพื่อแสดงผลข้อมูลบนหน้าจอ โดยการกำหนดพารามิเตอร์สี่ตัวให้กับฟังก์ชันวาดเส้น (จุดเริ่มต้นและจุดสิ้นสุดบนแกน x และ y) ตอนนี้เราก็สามารถวาดเส้นได้เหมือนภาพด้านล่าง:

ในตัวอย่างนี้ เส้นจะลากจาก (0,0) ไปยัง (63,31) หรือพูดอีกอย่างคือลากจากมุมล่างซ้ายไปยังจุดกึ่งกลางของหน้าจอ

วิธีวาดรูปสี่เหลี่ยม?

เราสามารถใช้โค้ดต่อไปนี้เพื่อวาดรูปสี่เหลี่ยมบนหน้าจอ:

#include<Wire.h> //Include Wire library for I2C communication
#define HEIGHT 64
#define WIDTH 128
const int RST = 10; //Assign pin 10 for Reset  
int i; //Set variable i as integer
static unsigned char array[1024]; //Buffer array
 
void setup() { 
  pin_init(); //Initialize pins
  initialize_OLED(); //Initialize screen
  memset(array, 0, sizeof(array)); //Initialize array with 0s
  square(117,127,53,63); //Draw square 
  Flush(); //Send data
}
 
void loop() { 
}
 
void pin_init(){
  Serial.begin(9600); //Set baud for serial transmission
  pinMode(RST, OUTPUT); //Set RST as output
}
 
void initialize_OLED(){
  Wire.begin(); //Initialize I2C interface
  digitalWrite(RST, LOW); //Set RST pin low
  delay(100); //Wait 100 ms
  digitalWrite(RST, HIGH); //Set RST pin high
  Wire.beginTransmission(0x3D); // Start communication with slave
  Wire.write(0x00); //Command stream
  Wire.write(0xAE); //Set display Off
  Wire.write(0xD5); //Set display clock divide ratio/oscillator frequency
  Wire.write(0x80);
  Wire.write(0xA8); //Set multiplex ratio
  Wire.write(0x3F);
  Wire.write(0xD3); //Set display offset
  Wire.write(0x00);
  Wire.write(0x40); //Set display start line
  Wire.write(0x8D); //Set charge pump
  Wire.write(0x14); //VCC generated by internal DC/DC circuit
  Wire.write(0xA1); //Set segment re-map 
  Wire.write(0xC0); //Set COM output scan direction
  Wire.write(0xDA); //Set COM pins hardware configuration
  Wire.write(0x12);
  Wire.write(0x81); //Set contrast control
  Wire.write(0xCF);
  Wire.write(0xD9); //Set pre-changed period
  Wire.write(0xF1);
  Wire.write(0xDB); //Set VCOMH Deselected level
  Wire.write(0x40);
  Wire.write(0xA4); //Set entire display on/off
  Wire.write(0xA6); //Set normal/inverse display 
  Wire.write(0x20); //Set memory address mode
  Wire.write(0x00); //Horizontal
  Wire.write(0xAF); //Set display on
  Wire.endTransmission(); //End communication with slave
}
 
/*Function to draw square*/
 
void square(int x1, int x2, int y1, int y2){
 
  int x, y; //Define x and y as integer variables
 
  Wire.beginTransmission(0x3D); //Start communication with slave
  for(x=x1; x<x2; x++){ //Iterate over x range, draw line on y1
    draw_pixel(x,y1); //Draw pixel
  }
  Wire.endTransmission(); //End communication with slave
 
  Wire.beginTransmission(0x3D); //Start communication with slave
  for(x=x1; x<x2; x++){ //Iterate over x range, draw line on y2
    draw_pixel(x,y2); //Draw pixel
  }
  Wire.endTransmission(); //End communication with slave
 
  Wire.beginTransmission(0x3D); //Start communication
  for(y=y1; y<y2; y++){ //Iterate over y range, draw line on x1
    draw_pixel(x1,y); //Draw pixel
  }
  Wire.endTransmission(); //End communication with slave
 
  Wire.beginTransmission(0x3D); //Start communication with slave
  for(y=y1; y<y2; y++){ //Iterate over y range, draw line on x2 
    draw_pixel(x2,y); //Draw pixel
  }
  Wire.endTransmission(); //End communication with slave
}
 
void draw_pixel(int x, int y){
  if((x<0) || (x>=WIDTH) || (y<0) || (y>=HEIGHT)){ //Check for boundaries
    return;
  }
  else{
    array[x+(y/8)*WIDTH] |= _BV((y%8)); //Store pixel in array
  }
}
 
void Flush(){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x00); //Command stream
 Wire.write(0x00); //Set lower column start address for page addressing mode
 Wire.write(0x10); //Set higher column start address for page addressing mode
 Wire.write(0x40); //Set display start line
 Wire.endTransmission(); //End communication with slave
 
 unsigned char twbrbackup = TWBR; //Two wire bit rate register
 TWBR = 12; //Set to 400 kHz
 
 for(unsigned short q=0; q<(WIDTH*HEIGHT/8); q++){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x40); //Data stream
 for(unsigned char w=0; w<16; w++){
    Wire.write(array[q]); //Transmit data to be displayed
    q++;
 }
 q--;
  Wire.endTransmission(); //End communication with slave
}
TWBR = twbrbackup;
}

ฟังก์ชันสี่เหลี่ยมรับพารามิเตอร์สี่ตัว ได้แก่ จุดเริ่มต้นและจุดสิ้นสุดบนแกน x และ y เพื่อกำหนดความสูงและความกว้างของสี่เหลี่ยม จากนั้นเส้นสี่เส้นจะถูกวาดแยกจากกันโดยใช้ฟังก์ชัน Pixel อีกครั้ง เส้นแรกที่จะวาดคือเส้นฐานล่างของสี่เหลี่ยมจาก x1-x2 บนแกน y1 เส้นที่สองที่จะวาดคือเส้นด้านบนจาก x1-x2 บนแกน y2 เส้นที่สามคือด้านซ้ายจาก y1-y2 บนแกน x1 และเส้นสุดท้ายคือด้านขวาจาก y1-y2 บนแกน x2 เมื่อ Pixel ของเส้นทั้งหมดถูกเก็บไว้ใน Array แล้ว ฟังก์ชัน Flush จะถูกใช้เพื่อแสดงผลเส้นทั้งสี่ ด้านล่างคือภาพสี่เหลี่ยมขนาด 10 x 10 Pixel ที่อยู่มุมบนขวาของหน้าจอ: วิธีวาดวงกลม?

เราสามารถใช้โค้ดต่อไปนี้เพื่อสร้างวงกลมบนหน้าจอ:

#include<Wire.h> //Include Wire library for I2C communication
#define HEIGHT 64
#define WIDTH 128
const int RST = 10; //Assign pin 10 for Reset 
int i; //Set variable i as integer
static unsigned char array[1024]; //Buffer array
 
void setup() {
  pin_init(); //Initialize pins
  initialize_OLED(); //Initialize screen
  memset(array, 0, sizeof(array)); //Initialize array with 0s
  circle(63,31,10); //Draw circle, (x,y,R)
  Flush(); //Send data
}
 
void loop() {   
}
 
void pin_init(){
  Serial.begin(9600); //Set baud for serial transmission
  pinMode(RST, OUTPUT); //Set RST as output
}
 
void initialize_OLED(){
  Wire.begin(); //Initialize I2C interface
  digitalWrite(RST, LOW); //Set RST pin low
  delay(100); //Wait 100 ms
  digitalWrite(RST, HIGH); //Set RST pin high
  Wire.beginTransmission(0x3D); // Start communication with slave
  Wire.write(0x00); //Command stream
  Wire.write(0xAE); //Set display Off
  Wire.write(0xD5); //Set display clock divide ratio/oscillator frequency
  Wire.write(0x80);
  Wire.write(0xA8); //Set multiplex ratio
  Wire.write(0x3F);
  Wire.write(0xD3); //Set display offset
  Wire.write(0x00);
  Wire.write(0x40); //Set display start line
  Wire.write(0x8D); //Set charge pump
  Wire.write(0x14); //VCC generated by internal DC/DC circuit
  Wire.write(0xA1); //Set segment re-map 
  Wire.write(0xC0); //Set COM output scan direction
  Wire.write(0xDA); //Set COM pins hardware configuration
  Wire.write(0x12);
  Wire.write(0x81); //Set contrast control
  Wire.write(0xCF);
  Wire.write(0xD9); //Set pre-changed period
  Wire.write(0xF1);
  Wire.write(0xDB); //Set VCOMH Deselected level
  Wire.write(0x40);
  Wire.write(0xA4); //Set entire display on/off
  Wire.write(0xA6); //Set normal/inverse display 
  Wire.write(0x20); //Set memory address mode
  Wire.write(0x00); //Horizontal
  Wire.write(0xAF); //Set display on
  Wire.endTransmission(); //End communication with slave
}
 
/*Midpoint circle algorithm*/
 
void circle(int x0, int y0, int R){
  int x = R; //Set x equal to radius
  int y = 0;
  int de = 1-x; 
 
  while(x>=y){
    draw_pixel(x+x0, y+y0); //First octant
    draw_pixel(y+x0, x+y0); //Second octant 
    draw_pixel(-y+x0, x+y0); //Third octant
    draw_pixel(-x+x0, y+y0); //Fourth octant
    draw_pixel(-x+x0, -y+y0); //Fifth octant
    draw_pixel(-y+x0, -x+y0); //Sixth octant
    draw_pixel(y+x0, -x+y0); //Seventh octant
    draw_pixel(x+x0, -y+y0); //Eight octant                 
    y++; 
    if(de<=0){
      de += 2*y+1;
    }
    else{ 
      x--;
      de += 2*(y-x)+1; 
   }
  }
}
 
void draw_pixel(int x, int y){
  if((x<0) || (x>=WIDTH) || (y<0) || (y>=HEIGHT)){ //Check for boundaries
    return;
  }
  else{
    array[x+(y/8)*WIDTH] |= _BV((y%8)); //Store pixel in array
  }
}
 
void Flush(){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x00); //Command stream
 Wire.write(0x00); //Set lower column start address for page addressing mode
 Wire.write(0x10); //Set higher column start address for page addressing mode
 Wire.write(0x40); //Set display start line
 Wire.endTransmission(); //End communication with slave
 
 unsigned char twbrbackup = TWBR; //Two wire bit rate register
 TWBR = 12; //Set to 400kHz
 
 for(unsigned short q=0; q<(WIDTH*HEIGHT/8); q++){
 Wire.beginTransmission(0x3D); //Start communication with slave
 Wire.write(0x40); //Data stream
 for(unsigned char w=0; w<16; w++){
    Wire.write(array[q]); //Transmit data to be displayed
    q++;
 }
 q--;
  Wire.endTransmission(); //End communication with slave
}
TWBR = twbrbackup;
}
 

ฟังก์ชันวงกลมอ้างอิงจาก Midpoint Circle Algorithm ที่ใช้สร้างวงกลมด้วย Pixel อัลกอริทึมนี้จะวาดทีละ Pixel ในแต่ละเสี้ยว (octant) ของวงกลมโดยอาศัยหลักสมมาตรจนกว่าจะครบวงรอบ และฟังก์ชัน Pixel ก็จะถูกนำมาใช้เพื่อวาดแต่ละจุดของวงกลมทุกครั้งที่ถูกเรียกใช้ในโปรแกรม สามารถดูข้อมูลเพิ่มเติมเกี่ยวกับอัลกอริทึมได้ที่ลิงก์ต่อไปนี้:

โดยการระบุพารามิเตอร์สามตัวให้กับฟังก์ชันวงกลม (จุดศูนย์กลางที่ (x,y) และรัศมี) ตอนนี้เราก็สามารถวาดวงกลมได้เหมือนภาพด้านล่าง:

ในตัวอย่างนี้ จุดศูนย์กลางของวงกลมอยู่ที่ (63,31) และมีรัศมี 10 ทำให้เกิดวงกลมที่กลางหน้าจอด้วยรัศมี 10 Pixel

เบ็ดเตล็ด

หากเราใช้การแสดงผลแบบ Buffer ที่มีการระบุค่าไว้ล่วงหน้า เราจะสามารถแสดงผลภาพใดๆ ที่เราต้องการบนหน้าจอได้ โค้ดต่อไปนี้แสดงวิธีการดังกล่าว:

#include<Wire.h> //Include Wire library for I2C communication
 
const int RST = 10; //Assign pin 10 for Reset
int i; //Set variable i as integer
const unsigned char js[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0xC0,
0x80, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0F, 0x1F,
0x1F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x1F, 0x3F, 0x3F,
0x3F, 0x3F, 0x1F, 0x1F, 0x3F, 0x3F, 0x1F, 0x1F, 0x3F, 0x3F, 0x1F, 0x1F, 0x3F, 0x3F, 0x1F, 0x1F,
0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x80, 0x60,
0x50, 0xA0, 0xA8, 0x50, 0xA0, 0x5C, 0xA4, 0x48, 0xA8, 0x50, 0xA6, 0x58, 0x90, 0x64, 0x58, 0xA4,
0x58, 0x24, 0x98, 0x68, 0xA8, 0x54, 0x68, 0x22, 0x50, 0xA4, 0x48, 0xB4, 0xA0, 0x5C, 0x94, 0x48,
0x94, 0x68, 0xA4, 0x50, 0x58, 0xA4, 0x58, 0x94, 0x24, 0x58, 0xA4, 0x58, 0xA0, 0x58, 0x04, 0x00,
0x54, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x84, 0x00, 0x60, 0x2A, 0x90, 0x64, 0x58, 0xA4, 0x58, 0x24, 0x98, 0x68, 0xA8, 0x54, 0x68, 0x24,
0x24, 0x58, 0xA4, 0x58, 0xA4, 0x48, 0x94, 0x68, 0x90, 0x6A, 0xD4, 0x28, 0x20, 0xD4, 0x68, 0x12,
0x50, 0xA4, 0x48, 0xB4, 0xA4, 0x18, 0x50, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x25, 0x7E, 0x9A, 0xE5,
0x76, 0x59, 0xCA, 0xB5, 0x9D, 0x6A, 0xFD, 0x92, 0xDA, 0x61, 0x60, 0xA0, 0x80, 0xC0, 0x20, 0xC0,
0x40, 0xA0, 0x80, 0xE0, 0x40, 0xC0, 0x40, 0xA0, 0x80, 0xC0, 0x20, 0xC0, 0x40, 0xA0, 0x80, 0xE0,
0x40, 0xC0, 0x40, 0xA0, 0x80, 0xC0, 0x20, 0xC0, 0x40, 0xC0, 0x80, 0x60, 0xC0, 0xA0, 0x80, 0xC0,
0xC0, 0x6D, 0x6F, 0xDF, 0xBF, 0xAF, 0x7F, 0xCF, 0xBF, 0xBF, 0xDF, 0x6F, 0x7F, 0xDF, 0x9F, 0xAF,
0xC0, 0x40, 0x80, 0xA0, 0xC0, 0x40, 0x40, 0xC0, 0xC0, 0x40, 0x40, 0xC0, 0xC0, 0x80, 0xE0, 0x40,
0x40, 0xC0, 0x40, 0xA0, 0x80, 0xC0, 0x20, 0xC0, 0x40, 0xC0, 0x80, 0xC0, 0x00, 0xC0, 0xC0, 0x00, 0xC0, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x81, 0xC1, 0xC3, 0xC2, 0xC2, 0x85, 0x87, 0xC6, 0x87, 0x09, 0x0F, 0x02, 0x0F, 0x05, 0x0F, 0x06, 0x06, 0x07, 0x05, 0x0F, 0x09, 0x05, 0x0F, 0x06, 0x06, 0x07, 0x0D, 0x07, 0x0C, 0x07, 0x05, 0x0F, 0x0A, 0x05, 0x0F, 0x06, 0x06, 0x07, 0x0D, 0x07, 0x0C, 0x07, 0x05, 0x0F, 0x0A, 0x05, 0x0F, 0x06, 0x06, 0x0F, 0xCA, 0xEE, 0xFB, 0xF3, 0xFD, 0xFB, 0xEE, 0xEE, 0xFB, 0xEE, 0xF3, 0xFB, 0xFE, 0xFB, 0xCE, 0x03, 0x0E, 0x0B, 0x0E, 0x03, 0x0E, 0x0A, 0x07, 0x03, 0x0E, 0x0B, 0x0E, 0x03, 0x0E, 0x0A, 0x07, 0x07, 0x0D, 0x07, 0x0C, 0x07, 0x05, 0x0F, 0x0A, 0x0E, 0x0B, 0xB5, 0xEF, 0x6A, 0xFF, 0x7B, 0xEC, 0xFF, 0x69, 0xFF, 0xAA, 0xB7, 0xFC, 0x6E, 0xF8, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x78, 0x7C, 0xDC, 0xFC, 0x7E, 0xF8, 0xFE, 0xBC, 0xFC, 0xFE, 0xF6, 0xDC, 0xEC, 0xF6, 0xFC, 0xFE, 0xFE, 0xBC, 0x7A, 0xFC, 0xFC, 0xFE, 0xE8, 0xFE, 0xFC, 0xBE, 0xEC, 0x10, 0x34, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xD8, 0x00, 0x6C, 0xFC, 0xFC, 0xFA, 0xBE, 0xFC, 0xEC, 0xF6, 0xFC, 0xFE, 0xFE, 0x7C, 0x7A, 0xFC, 0xFC, 0x7E, 0xF6, 0xFC, 0xFE, 0xDC, 0xFC, 0xEE, 0xBE, 0xFE, 0xFF, 0xE7, 0xFE, 0x7F, 0xFB, 0x7F, 0x7E, 0x6F, 0x3F, 0x3B, 0x1E, 0x1F, 0x0F, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xF0, 0xF0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xF0, 0xE0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xF0, 0xE0, 0xE0, 0xF0, 0xF0, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07, 0x03, 0x03, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x07, 0x0F, 0x07, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x0F, 0x0F, 0x07, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x0F, 0x0F, 0x07, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x0F, 0x0F, 0x07, 0x0F, 0x07, 0x07, 0x0F, 0x07, 0x0F, 0x0F, 0x07, 0x0F, 0x07, 0x07, 0x07, 0x0F, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x07, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };   void setup() {
  pin_init(); //Initialize pins
  initialize_OLED(); //Initialize screen
  pattern(); //Display image
}
  void loop() {
}
  void pin_init(){
  Serial.begin(9600); //Set baud for serial transmission
  pinMode(RST, OUTPUT); //Set RST as output
}
  void initialize_OLED(){
  Wire.begin(); //Initialize I2C interface
  digitalWrite(RST, LOW); //Set RST pin low
  delay(100); //Wait 100 ms
  digitalWrite(RST, HIGH); //Set RST pin high
  Wire.beginTransmission(0x3D); // Start communication with slave
  Wire.write(0x00); //Command stream
  Wire.write(0xAE); //Set display Off
  Wire.write(0xD5); //Set display clock divide ratio/oscillator frequency   Wire.write(0x80);
  Wire.write(0xA8); //Set multiplex ratio
  Wire.write(0x3F);
  Wire.write(0xD3); //Set display offset
  Wire.write(0x00);
  Wire.write(0x40); //Set display start line
  Wire.write(0x8D); //Set charge pump
  Wire.write(0x14); //VCC generated by internal DC/DC circuit
  Wire.write(0xA1); //Set segment re-map 
  Wire.write(0xC8); //Set COM output scan direction
  Wire.write(0xDA); //Set COM pins hardware configuration
  Wire.write(0x12);
  Wire.write(0x81); //Set contrast control
  Wire.write(0xCF);
  Wire.write(0xD9); //Set pre-changed period
  Wire.write(0xF1);
  Wire.write(0xDB); //Set VCOMH Deselected level
  Wire.write(0x40);
  Wire.write(0xA4); //Set entire display on/off
  Wire.write(0xA6); //Set normal/inverse display 
  Wire.write(0x20); //Set memory address mode
  Wire.write(0x00); //Vertical
  Wire.write(0xAF); //Set display on
  Wire.endTransmission(); //End communication with slave
}
 
void pattern(){
  for(i=0; i<1024; i++){
  Wire.beginTransmission(0x3D); //Start communication with slave
  Wire.write(0x40); //Data stream
  for(unsigned char x=0; x<16; x++){
     Wire.write(js[i]); //Transmit data to be displayed
     i++;
  }
  i--;
  Wire.endTransmission(); //End communication with slave
 }
}
 

ในตัวอย่างก่อนหน้านี้ เราจะใช้ฟังก์ชัน Pixel เพื่อสร้างรูปทรงต่างๆ โดยการวางแต่ละ Pixel ลงในตำแหน่งที่ระบุภายใน Array จากนั้นเราจะใช้ฟังก์ชัน Flush เพื่อแสดงข้อมูลของ Array บนหน้าจอตามรูปทรงที่ต้องการ ในกรณีนี้ แทนที่จะสร้างค่าของ Array buffer ผ่านการใช้ Iteration เราจะให้ข้อมูล Array จำนวน 1024 Byte ที่เป็นตัวแทนของภาพที่เราต้องการแสดงผล วิธีนี้ช่วยให้เราแสดงผลภาพใดๆ ก็ได้ตามต้องการ แต่ก็มีข้อจำกัดบางประการ แล้วเราจะได้ค่าเหล่านี้มาได้อย่างไร? ขั้นแรกเราต้องหาภาพที่ต้องการแสดงก่อน เราต้องแน่ใจว่าภาพนั้นมีขนาด 128x64 (ความละเอียดของหน้าจอเรา) และเป็นภาพแบบ Monochrome (ขาวดำ) ผมนำภาพนี้มาจากอินเทอร์เน็ต:

เมื่อเราเลือกภาพได้แล้ว เราต้องแปลงจาก JPEG เป็น Bitmap ทำได้ง่ายๆ โดยเปิดรูปภาพใน Paint แล้วบันทึกเป็น Monochrome bitmap (.bmp) เราสามารถใช้ซอฟต์แวร์กราฟิกอื่นๆ ในการแปลงไฟล์ภาพได้หากต้องการ จากนั้น ด้วยความช่วยเหลือของ LCD Assistant, เราจะสามารถโหลดภาพ BMP และบันทึกเป็นไฟล์ CPP ได้ ซึ่งจะสร้างค่า Array ที่เราต้องการนำไปใช้ในโค้ดเพื่อแสดงผลภาพ เมื่อโปรแกรมทำงาน เราจะได้ผลลัพธ์ดังนี้:

นี่คืออีกหนึ่งตัวอย่างพร้อมโลโก้บริษัทของ Jaycon System:

หากคุณมีคำถามใดๆ เกี่ยวกับบทเรียนนี้ อย่าลังเลที่จะโพสต์ความคิดเห็น ส่งอีเมลมาหาเรา หรือโพสต์ในฟอรัมของเราได้เลย

Code

🔒 ปลดล็อก Code

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

รหัสอ้างอิงโปรเจกต์: getting-started-with-oled-displays-accc71
1120 บาท
PromptPay QR Code

ประเมิน Project

อยากได้งานคล้ายโปรเจคนี้? กดไปหน้าประเมินราคา

เอาฟอร์มยาวออกจากท้ายหน้า Project แล้ว เหลือเป็นปุ่มให้กดไปกรอกหน้าเดียว ตัวใหญ่ เว้นบรรทัดเยอะ อ่านง่ายกว่า

รีวิวจากคนใช้งานจริง

รีวิวจากลูกค้าและคนที่เคยใช้งาน

ถ้าเคยสั่งงาน เคยอ่านหน้านี้แล้วได้ประโยชน์ หรือมีข้อเสนอแนะ ฝากรีวิวไว้ได้เลย

กำลังโหลดรีวิว...