การเขียนโปรแกรมบนไมโครคอนโทรลเลอร์ เพื่อสื่อสารทาง USART

การเขียนโปรแกรมบนไมโครคอนโทรลเลอร์ เพื่อสื่อสารทาง USART

    มาถึง ตอนที่ 3 หลังจากที่เราได้สร้างโค๊ดที่จะทำงานบน PC ใน ตอนที่ 2 เสร็จไปเรียบร้อยแล้ว ก็มาถึงคราวที่จะต้องสร้างโค๊ดบนฝั่งไมโครคอนโทรลเลอร์กันบ้าง เพื่อให้ทั้งสองฝั่งสื่อสารได้เข้าใจกัน เราก็ยังต้องยึดเอาข้อตกลงทาง Protocol ที่เราสร้างขึ้นเองนั้น มาเขียนเป็นโค๊ดทางฝั่งไมโครฯ กัน 

ในที่นี้ ผมจะเขียนโค๊ดด้วยรูปแบบภาษา wiring บน Arduino เพื่อตัดปัญหาความยุ่งยากในเรื่องโค๊ดออกไปก่อน เพราะเราต้องการแค่เข้าใจคอนเซ็ปต์การรับส่งข้อมูลกันก่อนเท่านั้น ส่วนแต่ละท่าน หาก ถนัดภาษาใด กับไมโครคอนโทรลเลอร์ตระกูลไหน ก็ยังเอาโปรแกรมใน ตอนที่ 2 ยังไปใช้งานได้อยู่ ขอเพียงโค๊ดที่อยู่ทางฝั่งไมโครทำงานได้ตามเงื่อนไข ที่เรากำหนดไว้ใน Protocol ที่เราตกลงกันไว้แต่แรกแล้ว 

 

    ทางฝั่งไมโครคอนโทรลเลอร์ หรือ Arduino ที่เรากำลังเขียนอยู่นี้ อย่างแรกเลย ก็ต้องทำการเปิดการใช้งาน USART module ก่อน สำหรับ Arduino แล้ว มันง่ายมากๆ ที่จะเปิด module นี้ เพียงเรากำหนด Serial.bigin(9600); ใน void setup(){.....} เราก็เปิดการใช้งาน USART แล้ว

void setup()

{

  pinMode(ledPin1, OUTPUT);

  pinMode(ledPin2, OUTPUT);

  pinMode(ledPin3, OUTPUT);

  // initialize the serial communication:

  Serial.begin(9600);

}

เมื่อเราเปิดใช้งานแล้ว ขั้นตอนต่อไป ก็เขียนโค๊ด ไว้ดักรอข้อมูลที่ถูกส่งเข้ามาทางขา RXD ของ Arduino แล้วแสดงผลออกทาง Logic Probe ที่ต่อไว้ที่ PB3...PB5 ซึ่งก็คือ ขา Digital 11,12,13 ของ Arduno แล้วในขณะที่ทำงานไปนั้น หากมีการเปลี่ยนแปลงเกิดขึ้นที่ขา ADC0...ADC2 (ในที่นี้เราจะจำลองด้วยการปรับ VR แทนการเปลี่ยนแปลงแรงดันที่ขา Analog input) ก็ให้ทำการส่งข้อมูลของ Analog out ออกไปทางขา TXD ของ Arduino วงจรการทำงานก็เป็นดั่งรูปภาพด้านล่างนี้ 

    ในส่วนของการส่งค่านั้น เพียงแค่ทำตามรูปแบบที่เราตกลงไว้ จะเห็นว่าผมได้ทำการ นำสตริงมาต่อกันก่อน แล้วผมก็ค่อยส่งค่าออกทาง USART ด้วยคำสั่ง Serial.println(string); จะเห็นว่าผมได้ทำการการส่งแบบ มี \r\n ต่อท้ายแปะไปด้วย ( อ่านเพิ่มเติมเรื่อง Serial.println ) ก็เพื่อให้สอดคล้องงกับโค๊ดในโปรแกรม C# ครับ (string d = serial.ReadLine();)  เพราะผมได้ให้โปรแกรม C# อ่านข้อมูลที่อยู๋ใน serial buffer จนกว่าจะเจอข้อมูลที่มี \r\n จึงให้หยุดอ่านข้อมูล ทำให้มันสอดคล้องกันครับ ปัญหาจะได้น้อยลงในการเขียนโค๊ด ครับ 

String string = String("#");

    string += String(sensorValue1);

    string += String(",");

    string += String(prevValue2);

    string += String(",");

    string += String(prevValue3);

    string += String("*");

    Serial.println(string);

     ในส่วนของการรับข้อมูลนั้น ค่อนข้างซับซ้อน ผมขออธิบายกลไกการรับข้อมูลทาง RXD ของ Arduino ดังนี้ครับ 

เรานำโค๊ดมาวางไว้ที่ void loop(){...} ซึ่งมันจะทำงานในส่วนนี้ วนไม่รู้จบอยู๋แล้ว ทีนี้ ผมเขียนเงื่อนไขเช็คว่าถ้ามีข้อมูมาที่ RXD เราจะใช้ฟังก์ชั่น while (Serial.available() > 0) {......} จะทำให้เงื่อนไขเป็นจริง เกิดการทำงานเข้าไปใน while() ทีนี้ผมก็ใช้ฟังก์ชั่น Serial.parseInt(); เพื่อดึงข้อมูลที่เป็นตัวเลข ออกจาก usart buffer ทางฝั่ง Arduino และเมื่อเราอ่านข้อมูลไปจนเจอ * แสดงว่าข้อมูลที่อยู๋ใน usart buffer นั้น สิ้นสุดแล้ว เราก็สั่งให้แสดงผลออกทาง led มาดูโค๊ดที่อยู่ในส่วนรับข้อมูลกันครับ

 while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:

    int led1 = Serial.parseInt(); 

    // do it again:

    int led2 = Serial.parseInt(); 

    // do it again:

    int led3 = Serial.parseInt();

    if (Serial.read() == '*') {

       digitalWrite(ledPin1, led1);

       digitalWrite(ledPin2, led2);

       digitalWrite(ledPin3, led3);

    }   

  }

นี่่คือโค๊ดทั้งหมดครับ 

byte data;

const int ledPin1 = 11;

const int ledPin2 = 12;

const int ledPin3 = 13;

const int analogInPin1 = A0; 

const int analogInPin2 = A1; 

const int analogInPin3 = A2; 

int sensorValue1 = 0;        // value read from the pot

int sensorValue2 = 0;

int sensorValue3 = 0;

int prevValue1 = 0;

int prevValue2 = 0;

int prevValue3 = 0;

void setup()

{

  pinMode(ledPin1, OUTPUT);

  pinMode(ledPin2, OUTPUT);

  pinMode(ledPin3, OUTPUT);

  // initialize the serial communication:

  Serial.begin(9600);  

}

void loop()

{  

  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:

    int led1 = Serial.parseInt(); 

    // do it again:

    int led2 = Serial.parseInt(); 

    // do it again:

    int led3 = Serial.parseInt();

    if (Serial.read() == '*') {

       digitalWrite(ledPin1, led1);

       digitalWrite(ledPin2, led2);

       digitalWrite(ledPin3, led3);

    }   

  }

  sensorValue1 = analogRead(analogInPin1);

  sensorValue2 = analogRead(analogInPin2);

  sensorValue3 = analogRead(analogInPin3);

  if(sensorValue1 != prevValue1){

    delay(20);

    String string = String("#");

    string += String(sensorValue1);

    string += String(",");

    string += String(prevValue2);

    string += String(",");

    string += String(prevValue3);

    string += String("*");

    Serial.println(string);

    prevValue1 = sensorValue1;

  }   

  

  if(sensorValue2 != prevValue2){

    delay(20);

    String string = String("#");

    string += String(prevValue1);

    string += String(",");

    string += String(sensorValue2);

    string += String(",");

    string += String(prevValue3);

    string += String("*");

    Serial.println(string);

    prevValue2 = sensorValue2;

  }

  

  if(sensorValue3 != prevValue3){

    delay(20);

    String string = String("#");

    string += String(prevValue1);

    string += String(",");

    string += String(prevValue2);

    string += String(",");

    string += String(sensorValue3);

    string += String("*");

    Serial.println(string);

    prevValue3 = sensorValue3;

  }   

}

ส่วนไฟล์ Proteus ผมก็อัพโหลดไว้ให้แล้วนะ ลองโหลดไปทดสองกันได้ครับ