วันพฤหัสบดีที่ 19 พฤษภาคม พ.ศ. 2559

AVR C การทำงานระดับบิต

การเขียนโปรแกรมในไมโครคอนโทรลเลอร์หลีกเลี่ยงการใช้งานระดับบิตไม่ได้ และมีความสำคัญเป็นอย่างยิ่งที่ต้องเรียนรู้หลักการให้เข้าใจ

วิธีการเรียนรู้ที่เข้าใจง่าย คือ การลงมือสร้างตัวอย่างขึ้นเพื่อให้เกิดความเข้าใจอย่างถ่องแท้

การเรียนรู้ที่ง่ายที่สุดก็เริ่มจาก LED โดยจะต่อ LED 8 ดวง เข้ากับขา I/O ให้ครบ 8bit คือ ต่อตั้งแต่ PINx0 - PINx7 ในบทความนี้ใช้ LED แบบแพ็ก 10 แต่ใช้เพียง 8 ดวงเท่านั้น และอย่าลืมต่อ R ค่า 220 หรือ 330 โอห์มพ่วงไว้สักนิดจะได้ช่วยปกป้องทั้ง IC และ LED

อุปกรณ์เรียนรู้การทำงานระดับบิต

การต่ออุปกรณ์ 


  • ต่อขา LED 1-8 เข้าขา PB0-7
  • ต่อขาอีกข้าของ LED เข้ากับ R ค่า 330 โอห์ม และต่อลง GND

โปรแกรมคำสั่ง


  1. #define F_CPU 8000000L
  2. #include <avr/io.h>
  3. #include <util/delay.h>

  4. int main(void){
  5.   int i = 0;
  6.   DDRB = 0b11111111;
  7.   PORTB = 0b00000000;

  8.   while (1){
  9.     for (i = 0; i<8; i++){
  10.       PORTB |= (1<<i);
  11.       _delay_ms(300); 
  12.          }
  13.     PORTB = 0;
  14.   }
  15. }
บรรทัดที่ 6 เริ่มกำหนดให้ i มีค่าตั้งแต่ 0 เพื่อทำงานกับบิต 0
บรรทัดที่ 7 กำหนดให้ขา I/O ชุด B เป็นเอาท์พุททั้งหมด เพื่อเขียนคำสั่งออกไปยัง I/O
บรรทัดที่ 8 กำหนดให้ขา I/O เป็น 0 หรือกำหนดให้เป็น LOW เพื่อปิด LED ทุกตัว
บรรทัดที่ 10 คำสั่ง while (1) จะวนรอบไปเรื่อยๆ ไม่สิ้นสุดจนกว่าจะปิดเครื่อง
บรรทัดที่ 11 คำสั่ง for จะเริ่มตั้งแต่ 0 ไปจนถึง 7 ตามเงื่อนไข i < 8 
บรรทัดที่ 12 กำหนดให้ PORTB เป็น 1 เริ่มจากบิต 0 ไปเรื่อยๆ จนถึงบิตที่ 7
บรรทัดที่ 13 ให้หยุดรอ 300ms
บรรทัดที่ 15 กำหนดให้ PORTB ทุกขามีค่าเป็น 0 หรือ LOW แล้วกลับไปวนรอบใหม่




*** ดูจากคลิปวีดีโอแล้วจะเห็นว่าจังหวะสุดท้ายที่ LED ดวงที่ 8 ดับลง ดวงที่ 1 ยังติดค้างอยู่ ในโปรแกรมจึงต้องเพิ่มคำสั่ง _delay_ms(300) ไว้บรรทัดล่างของ PORTB = 0;

อธิบายเพิ่มเติม


PORTB |= (1<<i);

คำสั่งในบรรทัดที่ 12 จะเป็นตัวกำหนดค่าให้กับขาแต่ละขาของ PORTB โดยจะเริ่มจาก 0 ตามค่า i โดยจะจำลองสถานการณ์ของ PORTB ดังนี้

เริ่มต้น PORTB = 0b00000000

เมื่อค่า i = 0 บรรทัดที่ 12 จะเป็น

PORTB |= (1<<0); ให้ PORTB ทำบิตออร์กับ 0b00000001 โดยจะเขียนใหม่เป็น

PORTB = PORTB | 0b00000001; เขียนแทนค่า PORTB อีกครั้งหนึ่งเป็น

PORTB = 0b00000000 
                   | 
        0b00000001 
PORTB = 0b00000001

ดังนั้นคำสั่ง PORTB |= (1<<0) จึงเป็นการสั่งให้บิต 0 มีค่าเป็น 1 หรือ HIGH ส่งผลให้ไฟ LED ติดสว่าง

เมื่อค่า i = 1 บรรทัด 12 จะเป็น 

PORTB  |= (1<<1); กำหนดให้ PORTB บิตออร์กับ 0b00000010 โดยเขียนใหม่เป็น
PORTB  = PORTB | 0b00000010; ตอนนี้ค่า PORTB เดิมเป็น 0b00000001 จึงเขียนได้ว่า

PORTB = 0b00000001
                   |
        0b00000010
PORTB = 0b00000011

ถึงตอนนี้เมื่อ i มีค่าเป็น 1 ส่งผลให้ไฟ LED ติดสองดวง เพราะ บิต 0 และ บิต 1 ต่างก็เป็น HIGH ทั้งคู่

เมื่อ i = 7 บรรทัดที่ 12 จะเป็น

PORTB |= (1<<7); กำหนดให้ PORTB บิตออร์กับ 0b10000000 โดยเขียนใหม่เป็น
PORTB = PORTB | 0b10000000; ตอนนี้ค่า PORTB เป็น 0b01111111 จึงเขียนใหม่ได้ว่า

PORTB = 0b01111111
                   |
        0b10000000
PORTB = 0b11111111

การทำงานจะวนไปเรื่อยๆ ถึงบิต 7 ไฟ LED จะติดสว่างทุกดวง และ i มีค่า เท่ากับ 8 โปรแกรมจึงไม่ทำงาน โดยจะออกจากลูป for ไปทำคำสั่ง

PORTB = 0; 

คือสั่งให้ทุกขา I/O ของ PORTB เป็น 0 หรือ LOW เพื่อปิดไฟ LED ซึ่งการเขียนสามารถเขียนแบบอื่นได้ เช่น

PORTB = 0x00; หรือ
PORTB = 0b00000000; 

ซึ่งทั้ง 3 แบบก็มีค่าเท่ากัน เมื่อ LED ดับหมดทุุุกดวงแล้วโปรแกรมก็จะเริ่มที่บรรทัด 12 ใหม่อีกครั้งหนึ่ง วนไปเรื่อยๆ ไม่รู้จบ 

ตัวอย่างนี้เราจึงเห็นหลอด LED ติดสว่างจากหลอดที่ 1 ถึงหลอดที่ 8 (bit 0 ถึง bit 7) เมื่อติดครบแล้วก็เริ่มใหม่ ก่อนจะเริ่มใหม่ LED ทุกดวงจะดับก่อน


สุดท้ายเราสามารถเขียนโปรแกรมโดยใช้เลขฐานสิบหกเป็นค่าของ PORTB ได้เช่นกัน คือ

int main(void){
  int i = 0;
  DDRB = 0xFF;
  while (1){
    PORTB = 0x00;
    for (i = 0; i<8; i++){
      PORTB |= (1<<i);
      _delay_ms(300);
    }
    _delay_ms(300);
  }
}


นี่เป็นเพียงการเริ่มต้น ต่อไปจะนำเรื่องอื่นๆ ที่เกี่ยวข้องกับ Bitwise Operator มานำเสนอต่อนะครับ... สวัสดีครับ

ไม่มีความคิดเห็น:

แสดงความคิดเห็น

Gtk4 ตอนที่ 6 Defining a Child object

Defining a Child object A Very Simple Editor ในบทความที่ผ่านมาเราสร้างโปรแกรมอ่านไฟล์ชนิดข้อความ และในบทความนี้ก็จะมาปรับแต่งโปรแกรมกันสักหน...