Posted on Leave a comment

Coupling กับ Decoupling capacitor คืออะไร?

คำว่า coupling ถ้าแปลกันตรง ๆ ก็คือ “การเชื่อมต่อ” และ decoupling ก็แปลกันง่าย ๆ ว่า “การไม่เชื่อมต่อ” แล้วมันเชื่อมต่อหรือไม่เชื่อมต่ออะไรล่ะ?  ในทาง electronics พูดง่ายๆ ว่า มันเชื่อมต่อ หรือไม่เชื่อมต่อ “สัญญาณทางไฟฟ้า” นั่นเอง แล้วเมื่อพูดถึงสัญญาณทางไฟฟ้า ก็มักจะหมายถึงการเปลี่ยนแปลงแรงดันไฟฟ้า หรือบางครั้งก็เรียกว่า ไฟ AC ซึ่งแตกต่างจากแรงดันไฟฟ้าที่ไม่เปลี่ยนแปลง หรือ DC ซึ่งมักจะเป็นไฟเลี้ยงวงจรไฟฟ้า

ดังนั้นเรามาสรุปย่อ ๆ ตรงนี้ก่อนว่า ในวงจร electronics นั้น มักจะมีทั้ง ไฟ DC ซึ่งเอาไว้เลี้ยงวงจรไฟฟ้า และ ไฟ AC ซึ่งมักจะเป็นสัญญาณไฟฟ้า และ coupling capacitor ก็ทำหน้าที่เชื่อมต่อสัญญาณไฟฟ้านั้น ส่วน decoupling capacitor ก็ทำหน้าที่ไม่เชื่อมต่อสัญญาณไฟฟ้านั้น

ทำไมต้องใช้ capacitor ในการ coupling หรือเชื่อมต่อสัญญาณด้วยล่ะ? ทำไมไม่ใช้ทองแดงต่อตรงไปเลย?

ในวงจร electronics นั้น (โดยเฉพาะที่เป็นในส่วนของวงจร analog นั้น) สัญญาณมักจะรวมอยู่กับ ไฟเลี้ยงซึ่งก็ไม่มีปัญหาอะไร แต่พอเราจะส่งสัญญาณจากจุดหนึ่งไปอีกจุดหนึ่งในวงจร หรือจากวงจรหนึ่งไปอีกวงจรหนึ่ง บางครั้งเราต้องการแค่เฉพาะตัวสัญญาณ ไม่ต้องการไฟเลี้ยง (อาจเป็นเพราะทั้งสองส่วนของวงจร หรือสองวงจรนั้น มีไฟเลี้ยงไม่เท่ากัน) เราจึงต้องอาศัยสมบัติของตัว capacitor ที่ยอมให้ไฟ AC ไหลผ่านมาช่วยเชื่อมต่อสัญญาณ และกันไม่ให้ DC ผ่านไปได้ เราจึงเรียก capacitor ที่ทำหน้าที่เชื่อมต่อสัญญาณนี้ว่า coupling capacitor นั่นเอง

ถ้าสัญญาณคือสิ่งที่เราต้องการ แล้วทำไมต้องมี decoupling capacitor ด้วยล่ะ?

ในวงจรหนึ่ง ๆ นอกจากไฟ AC ที่เป็นสัญญาณที่เราต้องการแล้ว ยังมักมีไฟ AC ที่เป็นสัญญาณที่เราไม่ต้องการด้วย เราเรียกสัญญาณ หรือไฟ AC ที่เราไม่ต้องการนี้ว่า noise (หรือ spike หรือ ripple หรืออื่น ๆ แล้วแต่รูปแบบการปรากฎตัวของมัน สรุปว่ามันคือสัญญาณที่เราไม่ต้องการ) โดยที่ noise นี้ มักจะเป็นสัญญาณที่มีความถี่สูงกว่าสัญญาณที่เราต้องการ แน่นอนว่าเราไม่อยากส่งต่อ noise ไปยังส่วนอื่นของวงจร หรือไม่อยากส่งต่อไปวงจรอื่น เราต้องเอา capacitor มาต่อระหว่างสายส่งสัญญาณกับ ground เพื่อให้ noise ลง ground ไป ไม่ให้เชื่อมต่อไปยังส่วนอื่น และ capacitor ที่ทำหน้าที่นี้ ก็เรียกว่า decoupling capacitor นั้นเอง หรือ capacitor ที่ทำหน้าที่ไม่เชื่อมต่อสัญญาณที่ไม่ต้องการ นั่นเอง

สรุปว่า ไม่ว่าจะเป็น coupling capacitor หรือ decoupling capacitor ก็คือ capacitor (ตัวเก็บประจุ) เหมือนกันนี่แหละ แต่ทำหน้าที่ต่างกัน โดยที่ coupling capacitor ทำหน้าที่เชื่อมต่อสัญญาณที่ต้องการ ส่วน decoupling capacitor ทำหน้าที่ไม่เชื่อมต่อสัญญาณที่ไม่ต้องการ บางครั้งเรียก decoupling capacitor นี้ว่า bypassing capacitor เพราะมัน bypass สัญญาณที่ไม่ต้องการไปทางอื่น เช่น ลง ground แต่สำหรับบางคน หรือบางบริบทก็อาจบอกว่ามันไม่เหมือนกันซะทีเดียวนะครับ

Posted on Leave a comment

วัดปริมาณ carbon dioxide ด้วย SCD-40 (Low power)

บทความนี้เป็นบทความต่อขยายจากบทความหลักในเรื่องของ “วัดปริมาณ carbon dioxide ด้วย SCD-40” โดยในบทความนี้จะกล่าวถึงการทำงานในโหมด Low power ซึ่งจะช่วยให้เราประหยัดพลังงานได้ โดยในบทความนี้สาธิตว่าทำอย่างไร และที่สำคัญ นอกจากช่วยลดการใช้พลังงงานแล้ว มีผลกระทบอื่น ๆ หรือไม่ แก้อย่างไร มาติดตามกันเลย

Low Power Periodic Measurement

ก่อนอื่นต้องทราบก่อนว่าส่วนที่ใช้พลังงานมากที่สุดของ SCD40 นี้คือการทำงานในส่วนของการวัดปริมาณ carbon dioxide ดังนั้นการลดความถึ่ในการวัดปริมาณ cabon dioxide จึงเป็นวิธีที่ตรงไปตรงมา และได้ผลมากโดยทางผู้ผลิตอ้างว่า สามารถลดพลังงานได้มากกว่า 80% เลยทีเดียว ซึ่งวิธีการก็ง่าย ๆ ไม่ยุ่งยากอะไร คือ ทางผู้ผลิตได้เตรียม function การใช้งานสำหรับเรื่องนี้มาโดยเฉพาะอยู่แล้ว นั่นคือ การใช้คำสั่ง startLowPowerPeriodicMeasurement แทนคำสั่ง startPeriodicMeasurement โดยคำสั่ง startLowPowerPeriodicMeasurement นี้เป็นการสั่งให้ SCD40 ทำการวัดค่า carbon dioxide ประมาณทุก ๆ 30 วินาที (จากเดิมทุก ๆ 5 วินาที) ซึ่งก็จะได้ code ดังนี้ (code ทั้งหมดจะให้ไว้ที่ด้านล่างของบทความนะครับ)

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  // scd40.startPeriodicMeasurement();          // Performance mode (every 5s)
  scd40.startLowPowerPeriodicMeasurement();     // Low Power mode (every 30s)

แต่เรื่องมันไม่ได้จบแค่นี้ (ถ้าจบแค่นี้ก็ไม่สนุกใช่ไหมล่ะ)

Temperature Offset

เมื่อใช้ Low power mode นั้น ค่าของอุณหภูมิที่อ่านได้ จะคลาดเคลื่อนจากตอนที่อยู่ในโหมดปกตินิดหน่อย คาดว่าเกิดจากการใช้พลังงานลดลง ทำให้อุณหภูมิของตัวเอง (self-heating) ลดลง ทำให้ค่าอุณหภูมิที่วัดได้ต่างจากเดิมนิดหน่อย ดังนั้นเพื่อให้ sensor รายงานค่าอุณหภูมิ และความชื้นสัมพัทธ์ได้ถูกต้อง เราต้องปรับ offset ของการวัดอุณหภูมิของ sensor ด้วย ซึ่งตัว sensor เองก็มี function การทำงานในส่วนนี้รองรับไว้อยู่แล้ว (เจ๋ง ใช่ไหมล่ะ) นั่นคือใช้คำสั่ง setTemperatureOffset โดยที่ค่า offset ที่จะใส่เข้าไป สามารถหาได้ตามสูตร (จาก datasheet) ดังนี้

Toffset_actual = TSCD40TReference + Toffset_previous

Toffset_actual : ค่า offset ที่จะใส่เข้าไป

TSCD40 : ค่าอุณหภูมิที่ SCD40 อ่านได้

TReference : ค่าอุณหภูมิอ้างอิง (ที่เราคิดว่าถูกต้อง)

Toffset_previous : ค่า offset ปัจจุบัน (ก่อนที่จะใส่ offset ใหม่)

นอกจากปัจจัยในเรื่องของ self-heating ของตัว sensor เองแล้ว ยังมีปัจจัยจากสิ่งแวดล้อม เช่นความร้อนของอุปกรณ์ข้างเคียงอีก ดังนั้นเราควรหาค่า offset หลังจากที่ประกอบอุปกรณ์ในลักษณะพร้อมใช้ และติดตั้งในสถานที่จริงเรียบร้อยแล้ว ซึ่งจะเป็นลักษณะของใครของมัน ส่วนของผมนั้น ค่าอุณหภูมิที่อ่านได้ (TSCD40) จะน้อยกว่าค่าที่คิดว่าถูกต้อง (เมื่อเทียบกับ thermometer ที่เราเชื่อใจ ) อยู่ประมาณ 3.5 องศา (TSCD40TReference = -3.5) ส่วนค่า Toffset_previous คือค่า offset ปัจจุบัน เราสามารถหาได้จากคำสั่ง getTemperatureOffset

เมื่อได้ offset ที่ต้องการแล้ว เราก็ใส่ offset เข้าไปด้วยคำสั่ง setTemperatureOffset ซึ่งจะได้ code ดังนี้

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  // scd40.startPeriodicMeasurement();          // Performance mode (every 5s)
  float tempOffsetPre = 0.0;
  scd40.getTemperatureOffset(tempOffsetPre);
  float tempOffset = -3.5 + tempOffsetPre;
  scd40.setTemperatureOffset(tempOffset);
  scd40.startLowPowerPeriodicMeasurement();     // Low Power mode (every 30s)

เมื่อเราปรับ code เป็นอย่างนี้แล้ว เราก็จะได้ค่าอุณหภูมิ และความชื้นสัมพัทธ์ถูกต้อง(มากขึ้น) ซึ่งการปรับค่าอุณหภูมินี้มีผลแค่การคำนวนค่าความชื้นสัมพัทธ์เท่านั้นนะครับ ไม่มีผลต่อการวัดค่า carbon dioxide ส่วนค่าที่จะมีผลต่อการวัดค่า carbon dioxide คือค่าความดันอากาศ ซึ่งยังไม่ได้กล่าวถึงในบทความนี้ แต่ใครสนใจสามารถศึกษาเพิ่มเติมได้จาก datasheet

Reload user setting from EEPROM

เอาหละ ถ้าดูผิวเผินก็เหมือนจะจบแค่นี้ แต่… ใช่แล้วครับ ความสนุกยังไม่จบแค่นี้ คนที่มีประสบการณ์ด้านการเขียนโปรแกรมมาเยอะ (ผิดพลาดมาเยอะ) ก็น่าจะรู้อยู่แล้วว่ามันยังไม่จบง่าย ๆ แบบนี้แน่ นั่นคือ ยังจำเหตุที่เราต้องใส่คำสั่ง stopPeriodicMeasurement ก่อนที่จะสั่ง startPeriodicMeasurement ได้ไหมครับ นั่นคือ เมื่อเรากด reset ที่ microcontroller ตัว SCD40 จะไม่ได้ reset ไปด้วย ดังนั้นถ้าเราปล่อยไว้อย่างนี้ จะทำให้ค่า offset จะถูกลดลงไป 3.5 องศาในทุก ๆ ครั้งที่เรากด reset ซึ่งไม่ดีแน่ แล้วเราจะแก้อย่างไรล่ะ

เราต้องเข้าใจการทำงานของ SCD40 เพิ่มอีกหน่อย นั่นคือ เมื่อเราจ่ายไฟให้กับ SCD40 นั้น ตัว sensor จะทำการ load ค่า setting ต่าง ๆ จาก EEPROM เข้าสู่ RAM เพื่อใช้ในการวัดค่าต่าง ๆ และคำสั่ง setTemperatureOffset ที่เราใช้เปลี่ยนค่า offset นี้ ก็ไปทำการเปลี่ยนค่า offset ที่ RAM เท่านั้น (ที่จริง เราสามารถบันทึกค่า offset ใหม่นี้ใส่ EEPROM ได้ แต่จะยังไม่พูดถึงในที่นี้) ดังนั้นเมื่อมีการกด reset ที่ microcontroller เราต้องการให้ SCD40 ทำการ reload ค่า setting ต่าง ๆ ขึ้นมาใหม่ด้วย ซึ่งแน่นอนว่าเค้าเตรียมให้เราอยู่แล้ว นั่นคือคำสั่ง reinit ซึ่งคำสั่งนี้ก็ต้องสั่งหลังจากคำสั่ง stopPeriodicMeasurement เช่นกัน ดังนั้นเราจะได้ code ออกมาอย่างนี้

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  scd40.reinit();
  // scd40.startPeriodicMeasurement();          // Performance mode (every 5s)
  float tempOffsetPre = 0.0;
  scd40.getTemperatureOffset(tempOffsetPre);
  float tempOffset = -3.5 + tempOffsetPre;
  scd40.setTemperatureOffset(tempOffset);
  scd40.startLowPowerPeriodicMeasurement();     // Low Power mode (every 30s)

เพียงเท่านี้เราก็จะได้ โหมดประหยัดพลังงานที่อ่านค่า อุณหภูมิ และความชื้นสัมพัทธ์ ได้อย่างถูกต้องมากขึ้นแล้ว ที่จริง การใส่ offset นี้ ไม่จำเป็นต้องรอเปลี่ยนมาเป็น Low power mode ก็ได้ ใน mode ปกติ ถ้าเราเห็นว่าค่าอุณหภูมิที่อ่านได้ไม่ถูกต้อง เราก็สามารถมาปรับ offset ได้เหมือนกัน

สลับโหมด

เอาหละ เหมือนจะจบแล้ว แต่ไหน ๆ เราก็เปลี่ยนโหมดได้ และมีโอกาสที่เราจะต้องการเปลี่ยนโหมดไปมาชั่วคราว เพื่อไม่ต้องเสียเวลามา upload program ใหม่ เราจะใช้สายไฟเพิ่มอีกสายหนึ่ง เพื่อให้เราสามารถกำหนดได้ว่า เราอยากใช้โหมดไหน โดยใช้ขาที่ยังว่าง ซึ่งก็มีอยู่มากมาย ในที่นี้จะใช้ขา D2 โดยถ้า D2 เป็น Low (ขา D2 ต่อลง GND)ให้ใช้ Low power mode ถ้าเป็น High (ขา D2 ต่อ 3.3 V) ให้ใช้ โหมดปกติ เราจะได้ code ดังนี้

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  scd40.reinit();
  pinMode(2, INPUT);
  if (digitalRead(2)) {
    scd40.startPeriodicMeasurement();  // Performance mode (every 5s)
  } else {
    float tempOffsetPre = 0.0;
    scd40.getTemperatureOffset(tempOffsetPre);
    float tempOffset = -3.5 + tempOffsetPre;
    scd40.setTemperatureOffset(tempOffset);
    scd40.startLowPowerPeriodicMeasurement();  // Low Power mode (every 30s)
  }

เพียงเท่านี้ เราก็สามารถเลือกใช้ได้ทั้งสองโหมดเพียงแค่เปลี่ยนการเชื่อมต่อของขา D2 ด้วยสายไฟเพียงเส้นเดียว และอย่าลืมว่า เมื่อเปลี่ยนการเชื่อมต่อแล้วต้องกด reset ที่ microcontroller ด้วยนะครับ

Code ทั้งหมด

#include <SensirionI2CScd4x.h>
#include <U8g2lib.h>

#define BUZZER_PIN 7             // D7
#define CO2_THRESHOLD_BASE 1500  // ppm
#define ALARM_INTV 5000          // ms
#define ON 1
#define OFF 0

unsigned int alarmThreshold = CO2_THRESHOLD_BASE;
bool alarmStatus = OFF;
unsigned long alarmStart = 0;

SensirionI2CScd4x scd40;
uint16_t co2 = 0;
float temperature = 0.0;
float humidity = 0.0;

U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

void setup() {

  Serial.begin(115200);
  // while (!Serial) {      // Waiting for connection wiht computer completed
  //     delay(100);
  // }

  oled.begin();
  oled.clearDisplay();
  oled.setContrast(1);

  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, OFF);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, OFF);

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  scd40.reinit();
  pinMode(2, INPUT);
  if (digitalRead(2)) {
    scd40.startPeriodicMeasurement();  // Performance mode (every 5s)
  } else {
    float tempOffsetPre = 0.0;
    scd40.getTemperatureOffset(tempOffsetPre);
    float tempOffset = -3.5 + tempOffsetPre;
    scd40.setTemperatureOffset(tempOffset);
    scd40.startLowPowerPeriodicMeasurement();  // Low Power mode (every 30s)
  }
  
  Serial.println("Waiting for measurement...");

  oled.clearBuffer();
  oled.setFont(u8g2_font_siji_t_6x10);
  oled.drawStr(0, 30, "Waiting for");
  oled.drawStr(0, 40, "measurement....");
  oled.sendBuffer();
}

void loop() {

  bool dataReady = false;
  scd40.getDataReadyFlag(dataReady);
  if (dataReady) {

    scd40.readMeasurement(co2, temperature, humidity);

    Serial.print("CO2:");
    Serial.print(co2);
    Serial.print("  ");
    Serial.print("Temperature:");
    Serial.print(temperature);
    Serial.print("  ");
    Serial.print("Humidity:");
    Serial.println(humidity);

    oled.clearBuffer();

    oled.setFont(u8g2_font_8x13_tf);
    oled.drawStr(0, 10, "CO");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(16, 14, "2");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(0, 22, "(ppm)");

    String co2_string = String(co2);
    oled.setFont(u8g2_font_courB24_tf);
    int x_pos = (oled.getDisplayWidth() - oled.getStrWidth(co2_string.c_str()));
    oled.setCursor(x_pos, 22);
    oled.print(co2_string);

    oled.setFontMode(1);
    oled.setDrawColor(2);
    oled.drawBox(0, 31, 60, 11);
    oled.drawBox(70, 31, 60, 11);
    oled.setFont(u8g2_font_6x12_t_symbols);
    oled.drawGlyph(20, 41, 176);
    oled.drawGlyph(26, 40, 67);
    oled.drawStr(90, 40, "%");
    oled.drawStr(100, 40, "RH");

    oled.setFont(u8g2_font_courB18_tf);
    oled.setCursor(0, 62);
    oled.print(temperature, 1);
    oled.setCursor(70, 62);
    oled.print(humidity, 1);

    oled.sendBuffer();
  }  // if (dataReady)

  // Alarm Control
  alarmControl();

}  // Loop

void alarmControl(void) {
  if (co2 >= alarmThreshold) {
    if ((alarmStatus == OFF)) {
      setAlarm(ON);
      alarmStart = millis();

    } else if ((millis() - alarmStart) > ALARM_INTV) {
      setAlarm(OFF);
      alarmStart = 0;
      alarmThreshold = co2 + 500;
    }
  } else {
    setAlarm(OFF);
    alarmStart = 0;

    if (co2 < CO2_THRESHOLD_BASE) {
      alarmThreshold = CO2_THRESHOLD_BASE;
    }
  }
}

void setAlarm(bool state) {
  digitalWrite(BUZZER_PIN, state);
  digitalWrite(LED_BUILTIN, state);
  alarmStatus = state;
}

สรุป

บทความนี้เราได้เรียนรู้การใช้ SCD40 ในโหมดประหยัดพลังงาน และได้เรียนรู้วิธีการใส่ offset ให้กับการวัดอุณหภูมิ ทำให้ SCD40 รายงานค่าอุณหภูมิและความชื้นสัมพัทธ์ได้ถูกต้องมากยิ่งขึ้น ซึ่งการที่เราใส่ offset ได้ถือว่าดีมาก ๆ ซึ่งต่างจาก sensor หลาย ๆ ตัวที่ไม่สามารถทำได้

ถาม: เราสามารถชดเชย (offset) ค่าอุณหภูมิเองใน code ได้หรือไม่ โดยไม่ต้องใช้ offset ใน sensor

ตอบ: สำหรับอุณหภูมิเราอาจจะ ชดเชยเองใน code ได้ แต่เราก็จะได้ค่าของความชื้นสัมพัทธ์ไม่ถูกต้องอยู่ดี เพราะค่าความชื้นสัมพัทธ์ที่ sensor รายงานก็จะขึ้นอยู่กับอุณหภูมิที่ sensor อ่านได้ และการชดเชยเองก็ทำได้ยากกว่า

ขอจบความสนุกของบทความนี้ไว้เพียงเท่านี้ ส่วนใครที่ยังไม่อยากหยุดสนุก ผมก็ขอฝากโจทย์ว่า จาก code ที่ให้ไปเป็นการใส่ offset ในส่วนของโหมด low power เท่านั้น ถ้าต้องการใส่ offset ที่โหมดปกติด้วย จะต้องปรับ code อย่างไร

ที่มา

  1. SCD4X datasheet
  2. SCD4X Low power operation
Posted on Leave a comment

วัดปริมาณ carbon dioxide ด้วย SCD-40

ในบทความนี้เป็นการสาธิตการใช้ SCD-40 ในการวัดปริมาณ Carbon dioxide (CO2) ซึ่ง SCD-40 มีความยืดหยุ่นน่าใช้มาก ๆ เช่น มีทั้งโหมดปกติ และ โหมดประหยัดพลังงานให้เลือกใช้ให้เหมาะสมกับความต้องการ สามารถ calibrate ได้ทั้งแบบ auto และ manual และยังสามารถปรับ offset ให้กับค่าอุณหภูมิที่วัดได้เพื่อให้ SCD-40 คำนวนค่าความชื้นได้ถูกต้องมากยิ่งขึ้น โดยในครั้งนี้เราจะทำแบบง่าย ๆ ก่อน โดยให้วัดค่า carbon dioxide ในโหมดปกติ แล้วแสดงผลที่ computer ผ่าน USB พร้อมทั้งแสดงผลที่หน้าจอ OLED และสามารถร้องเตือน (Alarm) เมื่อค่า carbon dioxide ที่อ่านได้เกินค่าที่กำหนด ในที่นี้จะกำหนดค่าเริ่มต้นที่ 1500 ppm

สิ่งที่ต้องเตรียมมีดังนี้

อุปกรณ์

  1. Arduino Nano RP2040 Connect
  2. Carbon dioxide Sensor (SCD-40)
  3. 128×64 SSD1036 OLED 
  4. Buzzer
  5. Breadboard and Jumping Wire

Library

  1. SCD-40 library (Sensirion)
  2. SSD1036 OLED library (U8g2)

ติดตั้ง Hardware

เนื่องจากเราจะสื่อสารระหว่าง Arduino Nano RP2040 Connect กับ SCD-40 และ OLED ผ่าน I2C และ ควบคุม Buzzer ผ่าน Digital I/O โดยเลือกขาที่สะดวก ในที่นี้คือ ขา D7 ดังนั้นเราจะต่อ hardware ดังนี้

Arduino Nano ConnectSCD-40OLEDBuzzer
VINVCCVCC 
GNDGNDGND 
A5 (SLK)SLKSLK 
A4 (SDA)SDASDA 
D7  ขาบวก (ขาที่ยาวกว่า)
Hardware connecting table

ติดตั้ง Library

            ในที่นี้เราจะใช้ library ของ Sensirion สำหรับ SCD-40 และ U8g2 สำหรับ OLED โดยวิธีการติดตั้งสามารถดูได้จากบทความเรื่อง “การติดตั้ง library

Code

#include

โดยเริ่มต้นเราต้อง include สิ่งที่เราต้องใช้ในที่นี้คือ library ต่าง ๆ เช่น SCD-40 และ OLED

#include <SensirionI2CScd4x.h>
#include <U8g2lib.h>

กำหนดชื่อให้กับ ขาที่ต่อกับ Buzzer และเงื่อนไขในการร้องเตือน (Alarm) ของ Buzzer โดยต้องการให้ Buzzer ร้องเตือนเมื่อค่า carbon dioxide ที่อ่านได้มีค่าตั้งแต่ 1500 ppm ขึ้นไป (CO2_THRESHOLD_BASE) และให้ร้องเตือนเป็นเวลา 5 วินาที (ALARM_INTV) 

#define BUZZER_PIN 7              // D7
#define CO2_THRESHOLD_BASE 1500   // ppm
#define ALARM_INTV 5000           // ms
#define ON 1
#define OFF 0

สร้างตัวแปรที่จำเป็นสำหรับการควบคุมการร้องเตือน โดยมีตัวแปรสำหรับเก็บค่า threshold ที่จะร้องเตือน (alarmThreshold)  ตัวแปรใช้เก็บเวลาที่เริ่มร้องเตือน (alarmStart) และ ตัวแปรสำหรับเก็บสถานะการร้องเตือน (alarmStatus)

unsigned int alarmThreshold = CO2_THRESHOLD_BASE;
bool alarmStatus = OFF;
unsigned long alarmStart = 0;

สร้าง object ที่เป็น sensor และกำหนดตัวแปรสำหรับรับค่าที่อ่านได้จาก SCD40

SensirionI2CScd4x scd40;
uint16_t co2 = 0;
float temperature = 0.0;
float humidity = 0.0;

สร้าง object ที่เป็นหน้าจอ OLED

U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

Setup()

เตรียมความพร้อม(initial)ให้กับ hardware ต่าง ๆ ของเรา

เริ่มจากเชื่อมต่อกับ computer ผ่าน Serial (USB) ด้วยคำสั่ง begin และรอให้การเชื่อมต่อเสร็จเรียบร้อย (ด้วย while loop) ก่อนที่จะทำงานอื่น ๆ ต่อไป เพื่อที่ว่า ถ้าเราจะรีบส่งข้อความอะไรไปยัง computer ข้อความเหล่านั้นจะได้ไม่ตกหล่น ถ้าการเชื่อมต่อยังไม่เสร็จเรียบร้อย ข้อความที่เราส่งก็จะตกหล่นหายไป

แต่ถ้าเราไม่ได้เชื่อมต่อกับ computer ก็ต้อง comment สามบรรทัดนี้ ตามตัวอย่าง ไม่อย่างนั้น พอทำงานมาถึงจุดนี้มันจะรอเชื่อมต่อให้เสร็จทั้ง ๆ ที่เราไม่ได้เชื่อมต่อกับ computer ผลก็คือ โปรแกรมจะไม่ไปไหน จะหยุดแค่ตรงนี้เท่านั้น

  Serial.begin(115200);
  // while (!Serial) {      // Waiting for connection wiht computer completed
  //     delay(100);
  // }

เริ่มต้นการทำงานของ OLED ด้วยคำสั่ง begin แล้วสั่งให้ clear หน้าจอ และปรับความสว่างที่ต้องการ (โดยใช้คำสั่ง setContrast())

  oled.begin();
  oled.clearDisplay();
  oled.setContrast(1);

กำหนดโหมดและค่าเริ่มต้นให้กับ I/O ซึ่งก็คือขาควบคุม Buzzer และ LED_BUILTIN

  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, OFF);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, OFF);

เริ่มต้นการทำงานของ carbon dioxide sensor (SCD-40) โดยส่งคำสั่ง begin แล้วตามด้วยคำสั่ง stopPeriodicMeasurement (stop) ก่อนที่จะสั่ง startPeriodicMeasurement (start) เพื่อเริ่มการวัดค่า carbon dioxide 

สังเกตว่า เราต้องสั่ง stop ก่อนสั่ง start นั่นเพราะว่า เมื่อเราสั่ง start แล้ว sensor จะไม่รับหลาย ๆ คำสั่ง รวมทั้ง start ซ้ำด้วย ดังนั้น ถ้าเราไม่สั่ง stop ก่อนที่จะสั่ง start นั้นจะทำให้เกิดปัญหาเวลาที่เรา upload โปรแกรมเข้าไปใหม่ ในระหว่างการพัฒนา หรือ ตอนที่เรากด “reset” ที่ตัว Arduino เพราะ SCD40 จะมองว่าเป็นการสั่ง start ซ้ำ เนื่องจากเวลาที่เรา upload โปรแกรมใหม่ หรือ การกดปุ่ม reset ที่ตัว Arduino นั้น ตัว sensor ไม่ได้ reset ไปพร้อมกับ Arduino ด้วยนั่นเอง

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  scd40.startPeriodicMeasurement();

จากคู่มือของ SCD40 เมื่อสั่ง startPeriodicMeasurement แล้ว sensor จะทำการอ่านค่า carbon dioxide ทุก ๆ 5 วินาที ดังนั้น เมื่อสั่ง start แล้วเราก็ต้องรออย่างน้อย 5 วินาที ถึงจะอ่านค่าได้ ดังนั้นแทนที่จะรออยู่เงียบ ๆ เราก็แจ้งให้ผู้ใช้ทราบเสียหน่อยว่า เรากำลังรอการวัดค่าอยู่นะ เพื่อป้องกันการตกใจว่า เอ๊ะ! ทำไมไม่ทำงาน โดยการ ส่งข้อความไปแสดงที่ computer และแสดงข้อความที่หน้าจอ OLED ด้วย

  Serial.println("Waiting for measurement...");

ส่วนการแสดงข้อความที่หน้าจอ OLED จะยุ่งยากกว่านิดหน่อย และการที่เราจะสั่งว่าให้แสดงอะไรออกที่หน้าจอนั้น มันจะไม่ได้ออกไปที่หน้าจอทันที มันจะเป็นการเก็บข้อมูลที่เราจะให้แสดงออกหน้าจอนั้นไว้ที่ memory ที่เรียกว่า buffer ก่อน แล้วค่อยส่งข้อมูลจาก buffer ออกหน้าจอทีเดียว ดังนั้น ขั้นตอนในการแสดงข้อมูลที่หน้าจอก็จะเริ่มด้วย การ clear buffer (clearBuffer) แล้วก็ส่งข้อมูลที่จะแสดงที่หน้าจอไปเก็บยัง buffer โดยที่เราต้องกำหนด Font เอง ซึ่งเราต้องเลือกทั้งลักษณะ และขนาด (เลือกได้จาก //github.com/olikraus/u8g2/wiki/fntlistall) และ กำหนดตำแหน่งที่จะแสดงตัวหนังสือบนหน้าจอเองด้วย รวมทั้ง ถ้าข้อความยาวเกินกว่าหน้าจอ เราก็ต้องแบ่งบรรทัดเองอีกด้วย (แต่ถึงแม้ว่าจะรู้สึกว่ามันยุ่งยากจัง แต่พอเริ่มชินแล้วเราจะชอบ เพราะมันให้อิสระเราในการทำอะไรกับหน้าจอก็ได้เลย) หลังจากสั่งว่าจะให้แสดงอะไรออกที่หน้าจอแล้ว เราก็ทำการส่งข้อความทั้งหมดที่อยู่ใน buffer (sendBuffer) ออกไปที่หน้าจอพร้อมกันก็จะได้โค้ดดังนี้

  oled.clearBuffer();
  oled.setFont(u8g2_font_siji_t_6x10);
  oled.drawStr(0, 30, "Waiting for");
  oled.drawStr(0, 40, "measurement....");
  oled.sendBuffer();

Loop()

ในส่วนของ loop เราจะให้มีการทำงานดังนี้

Data Ready?

เนื่องจากการทำงานของตัว SCD40 ในโหมดนี้จะวัดค่า CO2 และเตรียมข้อมูลให้เราอ่านทุก ๆ 5 วินาที ดังนั้นเราต้องตรวจว่ามีข้อมูลให้เราหรือยัง โดยการเรียกใช้คำสั่ง getDataReadyFlag ดังนี้

  bool dataReady = false;
  scd40.getDataReadyFlag(dataReady);
  if (dataReady) {

อ่านค่า CO2, Temperature, Humidity

ถ้ามีข้อมูลแล้ว ค่อยเรียกใช้คำสั่ง readMeasurement เพื่ออ่านข้อมูลจาก SCD40 ง่าย ๆ ทีเดียวได้ทั้งสามค่าเลย  ดังนี้

    scd40.readMeasurement(co2, temperature, humidity);

แสดงค่าที่ computer

จากนั้นก็นำค่าที่ได้เหล่านี้ส่งไปที่ computer ผ่านสาย USB ด้วยคำสั่ง Serial.print() ดังนี้

    Serial.print("CO2:");
    Serial.print(co2);
    Serial.print("  ");
    Serial.print("Temperature:");
    Serial.print(temperature);
    Serial.print("  ");
    Serial.print("Humidity:");
    Serial.println(humidity);

คำสั่ง print() ทั้งหมดนี้จะแสดงค่าต่าง ๆ ออกมาอยู่บรรทัดเดียวกัน และมีคำสั่ง println() ในบรรทัดสุดท้าย เพื่อบอกว่า เมื่อแสดงค่าแล้วให้ขึ้นบรรทัดใหม่ เพื่อเตรียมแสดงข้อมูลชุดต่อไป ซึ่งถ้าเราใช้ Tools -> Serial Monitor ก็จะเห็นข้อมูลส่งมาดังนี้

และเมื่อเราใช้ Tools -> Serial Plotter ก็จะได้กราฟแสดงข้อมูลทั้งสามออกมาสวย ๆ ดังนี้

เราสามารถแสดงข้อมูลบางตัวได้ โดยการติ๊กที่เครื่องหมายถูกด้านหน้าชื่อค่าต่าง ๆ ได้ด้วย ทำให้กราฟเราแสดงช่วงของค่าที่วัดได้ให้เหมาะสมมากยิ่งขึ้น ลองกดเล่นกันดูนะครับ

แสดงค่าที่ OLED

ต่อมาเราก็แสดงค่าที่อ่านได้บนหน้าจด OLED ด้วย โดยเราเริ่มจาก clearBuffer เพื่อที่จะล้าง memory ที่เก็บข้อมูลสำหรับแสดงที่หน้าจอ OLED แล้วเราก็ใส่คำสั่งต่าง ๆ เพื่อที่จะส่งค่าที่จะแสดงที่หน้าจอลง buffer แล้วปิดท้ายด้วยคำสั่ง sendBuffer() เพื่อส่งข้อมูลใน buffer ทั้งหมดไปแสดงที่หน้าจอ OLED ดังนี้

    oled.clearBuffer();

    oled.setFont(u8g2_font_8x13_tf);
    oled.drawStr(0, 10, "CO");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(16, 14, "2");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(0, 22, "(ppm)");

    String co2_string = String(co2);
    oled.setFont(u8g2_font_courB24_tf);
    int x_pos = (oled.getDisplayWidth() - oled.getStrWidth(co2_string.c_str()));
    oled.setCursor(x_pos, 22);
    oled.print(co2_string);

    oled.setFontMode(1);
    oled.setDrawColor(2);
    oled.drawBox(0, 31, 60, 11);
    oled.drawBox(70, 31, 60, 11);
    oled.setFont(u8g2_font_6x12_t_symbols);
    oled.drawGlyph(20, 41, 176);
    oled.drawGlyph(26, 40, 67);
    oled.drawStr(90, 40, "%");
    oled.drawStr(100, 40, "RH");

    oled.setFont(u8g2_font_courB18_tf);
    oled.setCursor(0, 62);
    oled.print(temperature, 1);
    oled.setCursor(70, 62);
    oled.print(humidity, 1);

    oled.sendBuffer();

ซึ่งจากโค้ดด้านบน ก็จะได้หน้าจอออกมาแบบนี้ ส่วนใครชอบแบบไหนก็ลองปรับแต่งกันดู

ควบคุม Alarm (alarmControl)

ในส่วนของ การควบคุม Alarm (buzzer ส่งเสียง และ LED สว่าง) จะแยกเป็นอีก function เพื่อไม่ให้ดูยุ่งเกินไป ในส่วนของ Alarm นี้อาจทำง่าย ๆ แค่ ถ้าค่า COที่อ่านได้เกินค่าที่กำหนด ก็ให้ Alarm ถ้าเมื่อใดค่าที่อ่านได้ต่ำกว่าค่าที่กำหนดก็หยุด Alarm 

แต่จากประสบการณ์ มันจะค่อนข้างน่ารำคาญถ้าจะให้ Alarm โดยให้ buzzer ดังตลอดจนกว่าค่า CO2 จะต่ำกว่าที่กำหนด ดังนั้นจึงให้ Alarm แค่เวลาที่กำหนด (ในที่นี้คือ 5 วินาที ซึ่งสามารถเปลี่ยนแปลงได้โดยเปลี่ยนค่า ALARM_INTV) แล้วให้ดังอีกครั้งเมื่อค่า CO2 ที่วัดได้เกินค่าปัจจุบันไปอีก 500 ppm ซึ่งก็จะ Alarm อย่างนี้ไปเรื่อย ๆ จนกว่าค่า CO2 จะต่ำกว่าค่าเริ่มต้น (CO2_TRESHOLD_BASE) จึงปรับค่า threshold กลับมาเป็น ค่าเริ่มต้นอีกครั้ง โดยมี logic การทำงานดังนี้

ก็จะได้ code ออกมาดังนี้

void alarmControl() {
  if (co2 >= alarmThreshold) {
    if ((alarmStatus == OFF)) {
      digitalWrite(BUZZER_PIN, HIGH);   // Alarm
      digitalWrite(LED_BUILTIN, HIGH);  // Alarm
      alarmStatus = ON;                 // Alarm
      alarmStart = millis();

    } else if ((millis() - alarmStart) > ALARM_INTV) {
      digitalWrite(BUZZER_PIN, LOW);    // Alarm
      digitalWrite(LED_BUILTIN, LOW);   // Alarm
      alarmStatus = OFF;                // Alarm
      alarmStart = 0;
      alarmThreshold = co2 + 500;
    }
  } else {
    digitalWrite(BUZZER_PIN, LOW);      // Alarm
    digitalWrite(LED_BUILTIN, LOW);     // Alarm
    alarmStatus = OFF;                  // Alarm
    alarmStart = 0;

    if (co2 < CO2_THRESHOLD_BASE) {
      alarmThreshold = CO2_THRESHOLD_BASE;
    }
  }
}

ข้อสังเกต

จาก code ด้านบนจะเห็นว่า ในส่วนที่เป็น Alarm นั้นมีหลายบรรทัด และถูกเขียนซ้ำกันบ่อย และต่อไปถ้าจะแก้ไขในส่วนของ Alarm ไม่ว่าจะเพิ่มหรือลดการทำงานของ Alarm ก็จะต้องแก้ทั้งสามที่เหมือน ๆ กัน ทำให้มีโอกาสแก้ไม่ครบ ดังนั้นจึงแยก code ส่วนนี้ออกมาเป็นอีก function ดังนี้

void setAlarm(bool state) {
  digitalWrite(BUZZER_PIN, state);
  digitalWrite(LED_BUILTIN, state);
  alarmStatus = state;
}

และ code ในส่วน alarmControl() ก็จะเป็นอย่างนี้

void alarmControl(void) {
  if (co2 >= alarmThreshold) {
    if ((alarmStatus == OFF)) {
      setAlarm(ON);
      alarmStart = millis();

    } else if ((millis() - alarmStart) > ALARM_INTV) {
      setAlarm(OFF);
      alarmStart = 0;
      alarmThreshold = co2 + 500;
    }
  } else {
    setAlarm(OFF);
    alarmStart = 0;

    if (co2 < CO2_THRESHOLD_BASE) {
      alarmThreshold = CO2_THRESHOLD_BASE;
    }
  }
}

เพียงเท่านี้ เราก็จะได้เครื่องวัด carbon dioxide ไว้เล่นสนุกแล้ว

เพื่อความสะดวกในการใช้งาน และความสวยงาม ก็สามารถนำไปใส่กล่อง หรือขวดให้เหมาะสมได้

เพื่อความสะดวก ด้านล่างนี้คือ code ทั้งหมดครับ

#include <SensirionI2CScd4x.h>
#include <U8g2lib.h>

#define BUZZER_PIN 7              // D7
#define CO2_THRESHOLD_BASE 1500   // ppm
#define ALARM_INTV 5000           // ms
#define ON 1
#define OFF 0

unsigned int alarmThreshold = CO2_THRESHOLD_BASE;
bool alarmStatus = OFF;
unsigned long alarmStart = 0;

SensirionI2CScd4x scd40;
uint16_t co2 = 0;
float temperature = 0.0;
float humidity = 0.0;

U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

void setup() {
  
  Serial.begin(115200);
  while (!Serial) {      // Waiting for connection wiht computer completed
      delay(100);
  }

  oled.begin();
  oled.clearDisplay();
  oled.setContrast(1);

  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, OFF);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, OFF);

  scd40.begin(Wire);
  scd40.stopPeriodicMeasurement();
  scd40.startPeriodicMeasurement();

  Serial.println("Waiting for measurement...");

  // oled.clearBuffer();
  oled.setFont(u8g2_font_siji_t_6x10);
  oled.drawStr(0, 30, "Waiting for");
  oled.drawStr(0, 40, "measurement....");
  oled.sendBuffer();
}

void loop() {

  bool dataReady = false;
  scd40.getDataReadyFlag(dataReady);
  if (dataReady) {

    scd40.readMeasurement(co2, temperature, humidity);

    Serial.print("CO2:");
    Serial.print(co2);
    Serial.print("  ");
    Serial.print("Temperature:");
    Serial.print(temperature);
    Serial.print("  ");
    Serial.print("Humidity:");
    Serial.println(humidity);

    oled.clearBuffer();

    oled.setFont(u8g2_font_8x13_tf);
    oled.drawStr(0, 10, "CO");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(16, 14, "2");
    oled.setFont(u8g2_font_siji_t_6x10);
    oled.drawStr(0, 22, "(ppm)");

    String co2_string = String(co2);
    oled.setFont(u8g2_font_courB24_tf);
    int x_pos = (oled.getDisplayWidth() - oled.getStrWidth(co2_string.c_str()));
    oled.setCursor(x_pos, 22);
    oled.print(co2_string);

    oled.setFontMode(1);
    oled.setDrawColor(2);
    oled.drawBox(0, 31, 60, 11);
    oled.drawBox(70, 31, 60, 11);
    oled.setFont(u8g2_font_6x12_t_symbols);
    oled.drawGlyph(20, 41, 176);
    oled.drawGlyph(26, 40, 67);
    oled.drawStr(90, 40, "%");
    oled.drawStr(100, 40, "RH");

    oled.setFont(u8g2_font_courB18_tf);
    oled.setCursor(0, 62);
    oled.print(temperature, 1);
    oled.setCursor(70, 62);
    oled.print(humidity, 1);

    oled.sendBuffer();
  }  // if (dataReady)

  // Alarm Control
  alarmControl();

}  // Loop

void alarmControl(void) {
  if (co2 >= alarmThreshold) {
    if ((alarmStatus == OFF)) {
      setAlarm(ON);
      alarmStart = millis();

    } else if ((millis() - alarmStart) > ALARM_INTV) {
      setAlarm(OFF);
      alarmStart = 0;
      alarmThreshold = co2 + 500;
    }
  } else {
    setAlarm(OFF);
    alarmStart = 0;

    if (co2 < CO2_THRESHOLD_BASE) {
      alarmThreshold = CO2_THRESHOLD_BASE;
    }
  }
}

void setAlarm(bool state) {
  digitalWrite(BUZZER_PIN, state);
  digitalWrite(LED_BUILTIN, state);
  alarmStatus = state;
}

คำเตือน

ขอย้ำอีกครั้งว่า ค่าที่อ่านได้อาจคลาดเคลื่อนด้วยหลายปัจจัย อย่านำไปใช้ในสถานการณ์ที่ความคลาดเคลื่อนนี้อาจก่อให้เกิดความเสียหายต่อชีวิตและทรัพย์สินรวมถึงสิ่งแวดล้อมนะครับ

ในตอนต่อ ๆ ไป เราจะมาปรับปรุงระบบนี้ให้น่าสนใจมากยิ่งขึ้นไปอีก เพราะยังมีอะไรให้ทำกับระบบนี้อีกมาก เช่น สามารถ calibrate ค่า CO2 ได้ สามารถกำหนด offset ให้กับค่าอุณหภูมิที่อ่านได้ ทำให้ได้ค่าอุณหภูมิ และความชื้นที่ถูกต้องมากยิ่งขึ้น รวมทั้ง เราจะใช้ความสามารถความเป็น dual core ของ RP2040 มาใช้ประโยชน์ และการอ่านค่าจากระยะไกล โดยใช้ Bluetooth หรือแม้แต่ส่งขึ้น cloud เพื่อ monitor ได้จากมืออีกด้วย น่าสนใจมาก ๆ ใช่ไหมล่ะครับ คอยติดตามกันนะครับ

เอกสารอ้างอิง

  1. SCD-40 data sheet (//sensirion.com/media/documents/E0F04247/631EF271/CD_DS_SCD40_SCD41_Datasheet_D1.pdf)
Posted on Leave a comment

Bluetooth BR/EDR และ Bluetooth Low Energy (LE) คืออะไร

Bluetooth BR/EDR

Bluetooth BR/EDR หรือเรียกว่า Bluetooth Classic เป็นจุดเริ่มต้นของ Bluetooth technology โดยเริ่มต้นจากการเป็น technology ติดต่อสื่อสารระหว่าง 2 อุปกรณ์แบบ 1 ต่อ 1 (point to point) โดยไม่ต้องมีอุปกรณ์ช่วยสื่อสารอื่น ๆ เข้ามาเกี่ยวข้อง โดยเริ่มต้นนั้นเป็น Bluetooth BR (Basic rate) ที่มีความเร็วในการส่งข้อมูลที่ 1 Mb/s และต่อมาได้พัฒนาให้มีความสามารถส่งข้อมูลได้เร็วขึ้นเป็น 2 Mb/s เรียกว่า Bluetooth EDR (Enhance Data rate) ซึ่ง Bluetooth Classic ได้รับความนิยมอย่างมากสำหรับอุปกรณ์ไร้สายต่าง ๆ เช่น mouse หรือ keyboard โดยเฉพาะอย่างยิ่ง  audio streaming เช่น ลำโพงไร้สายต่าง ๆ

Bluetooth Low Energy (LE)

ตั้งแต่ Bluetooth v4.0 เป็นต้นมา Bluetooth ได้ถูกพัฒนาให้ใช้พลังงานอย่างมีประสิทธิภาพมากขึ้น เรียกว่า Bluetooth Low Energy (LE) นอกจากนี้ยังถูกพัฒนาให้รองรับการเชื่อมต่อหลายรูปแบบ ทั้ง 1 – 1, Broadcast, Mesh ทำให้สามารถสร้างกลุ่มของการสื่อสารของอุปกรณ์หลาย ๆ ตัวได้ และสื่อสารได้ไกลขึ้น โดยการถ่ายทอดข้อมูลผ่านอุปกรณ์ตัวที่อยู่ใกล้เคียงออกไปยังอุปกรณ์ที่ต้องการ ในปัจจุบันยังรองรับการทำ device positioning คือการบอกตำแหน่ง และทิศทางของตัวอุปกรณ์ได้อีกด้วย เหมาะสำหรับการบอกตำแหน่งของอุปกรณ์ในพื้นที่ไม่กว้างมากนัก เช่น ในอาคาร หรือลานจอดรถได้เป็นอย่างดี

อ้างอิงจาก:

//www.bluetooth.com/learn-about-bluetooth/tech-overview/

Posted on Leave a comment

Transmissive & Photoacoustic NDIR sensing technology คืออะไร

เป็น technology ในการวัดปริมาณก๊าซ โดยใช้สมบัติการดูดกลืนคลื่นแม่เหล็กไฟฟ้าของโมเลกุลของก๊าซช่วง infra-red (IR)

หลักการทำงาน

ก่อนจะอธิบายการทำงานของ sensor ต้องขออธิบายธรรมชาติของก๊าซที่สำคัญอย่างหนึ่งก่อน นั่นคือ โมเลกุลของก๊าซ สามารถดูดกลืนคลื่นแม่เหล็กไฟฟ้าในบางความยาวคลื่นได้ โดยที่โมเลกุลของก๊าซแต่ละชนิดสามารถดูดกลืนคลื่นแม่เหล็กไฟฟ้าได้ดีที่ความยาวคลื่นต่างกัน เช่น carbon dioxide นั้น สามารถดูดกลืนแม่เหล็กไฟฟ้าที่ความยาวคลื่นประมาณ 4.2 ไมโครเมตร ได้ดี

ซึ่งคลื่นแม่เหล็กไฟฟ้าที่ความยาว 4.2 ไมโครเมตรนี้อยู่ในช่วงที่เรียกว่า Infra-red (IR) จากสมบัติที่สำคัญนี้ทำให้เราสามารถตรวจวัดปริมาณของก๊าซ carbon dioxide ได้ โดยดูจากประมาณการดูดกลืนคลื่นแม่เหล็กไฟฟ้าที่ความยาวคลื่น 4.2 ไมโครเมตรนี้ 

Non Dispersive Infra-red (NDIR)

โดยปกติ ถ้าเราต้องการคลื่นแม่เหล็กไฟฟ้าความยาวคลื่นเดียว หรืออยู่ในช่วงแคบ ๆ เราอาจต้องใช้อุปกรณ์ช่วยในการแยกคลื่นแม่เหล็กไฟฟ้าที่เราต้องการออกจากคลื่นแม่เหล็กไฟฟ้าความยาวคลื่นอื่น ๆ เนื่องจากแหล่งกำเนิดมักมีคลื่นแม่เหล็กไฟฟ้าหลายความยาวคลื่นปนกันมา ยกตัวอย่างคลื่นแม่เหล็กไฟฟ้าที่รู้จักกันดีคือ คลื่นแสง ซึ่งประกอบด้วยคลื่นแม่เหล็กไฟฟ้าความยาวคลื่นตั้งแต่ 400 นาโนเมตร ไปจนถึง 750 นาโนเมตร ดังนั้น  การจะได้ความยาวคลื่นเดียว ก็ต้องใช้ อุปกรณ์ที่เป็นตัวกระจาย (dispersive element) คลื่นแสง เช่น ปริซึม (prism) หรือ เกรตติ้ง(diffraction grating) หรืออีกวิธีหนึ่งคือการใช้ filter คืออุปกรณ์ที่ยอมให้คลื่นแสงที่เราต้องการผ่านไปได้เท่านั้น วิธีนี้ไม่ใช้ dispersive element จึงเรียกว่า Non Dispersive ในทำนองเดียวกัน ถ้าเราใช้ filter เพื่อให้ได้คลื่นแม่เหล็กไฟฟ้าที่ความยาวช่วง IR เราก็จะเรียกว่า Non Dispersive Infra-red (NDIR)

Transmissive NDIR

จากการที่โมเลกุลของก๊าซสามารถดูดกลืนคลื่นแม่เหล็กไฟฟ้าที่ความยาวคลื่น 4.2 ไมโครเมตร ได้นี้ เราก็สามารถวัดปริมาณ carbon dioxide ได้ โดยตรวจวัดปริมาณคลื่นแม่เหล็กไฟฟ้าที่ไม่ถูกดูดกลืน วิธีที่เรียกว่า Transmissive NDIR โดยมีแหล่งกำเนิดของคลื่นแม่เหล็กไฟฟ้าในช่วง IR แล้วผ่าน filter เพื่อให้ได้คลื่น 4.2 ไมโครเมตร แล้วผ่าน ห้องวัด(measurement chamber) ที่มีก๊าซ carbon dioxide แล้วให้คลื่น IR ที่เหลือจากการดูดกลืนตกกระทบบน sensor สำหรับตรวจ IR เพื่อวัดปริมาณ IR ที่เหลือจากการดูดกลืนของโมเลกุลของ carbon dioxide

ถ้าปริมาณคลื่น IR ผ่านกระทบกับ IR sensor ได้มาก แสดงว่ามี carbon dioxide อยู่น้อย ถ้ามีปริมาณ IR ผ่านมาได้น้อย แสดงว่ามีปริมาณ carbon dioxide อยู่มากนั่นเอง วิธีนี้ตัว IR sensor นั้นต้องอยู่ตรงข้ามกับแหล่งกำเนิด IR และมี carbon dioxide อยู่ระหว่างนั้น ทำให้ตัวเครื่องมือวัดต้องมีความยาวพอสมควร

Photoacoustic NDIR

อีกวิธีหนึ่งที่ใช้วัดปริมาณก๊าซได้ โดยทำงานด้วยหลักการที่ว่า เมื่อโมเลกุลของก๊าซ carbon dioxide ดูดกลืนคลื่นแม่เหล็กไฟฟ้าเข้าไปแล้ว จะเกิดการสั่นของโมเลกุล เมื่อมีการสั่นก็จะทำให้เกิดเสียง ดังนั้นจึงใช้ไมโครโฟน(ขนาดเล็กมาก) ตรวจจับปริมาณเสียงนี้ได้ จึงเรียกว่า Photoacoustic NDIR

ถ้ามีโมเลกุลของ carbon dioxide มาก ก็จะสามารถตรวจจับเสียงนี้ได้มาก และเนื่องจากเสียงกระจายทุกทิศทาง ดังนั้นจะวาง microphone ไว้ตรงไหนใน measurement chamber ก็ได้ ทำให้ตัวตรวจวัดแบบนี้มีขนาดเล็กกว่าแบบ Transmissive NDIR เช่น carbon dioxide sensor (SCD4x) ของ Sensirion ที่มีขนาดเล็กกะทัดรัด

ที่มา

Posted on Leave a comment

RP2040 (microcontroller) คืออะไร

RP2040

คือ microcontroller ของค่าย Raspberry Pi ออกแบบโดย Raspberry Pi บนสถาปัตยกรรม ARM Cortex-M0+ รองรับการเขียนโปรแกรม สำหรับมือสมัครเล่น (ที่ไม่ใช่เล่น ๆ ) นิยมใช้อย่าง MicroPython และรองรับการเขียนโปรแกรมระดับมืออาชีพ โดยรองรับ C/C++ ด้วย จุดเด่นของ microcontroller ตัวนี้คือประสิทธิภาพสูง โดยเป็น dual-core ARM Cortex-M0+ 32bit ทำงานที่ความถี่ 133 MHz มี Flash ขนาด 2MB และ SRAM ขนาด 264KB ซึ่งสูงมากเมื่อเทียบกับรุ่นพี่เก่าแก่อย่าง Arduino UNO ที่ใช้ ATmega328p ทำงานที่ความถี่ 16MHz มี Flash ขนาด 32K และ SRAM ขนาด 2K ที่สำคัญคือราคาไม่สูงมาก และมีหลายบริษัทฯได้พัฒนาบอร์ดของตัวเองโดยใช้ chip ตัวนี้ บริษัทที่เป็นที่รู้จักกันดีเช่น Arduino, Adafruit, Sparkfun และอื่นๆ อีกมาก ที่สำคัญอีกอย่างคือมีการ port TensorFlow Lite Micro ไว้รองรับงาน Machine Learning ด้วย

ถือว่าเป็น microcontroller ที่น่าสนใจมาก ๆ ทั้งความที่เป็น dual-core ARM และมีการ port TensorFlow Lite Micro มาให้ใช้ด้วย

ที่มา

//www.raspberrypi.com/products/rp2040/

Posted on Leave a comment

Differential Signaling vs Single-ended Signaling ต่างกันอย่างไร

Differential signaling

เป็นการส่งสัญญาณผ่านสายสัญญาณ 2 เส้น โดยที่ทั้งสองเส้นนั้นมีขนาดของสัญญาณเท่ากัน แต่ขั้วตรงกันข้าม เช่น ในขณะที่เส้นหนึ่งเป็น 5v อีกเส้นจะเป็น -5v ข้อดีของระบบนี้คือ สามารถกำจัดสัญญาณรบกวนที่เป็น common-mode (สัญญาณที่ทั้งสองสายมีเหมือนกันทั้งขนาดและขั้ว) ได้ดี เช่น สัญญาณรบกวนจากคลื่นแม่เหล็กไฟฟ้าในสายส่งสัญญาณ เนื่องจากสัญญาณที่เราต้องการส่งนั้นมีทิศทางตรงข้ามกัน แต่สัญญาณรบกวนที่เข้ามาในสายสัญญาณนั้น ก็จะเข้าเหมือนกันทั้งสองสาย จึงสามารถกำจัดได้ง่าย โดยใช้ differential amplifier ทำให้ระบบ differential signaling ทนต่อสัญญาณรบกวนได้ดี และทำให้ส่งสัญญาณได้ไกล และเร็ว

Single-ended Signaling

เป็นการส่งสัญญาณผ่านสายสัญญาณ 2 เส้น โดยที่จะมีการเปลี่ยนแปลงสัญญาณ หรือระดับแรงดันไฟฟ้า เพียงเส้นเดียว อีกเส้นจะเป็นระดับอ้างอิงคงที่เสมอ ซึ่งมักจะเป็น ground ของระบบ ระบบนี้จะแยกสัญญาณรบกวนออกได้ยากกว่า โดยเฉพาะเมื่อต้องการส่งสัญญาณที่ความถี่สูง เพราะตัวสัญญาณรบกวนเองก็มักจะความถี่สูง ระบบจึงแยกสัญญาณรบกวนออกจากสัญญาณที่ต้องการได้ยาก ทำให้ส่งสัญญาณที่ความถี่สูงมากไม่ได้ และระยะทางก็ได้ไม่ไกล เนื่องจากยิ่งไกลมาก ก็ยิ่งมีโอกาสถูกรบกวนได้ง่าย อีกทั้งยังมีผลของค่าความจุ และความเหนี่ยวนำในสายสัญญาณอีก แต่ข้อดีคือเป็นระบบที่เรียบง่าย ไม่มีอุปกรณ์อะไรมาก ทำให้ต้นทุนต่ำ

อ้างอิง

Posted on Leave a comment

Simplex vs Duplex (communication) คืออะไร

Simplex communication คืออะไร

Simplex communication คือ การส่งสัญญาณระหว่างจุด 2 จุด โดยที่จุดหนึ่งส่งสัญญาณ อีกจุดรับสัญญาณ ไม่สามารถส่งกลับได้ สมมติว่าเป็นการส่งสัญญาณระหว่างจุด A กับจุด B โดยจุด A จะมีอุปกรณ์ในการส่งสัญญาณเท่านั้น ไม่สามารถรับสัญญาณได้ ส่วนจุด B มีอุปกรณ์รับสัญญาณเท่านั้น ไม่สามารถส่งสัญญาณได้ ตัวอย่างเช่น การถ่ายทอดสัญญาณโทรทัศน์ สถานีโทรทัศน์ก็จะมีเครื่องส่งสัญญาณอย่างเดียว ส่วนทีวีก็ทำหน้าที่รับสัญญาณอย่างเดียว ไม่สามารถส่งสัญญาณกลับไปที่สถานีได้ นอกจากนี้ อุปกรณ์พวก remote control ต่างๆ ก็เป็นการส่งสัญญาณแบบ simplex ด้วยเหมือนกัน คือ ตัวรีโมท ทำหน้าที่ส่งอย่างเดียว ส่วนเครื่องใช้ไฟฟ้าก็ทำหน้าที่รับอย่างเดียว ส่งกลับไม่ได้

Duplex communication คืออะไร

Duplex communication คือ การส่งสัญญาณระหว่างจุด 2 จุด โดยที่ทั้งสองจุดสามารถส่งสัญญาณสวนทางกันได้ คือ ทั้งสองจุดมีทั้งตัวส่งสัญญาณ และตัวรับสัญญาณ แต่การส่งข้อมูลสวนทางกันได้นี้ก็แบ่งได้เป็น 2 แบบ คือ Half-Duplex (HDX) และ Full-Duplex (FDX)

Half-Duplex 

คือ ระบบ duplex ที่สามารถสื่อสารสวนทางกันได้ แต่ต้องผลัดกัน ไม่สามารถสื่อสารสวนทางกันได้พร้อมกัน เช่น walkie-talkie โดยเมื่อฝ่ายหนึ่งจะพูดต้องกด switch เมื่อกดแล้ว ระบบจะปิดการทำงานของตัวรับสัญญาณ ทำให้ไม่สามารถรับสัญญาณได้ และเปิดการทำงานของตัวส่งสัญญาณ ทำให้สามารถพูดหรือส่งสัญญาณได้ และเมื่อปล่อย switch ระบบก็จะปิดการทำงานของตัวส่งสัญญาณ และเปิดการทำงานของตัวรับสัญญาณอีกครั้ง เพื่อรอรับสัญญาณ จะเห็นว่า ถ้าทั้งสองฝั่งกด switch พูดพร้อมกัน ก็ไม่มีตัวรับสัญญาณ การส่งสัญญาณหรือการสื่อสารก็ไม่สมบูรณ์

Full-Duplex 

คือ ระบบ duplex ที่ทั้งสองจุดสามารถสื่อสารสวนทางกันได้พร้อมกัน เช่น โทรศัพท์ ที่เราใช้กัน

อ้างอิง

Posted on Leave a comment

การใช้งาน e-paper 2.13 inch 250×122 pixel White-Black-Red

ในบทความนี้จะเป็นการใช้งาน e-paper ง่าย ๆ ไม่ใช้ RAM เยอะ และใช้ library แค่ SPI เท่านั้น

สิ่งที่ต้องมี

การต่อสาย

Arduino NanoE-paper
5VVCC
GNDGND
11SDI
13SCLK
10CS
9D/C
8Reset
7Busy
Arduino Nano and E-paper connecting table
Arduino Nano and E-paper wiring

ขั้นตอน

ขั้นตอนการใช้งาน ก็มีแค่ 4 ขั้นตอนง่าย ๆ คือ อันดับแรก เราต้องสร้างภาพที่เราต้องการแบบเต็มจอ (screen) เสียก่อน แล้วนำภาพนั้นไปแปลงเป็นตัวเลข จากนั้นก็ทำตัวเลขเหล่านั้นมาใส่ลง file แล้วโปรแกรมลง microcontroller ก็เป็นอันเสร็จเรียบร้อย

ขั้นตอนการใช้ e-paper

สร้างภาพแบบเต็ม screen

เนื่องจาก screen นี้มีขนาด 250×122 pixel โดยมีสามสี คือ ขาว ดำ และ แดง ดังนั้นเราก็จะต้องสร้างภาพที่มีขนาดและสีตามนี้ (ในที่นี้จะไม่กล่าวถึงวิธีทำภาพ)

ภาพที่ต้องการแสดงบน screen (mavigo_bwr.png)

เมื่อได้ภาพที่ต้องการแล้ว ก็ทำการแบ่งเป็น 2 ภาพ คือ ภาพที่เป็นสีดำล้วน กับสีแดงล้วน (เนื่องจาก memory สำหรับภาพสีดำ กับสีแดงใน e-paper นั้นจะแยกกัน) โดยให้ภาพอยู่ในรูปแบบของ JPG, JPEG, PNG, หรือ BMP

mavigo_bw.png
mavigo_r.png

เปลี่ยนภาพให้เป็นตัวเลข

ในการเปลี่ยนภาพให้เป็นตัวเลข ขอแนะนำเว็บของผู้ผลิต screen นั่นคือ good-display.com ซึ่งที่จริง เค้ามีโปรแกรมแบบไม่ online ให้ใช้ด้วย แต่ในที่นี้จะแนะนำแบบ online เท่านั้น เมื่อเปิดหน้าเว็บแล้วให้ใส่ข้อมูลดังนี้

1. เลือก screen model 2.13 และ GDEH213Z98 แล้ว check confirm

2. กด “Choose Files” แล้วเลือก file ภาพสีดำที่เตรียมไว้

3. ตรวจสอบว่า Preview ถูกต้องหรือไม่ โดยที่จะเป็นภาพกลับด้าน ถ้าไม่ถูกต้อง ลองตรวจสอบชนิดของ file, ขนาดของภาพ หรือนำ alpha channel ออกจากภาพ แล้วค่อย upload อีกครั้ง

4. เลือก Output Type: เป็นแบบ “Plain” , Pattern: “Horizontal -1 bit per pixel” แล้วกด “Output” ก็จะได้ ตัวเลขออกมา แล้วกด copy

นำตัวเลขที่ได้ใส่ลง file

เมื่อได้ตัวเลขแล้ว เราก็นำตัวเลขมาใส่ file โดยที่ file จะมีรูปแบบด้านล่าง (รูปแบบ file อ้างอิงมาจาก good-display.com) โดยให้วางตัวเลขที่ copy มานั้น ใส่ลงใน array ตัวแรก ซึ่งเตรียมไว้สำหรับภาพสีดำ จากนั้น ก็กลับไปที่เว็บอีกครั้ง โดยคราวนี้ทำเหมือนเดิม แต่เลือกภาพสีแดงแทน แล้วนำตัวเลขที่ได้มาใส่ลงใน array ที่สอง (ที่จริงเว็บรองรับที่จะทำการ convert พร้อมกันทีละ 2 ภาพ แต่เพื่อลดโอกาสสับสน จึงให้ทำทีละภาพ)

#include <avr/pgmspace.h>
const unsigned char gImage_BW[4000] PROGMEM= { /* For black image */


};

const unsigned char gImage_R[4000] PROGMEM= { /* For red image */


};
avr/pgmspace.h เป็น library ช่วยในการจัดการ memory สำหรับ microcontroller ตระกูล avr จะเห็นว่า เราประกาศ array แล้วมี keyword “PROGMEM” ด้วย นั่นเป็นการบอกให้ compiler นำตัวแปลนี้ใส่ลงใน Flash memory แทนที่จะเป็น RAM เหมือนตัวแปลอื่น ๆ ทำให้ประหยัด RAM ไปได้ ถ้าเอา PROGMEM ออก compiler ก็จะฟ้องว่า RAM ไม่พอ เพราะ ATmega328p มี RAM แค่ 2k byte แต่เราประกาศตัวแปลตัวละ 4k byte เลยทีเดียว 

เมื่อใส่ตัวเลขลงใน array ทั้งสองตัวเรียบร้อยแล้วจะได้ file ลักษณะด้านล่างนี้ ต่อไปให้ save file ในชื่อ mavigo_demo.h เก็บไว้ที่เดียวกับ file ที่เก็บ code (___.ino) ถ้าเก็บไว้คนละที่กัน ตัว code จะเรียกหาไม่เจอ

#include <avr/pgmspace.h>
const unsigned char gImage_BW[4000] PROGMEM= { /* For black image */
// 'mavigo_bw', 122x250px
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x3f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf0, 0x07, 0x1e, 0x00, 0x00, 0x01, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xe0, 0x07, 0x07, 0x00, 0x00, 0x01, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xe0, 0x0f, 0x00, 0xe0, 0x00, 0x01, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x1f, 0x00, 0x1c, 0x00, 0x01, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x1f, 0x00, 0x07, 0x00, 0x01, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x3f, 0x00, 0x00, 0xe0, 0x01, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x3f, 0x00, 0x00, 0x1c, 0x01, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x3f, 0x80, 0x00, 0x03, 0x01, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xe0, 0x00, 0x00, 0xff, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xfc, 0x00, 0x00, 0x1f, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xff, 0x00, 0x00, 0x03, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0x7f, 0xff, 0xfc, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0xff, 0xff, 0xfe, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x00, 0x7f, 0xff, 0xf0, 0x00, 0x01, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xff, 0xc0, 0x00, 0x03, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xfe, 0x00, 0x00, 0x0f, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xf0, 0x00, 0x00, 0x7f, 0xfc, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x7f, 0xc0, 0x00, 0x01, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0x80, 0x3f, 0x00, 0x00, 0x0e, 0x01, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x3f, 0x00, 0x00, 0x70, 0x01, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x1f, 0x00, 0x01, 0xc0, 0x01, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xc0, 0x1f, 0x00, 0x0e, 0x00, 0x01, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xe0, 0x0f, 0x00, 0x70, 0x00, 0x01, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xe0, 0x0f, 0x01, 0xc0, 0x00, 0x01, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf0, 0x07, 0x8e, 0x00, 0x00, 0x01, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf0, 0x03, 0xfc, 0x00, 0x00, 0x01, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x80, 0x00, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x0f, 0xe0, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x8e, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x04, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0x04, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xfe, 0x08, 0x43, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xfe, 0x18, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xfe, 0x18, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0xfe, 0x10, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x0e, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x7e, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x06, 0x01, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x07, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x0f, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x07, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xe0, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x7f, 0xff, 0xfc, 0x1f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x0f, 0xff, 0xff, 0x9f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x01, 0xff, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xe3, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x83, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x03, 0xff, 0xff, 0xfe, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xfe, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x03, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x1c, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x0c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x04, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x04, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x04, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x02, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0x86, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x0f, 0x87, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x0f, 0x86, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x3c, 0xfc, 0x30, 0x06, 0x00, 0x0f, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf8, 0x00, 0x3c, 0xfc, 0x30, 0x06, 0x00, 0x0f, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0x30, 0xff, 0x39, 0xfe, 0x7f, 0xcf, 0xc0, 
0xff, 0xfc, 0x00, 0x3e, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0x30, 0xff, 0x39, 0xfe, 0x7f, 0xcf, 0xc0, 
0xff, 0xfc, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xf9, 0x81, 0x30, 0xc3, 0x37, 0x9e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x03, 0xff, 0xe0, 0x0f, 0xff, 0xf9, 0x81, 0x30, 0xc3, 0x37, 0x9e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xf9, 0x81, 0x33, 0xfc, 0xc0, 0x7e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xf9, 0x81, 0x33, 0xfc, 0xc0, 0x7e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x0f, 0xff, 0xf8, 0x0f, 0xff, 0xf9, 0x81, 0x30, 0xcc, 0x08, 0x7e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x0f, 0xc0, 0x78, 0x0f, 0xff, 0xf9, 0x81, 0x30, 0xcc, 0x08, 0x7e, 0x60, 0x4f, 0xc0, 
0xff, 0xf8, 0x07, 0xc0, 0x78, 0x0f, 0xff, 0xf9, 0xff, 0x30, 0x33, 0x31, 0xe6, 0x7f, 0xcf, 0xc0, 
0xff, 0xf8, 0x07, 0xc0, 0x70, 0x0f, 0xff, 0xf9, 0xff, 0x30, 0x33, 0x31, 0xe6, 0x7f, 0xcf, 0xc0, 
0xff, 0xf8, 0x03, 0xc0, 0x70, 0x0f, 0xff, 0xf8, 0x00, 0x33, 0x33, 0x36, 0x66, 0x00, 0x0f, 0xc0, 
0xff, 0xf8, 0x01, 0xc0, 0x60, 0x1f, 0xff, 0xf8, 0x00, 0x33, 0x33, 0x36, 0x66, 0x00, 0x0f, 0xc0, 
0xff, 0xfc, 0x00, 0xc0, 0x60, 0x1f, 0xff, 0xff, 0xff, 0xf3, 0x33, 0xff, 0xe7, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x01, 0xc0, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf3, 0x33, 0xff, 0xe7, 0xff, 0xff, 0xc0, 
0xff, 0xfc, 0x01, 0xc0, 0x00, 0x1f, 0xff, 0xf9, 0xf8, 0x3f, 0xf0, 0xff, 0xe0, 0x00, 0x3f, 0xc0, 
0xff, 0xfe, 0x01, 0xc0, 0x00, 0x3f, 0xff, 0xf9, 0xf8, 0x3f, 0xff, 0xff, 0xe0, 0x00, 0x1f, 0xc0, 
0xff, 0xfe, 0x01, 0xc0, 0x00, 0x3f, 0xff, 0xfe, 0x06, 0xf3, 0x3f, 0xff, 0x80, 0x79, 0x8f, 0xc0, 
0xff, 0xff, 0x01, 0xc0, 0x00, 0x7f, 0xff, 0xf9, 0xe0, 0x3c, 0xf8, 0x0f, 0x61, 0xe7, 0x9f, 0xc0, 
0xff, 0xff, 0xc3, 0xc0, 0x00, 0xff, 0xff, 0xf9, 0xe0, 0x3c, 0xe0, 0x03, 0xe1, 0xe7, 0xbf, 0xc0, 
0xff, 0xff, 0xe3, 0xc0, 0x00, 0xff, 0xff, 0xfe, 0x7f, 0xcf, 0xc3, 0xe1, 0xff, 0x87, 0xbf, 0xc0, 
0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xfe, 0x7f, 0xcf, 0x87, 0xf8, 0xff, 0x87, 0xbf, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x98, 0x03, 0x9f, 0xfc, 0x61, 0x81, 0xbf, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0x98, 0x03, 0x11, 0x06, 0x61, 0x81, 0xbf, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xfe, 0xf3, 0x30, 0x66, 0x77, 0x98, 0x4f, 0xc0, 
0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xf9, 0xfe, 0xf7, 0x3c, 0x0e, 0x37, 0x98, 0x4f, 0xc0, 
0xff, 0xff, 0xf8, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x01, 0x07, 0x3f, 0x87, 0x3e, 0x06, 0x4f, 0xc0, 
0xff, 0xff, 0xe0, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x01, 0x07, 0x3f, 0x87, 0x3e, 0x06, 0x4f, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x3c, 0x0e, 0x3e, 0x00, 0x0f, 0xc0, 
0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xff, 0x30, 0x26, 0x7e, 0x00, 0x0f, 0xc0, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xfe, 0x18, 0x03, 0x11, 0x06, 0x61, 0x86, 0x4f, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x18, 0x03, 0x9f, 0xfc, 0x61, 0x86, 0x4f, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, 0x60, 0xcd, 0x8f, 0xf8, 0xe0, 0x18, 0x4f, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xfe, 0x60, 0xcd, 0xc3, 0xe1, 0xe0, 0x18, 0x4f, 0xc0, 
0xff, 0xfc, 0x00, 0x3e, 0x00, 0x1f, 0xff, 0xff, 0x99, 0x0c, 0xe0, 0x03, 0xf9, 0x99, 0xff, 0xc0, 
0xff, 0xfc, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0x99, 0x0c, 0x78, 0x0f, 0xf9, 0x99, 0xff, 0xc0, 
0xff, 0xf8, 0x03, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xf9, 0xff, 0x3f, 0xff, 0xe6, 0x18, 0x4f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xf1, 0xff, 0x0f, 0xff, 0xe6, 0x18, 0x4f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xfe, 0x60, 0x3c, 0xcc, 0x0e, 0x00, 0x00, 0x3f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3d, 0xe7, 0xe0, 0x7f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x39, 0xe7, 0xe0, 0x7f, 0xc0, 
0xff, 0xf8, 0x07, 0xff, 0xf0, 0x0f, 0xff, 0xf8, 0x00, 0x3c, 0x0c, 0xd8, 0x06, 0x66, 0x0f, 0xc0, 
0xff, 0xf8, 0x03, 0xff, 0xf0, 0x0f, 0xff, 0xf8, 0x00, 0x3c, 0x0c, 0xc8, 0x06, 0x66, 0x0f, 0xc0, 
0xff, 0xfc, 0x01, 0xff, 0xe0, 0x1f, 0xff, 0xf9, 0xff, 0x30, 0xc3, 0x3e, 0x07, 0xe0, 0x7f, 0xc0, 
0xff, 0xfc, 0x00, 0xff, 0x80, 0x1f, 0xff, 0xf9, 0xff, 0x30, 0xc3, 0x3e, 0x07, 0xe0, 0x7f, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf9, 0x81, 0x30, 0xfc, 0xc9, 0x80, 0x06, 0x0f, 0xc0, 
0xff, 0xfc, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf9, 0x81, 0x30, 0xfc, 0xc9, 0x80, 0x06, 0x0f, 0xc0, 
0xff, 0xfe, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf9, 0x81, 0x3c, 0xcc, 0xc6, 0x19, 0x81, 0xbf, 0xc0, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf9, 0x81, 0x3c, 0xcc, 0xc6, 0x19, 0x81, 0xbf, 0xc0, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xf9, 0x81, 0x3f, 0xf3, 0xf1, 0xe7, 0xe0, 0x4f, 0xc0, 
0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0xf9, 0x81, 0x3f, 0xf3, 0xf1, 0xe7, 0xe0, 0x4f, 0xc0, 
0xff, 0xff, 0xc0, 0x00, 0x01, 0xff, 0xff, 0xf9, 0xff, 0x3f, 0xc0, 0xf1, 0xe1, 0x86, 0x3f, 0xc0, 
0xff, 0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xf9, 0xff, 0x3f, 0xc0, 0xf1, 0xe1, 0x86, 0x3f, 0xc0, 
0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x00, 0x30, 0xf0, 0xf9, 0xe1, 0x9f, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x30, 0xf0, 0xf9, 0xe1, 0x9f, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
};

const unsigned char gImage_R[4000] PROGMEM= { /* For red image */
// 'mavigo_r', 122x250px
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xfc, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1e, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0e, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1b, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1b, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x19, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x80, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7e, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x70, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x80, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7c, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x60, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1c, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x09, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x19, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1b, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x80, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1c, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x06, 0x58, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xfc, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x19, 0xec, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0x6c, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0x7c, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x38, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1c, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0x80, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0d, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x19, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1b, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x5f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x7f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xf8, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xfc, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x19, 0xec, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0x6c, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1e, 0x78, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x30, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0c, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x20, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x08, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0x80, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x18, 0x60, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xc0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xe0, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x07, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
};

Upload ไปยัง Arduino Nano

เมื่อเตรียมข้อมูลเรียนร้อยแล้ว ก็ทำการ upload ข้อมูลพร้อมทั้ง code ที่ช่วยในการนำข้อมูลภาพจาก flash memory ไปส่งให้กับ display ก็เป็นอันเสร็จเรียบร้อย แต่ก่อนอื่น เรามาทำความเข้าใจตัว code ที่ว่ากันก่อน (ตัว code นี้ได้ดัดแปลงมากจาก code ของ good-display.com

#include

ส่วนนี้จะ  include 2 อย่างคือ SPI.h ซึ่งเป็น library ที่เราใช้ในการสื่อสารกับ display อีก file คือ mavigo_demo.h ซึ่งเป็น file ที่เก็บภาพที่จะแสดงบน screen ซึ่งเราสร้างไว้ในขั้นตอนก่อนหน้านี้

#include <SPI.h>
#include"mavigo_demo.h"

IO setting

ส่วนนี้เป็นการกำหนดหน้าที่ให้กับ pin ต่าง ๆ 

int BUSY_Pin = 7; 
int RES_Pin = 8; 
int DC_Pin = 9; 
int CS_Pin = 10; 

#define

เป็นการกำหนดชื่อให้กับค่าคงที่เพื่อให้เข้าใจง่าย ในที่นี้เป็นการกำหนดขนาดของ RAM ที่ใช้แสดงภาพเต็ม screen ซึ่งก็คือ 4000 byte

#define ALLSCREEN_GRAGHBYTES  4000

//Functions declaration

เป็นการประกาศ function ที่จะใช้ โดยตัวเนื้อของ function จะถูกเขียนไว้หลังจาก loop() ในส่วนของ function definition

setup()

ในส่วนนี้เป็นการกำหนดทิศทางของข้อมูลของแต่ละ pin และ เตรียมพร้อมสำหรับการสื่อสาร SPI

   pinMode(BUSY_Pin, INPUT); 
   pinMode(RES_Pin, OUTPUT);  
   pinMode(DC_Pin, OUTPUT);    
   pinMode(CS_Pin, OUTPUT);   
   //SPI
   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 
   SPI.begin ();  

loop()

ใน loop function นี้จะแบ่ง code เป็นสองส่วนหลัก ๆ คือ ส่วนที่แสดงภาพบน screen กับส่วนที่ clear screen ในแต่ละส่วนก็จะมี function การทำงานที่ครบถ้วน คือ เริ่มตั้งแต่ Initial hardware (EPD_HW_Init()) นำภาพขึ้น screen (EPD_WhiteScreen_ALL()) หรือ clear screen (EPD_WhiteScreen_ALL_Clean()) และ เข้าสู่ Deep sleep mode (EPD_DeepSleep()) เพื่อประหยัดพลังงาน ซึ่งหลังจาก Deep sleep ถ้าจะให้ display ทำงานอีกครั้ง ต้องส่งสัญญาณ Hardware reset ซึ่งอยู่ใน (EPD_HW_Init())

    //Full screen refresh
    EPD_HW_Init(); //Electronic paper initialization
    EPD_WhiteScreen_ALL(gImage_BW,gImage_R); //Refresh the picture in full screen
    EPD_DeepSleep(); //Enter deep sleep,Sleep instruction is necessary, please do not delete!!! 
    delay(2000);   
    
    //Clean
    EPD_HW_Init(); //Electronic paper initialization
    EPD_WhiteScreen_ALL_Clean();
    EPD_DeepSleep(); //Enter deep sleep,Sleep instruction is necessary, please do not delete!!!
    delay(2000); 
    
    while(1); 

// Functions definition

ในส่วนสุดท้ายนี้เป็นรายละเอียดของ function ที่ใช้ในการควบคุม display ถ้าอยากทราบรายละเอียดอาจต้องเปิดคู่มือของ display และ driver IC (SSD1680) ควบคู่กันไป โดยในที่นี้จะยังไม่กล่าวถึงรายละเอียดของ function เหล่านี้

เพื่อความสะดวกให้สร้าง “New Sketch” copy code ด้านล่างนี้ไปวางทับ แล้วอย่าลืม วาง file ที่เก็บตัวเลขของภาพ (ในที่นี้คือ mavigo_demo.h) ไว้ใน folder เดียวกันนะครับ

#include <SPI.h>
#include"mavigo_demo.h"

//IO settings
int BUSY_Pin = 7; 
int RES_Pin = 8; 
int DC_Pin = 9; 
int CS_Pin = 10; 

//250*122///////////////////////////////////////

#define ALLSCREEN_GRAGHBYTES  4000

// Function declaration

void SPI_Write(unsigned char value);
void Epaper_Write_Command(unsigned char command);
void Epaper_Write_Data(unsigned char command);
//EPD
void Epaper_READBUSY(void);
void EPD_HW_Init(void); //Electronic paper initialization
void EPD_Update(void);
void EPD_DeepSleep(void);

//Display 
void EPD_WhiteScreen_ALL(const unsigned char *BW_datas,const unsigned char *R_datas);
void EPD_WhiteScreen_ALL_Clean(void);

void setup() {

   pinMode(BUSY_Pin, INPUT); 
   pinMode(RES_Pin, OUTPUT);  
   pinMode(DC_Pin, OUTPUT);    
   pinMode(CS_Pin, OUTPUT);   
   //SPI
   SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0)); 
   SPI.begin ();  

}

//Tips//
/*When the electronic paper is refreshed in full screen, the picture flicker is a normal phenomenon, and the main function is to clear the display afterimage in the previous picture.
  When the local refresh is performed, the screen does not flash.*/
/*When you need to transplant the driver, you only need to change the corresponding IO. The BUSY pin is the input mode and the others are the output mode. */
  
void loop() {
    //Full screen refresh
    EPD_HW_Init(); //Electronic paper initialization
    EPD_WhiteScreen_ALL(gImage_BW,gImage_R); //Refresh the picture in full screen
    EPD_DeepSleep(); //Enter deep sleep,Sleep instruction is necessary, please do not delete!!! 
    delay(2000);   
    
    //Clean
    EPD_HW_Init(); //Electronic paper initialization
    EPD_WhiteScreen_ALL_Clean();
    EPD_DeepSleep(); //Enter deep sleep,Sleep instruction is necessary, please do not delete!!!
    delay(2000); 
    
    while(1); 

}


// Function definition

//////////////////////SPI///////////////////////////////////

void SPI_Write(unsigned char value)                                    
{                                                           
  SPI.transfer(value);
}

void Epaper_Write_Command(unsigned char command)
{
  digitalWrite(CS_Pin,LOW);                   
  digitalWrite(DC_Pin,LOW);   // command write
  SPI_Write(command);
  digitalWrite(CS_Pin,HIGH);
}

void Epaper_Write_Data(unsigned char command)
{
  digitalWrite(CS_Pin,LOW);                   
  digitalWrite(DC_Pin,HIGH);   // data write
  SPI_Write(command);
  digitalWrite(CS_Pin,HIGH);
}

/////////////////EPD settings Functions/////////////////////

//////////////////////////////////////////////////////////////////////////////////////////////////
//SSD1680
void EPD_HW_Init(void)
{
  digitalWrite(RES_Pin,LOW);  // Module reset      
  delay(10); //At least 10ms delay 
  digitalWrite(RES_Pin,HIGH); 
  delay(10); //At least 10ms delay  

  Epaper_READBUSY();   
  Epaper_Write_Command(0x12);  //SWRESET
  Epaper_READBUSY();   

  Epaper_Write_Command(0x01); //Driver output control      
  Epaper_Write_Data(0xF9);
  Epaper_Write_Data(0x00);
  Epaper_Write_Data(0x00);

  Epaper_Write_Command(0x11); //data entry mode       
  Epaper_Write_Data(0x01);

  Epaper_Write_Command(0x44); //set Ram-X address start/end position   
  Epaper_Write_Data(0x00);
  Epaper_Write_Data(0x0F);    //0x0F-->(15+1)*8=128

  Epaper_Write_Command(0x45); //set Ram-Y address start/end position          
  Epaper_Write_Data(0xF9);   //0xF9-->(249+1)=250
  Epaper_Write_Data(0x00);
  Epaper_Write_Data(0x00);
  Epaper_Write_Data(0x00); 

  Epaper_Write_Command(0x3C); //BorderWavefrom
  Epaper_Write_Data(0x05); //0x05 or 0xC0

  Epaper_Write_Command(0x18); //Read built-in temperature sensor
  Epaper_Write_Data(0x80);  
  
  Epaper_Write_Command(0x21); //  Display update control
  Epaper_Write_Data(0x00);  
  Epaper_Write_Data(0x80);  

  Epaper_Write_Command(0x4E);   // set RAM x address count to 0;
  Epaper_Write_Data(0x00);
  
  Epaper_Write_Command(0x4F);   // set RAM y address count to 0XF9;    
  Epaper_Write_Data(0xF9);
  Epaper_Write_Data(0x00);
  Epaper_READBUSY();
  
}
//////////////////////////////All screen update////////////////////////////////////////////
void EPD_WhiteScreen_ALL(const unsigned char *BW_datas,const unsigned char *R_datas)
{
   unsigned int i;  
  Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {               
     Epaper_Write_Data(pgm_read_byte(&BW_datas[i]));
   }
  Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {               
     Epaper_Write_Data(~(pgm_read_byte(&R_datas[i])));
   }
   EPD_Update();   
}

void EPD_WhiteScreen_ALL_Clean(void)
{
   unsigned int i;  
  Epaper_Write_Command(0x24);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {               
     Epaper_Write_Data(0xff);
   }
  Epaper_Write_Command(0x26);   //write RAM for black(0)/white (1)
   for(i=0;i<ALLSCREEN_GRAGHBYTES;i++)
   {               
     Epaper_Write_Data(0x00);
   }
   EPD_Update();   
}

/////////////////////////////////////////////////////////////////////////////////////////
void EPD_Update(void)
{
  Epaper_Write_Command(0x22); //Display Update Control
  Epaper_Write_Data(0xF7);   
  Epaper_Write_Command(0x20);  //Activate Display Update Sequence
  Epaper_READBUSY();   

}

void EPD_DeepSleep(void)
{  
  Epaper_Write_Command(0x10); //enter deep sleep
  Epaper_Write_Data(0x01); 
  delay(100);
}

void Epaper_READBUSY(void)
{ 
  while(1)
  {   //=1 BUSY
     if(digitalRead(BUSY_Pin)==0) break;
  }  
}

//////////////////////////////////END//////////////////////////////////////////////////

ในการแสดงภาพบน screen จะมีการกะพริบหลายครั้งถือเป็นเรื่องปกติครับ ถ้า upload แล้วไม่เกิด error อะไร แต่ไม่แสดงภาพ ให้ลองตรวจสอบการต่อสายดูนะครับ หรือลองถอดสาย Busy แล้วเสียบใหม่ดูนะครับ

สรุป

การที่เราทำข้อมูลเป็นลักษณะของรูปภาพใส่ file แล้ว upload ไปยัง microcontroller ทำให้ความซับซ้อนในการโปรแกรมน้อย เพราะเขียนโปรแกรมแค่นำข้อมูลใน flash memory ไปส่งให้ตัว display เท่านั้นเอง และเนื่องจากความซับซ้อนของโปรแกรมน้อย ก็ทำให้ใช้ RAM น้อยไปด้วย เหมาะกับ microcontroller ขนาดเล็ก RAM ไม่มาก อย่าง ATmega328p ในบอร์ด Arduino Nano ส่วนในกรณีที่เราอยากให้มีการเปลี่ยนภาพได้ โดยที่เราไม่อยากมาทำการ upload ใหม่ทุกครั้งที่ต้องการเปลี่ยนภาพ เราก็สามารถทำภาพเตรียมไว้ใน flash memory ได้ แล้วก็เขียน code ให้สามารถเลือกได้ว่าจะนำภาพไหน ( array ตัวไหน)ใน memory ขึ้นมาแสดง โดยปกติแล้วถ้าเป็น screen แบบอื่น เช่น OLED หรือ TFT มักจะไม่ใช้วิธีนี้ เพราะ screen เหล่านั้นมักจะใช้แสดงภาพที่มีการ update บ่อย ๆ ดังนั้นการที่ต้องมา upload ใหม่ทุกครั้งจึงไม่สมเหตุสมผล แต่ไม่ค่อยมีปัญหาสำหรับ e-paper เพราะมักจะถูกใช้ในงานที่ไม่ต้อง update บ่อยอยู่แล้ว

Posted on Leave a comment

Arduino Nano with sensor (ก้าวที่สาม)

จาก Arduino Nano with Serial (ก้าวที่สอง) หวังว่าจะเข้าใจและทำแบบฝึกหัดกันได้นะครับ แต่ถ้าไม่ได้ก็ไม่เป็นไร เพราะค่อนข้างยากสำหรับมือใหม่ แต่ถ้าเข้าใจในก้าวที่สามนี้ จะต้องกลับไปทำแบบฝึกหัดได้อย่างแน่นอนเลยละครับ

จากตอนที่แล้ว(ก้าวที่สอง) เราได้เรียนรู้ function สำคัญที่ช่วยให้เราส่งข้อมูลจาก computer ให้ Arduino Nano ไปแล้ว คราวนี้เราจะให้ Arduino Nano ส่งข้อมูลกลับมาให้เราบ้าง โดยให้ Arduino Nano รับข้อมูลจาก sensor แล้วส่งมายัง computer โดยในที่นี้เราจะใช้ sensor ที่ผู้เขียนชอบตัวหนึ่งคือ BME280 ซึ่งเป็น sensor ที่วัด อุณหภูมิ ความชื้น และแรงดันอากาศ ด้วย 

โดยปกติแล้ว ถ้าเราจะเขียนโปรแกรมดึงข้อมูลจาก sensor สักตัว เราต้องเข้าใจการทำงานของ sensor ตัวนั้นอย่างละเอียด โดยดูจากคู่มือของ sensor นั้น ๆ จึงจะสามารถดึงข้อมูลมาได้อย่างถูกต้อง BME280 เองก็เหมือนกัน ถ้าเราจะเขียนโปรแกรมติดต่อเพื่อดึงข้อมูลเองนั้น เป็นเรื่องที่ต้องใช้เวลามากเลยทีเดียว (คู่มือ BME280) ดังนั้นจึงมีใครบางคนหรือบางกลุ่ม ได้ศึกษาการใช้งาน sensor และเขียนโปรแกรมเตรียมไว้ให้เรานำไปใช้ได้ง่าย ๆ สิ่งที่เค้าเขียนเตรียมไว้ให้นี้ ก็เป็นลักษณะของ function ให้เราเรียกใช้ โดยทั้งหมดที่เค้าเตรียมไว้ให้นั้น เรียกว่า library ดังนั้น เราต้องติดตั้ง library ของ BME280 ก่อน โดยวิธีการติดตั้ง library นั้นสามารถศึกษาได้จาก ขั้นตอนการติดตั้ง library ได้เลยครับ ในตัวอย่างนี้จะใช้ library ของ Adafruit ซึ่งต้องขอบคุณที่เค้าทำให้เราได้ใช้กันง่าย ๆ ฟรี ๆ ถ้ามีโอกาสก็อยากให้สนับสนุนสินค้าของ Adafruit เค้าด้วยนะครับ แล้วเราก็มาเริ่มกันเลย

สิ่งที่ต้องมี

เมื่อเตรียมอุปกรณ์พร้อมแล้ว ก็มาเริ่มกันเลย

Hardware

ต่อสาย โดยให้ต่อสายจาก Arduino Nano ไปที่ BME280 sensor module ดังนี้

Arduino Nano↔︎BME280 (Adafruit)
5V↔︎Vin
GND↔︎GND
A5↔︎SCK
A4↔︎SDI
Arduino Nano and BME280 connecting table
Arduino Nano and BME280 wiring

Software

หลังจากติดตั้ง library แล้ว มักจะมีตัวอย่างการใช้งาน library มาให้ด้วย และเป็นจุดเริ่มต้นที่ดีในการศึกษาการใช้ library นั้น ๆ ดังนั้น เราก็มาดูตัวอย่างกันเลย จากเมนู ให้ไปที่ File -> Examples -> AdafruitBME280 Library -> bme280test

//Comment

เมื่อเปิด code ตัวอย่าง เราต้องอ่านทั้ง comment และ code เพื่อให้เข้าใจว่า code ตัวอย่างนี้ถูกเขียนให้ใช้ hardware แบบไหน เช่น BME280 สามารถสื่อสารได้ทั้งแบบ I2C หรือ SPI แต่ใน code มักจะถูกเขียนให้เลือกใช้อย่างเดียว เราก็ต้องดูว่า code นั้นเลือกใช้การสื่อสารแบบไหน เหมือนกับที่เราต่อ hardware ไว้หรือไม่ เช่น ในระบบของเรา เราต่อ hardware เพื่อใช้ I2C อย่างน้อยเราก็ต้องดูให้แน่ใจว่า code ตัวอย่างนั้นใช้ I2C ด้วยเช่นกัน

เราเริ่มจาก comment ที่หัว file กันเลย จะเห็นว่า comment ก็บอกว่า ใช้ได้ทั้ง I2C หรือ SPI ถ้าเป็น I2C จะต้องใช้ address อะไรในการติดต่อกับ sensor และ อื่น ๆ ที่ผู้เขียนอยากจะสื่อสาร รวมทั้งใครเป็นคนเขียน code นี้ขึ้นมา และคนอื่น ๆ มีสิทธิใช้ code นี้แค่ไหนอย่างไร

/***************************************************************************
  This is a library for the BME280 humidity, temperature & pressure sensor

  Designed specifically to work with the Adafruit BME280 Breakout
  ----> //www.adafruit.com/products/2650

  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface. The device's I2C address is either 0x76 or 0x77.

  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!

  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
  See the LICENSE file for details.
 ***************************************************************************/

#include

ส่วนต่อมา เป็นการรวม file ที่เป็น header (filename.h) ที่เป็นของ library ต่าง ๆ ที่ต้องใช้ รวมเข้ามาใน code นี้ด้วย ถ้าไม่รวมเข้ามา เราก็จะใช้ library เหล่านั้นไม่ได้ ในที่นี้ ก็มีการรวม header ของ Wire, SPI, Adafruit_Sensor และ Adafruit_BME280 เข้ามา ซึ่งใน file เหล่านี้จะมีการประกาศค่าต่าง ๆ ที่ใช้ใน library เช่น ค่าคงที่ หรือ function ต่างๆ ที่เราสามารถเรียกใช้ได้

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define

ส่วนต่อมา เป็นเรื่องของการ กำหนดค่าคงที่ต่าง ๆ ในส่วนแรก เป็นการกำหนดชื่อให้ขา 13, 12, 11, และ 10 แล้วหลังจากนี้จะอ้างถึงขาเหล่านนี้โดยใช้ชื้อพวกนี้แทนเลขขา ต่อมาเป็นการกำหนดชื่อให้กับค่าคงที่ตัวหนึ่ง

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define SEALEVELPRESSURE_HPA (1013.25)

ส่วนต่อมา เป็นการประกาศตัว bme เป็นชนิด Adafruit_BME280 เสมือนว่า กำหนดให้ bme คือ sensor BME280 นั่นเอง โดยรายละเอียดของตัวแปรชนิดนี้จะอยู่ใน library ตรงนี้จะเห็นว่ามี 3 บรรทัด และ active เฉพาะบรรทัดแรก อีกสองบรรทัดถูก comment ไว้ ตรงนี้จะเป็นการเลือกว่า เราจะติดต่อสื่อสารกับ sensor แบบไหน โดยที่บรรทัดแรก เป็นการติดต่อแบบ I2C ซึ่งก็ตรงกับที่ต่อ hardware ไว้ บรรทัดที่สองเป็นแบบ SPI โดยใช้ hardware SPI ส่วนบรรทัดที่สามเป็นการติดต่อแบบ SPI แต่เป็นแบบ software SPI

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

ต่อมาเป็นการประกาศตัวแปร ชื่อ “delayTime” ก็น่าจะเอาไว้เก็บค่าเวลาที่จะให้ microcontroller หยุดนี่ง แต่ยังไม่กำหนดว่าให้เป็นค่าเท่าไร

unsigned long delayTime;

setup()

เริ่มด้วย เชื่อมต่อการสื่อสารกับ computer โดยใช้ฟังก์ชั้น Serial ที่ 9600 baud (baud คืออะไร) แล้วรอให้การเชื่อต่อเรียบร้อยก่อนที่จะไปต่อ จากตัวอย่างที่แล้ว “ก้าวที่สอง” ไม่มีคำสั่งนี้ เพราะหลังจากที่เราสั่งให้เริ่มการเชื่อมต่อแล้ว เราให้ microcontroller ทำอย่างอื่นต่อไปก่อนที่เราจะใช้การสื่อสาร จึงไม่จำเป็นต้องรอให้เชื่อมต่อเสร็จ แต่ในที่นี้ ตัวอย่างจะใช้การสื่อสารในคำสั่งต่อไปทันที เราจึงต้องให้ microcontroller หยุดรอให้การเชื่อมต่อเสร็จสิ้นก่อนที่จะเรียกใช้คำสั่งในการสื่อสารต่อไป

    Serial.begin(9600);
    while(!Serial);    // time to get serial running

เมื่อการเชื่อต่อเสร็จสิ้นแล้ว คำสั่งถัดมาคือ สั่งให้ microcontroller ส่งข้อมูล “BME280 test” กลับไปยัง computer ซึ่งจะแสดงที่หน้าต่าง serial monitor

    Serial.println(F("BME280 test"));

ต่อมาเป็น การประกาศตัวแปร status ขึ้นมา แล้วนำตัวแปรที่เพิ่งประกาศมารับค่าที่ส่งกลับมาจาก bme.begin() ซึ่งเป็นการสั่งให้เริ่มเตรียมพร้อมที่จะใช้งาน sensor BME280 (รายละเอียดของ function อยู่ใน library)

    unsigned status;
    
    // default settings
    status = bme.begin();  

แล้วตรวจดูว่า ผลที่ส่งมาให้กับ status เป็นอย่างไร ถ้าเริ่มเตรียมตัวไม่สำเร็จก็จะ ส่งข้อมูลใน if ไปที่ computer แล้วหยุดที่ while(1) delay10; ถ้าเข้าใจ ภาษา C ก็จะทราบว่า microcontroller จะหยุดอยู่ตรงนี้ ไม่ไปคำสั่งอื่นต่อแล้วจนกว่าจะถูก reset

    if (!status) {
        Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
        Serial.print("SensorID was: 0x"); Serial.println(bme.sensorID(),16);
        Serial.print("        ID of 0xFF probably means a bad address, a BMP 180 or BMP 085\n");
        Serial.print("   ID of 0x56-0x58 represents a BMP 280,\n");
        Serial.print("        ID of 0x60 represents a BME 280.\n");
        Serial.print("        ID of 0x61 represents a BME 680.\n");
        while (1) delay(10);
    }

ถ้าการเริ่มต้น ไม่มีปัญหาอะไร ก็จะส่งข้อมูล “–Default Test –” ไปที่แสดงที่ computer

    Serial.println("-- Default Test --");

กำหนดค่า 1000 ให้กับ ตัวแปร delayTime ซึ่งก่อนหน้านี้ไม่ได้กำหนด

    delayTime = 1000;

แล้วส่งบรรทัดว่าง ๆ 1 บรรทัดไปแสดงที่ computer

    Serial.println();

loop()

ใน loop นี้ไม่มีอะไรมากนอกจาก การเรียก function 2 คือ printValue() และ delay(1000) ซึ่งเป็นการสั่งให้หยุดนิ่ง 1000 ms ส่วน printValue() คืออะไร ก็ต้องไปดูรายละเอียดที่ function printValue() ที่อยู่ด้านล่าง

void loop() { 
    printValues();
    delay(delayTime);
}

printValues()

เริ่มแรกเป็นการส่งข้อมูล “Temperature = “ ไปที่ computer 

    Serial.print("Temperature = ");

ต่อมาเป็นการส่งข้อมูล bme.readTemperature() ไปที่ computer (รายละเอียดของคำสั่งนี้ก็อยู่ใน library) ซึ่งข้อมูลนี้ก็คือ ให้อ่านค่าอุณหภูมิจาก sensor ดังนั้นบรรทัดที่สองนี้จึงมีสองคำสั่งซ้อนกันอยู่ คืออ่านค่าอุณหภูมิจากsensor แล้ว ส่งให้ computer ด้วยคำสั่ง Serial.print() 

    Serial.print(bme.readTemperature());

จากนั้นก็ส่ง “ °C” ไปที่ computer 

    Serial.println(" °C");

สั่งเกตว่า คำสั่งสุดท้ายนี้ต่างจากสองคำสั่งก่อนหน้า คือ print() กับ println() โดยที่ print() เป็นการส่งข้อมูลที่อยู่ในวงเล็บเท่านั้น แต่ println() คือส่งข้อมูลในวงเล็บแล้วตามด้วยข้อมูลที่บอกให้ขึ้นบรรทัดใหม่ด้วย (‘\r’ และ ‘\n’) 

คำสั่งสามบรรทัดแรกนี้ เป็นชุดที่เป็นการส่งค่าอุณหภูมิไปให้ computer นั่นเอง แล้วมีการอ่านค่าอื่น ๆ แล้วส่งให้ computer ด้วย รูปแบบคำสั่งที่ซ้ำๆ กัน อีก 3 ชุด แล้วปิดท้ายด้วย การส่งข้อมูลให้ขึ้นบรรทัดใหม่

    Serial.print("Pressure = ");

    Serial.print(bme.readPressure() / 100.0F);
    Serial.println(" hPa");

    Serial.print("Approx. Altitude = ");
    Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA));
    Serial.println(" m");

    Serial.print("Humidity = ");
    Serial.print(bme.readHumidity());
    Serial.println(" %");

    Serial.println();

Output

ให้กด upload แล้วดู output ที่ Serial monitor โดยกดที่เครื่องหมายคล้ายแว่นขยายที่มุมบนขวา หรือ ไปที่เมนู Tools -> Serial Monitor ก็จะได้หน้าต่าง Serial Monitor แล้ว ข้อมูลที่ส่งมาจาก microcontroller ก็จะมาแสดงที่นี่

BME280 output

สรุป

คราวนี้เราได้เรียนรู้

  1. เราสามารถใช้ library ช่วยในการติดต่อกับ sensor หรือ อุปกรณ์อื่น ๆ ได้
  2. เราสามารถเรียนรู้การใช้ library ต่าง ๆ จากตัวอย่างของ library เองได้
  3. เราสามารถส่งข้อมูลจาก microcontroller กลับไปที่ computer โดยใช้ Serial function ได้

ทุกคนสามารถใช้แนวทางนี้ในการศึกษาการต่อ sensor อื่น ๆ รวมทั้งอุปกรณ์อื่น ๆ ที่ไม่ใช่ sensorด้วย เช่น display ซึ่งจะทำให้อุปกรณ์ของเราน่าสนใจมากยิ่งขึ้น

อย่าลืมกด like ที่ Facebook Page เพื่อติดตามเรื่องราวใหม่ ๆ จากเรานะครับ