บทความนี้เป็นการใช้งาน GPIO ของไมโครคอนโทรลเลอร์ PIC18F458 ที่เชื่อมต่อกับโมดูล ADC หรือโมดูลแปลงสัญญาณแอนาล็อกให้เป็นสัญญาณดิจิทัลเพื่อใช้ในการอ่านค่าระดับแรงดันที่อยู่ในช่วง 0 ถึง 5V จากขานำเข้าสัญญาณ ทำให้ผู้ออกแบบระบบสามารถพิจารณารายละเอียดของแรงดันจากวงจร เช่น จากตัวต้านทานเปลี่ยนแปลงค่าได้ ตัวต้านทานเปลี่ยนแปลงค่าตามค่าความสว่าง หรือไมโครโฟน เป็นต้น เพื่อนำค่าเหล่านี้ไปประมวลผล หรือเข้าสู่เงื่อนไขการทำงานต่อไป เช่น การอ่านค่าแรงดันเพื่อรายงานผลว่าเป็นแรงดันในระดับ Lo, Hi หรือไม่เสถียร เป็นต้น โดยบนบอร์ดทดลองประจำวิชาสถาปัตยกรรมคอมพิวเตอร์มีวงจรของตัวต้านทานปรับค่าได้อยู่ 4 ชุดดังภาพที่ 1 ทำให้สามารถศึกษาการเขียนโปรแกรมเพื่อใช้งานโมดูล ADC ได้และสามารถนำไปประยุกต์ใช้ต่อไป

ภาพที่ 1 โมดูลตัวต้านทานปรับค่าได้บนบอร์ดทดลอง

ADC

ADC หรือ Analog-to-Digital Convertor เป็นวิธีการแปลงค่าที่นำเข้าจากสัญญาณแอนาล็อกให้อยู่ในรูปของตัวเลขแบบดิจิทัล โดยค่าตัวเลขที่ได้จะอยู่ในช่วงของความละเอียดจากโมดูลแปลงสัญญาณ ซึ่งไมโครคอนโทรลเลอร์ PIC18F458 มีความละเอียดในการแปลงอยู่ที่ระดับ 10 บิต หรือ 210 ทำให้สามารถแปลงแรงดันที่อ่านจากขานำเข้าที่อยู่ในช่วง 0V ถึง 5V ให้เป็นค่าตัวเลข 0 ถึง 1023 หรือ 1024 ค่า

ขานำเข้าสัญญาณแอนาล็อก

ขานำเข้าสัญญาณที่เชื่อมต่อโมดูลการแปลงสัญญาณแอนาล็อกเป็นดิจิทัล มี 8 ขานำเข้าชื่อ AN0, AN1, AN2, AN3, NA4, AN5, AN6 และ AN7 ซึ่งกระจายอยู่ในพอร์ต A และ E ดังนี้

  • RA0 เป็นขานำเข้าสัญญาณ AN0
  • RA1 เป็นขานำเข้าสัญญาณ AN1
  • RA2 เป็นขานำเข้าสัญญาณ AN2
  • RA3 เป็นขานำเข้าสัญญาณ AN3
  • RA5 เป็นขานำเข้าสัญญาณ AN4
  • RE0 เป็นขานำเข้าสัญญาณ AN5
  • RE1 เป็นขานำเข้าสัญญาณ AN6
  • RE2 เป็นขานำเข้าสัญญาณ AN7

และผังการทำงานของโมดูลเป็นดังภาพที่ 2

ภาพที่ 2 ผังการทำงานของ ADC
ที่มา Figure 20-1 A/D BLOCK DIAGRAM หน้า243 จาก PIC18F458 Datasheet ของบริษัท Microchop (2006)

การควบคุมภาค ADC

การทำงานของโมดูล ADC ถูกควบคุมโดยเรจิสเตอร์ ADCON0 และ ADCON1 ส่วนค่าที่อ่านได้นั้นอยู่ในเรจิสเตอร์ ADRESH และ ADRESL เพื่อเก็บค่าไบต์สูลและไบต์ต่ำของค่าที่อ่านได้ ซึ่งทั้ง 4 ตัวเป็นเรจิสเตอร์ขนาด 8 บิต

ADCON0

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

บิต7บิต6บิต5บิต4บิต3บิต2บิต1บิต0
ADCS1ADCS0CHS2CHS1CHS0GO/DONE’ADON
ตาราง ep6-1 ค่าของ ADCON0

เมื่อไมโครคอนโทรลเลอร์เริ่มทำงานหรือถูกรีเซ็ตจะมีค่าเป็น 0000 00-0 แต่ถ้าเกิดการขัดจังหวะจาก WDT (Watch Dog Timer เป็นตัวตั้งเวลาเพื่อให้ฝั่งซอฟต์แวร์ส่งสัญญาณไปให้ตัวจับเวลาเพื่อให้ทราบว่าซอฟต์แวร์ยังทำงานได้อย่างถูกต้อง ทั้งนี้เพื่อใช้สำหรับการทวนสอบว่าซอฟต์แวร์แฮงค์หรือไม่ และถ้าแฮงค์จะทำการรีเซ็ตตัวเอง) และกลับมาสู่การทำงานในโปรแกรม ค่าของเรจิสเตอร์ตัวนี้จะไม่ถูกเปลี่ยนแปลงค่า

ADCON1

เรจิสเตอร์ ADCON1 อยู่ที่หน่วยความจำแรมของไมโครคอนโทรลเลอร์ตำแหน่ง 0xFC1 และมีรายละเอียดของแต่ละบิตดังนี้

บิต7บิต6บิต5บิต4บิต3บิต2บิต1บิต0
ADFMADCS2PCFG3PCFG2PCFG1PCFG0
ตาราง ep6-2 ค่าของ ADCON1

สถานะเริ่มต้นของ ADCON1 เมื่อเริ่มทำงานหรือถูกรีเซ็ตจะมีค่าเป็น 00== 0000 และหลังจากผ่านการทวนสอบของ WDT ที่ตั้งไว้ยังคงมีค่าเหมือนกับที่เคยตั้งค่าไว้ก่อนที่ WDT จะทำงาน

ความหมายของการตั้งค่าในเรจิสเตอร์ ADCON0 และ ADCON1 เป็นดังนี้

  • การกำหนดความถี่ของการทำงานของโมดูลแปลงสัญญาณจะกำหนดจากค่าของ ADCS2, ADCS1 และ ADCS0 ตามตาราง ep6-3
ADCON1.ADCS2ADCON0.ADCS1ADCON0.ADCS0ความหมาย
000FOSC/2
001FOSC/8
010FOSC/32
011FRC
100FOSC/4
101FOSC/16
110FOSC/64
111FRC
ตาราง ep6-3 การกำหนดความถี่ในการทำงาน
  • การเลือกช่องสัญญาณที่กำลังตั้งค่า กำหนดด้วย CHS0, CHS1 และ CHS2 ใน ADCON0 ดังตาราง ep6-4
CHS2CHS1CHS0ความหมาย
000เลือกตั้งค่า AN0
001เลือกตั้งค่า AN1
010เลือกตั้งค่า AN2
011เลือกตั้งค่า AN3
100เลือกตั้งค่า AN4
101เลือกตั้งค่า AN5
110เลือกตั้งค่า AN6
111เลือกตั้งค่า AN7
ตาราง ep6-4 การกำหนดช่องสัญญาณ ADC
  • การกำหนดให้ ADC ของช่องสัญญาณที่ระบุไว้ทำงาน ให้กำหนดบิต ADON โดยที่
    • 0 หมายถึง ปิดหรือหยุดการทำงาน
    • 1 หมายถึง เปิดการทำงานหรือทำงานต่อจากที่หยุดไว้
  • การตรวจสอบว่าารแปลงสัญญาณทำงานเสร็จสิ้นแล้วหรือไม่นั้น สามารถตรวจสอบได้จากบิต GO/DONE’ โดยถ้ามีค่าเป็น 0 หมายถึงทำงานเสร็จสิ้น แต่ถ้าเป็น 1 หมายถึงโมดูลแปลงสัญญาณกำลังทำงาน
  • การกำหนดรูปแบบของการเรียงบิตของผลลัพธ์ที่ได้ทำด้วยการกำหนดค่าแก่ ADFM ดังภาพที่ 3
    • 1 หมายถึง เป็นแบบ Right Justified จะเก็บค่าเรียงกจากขวาไปซ้าย คือ บิต 9,8,7,6,5,4,3,2,1 และ 0 โดยบิต 0 ถึง 7 เก็บใน ADRESL และ 8 ถึง 9 เก็บในบิตที่ 0 และ 1 ของ ADRESH
    • 0 หมายถึง เป็นแบบ Left Justified เพื่อเก็บเรียงจากซ้ายไปขวา หรือ บิตลำดับ 0,1,2,3,4,5,6,7,8 และ 9 ทำให้บิตที่ 0 ถึง 7 เก็บใน ADRESH และบิตที่ 8 และ 9 เก็บในบิตที่ 7 และ 6 ของ ADRESL
ภาพที่ 3 รูปแบบการเก็บค่าผลลัพธ์
ที่มา Figure 20-3 A/D RESULT JUSTIFIED หน้า247จาก PIC18F458 Datasheet ของบริษัท Microchop (2006)
  • การกำหนดโหมดของขาต่าง ๆ ในการทำ ADC จะกำหนดจากบิตด PCFG3, PCFG2, PCFG1 และ PCFG0 โดยให้ค่าตามตารางที่ ep6-5 และความหมายต่าง ๆ ดังนี้
    • A หมายถึง ทำงานเป็นขานำเข้าสัญญาณแอนาล็อก
    • D หมายถึง ทำงานเป็นขานำเข้าสัญญาณดิจิทัล
    • VREF+ หมายถึง ทำงานเป็นขานำเข้าแรงดันอ้างอิง REF+
    • VREF- หมายถึง ทำงานเป็นขานำเข้าแรงดันอ้างอิง REF-
    • VDD หมายถึง ใช้แรงดันอ้างอิงตามที่ใช้กับขา VDD
    • VSS หมายถึง ใช้แรงดันอ้างอิงตามที่ใช้กับขา VSS
    • C/R เป็นจำนวนขาที่เป็นขานำเข้าสัญญาณแอนาล็อกกับจำนวนของขาที่ถูกใช้เป็นแหบ่งนำเข้าแรงดันสำหรับการอ้างอิง
PCFGAN7AN6AN5AN4AN3AN2AN1AN0VREF+VREF-C/R
0000AAAAAAAAVDDVSS8/0
0001AAAAVREF+AAAAN3VSS7/1
0010DDDAAAAAVDDVSS5/0
0011DDDAVREF+AAAAN3VSS4/1
0100DDDDADAAVDDVSS3/0
0101DDDDVREF+DAAAN3VSS2/1
0110DDDDDDDD0/0
0111DDDDDDDD0/0
1000AAAAVREF+VREF-AAAN3AN26/2
1001DDAAAAAAVDDVSS6/0
1010DDAAVREF+AAAAN3VSS5/1
1011DDAAVREF+VREF-AAAN3AN24/2
1100DDDAVREF+VREF-AAAN3AN23/2
1101DDDDVREF+VREF-AAAN3AN22/2
1110DDDDDDDAVDDVSS1/0
1111DDDDVREF+VREF-DAAN3AN21/2
ตาราง ep6-5 การตั้งค่าของ PCFG

ดังนั้น ได้ข้อสรุปว่า

  1. ต้องตั้งค่าการทำงานของ TRISA หรือ TRISE ของช่องสัญญาณที่ต้องการนำเข้าสัญญาณแอนาล็อกเป็น 1
  2. การตั้งค่าการทำงานต้องกำหนดในเรจิสเตอร์ ADCON0 และ ADCON1
  3. ผลลัพธ์ที่ได้จากการแปลงสัญญาณจะถูกเก็บในเรจิสเตอร์ ADRESH และ ADRESL ตามรูปแบบที่กำหนดในบิต ADFM

ตัวอย่างโปรแกรม

ตัวอย่างโปรแกรมของบทความนี้เป้นการอ่านค่าจากตัวต้านทานปรับค่าได้บนบอร์ดทดลองที่ถูกเชื่อมต่อกับ AN0 หรือขา RA0 ดังภาพที่ 4 หลังจากนั้นทำการแปลงค่าที่ได้ให้ถูกแบ่งเป็น 9 ระดับ เพื่อนำไปแสดงผลที่หลอด LED จำนวน 8 หลอดที่ถูกเชื่อมต่อกับพอร์ต D ดังภาพที่ 5 โดยแต่ละระดับมีผลดังนี้

  • ระดับ 0 ค่า 0 ถึง 112 หมายถึง หลอด 0, 1, 2, 3, 4, 5, 6 และ 7 ดับ
  • ระดับ 1 ค่า 113 ถึง 225 หมายถึง หลอด 0 ติด
  • ระดับ 2 ค่า 226 ถึง 338 หมายถึง หลอด 0, และ 1 ติด
  • ระดับ 3 ค่า 339 ถึง 451 หมายถึง หลอด 0, 1 และ 2 ติด
  • ระดับ 4 ค่า 452 ถึง 564 หมายถึง หลอด 0, 1, 2 และ 3 ติด
  • ระดับ 5 ค่า 565 ถึง 677 หมายถึง หลอด 0, 1, 2, 3 และ 4 ติด
  • ระดับ 6 ค่า 678 ถึง 790 หมายถึง หลอด 0, 1, 2, 3, 4 และ 5 ติด
  • ระดับ 7 ค่า 791 ถึง 903 หมายถึง หลอด 0, 1, 2, 3, 4, 5 และ 6 ติด
  • ระดับ 8 ค่า 904 ถึง 1023หมายถึง หลอด 0, 1, 2, 3, 4, 5, 6 และ 7 ติด

การตั้งค่าแก่ ADCON0 และ ADCON1 เพื่อให้ AN0 ทำงาน โดยขาอื่นเป็นขาดิจิทัลเหมือนปกติ และเก็บข้อมูลแบบ Right Justified จึงทำได้ดังนี้

  • การกำหนดค่าแก่ ADCON0 จึงเป็นดังนี้
    • ADCS1, ADCS0 เป็น 0 กับ 0
    • CHS2, CHS1, CHS0 เป็น 0, 0 และ 0
  • สำหรับ ADCON1 ได้ค่าดังต่อไปนี้
    • ADFM เป็น 1
    • ADCS2 เป็น 0
    • PCFG3, PCFG2, PCFG1, PCFG0 เป็น 1,1,1 และ 0
ภาพที่ 4 การเชื่อมต่อระหว่าง V0 กับ RA0
ภาพที่ 5 การเชื่อมต่อระหว่าง PORTD กับ LED

ภาพวงจรของตัวต้านทานปรับค่าได้เป็นดังภาพที่ 6 และตัวอย่างผลลัพธ์เป็นดังคลิปที่ 1

ภาพที่ 6 วงจรของโมดูลรับค่าแรงดันจากตัวต้านทานปรับค่าได้
ที่มา คู่มือ PCK-1000

โค้ดโปรแกรมเป็นดังต่อไปนี้

#pragma config OSC = HS 
#pragma config OSCS = ON
#pragma config PWRT = OFF 
#pragma config BOR = ON  
#pragma config BORV = 25 
#pragma config WDT = OFF  
#pragma config WDTPS = 128 
#pragma config STVR = ON 
#pragma config LVP = ON 
#pragma config CP0 = OFF 
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF
#pragma config CPB = OFF
#pragma config CPD = OFF 
#pragma config WRT0 = OFF  
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF  
#pragma config WRT3 = OFF   
#pragma config WRTC = OFF
#pragma config WRTB = OFF 
#pragma config WRTD = OFF   
#pragma config EBTR0 = OFF 
#pragma config EBTR1 = OFF 
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF 
#pragma config EBTRB = OFF   

#define _XTAL_FREQ 20000000 

#include <xc.h>

void setup() {
    TRISA = 0b00000001; // AN0
    TRISD = 0x00; // input
    ADCON0 = 0B00000001;             // ADC Configurations bits - ADC on
    ADCON1 = 0B10001110;             // AN0 as AD, Internal REF V
}

unsigned int result;

void loop() {
    __delay_us(10);
    ADCON0bits.GO = 1;
    while (ADCON0bits.GO_nDONE); // wait
    result = ((ADRESH<<8)|ADRESL);
    if (result<113) {
        PORTD = 0b00000000;
    } 
    else if (result < 226) {
        PORTD = 0b00000001;
    }
    else if (result < 339) {
        PORTD = 0b00000011;
    }
    else if (result < 452) {
        PORTD = 0b00000111;
    }
    else if (result < 565) {
        PORTD = 0b00001111;
    }
    else if (result < 678) {
        PORTD = 0b00011111;
    }
    else if (result < 791) {
        PORTD = 0b00111111;
    }
    else if (result < 904) {
        PORTD = 0b01111111;
    }
    else {
        PORTD = 0b11111111;
    }
}

void main(void) {
    setup();
    while (1) {
        loop();
    }
    return;
}

คลิป 1 ตัวอย่างการทำงานของโปรแกรม ADC

สรุป

จากบทความนี้ผู้อ่านได้เรียนรู้หลักการทำงานของ ADC พร้อมทั้งวิธีการควบคุมการทำงานโมดูลแปลงสัญญาณแอนาล็อกมาเป็นสัญญาณดิจิทัลของไมครคอนโทรลเลอร์ PIC18F458 ที่เชื่อมต่อ AN0 หรือขา RA0 เข้ากับ V0 บนบอร์ดทดลแง และแสดงผลที่หลอดแอลอีดีทั้ง 8 หลอดที่เชื่อมต่อกับ PORTD จะพบว่าอ่านอ่านค่าจากสัญญาณแอนาล็อกนั้นไม่ยุ่งยาก แต่การตั้งค่าแก่ PCFG มีความสำคัญต่อการทำงานของภาคแปลงสัญญาณภายในชิพไมโครคอนโทรลเลอร์ และที่สำคัญ คือ ต้องกำหนด ADON ให้เป็น 1 และตั้งค่าหมายเลขช่องสัญญาณให้ตรงกับขาที่เลือกใช้เพื่อเปิดการทำงานของขาที่ต้องการใช้งานด้วย สุดท้าย ขอให้สนุกกับการเขียนโปรแกรมครับ

(C) 2022, โดย อ.อนุชาติ บุญมาก, อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ

ปรับปรุงเมื่อ 2022-02-22, 2022-03-19