ผู้เขียน หัวข้อ: [คำถามจากทางบ้าน] คำถาม kitbright จากเด็กบ้านเรียน :: [โปรแกรมทำงานไม่ทันเวลา]  (อ่าน 641 ครั้ง)

Watchara A.

  • Administrator
  • Sr. Member
  • *****
  • กระทู้: 297
  • Point: +0/-0
  • E25FGL / (alias : E22MHS,E22AAA)
    • ดูรายละเอียด
    • TSE Official Web
[คำถามจากทางบ้าน] คำถาม kitbright จากเด็กบ้านเรียน :: [โปรแกรมทำงานไม่ทันเวลา]
เห็นว่ามีประโยชน์จึงนำมาลงไว้ครับ

อ้างถึง
เรียน อาจารย์ วัชระ


ต้องขอโทษครับที่รบกวนเวลาของอาจารย์ คือนึกไม่ออกว่าจะถามใคร พอดีได้เข้ามาอยู่ในกลุ่ม kitbright ของธรรมศาสตร์ เลยต้องรบกวนอาจารย์เฉลยแนวทางแก้ปัญหาให้หน่อยครับ


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


โปรแกรมในส่วนข้อความบอกบุรุษไปรษณีย์ทำงาน
โปรแกรมในส่วนแจ้งเตือนทางไลน์ทำงาน

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


ขอบพระคุณ

รักเกียรติ ท.
« แก้ไขครั้งสุดท้าย: ตุลาคม 01, 2018, 02:31:37 PM โดย Watchara A. »
วัชระ อมศิริ
คณะวิศวกรรมศาสตร์ มหาวิทยาลัยธรรมศาสตร์
99 หมู่ 18 ตำบลคลองหนึ่ง อำเภอคลองหลวง
จังหวัดปทุมธานี 12120
awatchar@engr.tu.ac.th

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

Watchara A.

  • Administrator
  • Sr. Member
  • *****
  • กระทู้: 297
  • Point: +0/-0
  • E25FGL / (alias : E22MHS,E22AAA)
    • ดูรายละเอียด
    • TSE Official Web
โค๊ด: [Select]
#include <WiFi.h>
#include <WiFiClientSecure.h>

#define LINE_TOKEN "ZZZZ"

#define WIFI_STA_NAME "XXXX"
#define WIFI_STA_PASS "YYYYY"


#include "Adafruit_LEDBackpack.h"

Adafruit_8x16minimatrix matrix = Adafruit_8x16minimatrix();




bool LINE_Notify(String message) {
  WiFiClientSecure client;

  if (!client.connect("notify-api.line.me", 443)) {
    Serial.println("connection failed");
    return false;
  }

  String payload = "message=" + message;
  String req = "";
  req += "POST /api/notify HTTP/1.1\r\n";
  req += "Host: notify-api.line.me\r\n";
  req += "Authorization: Bearer " + String(LINE_TOKEN) + "\r\n";
  req += "User-Agent: ESP32\r\n";
  req += "Content-Type: application/x-www-form-urlencoded\r\n";
  req += "Content-Length: " + String(payload.length()) + "\r\n";
  req += "\r\n";
  req += payload;
  // Serial.println(req);
  client.print(req);

  delay(20);

  // Serial.println("-------------");
  long timeOut = millis() + 30000;
  while (client.connected() && timeOut > millis()) {
    if (client.available()) {
      String str = client.readString();
      // Serial.print(str);
    }
    delay(10);
  }
  // Serial.println("-------------");

  return timeOut > millis();
}

void setup() {
  Serial.begin(115200);
 
  pinMode(14, INPUT_PULLUP); // S2
  pinMode(16, INPUT_PULLUP); // S1
  pinMode(32, INPUT_PULLUP); //IN1
  pinMode(17, OUTPUT);    // Bluetooth monitor S1
  pinMode(2, OUTPUT);     // Wifi monitor wifi
  pinMode(15, OUTPUT);    // NTP monitot IN1
  pinMode(12, OUTPUT);    // IoT

//Initial state set all LED trig in1 to off
  digitalWrite(17, HIGH);
  digitalWrite(2, HIGH);
  digitalWrite(15, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(32, HIGH);

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WIFI_STA_NAME);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_STA_NAME, WIFI_STA_PASS);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    digitalWrite(2, LOW); //monitor wifi connect
  }


  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  matrix.begin(0x70);
  matrix.setRotation(1);
  matrix.setTextSize(1);
  matrix.setTextWrap(false);
  matrix.setTextColor(LED_ON);
  matrix.setRotation(1);
}

void loop() {
  if (digitalRead (32) == LOW){digitalWrite(15, LOW);in1();digitalWrite(15, HIGH);}
  if (digitalRead (16) == LOW) {S1(); }
}

void in1(){
for (int16_t x = 0; x >= -500; x--) {
    matrix.clear();
    matrix.setCursor(x, 0);
    matrix.print("Hello Mr. Postman. Lift Top cover up and put mail in. Thanks you. ");
    matrix.writeDisplay();
    delay(40);
  }
 
}

void S1(){
   if (digitalRead(16) == LOW) {
      Serial.println("You Have Mail !");
      digitalWrite(17, LOW);
      LINE_Notify("%E0%B8%A1%E0%B8%B5%E0%B8%9C%E0%B8%B9%E0%B9%89%E0%B8%9A%E0%B8%B8%E0%B8%81%E0%B8%A3%E0%B8%B8%E0%B8%81+%21%21%21");
      digitalWrite(17, HIGH);
      //while (digitalRead(PIR_PIN) == HIGH) delay(1);
    }
}

พิจารณาจากคำถาม ที่ถามเข้ามา
และ Sourcecode แล้ว พบว่าเป็นปัญหาที่มักพบบ่อย และ มีประโยชน์มากที่จะตอบเป็นสาธารณะครับ

ลักษณะนี้เรียกว่า การทำงานที่ไม่ทันเวลาของไมโครคอนโทรลเลอร์
ถ้าจะอธิบายอย่างง่ายคือ

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

เช่น ถ้าเขียนโปรแกรมด้วยภาษาซีบน Arduino ในลักษณะเช่นนี้
โค๊ด: [Select]
ฯลฯ
delay(10000);
if(digitalRead(1)==HIGH)
  {
    //digitalWrite(13,HIGH);
  }
ฯลฯ

ในขณะที่ดีเลย์ 10 วินาที นั้น จะไม่สามารถประมวลผลคำสั่งถัดไปได้เลย (กล่าวคือจะรอเฉยๆ 10 วินาที) เมื่อผ่าน 10 วินาทีไปแล้ว จึงจะทำคำสั่งบรรทัดถัดไป

ซึ่งเมื่อเปรียบเทียบกับ Sourcecode ที่ส่งเข้ามาแล้ว จะพบว่า
เมื่อ digitalRead(32); ให้ค่าออกมาเป็น LOW นั้น ฟังก์ชั่น inl(); ซึ่งใช้ในการแสดงข้อความผ่านทาง dot matrix display จะทำงาน
โดยจะค่อยๆเลื่อนตัวอักษรทีละตัว (ในทางเทคนิคคือเปิด-ปิดไฟ ทีละดวงด้วยความรวดเร็ว) ซึ่งใช้เวลาในการทำงานมาก จึงจำเป็นต้องรอให้ทำงานจบก่อน (ข้อความเลื่อนแสดงครบก่อน) จึงจะทำคำสั่ง digitalWrite(15, HIGH); และคำสั่งอื่นๆซึ่งอยู่ถัดไปได้

วิธีการแก้ไขทำได้โดย
- แบบง่าย
ทำงานที่เสร็จเร็วก่อน ในกรณีนี้คือ ส่งข้อความด้วย LineNotify ก่อน ค่อยมาแสดงข้อความวิ่งผ่าน dotmatrix display
- แบบยาก
ใช้ Real-Time Operating System มาช่วย ซึ่งเป็นการเขียนโปรแกรมในรูปแบบ Task โดยเมื่อ Microcontroller ทำงาน จะสามารถแบ่งย่อยจังหวะการทำงานของ Task ต่างๆให้ดูเหมือนว่าทำงานไปพร้อมกันได้ แต่ต้องใช้เทคนิคการเขียนที่ยากกว่า

ซึ่งจะได้อธิบายการประยุกต์ใช้ Real-Time Operating System (RTOS : ระบบปฏิบัติการแบบทันเวลา) ไว้ในโอกาสต่อไปครับ
« แก้ไขครั้งสุดท้าย: ตุลาคม 01, 2018, 02:26:15 PM โดย Watchara A. »
วัชระ อมศิริ
คณะวิศวกรรมศาสตร์ มหาวิทยาลัยธรรมศาสตร์
99 หมู่ 18 ตำบลคลองหนึ่ง อำเภอคลองหลวง
จังหวัดปทุมธานี 12120
awatchar@engr.tu.ac.th

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

Watchara A.

  • Administrator
  • Sr. Member
  • *****
  • กระทู้: 297
  • Point: +0/-0
  • E25FGL / (alias : E22MHS,E22AAA)
    • ดูรายละเอียด
    • TSE Official Web


ลักษณะการทำงานของ Real-Time Operating System
รูปบน - ความรู้สึกของเรา เมื่อใช้ RTOS และเขียนโปรแกรมในรูปแบบ Task :: เหมือนโปรแกรมทุกอย่างรันไปพร้อมๆกันตลอดเวลา
รูปล่าง - อันที่จริงแล้ว โปรแกรมของเราจะถูกซอยย่อยๆใน 1 หน่วยเวลา แล้วค่อยๆสลับทำงานแต่ละ Task

รูปจาก :: https://www.freertos.org/implementation/a00004.html
วัชระ อมศิริ
คณะวิศวกรรมศาสตร์ มหาวิทยาลัยธรรมศาสตร์
99 หมู่ 18 ตำบลคลองหนึ่ง อำเภอคลองหลวง
จังหวัดปทุมธานี 12120
awatchar@engr.tu.ac.th

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

Watchara A.

  • Administrator
  • Sr. Member
  • *****
  • กระทู้: 297
  • Point: +0/-0
  • E25FGL / (alias : E22MHS,E22AAA)
    • ดูรายละเอียด
    • TSE Official Web
มีผู้ใหญ่ใจดีในวงการ Embedded Systems ไทยหลายคน
เขียนบทความเกี่ยวกับ FreeRTOS (ระบบปฏิบัติการ RTOS แบบ Opensource) ในภาษาไทยไว้จำนวนมาก
สามารถติดตามดูได้ดังนี้ครับ

วัชระ อมศิริ
คณะวิศวกรรมศาสตร์ มหาวิทยาลัยธรรมศาสตร์
99 หมู่ 18 ตำบลคลองหนึ่ง อำเภอคลองหลวง
จังหวัดปทุมธานี 12120
awatchar@engr.tu.ac.th

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

sua123

  • Newbie
  • *
  • กระทู้: 1
  • Point: +0/-0
    • ดูรายละเอียด
ขอบพระคุณมากครับอาจารย์ที่สละเวลามาตอบคำถาม  ตอนนี้น่าจะแก้แบบง่ายไปก่อน เข้าใจแล้วว่าทำไมมันไม่เป็นอย่างที่เราคิด เพราะผมคิดแบบกราฟที่หนึ่งจริงๆ  ไม่เคยคิดถึงว่าแนวคิดแบบที่สองนั้นมีอยู่และเป็นไปได้ ตอนนี้เข้าใจในหลักการแล้วครับ  ในส่วนวิธีการยังไม่รู้จะเริ่มอย่างไร  ว่าจะเริ่มจากไปแกะรอย RTOS ตามลายแทงที่อาจารย์ให้ออกมาอีกทีครับ   ;D ;D ;D

รักเกียรติ

Watchara A.

  • Administrator
  • Sr. Member
  • *****
  • กระทู้: 297
  • Point: +0/-0
  • E25FGL / (alias : E22MHS,E22AAA)
    • ดูรายละเอียด
    • TSE Official Web
ขอบพระคุณมากครับอาจารย์ที่สละเวลามาตอบคำถาม  ตอนนี้น่าจะแก้แบบง่ายไปก่อน เข้าใจแล้วว่าทำไมมันไม่เป็นอย่างที่เราคิด เพราะผมคิดแบบกราฟที่หนึ่งจริงๆ  ไม่เคยคิดถึงว่าแนวคิดแบบที่สองนั้นมีอยู่และเป็นไปได้ ตอนนี้เข้าใจในหลักการแล้วครับ  ในส่วนวิธีการยังไม่รู้จะเริ่มอย่างไร  ว่าจะเริ่มจากไปแกะรอย RTOS ตามลายแทงที่อาจารย์ให้ออกมาอีกทีครับ   ;D ;D ;D

รักเกียรติ

ถ้าอยากเริ่มได้ไว
แกะรอยจาก Example ไฟล์ ก่อนก็ได้ครับ

อาจจะยากไปสักหน่อย แต่เพลินดีครับ  ;D ;D
วัชระ อมศิริ
คณะวิศวกรรมศาสตร์ มหาวิทยาลัยธรรมศาสตร์
99 หมู่ 18 ตำบลคลองหนึ่ง อำเภอคลองหลวง
จังหวัดปทุมธานี 12120
awatchar@engr.tu.ac.th

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