หลังจากที่ได้สร้างโครงงานและโค้ดโปรแกรมเบื้องต้นจากบทความการใช้ MPLAB X IDE ไปก่อนหน้านี้ บทความนี้เป็นการใช้งานไมโครคอนโทรลเลอร์เพื่อใช้เป็นหน่วยนำออกสัญญาณหรือการ Output และนำเข้าสัญญาณหรือ Input ผ่านทางพอร์ตของ PIC18F458 ทั้งพอร์ต A, B, C และ D ผ่านทางวงจร LED และ Switch
GPIO
GPIO หรือ General Purpose Input/Output เป็นขาของไมโครคอนโทรลเลอร์ที่สามารถสั่งงานให้ทำงานได้ทั้งเป็นส่วนนำเข้าสัญญาณ ส่วนนำออกสัญญาณ หรือหน้าที่พิเศษเฉพาะทาง เช่น ขาสำหรับ PWM, ขาสำหรับเป็นตัวนับ, ขาสำหรับเป็นขารอการขัดจังหวะ หรือขาสำหรับอ่าน/ส่งออกสัญญาณแอนาล็อก เป็นต้น
โดยจากผังการจัดวางขาของไมโครคอนโทรลเลอร์ PIC18F458 ในภาพที่ 2 จะพบว่า มีขาหลายขาที่เป็นทั้ง Input/Output และมีบางขาที่นำเข้าอย่างเดียว หรือนำออกเพียงอย่างเดียว นอกจากนี้บางขานั้นมีการทำหน้าที่มากกว่า 1 อย่าง เช่น ขาลำดับที่ 40 เป็นขาแบบทั้ง Input/Output ทำหน้าที่เป็น RB7 หรือขานำเข้าหรือส่งออกของพอร์ต B ลำดับที่ 8 (บิต 7) และทำหน้าที่ PGD ได้ด้วย หรือขาที่ 37 ที่ทำหน้าที่เป็นทั้ง Input และ Output แต่ทำหน้าที่ได้เพียงเป็นบิตที่ลำดับที่ 5 (บิต 4) ของพอร์ต B เป็นต้น
จากภาพที่ 3 จะเห็นว่าไมโครคอนโทรลเลอร์มีพอร์ต A, B, C, D และ E ที่เรียกชื่อว่า PORTA, PORTB, PORTC, PORTD และ PORTE โดยขาของพอร์ตเหล่านี้เป็น GPIO และชื่อเรียกของแต่ละขาเป็นดังนี้
- RA0,RA1,RA2,RA3,RA4,RA5และ RA6 รวมเป็น 7 ขาหรือ 7 บิต เป็นขาของพอร์ต A
- RB0, RB1, RB2, RB3, RB4, RB5, RB6 และ RB7 รวมเป็น 8 ขาหรือ 8 บิต เป็นขาของพอร์ต B
- RC0, RC1, RC2, RC3, RC4, RC5, RC6 และ RC7 รวมเป็น 8 ขาหรือ 8 บิต เป็นขาของพอร์ต C
- RD0, RD1, RD2, RD3, RD4, RD5, RD6 และ RD7 รวมเป็น 8 ขาหรือ 8 บิต เป็นขาของพอร์ต D
- RE0, RE1 และ RE2 รวมเป็น 3 ขาหรือ 3 บิต เป็นขาของพอร์ต E
การควบคุมทิศทาง
พอร์ต A, B, C, D และ E สามารถกำหนดทิศทางของการทำงานเพื่อให้เป็นขาสำหรับนำเข้าสัญญาณหรือนำออกสัญญาณด้วยการกำหนดค่าในเรจิสเตอร์ต่อไปนี้
- TRISA สำหรับกำหนดหน้าที่ของขาในพอร์ต A
- TRISB สำหรับกำหนดหน้าที่ของขาในพอร์ต B
- TRISC สำหรับกำหนดหน้าที่ของขาในพอร์ต C
- TRISD สำหรับกำหนดหน้าที่ของขาในพอร์ต D
- TRISE สำหรับกำหนดหน้าที่ของขาในพอร์ต E
กำหนดให้ขาใดเป็นขานำเข้าสัญญาณนำออกสัญญาณต้องให้ค่าประจำของขานั้นเป็น 0 และถ้าต้องการให้เป็นขานำเข้าสัญญาณให้กำหนดค่าของบิตหรือขานั้นเป็น 1
- นำเข้า ให้กำหนดเป็น 1
- ส่งออก ให้กำหนดเป็น 0
การเข้าถึง
การกำหนดค่า/อ่านค่าหรือการเข้าถึงขาในแต่ละพอร์ตสามารถกระทำได้ 2 แบบ คือ ระบุเป็นลำดับของขา ดังนี้
- สำหรับพอร์ต A ได้แก่ RA0, RA1, RA2, RA3, RA4, RA5 และ RA6
- สำหรับพอร์ต B ได้แก่ RB0, RB1, RB2, RB3, RB4, RB5, RB6 และ RB7
- สำหรับพอร์ต C ได้แก่ RC0, RC1, RC2, RC3, RC4, RC5, RC6 และ RC7
- สำหรับพอร์ต D ได้แก่ RD0, RD1, RD2, RD3, RD4, RD5, RD6 และ RD7
- สำหรับพอร์ต E ได้แก่ RE0, RE1 และ RE2
หรืออ้างอิงถึงชื่อพอร์ตดังนี้
- PORTA สำหรับแทนชื่อพอร์ต A
- PORTB สำหรับแทนชื่อพอร์ต B
- PORTC สำหรับแทนชื่อพอร์ต C
- PORTD สำหรับแทนชื่อพอร์ต D
- PORTE สำหรับแทนชื่อพอร์ต E
การนำส่งค่าให้ขาหรือพอร์ตมีรูปแบบดังนี้ โดยการนำออก 1 หมายถึงส่งแรงดันที่มีสถานะในระดับ 1 ในสัญญาณดิจิทัลไปยังขานั้น และ 0 หมายถึงให้ขานั้นมีสถานะเป็นกราวด์ (Ground หรือ GND) ส่วนกรณีที่เป็นการส่งข้อมูลไปที่พอร์ตขจะเป็นตัวเลขจำนวนเต็มแบบไม่มีเครื่องหมาย +/-
ชื่อขา = 1
ชื่อขา = 0
ชื่อพอร์ต = ค่าขนาด 8 บิต
และกรณีของการอ่านค่าจากขาหรือพอร์ตมีรูปแบบดังนี้
ขา = ชื่อขา
พอร์ต = ชื่อพอร์ต
วงจร I/O
วงจรสำหรับนำเข้าและส่งออกมีหลักการทำงานแตกต่างกัน คือ
- การนำเข้าจะเป็นการอ่านค่าจากสถานะที่ปรากฎ ณ ขณะที่ขาที่อ่านค่านั้นเป็นอยู่
- การนำออกสัญญาณนั้นต้องพิจารณาวงจรที่รับสัญญาณขาออกจากไมโครคอนโทรลเลอร์วาต้องการแรงดันและกระแสเท่าใด
- ถ้าไมโครคอนโทรลเลอร์สามารถขับแรงดันและกระแสได้โดยตรงให้เชื่อมต่อขาของไมโครคอนโทรลเลอร์เข้ากับวงจรภาคนำออกได้ โดยเรียกการขับแรงดันและกระแสโดยตรงนี้ว่าการทำ Source Current หรือไมโครคอนโทรลเลอร์เป็นแหล่งจ่ายไฟให้กับวงจรภายนอก
- ส่วนกรณีที่ไมโครคอนโทรลเลอร์มีกระแสไม่มากพอสำหรับขับวงจรภายนอก ให้ออกแบบวงจรภายนอกทำงานเมื่อขาของไมโครคอนโทรลเลอร์เป็น 0 หรือ GND เรียกการทำงานแบบนี้ว่า Sunk Current
ตัวอย่างวงจรภาคนำเข้าและส่งออกที่เลือกใช้เป็นวงจรที่อยู่บนบอร์ดประจำการทำแล็บ คือ Switch และ LED
วงจร LED
วงจรนำออกสัญญาณดิจิทัลของบอร์ดทดลองเป็นวงจรที่ทำงานแบบ Source Current คือขับกระแสมาจากขาของไมโครคอนโทรลเลอร์ เนื่องจาก PIC18F458 สามารถขับกระแสได้มากพอสมควร และวงจรที่เป็นหลอด LED นั้นต้องการกระแสในการทำงานไม่มากจึงไม่ต้องออกแบบให้ทำงานแบบ Sink Current
จากภาพที่ 4 จะพบว่าฝั่งขาด้านหนึ่งของ LED ต่อเข้ากับตัวต่านทานที่ต่อตรงจากขาไมโครคอนโทรลเลอร์ และอรกด้านต่อเข้ากับ GND ของระบบ ดังนั้น เมื่อส่งสัญญาณดิจิทัล 1 จึงทำให้วงจรครบการทำงานส่งผลให้หลอดแอลอีดีสว่าง ในทางตรงกันข้ามเมื่อส่ง 0 ทำให้ไม่มีแรงดันไหลผ่านหลอดแอลอีดีจึงทำให้หลอดแอลอีดีไม่สว่าง
วงจร Switch
สวิตช์เป็นอุปกรณ์นำเข้าสัญญาณประเภทหนึ่งที่ใช้กับระบบคอมพิวเตอร์ โดยบนบอร์ดทดลองมีสวิตช์จำนวน 5 ตัว ซึ่งเป็นสวิตช์แบบดิป (Dip Switch) จำนวน 1 ตัว (ตัวถังสีฟ้า และคันโยกเป็นสีขาว) กับสวิตช์แบบปุ่ม (Push Button) แบบกดติดปล่อยดับจำนวน 4 ตัว
จากภาพที่ 5 จะพบว่า S2 หรือ SW DIP-8 ที่เป็นสวิตช์ของตัวดิปสวิตช์นั้นต่อเข้ากับขา SW1,SW2, SW3, SW4, SW5, SW6, SW7 และ SW8 ส่วนสวิตช์แบบกดติดปล่อยดับ S3, S4, S5 และ S6 ต่อเข้ากับ SW5, SW6, SW7 และ SW8
เมื่อพิจารณาวงจรจะพบว่า มีการต่อไฟเข้ากับขาด้านหนึ่งของสวิตช์และเป็นด้านเดียวกันกับที่ต่อเข้ากับขานำเข้าสัญญาณของไมโครคอนโทรลเลอร์ ส่วนอีกด้านของสวิตช์ต่อเข้ากับ GND ของระบบ ดังนั้น
- ถ้า SW DIP-8, หรือ S3, S4, S5, S6 มีสถานะเป็นปิดวงจร (หรือกดสวิตช์) จะทำให้แรงดันไหลผ่านจากแหล่งจ่ายไฟไปลง GND อย่างรวดเร็วทำให้ไม่มีแรงดันไปโผล่ที่ขาของไมโครคอนโทรลเลอร์ ส่งผลให้ได้รับค่าแรงดันเป็นสัญญาณดิจิทัล 0
- ถ้าสถานะของสวิตช์เป็นแบบเปิดหรือไม่ถูกกดจะมีแรงดันอยู่ที่ขาของไมโครคอนโทรลเลอร์ทำให้อ่านค่าแรงดันที่ขาได้เป็นสัญญาณดิจิทัล 1
ตัวอย่างโปรแกรม
จากหลักการควบคุมทิศทางการทำงานของพอร์ต การเข้าถึงพอร์ต และตัวอย่างวงจร LED และ Switch เมื่อนำมาประยุกต์เขียนโปรแกรมเพื่อเป็นแนวทางได้ดังนี้
กระพริบหลอด LED จาก RA0, RB0, RC0, RD0
ตัวอย่างแรกเป็นการต่อขา RA0, RB0, RC0 และ RD0 เข้ากับวงจรหลอด LED ที่หลอด 0, 1, 2 และ 3 โดยต้องกำหนดให้พอร์ต A, B, C และ D ทั้งหมดเป็น OUTPUT ด้วยคำสั่งต่อไปนี้
การส่งแรงดันไปที่ขาใช้คำสั่งต่อไปนี้
การเปลี่ยนสถานะของขาให้เป็น GND เพื่อให้หลอดดับสังงานดังนี้
และการหน่วงเวลาจะต้องกำหนดความเร็วของ XTal เป็น 20MHz พร้อมทั้งกำหนด OSC เป็น HS ส่วนคำสั่งหน่วงเวลาคือ __delay_ms( จำนวนมิลลิวินาที )
// CONFIG1H
#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
#include <xc.h>
#define _XTAL_FREQ 20000000 // กำหนดค่าความถี่ของ XTal
void main(void) {
// กำหนดให้ทุกขาของพอร์ต A, B, C และ D เป็น Output
TRISA = 0x00;
TRISB = 0x00;
TRISC = 0x00;
TRISD = 0x00;
// วนรอบเรื่อย ๆ
while (1) {
RA0 = 1; // LED ON
RB0 = 1; // LED ON
RC0 = 1; // LED ON
RD0 = 1; // LED ON
__delay_ms(500); // 1 Second Delay
RA0 = 0; // LED OFF
RB0 = 0; // LED OFF
RC0 = 0; // LED OFF
RD0 = 0; // LED OFF
__delay_ms(500); // 1 Second Delay
}
return;
}
ตัวอย่างการทำงานเป็นดังคลิป 1
ไฟวิ่งด้วย PORTC
ตัวอย่างนี้ใช้พอร์ต C ทั้งหมดเป็นขา OUTPUT และเริ่มต้นให้มีค่าเป็น 000000012 หรือ 0x01 หลังจากนั้นทำการเลื่อนบิตไปทางซ้าย หลังจากเลื่อนไปจนเป็นตำแหน่ง 100000002 หรือ 0x80 ให้กลับค่ามาเป็น 0x01 ใหม่่อีกครั้ง และทำซ้ำต่อไปเรื่อย ๆ
// CONFIG1H
#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
#include <xc.h>
#define _XTAL_FREQ 20000000 // กำหนดค่าความถี่ของ XTal
void main(void) {
unsigned char patt = 0x01;
TRISC = 0x00;
while (1) {
PORTC = patt;
__delay_ms(100);
patt <<= 1;
if (patt == 0) {
patt = 0x01;
}
}
return;
}
ตัวอย่างการทำงานเป็นดังคลิป 2
กดติดปล่อยดับ
ตัวอย่างนี้เป็นการใช้พอร์ต C จำนวน 4 บิตสำหรับเป็นขา OUTPUT และอีก 4 บิตสำหรับ INPUT ดังนั้น
- RC0 ต่อกับ SW5
- RC1 ต่อกับ SW3
- RC2 ต่อกับ SW7
- RC3 ต่อกับ SW8
- RC4 ต่อกับ LED0
- RC5 ต่อกับ LED1
- RC6 ต่อกับ LED2
- RC7 ต่อกับ LED3
ทำให้ต้องกำหนดค่าของ TRISC เป็น 0x0F หรือ 000011112 โดยความสัมพันธ์ของการทำงานเป็นดังนี้
- นำค่าจาก RC0 ไปลบ 1 แล้วนำผลลัพธ์ ส่งไปที่ RC4
- นำค่าจาก RC1 ไปลบ 1 แล้วนำผลลัพธ์ ส่งไปที่ RC5
- นำค่าจาก RC2 ไปลบ 1 แล้วนำผลลัพธ์ ส่งไปที่ RC6
- นำค่าจาก RC3 ไปลบ 1 แล้วนำผลลัพธ์ ส่งไปที่ RC7
// CONFIG1H
#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
#include <xc.h>
#define _XTAL_FREQ 20000000 // กำหนดค่าความถี่ของ XTal
void main(void) {
TRISC = 0x0F;
while (1) {
RC4 = 1-RC0;
RC5 = 1-RC1;
RC6 = 1-RC2;
RC7 = 1-RC3;
__delay_ms(100);
}
return;
}
ตัวอย่างการทำงานเป็นดังคลิป 3
สรุป
จากบทความนี้ผู้อ่านได้เรียนรู้ขั้นตอนของการกำหนดทิศทางการทำงานของพอร์ต การเข้าถึงพอร์ต การเข้าถึงขาของพอร์ต และประยุกต์หลักการเข้ากับวงจรของภาค LED และ Switch บนบอร์ดทดลองประจำวิชาอันเป้นพื้นฐานสำหรับการนำไปประยุกต์ใช้ต่อไป เช่น เปลี่ยนจากวงจร LED เป็นวงจรรีเลย์สำหรับเปิดปิดไฟ หรือโซลินอยด์ เพื่อเปิดปิดน้ำ เป็นต้น สุดท้าย ขอให้สนุกกับการเขียนโปรแกรมครับ
(C) 2022, โดย อ.อนุชาติ บุญมาก, อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2022-02-11, 2022-02-18, 2022-03-14