บทความ |
|
การเขียนโปรแกรมภาษาซี ด้วย CCS กับ
PIC16F877 ให้พอร์ตเทเบิล
ตอน 1. การควบคุมพอร์ตของ
PIC16F877
ในการเขียนโปรแกรมควบคุมและใช้งานไมโครคอนโทรลเลอร์หลายคนคงปฏิเสธไม่ได้ว่าภาษาแอสเซมบลี(Assembly)
เป็นภาษาที่มีประสิทธิภาพสูงสุดในการควบคุมการทำงานของไมโครคอนโทรลเลอร์
แต่ข้อเสียที่เห็นได้ชัดเจนคือ
เราต้องผูกติดกับภาษานี้ไปพร้อมกับไมโครคอนโทรลเลอร์ตระกูลนั้นเช่น
เขียนแอสเซมบลีบน PIC ไม่สามารถนำไปใช้งานได้บน
mcs-51 เป็นต้น
แต่มีอยู่ภาษาหนึ่งที่ศึกษาและเขียนเพียงครั้งเดียวแต่สามารถนำไปใช้งานได้บนไมโครคอนโทรลเลอร์อีกตระกูลหนึ่งได้
เพียงแก้ไขเล็กน้อยเท่านั้น
โดยมีเงื่อนไขในการเขียนโค้ดครั้งแรกที่ต้องคำนึงถึงคือเรื่องของความสามารถในการย้ายข้ามระบบ(Portability)เป็นสำคัญนั้นคือภาษาซี(c
language)
ในบทความนี้จะเป็นการนำเสนอการเขียนโค้ดด้วยคอมไพเลอร์ CCS
แล้วสามารถที่จะย้ายโค้ดไปทำงานบนคอมไพเลอร์ของตัวอื่นในตระกูล
PIC ได้เช่นเดียวกัน
พื้นฐานในการเขียนโปรแกรมให้พอร์ตเทเบิล
เพื่อที่สามารถนำโค้ดที่ได้เขียนไว้แล้วไปใช้งานอื่นได้ต่อหรือพอร์ตไประบบอื่น
โดยการแก้ไขใหม่อีกเพียงเล็กน้อยเท่านั้น มีหลักสำคัญหรือพื้นฐานเพียง 2 ข้อคือ
1.
ใช้ไดเรกทีฟ #define หรือ
typedef ในการกำหนดใช้งานตัวแปรและค่าคงที่
เพื่อใช้ในการควบคุมค่าคงที่ต่าง ๆ
รวมถึงชนิดและขนาดของตัวแปรที่แตกต่างกันของแต่ละคอมไพเลอร์
2. สร้างชุดคำสั่งใหม่ด้วยฟังก์ชัน
ถ้าคำสั่งนั้นไม่ได้เป็นคำสั่งมาตรฐานของภาษาซี
เพื่อใช้ในการรวบรวมชุดคำสั่งของคอมไพเลอร์นั้นให้อยู่ในโมดูลที่เราเขียนไว้
เมื่อมีการแก้ไขชุดคำสั่งทำให้ สามารถที่จะแก้ไขเพียงฟังก์ชันในโมดูลที่เราได้เขียนขึ้นมา
พอร์ตใช้งานของ
PIC16F877
ไมโครคอนโทรลเลอร์
PIC16F877 มีพอร์ตให้เราใช้งานได้ทั้งหมด 5 พอร์ตคือ
- พอร์ต A
จำนวน 6 ช่อง(RA0-RA5)
เน้นใช้งานเป็นพอร์ตอินพุตเอาต์พุตปกติและการแปลงสัญญาณ
ADC
- พอร์ต B
จำนวน 8 ช่อง(RB0-RB7)
เน้นใช้งานเป็นพอร์ตที่เกี่ยวข้องกับการใช้งานอินเตอร์รัปต์
- พอร์ต C
จำนวน 6 ช่อง(RC0-RC5)
เน้นใช้งานเป็นพอร์ตที่เกี่ยวข้องกับตัวนับ/จับเวลาและการสื่อสาร
- พอร์ต D
จำนวน 8 ช่อง(RD0-RD7)
เน้นใช้งานเป็นพอร์ตอินพุตเอาต์พุตแบบขนาน
- พอร์ต E
จำนวน 8 ช่อง(RE0-RE7)
เน้นใช้งานเป็นพอร์ตแปลงสัญญาณ ADC
และพอร์ตที่เกี่ยวข้องกับพอร์ต D
หมายเหตุ
รายละเอียดและหน้าที่ของแต่ละขาของแต่ละพอร์ตดูได้จากคู่มือการใช้งานที่มากับบอร์ดทดลอง
การควบคุมพอร์ต
PIC16F877 สำหรับ CCS
ในการควบคุมพอร์ตของไมโครคอนโทรลเลอร์ตระกูล PIC
จะต้องมีการกำหนดเงื่อนไขก่อนการใช้งานว่าต้องการให้ขาของพอร์ตที่จะใช้งานทำหน้าที่เป็นขาพอร์ตอินพุตหรือเอาต์พุต
โดยการกำหนดค่าให้กับขาพอร์ตในรีจีสเตอร์ TRIS ก่อน
จุดนี้สำคัญมาก
เพราะถ้าไม่ระวังแล้วอาจทำให้ขาพอร์ตเสียหายได้
ถ้ากำหนดเป็นลอจิก
"0"
แสดงว่าต้องการให้ขาพอร์ตทำหน้าที่เป็นเอาต์พุต
ถ้ากำหนดเป็นลอจิก "1"
แสดงว่าต้องการให้ขาพอร์ตทำหน้าที่เป็นอินพุต
คำสั่งกำหนดหน้าที่ของพอร์ต
set_tris_a (value)
กำหนดหน้าที่ของพอร์ต A
set_tris_b (value) กำหนดหน้าที่ของพอร์ต
B
set_tris_c (value) กำหนดหน้าที่ของพอร์ต
C
set_tris_d (value) กำหนดหน้าที่ของพอร์ต
D
set_tris_e (value) กำหนดหน้าที่ของพอร์ต
E
การเขียนโค้ดกำหนดหน้าที่ของพอร์ตแสดงดังตัวอย่างข้างล่างนี้
SET_TRIS_B(
0x0F ); // B7,B6,B5,B4
ให้เป็นเอาต์พุต B3,B2,B1,B0
ให้เป็นอินพุต
จากตัวอย่างข้างต้นเป็นการกำหนดพอร์ต
B ให้เป็นพอร์ตเอาต์พุต 4 บิตบนและอินพุต 4
บิตล่างหลังจากที่เรากำหนดหน้าที่ของขาพอร์ตแล้วเราจะควบคุมการทำงานของแต่ละพอร์ตตามหน้าที่ที่เราได้กำหนดไว้ดังนี้
ถ้ากำหนดเป็นอินพุต
เราจะใช้ฟังก์ชัน input(pin)
สำหรับการอ่านค่าของแต่ละขาของพอร์ต และใช้คำสั่ง
input_a(),input_b(),..,input_e() สำหรับการอ่านค่าที่ละ 8
บิตหรืออ่านทั้งพอร์ต รูปแบบการใช้งานจะเป็นดังนี้
อินพุตค่าในระดับบิต(สำหรับอ่านเฉพาะเจาะจงไปที่ขาใดขาหนึ่ง)
value = input (pin)
ตัวอย่างเช่น
value = input(PIN_B1)
// อ่านค่าที่ขาพอร์ต B
ที่บิต 1 หรือ RB1
อินพุตค่าในระดับไบต์(สำหรับอ่านคราวละ
8 บิตหรือทั้งพอร์ต)
value = input_a()
value = input_b()
value = input_c()
value = input_d()
value = input_e()
ตัวอย่างเช่น
set_tris_b(0xFF); //
B7,B6,B5,B4,B3,B2,B1,B0
ให้เป็นอินพุต
value =
input_b()
// อ่านค่าที่พอร์ต B
ถ้ากำหนดเป็นเอาต์พุต
เราจะใช้ฟังก์ชัน output_bit (pin, value),output_float (pin),output_high
(pin) ส่งค่าที่ละบิต และoutput_low (pin),output_a
(value),output_b (value),...,output_e (value) ส่งค่าที่ละ 8 บิต
รูปแบบการใช้งานจะเป็นดังนี้
เอาต์พุตค่าในระดับบิต
output_bit (pin, value)
ตัวอย่างเช่น output_bit(PIN_B0, 0);
// กำหนดให้ขาพอร์ต B0
มีสถานะลอจิก "0"
output_float (pin)
ตัวอย่างเช่น output_float(PIN_B0);
// กำหนดให้ขาพอร์ต B0
มีสถานะ high
output_high (pin)
ตัวอย่างเช่น output_high(PIN_B0);
// กำหนดให้ขาพอร์ต B0
มีสถานะลอจิก high
output_low (pin)
ตัวอย่างเช่น output_low(PIN_B0);
// กำหนดให้ขาพอร์ต B0 มีสถานะลอจิก
low
เอาต์พุตค่าในระดับไบต์
output_a (value)
output_b (value)
output_c (value)
output_d (value)
output_e (value)
ตัวอย่างเช่น output_b(0xF0);
หลังจากที่เรารู้เกี่ยวกับฟังก์ชันหรือชุดคำสั่งที่เกี่ยวข้องกับการควบคุมและใช้งานพอร์ตแล้ว
เราสามารถที่จะเขียนโปรแกรมควบคุมขาพอร์ตของ PIC
เพื่อให้พอร์ตเทเบิลได้โดยการสร้างฟังก์ชันที่เกี่ยวข้องกับอินพุตเอาต์พุตพอร์ตใหม่รวมทั้งการกำหนดชนิดของตัวแปรเพื่อการใช้งานดังนี้
// กำหนดให้
bit แทนตัวแปรชนิด int1
ซึ่งมีการใช้งานใน CCS
แต่อาจไม่มีในคอมไพเลอร์ตัวอื่น
typedef int1 bit;
//
สร้างฟังก์ชันควบคุมคำสั่งเฉพาะของคอมไพเลอร์ CCS
void delay_millisec(int n) {
delay_ms(n);
}
void outportb_high(int pin) {
switch(pin) {
case 1: output_high(PIN_B1);
break;
case 2: output_high(PIN_B2);
break;
case 3: output_high(PIN_B3);
break;
case 4: output_high(PIN_B4);
break;
case 5: output_high(PIN_B5);
break;
case 6: output_high(PIN_B6);
break;
}
delay_millisec(delay_time);
}
ฟังก์ชันและตัวแปรที่พอร์ตเทเบิล
ในตัวอย่างข้างต้นเราสามารถที่จะแก้ไขตัวแปรและฟังก์ชันที่เกี่ยวข้องกับเอาต์พุตพอร์ตได้ในส่วนของ
outportb_high() และในส่วนของการหน่วงเวลาใน
delay_millisec()
โปรแกรมตัวอย่าง
ในบทนี้จะแสดงการทำงานของไฟวิ่งด้วย LED
โดยเริ่มต้นการทำงานจากซ้ายไปขวาแล้วรอค่าที่รับเข้ามาจากขา RB7
และ RB0 ทำงานที่ลอจิกศูนย์
เพื่อสลับการวิ่งของไฟ LED จากซ้าย
เป็นขวาหรือขวาเป็นซ้าย การทดลองนี้จะใช้บอร์ดทดลอง NX-877
(บอร์ดไมโครคอนโทรลเลอร์
PIC16F877) เมนหลักของโปรแกรมแสดงดังนี้
void main(void) {
int1 bit_chk;
set_tris_B(0x81); // 10000001 set trisb RB0,RB7 input, RB1-RB6 output
while(1) {
if(!input(PIN_B0)) bit_chk = TRUE; // active low
if(!input(PIN_B7)) bit_chk = FALSE; // active low
if(bit_chk) {
left_led();
} else {
right_led();
}
}
}
ผลการทดลองแสดงดังรูป

การต่อสายใช้งาน

ปุ่มควบคุมการแสดงผล ซ้ายขวาของ LED

ผลการทำงานของโปรแกรม
Home Page
|