การทดลองที่ 1 I/O Port 16F87X

???????พอร์ตของ PIC16F877 จะประกอบด้วย PORTA, PORTB, PORTC, PORTD และพอร์ตของ PIC16F873 จะประกอบด้วย PORTA, PORTB, PORTC ในแต่ละพอร์ตนอกจากจะเป็น Digital I/O ปกติแล้วบางพอร์ตยังทำงานเป็น analog อินพุต ได้ด้วย ก่อนการใช้งานต้อง config พอร์ตก่อน

หลังจาก Power on Reset แล้วโดยปกติแล้ว PORTA จะกำหนดให้เป็นโหมด Analog

??????โครงสร้างพอร์ตของ PIC จะต่างจาก MCS-51 ตรงที่มี Register ที่กำหนดทิศทางของข้อมูลว่าเป็นอินพุตหรือเอาต์พุต หรือเรียกว่า TRIS Register เช่น TRISA

??????ในการ Compile จะให้ไฟล์เอ้าพุตออกมา อาจจะอยู่ในนามสกุล COF หรือ HEX ให้เข้าไปกำหนดให้เป็น HEX ก่อนโดยการกด Project –> Build Options… –> Project –> Restore Defaults

รูปที่ 1

?

??????ตอนแรกผมกะว่าจะใช้้บอร์ดของ ETT ตัวนี้โปรแกรมผ่าน Parallel Port แต่ Port ผมพัง ผมเลยใช้วิธีถอด IC มาโปรแกรมเอา แล้วทีนี้เกิดการผิดพลาดใส่เจ้า 16F877A กลับด้าน มันเลยลาโลกไปซะ ผมเคยต่อไมโครคอนโทรลเลอร์ของ ATMEL พวก 89C52 และ AVR เวลาต่อกลับขั้ว IC มันก็ร้อนๆนะ แต่ไม่ถึงกับพัง พอมาใช้ PIC + ความสะเพร่าของผม ต่อกลับด้านพังไปหลายตัวแล้ว

??????ผมเลยหาเบอร์ตระกูล 16F87X ที่พอมีอยู่ ก็มี 16F873A น่าจะพอแก้ขัดกันได้ ใครจะใช้ 16F877 ก็เปลี่ยน Device ใน MPLAB ได้เลยนะครับ

รูปที่ 2 บอร์ดทดลอง CP-PIC877 V2.0 ของ ETT

รูปที่ 3 ทำการทดลองใน Proto board

รูปที่ 4 Schematic ที่ใช้ในการทดลอง

สำหรับตัวโหลดที่ใช้ในการทดลองผมทำขึ้นมาเองครับ ผมจะเอาตัวโหลดเสียบที่ Target Board แล้วทำการโปรแกรมผ่านทาง ICD2??

การทดลองนี้เราจะเขียน Code ให้ LED ที่ต่อยู่กับ PORTB ติดเรียงกันไปจาก

ในส่วนของค่า Configure ใน MPLAB เนื่องจากเรากำหนดไว้ใน code แล้ว

บรรทัดนี้ __CONFIG(XT & WDTDIS & PWRTEN & BORDIS & LVPDIS & DEBUGDIS & UNPROTECT);

เราจึงไม่ต้อง Configure ใน MPLAB อีก

//****************************************************************//
//Project : first873.mcp
//Description : I/O Port
//Device : PIC16F873A
//By : ThaiEmbedded 2006
//****************************************************************//

#include <pic.h>
#include <stdio.h>
#include <stdlib.h>

__CONFIG(XT & WDTDIS & PWRTEN & BORDIS & LVPDIS & DEBUGDIS & UNPROTECT);

unsigned char i;
unsigned char dat;
//——————————————————————————//
// Delay (mSec)
//——————————————————————————//
void dmsec (unsigned int Count)
{ unsigned char i;
????? while (Count)
????? {
????? ????? for (i=0;i<=100;i++);
????? ????? Count–;
????? }
}
//——————————————————————————//
// Main Program
//——————————————————————————//
void main ()
{
?????TRISB = 0b00000000; //Output mode
????? while(1) //Loop Forever
????? {
?????????? dat = 0×01;
?????????? for(i=0;i<8;i++)
?????????? {
?????????? ????PORTB = dat;
????? ????? ???dat <<= 1;
????? ????? ???dmsec(500);
?????????? }
????? }
}

Download Code การทดลองที่ 1

การทดลองที่ 3 เทคนิคการเก็บข้อมูล Long, Float ลง EEPROM ด้วยวิธี UNION

การเก็บข้อมูลที่มีขนาดมากกว่า 1 Byte เราสามารถทำได้ประมาณ 3 วิธี

1. ทำการแบ่ง Byte ข้อมูลเป็นส่วนๆ ด้วยการหารเช่นกรณี unsigned int ถ้าเราหารด้วย 256 ก็จะได้ตัวแปร Byte High ถ้าเรา mod ด้วย 256 ก็จะได้ตัวแปร Byte Low จากนั้นก็เอาตัวแปรแต่ละตัวไปเก็บไว้ใน EEPROM วิธีนี้จะเสีย CYCLE ในการประมวลผลไปเปล่าๆ

2. ใช้ Pointer เราประกาศ Pointer เป็น char แล้วก็เลื่อน Pointer ไปทีละ 1 ไบต์ก็จะได้ตัวแปรแต่ละไบต์

3. ใช้ UNION วิธีนี้เป็นวิธีที่ผมใช้บ่อย ก่อนที่จะอธิบายการจัดเก็บ ผมขออธิบาย UNION ก่อนว่า UNION คืออะไร

UNION เป็นการประกาศตัวแปรที่ใช้หน่วยความจำร่วมกัน ตัวแปรที่ประกาศแบบ UNION จะมีหน่วยความจำอยู่ตำแหน่งทับกันหมดทุุกตัว เช่นตัวอย่างตัวแปร Dat_long.word ใช้ตำแหน่งหน่วยความจำเดียวกัน การแก้ไขตัวแปร Dat_long.word ก็จะมีผลกับตัวแปร Dat_long.byte[0-3]

รูปที่ 1 memory จากการใช้คำสั่ง UNION

รูปที่ 2 Schematic ที่ใช้ในการทดลอง 3

การประยุกต์ใช้งานกับหน่วยความจำ เพียงย้ายข้อมูลมาไว้ Float, long แล้ว เอาข้อมูลจากตัวแปร์ array มาเก็บไว้ใน EEPROM

//*******************************************************************//
//Project : union.mcp
//Description : Union
//Device : PIC16F873A
//By : ThaiEmbedded 2006
//Date : 25 Nov 2006
//*******************************************************************//

#include <pic.h>
#include <stdio.h>
#include <stdlib.h>

__CONFIG(XT & WDTDIS & PWRTEN & BORDIS & LVPDIS & DEBUGDIS & UNPROTECT);

long ee_buff[2];

union dat_long
{
?????unsigned char byte[4];
?????long word;
}Dat_long;
union dat_long Dat_long;
//——————————————————————————//
// Delay (mSec)
//——————————————————————————//
void dmsec (unsigned int Count)
{?????

?????unsigned char i;
?????while (Count)
?????{
??????????for (i=0;i<=100;i++);
??????????Count–;
?????}
}
//——————————————————————————//
// Main Program
//——————————————————————————//
void main ()
{
?????dmsec(200);
?????TRISB = 0b00000000; //Output mode

?????ee_buff[0] = 123456;
?????Dat_long.word = ee_buff[0];
?????EEPROM_WRITE(0, Dat_long.byte[0]);
?????EEPROM_WRITE(1, Dat_long.byte[1]);
?????EEPROM_WRITE(2, Dat_long.byte[2]);
?????EEPROM_WRITE(3, Dat_long.byte[3]);

?????dmsec(200);
?????Dat_long.word = 0;

?????Dat_long.byte[0] = EEPROM_READ(0);
?????Dat_long.byte[1] = EEPROM_READ(1);
?????Dat_long.byte[2] = EEPROM_READ(2);
?????Dat_long.byte[3] = EEPROM_READ(3);

?????ee_buff[1] = Dat_long.word;

?????if(ee_buff[0]==ee_buff[1])
??????????PORTB = 1;
?????else
??????????PORTB = 3;

?????while(1); //Loop Forever????????
}

?

แบบฝึกหัด

ลองเปลี่ยนตัวแปรจาก Long เป็น float ลอง Compile ดูว่า ให้ผลลัพท์เหมือนเดิมไหม

Download Code การทดลองที่ 3

สื่อสารข้อมูลแบบไร้สายด้วยโมดูล TLP434/RLP434

ในปัจจุบัันการส่งข้อมูลแบบไร้สายจำแนกได้เป็น 2 อย่าง 1. สื่อสารทางแสง อาจจะเป็นแสงไฟหรือแสงอินฟราเรด 2. การสื่อสารผ่านทางคลื่นวิทยุ เช่น Bluetooth

สำหรับไมโครคอนโทรลเลอร์ก็เช่นกันสามารถสื่อสารทางแสงหรือคลื่นวิทยุได้เหมือนกัน เมื่อประมาณปี 2548 ได้ลองเล่นโมดูลรับส่งชุดนึง สามารถต่อโดยตรงกับไมโครคอรโทรลเลอร์ได้่เลย ตอนนั้นงานผมจะใช้ PIC16F ซะเป็นส่วนใหญ่ เลยเอามาต่อเป็นตัวรับตัวส่ง ก็ใช้งานได้ดีพอสมควร สมราคาโมดูล RF

Frequency : 433.92 MHz

Modulation : ASK

Voltage Operation : 2-12V

RF Output Power : 8mW@3.6V

ขนาดตัวส่งโดยประมาณ : 10×15 mm

ขนาดตัวรับโดยประมาณ : 43×10 mm

?

รูปที่ 1 โมดูลรับส่ง RF TLP/RLP434 (ด้านหลัง)

รูปที่ 2 โมดูลรับส่ง RF TLP/RLP434 (ด้านหน้า)

อยู่มาวันนึงผมก็เกิดไอเดียว่าจะเอาโมดูลรับส่งมาทำอะไรดี เลยเอามาลองใช้เป็นออดไร้สายเรียกคนในบ้้าน ให้ช่วยเปิดประตู เวลาจะขับรถเข้าบ้าน ระบบไร้สายถ้าจะให้คล่องตัวก็ต้องใส่ถ่าน ถ้าจะใช้พวก MCS-51 มันก็คงจะกินไฟมากกว่า เลยเอามาต่อกับ USART ของ PIC16F628A ทำเป็นภาคตัวส่ง

ส่วนภาครับก็ใช้ 16F628A มารับสัญญาณจาก RLP434 หลังจากรับสัญญาณแล้วก็ทำการเช็คความถูกต้องของข้อมูล ตรงนี้จะสำคัญมาก เพราะเจ้าตัวรับ (RLR434) จะรับข้อมูลขยะเข้ามาตลอดเวลา ถ้าไม่มีการเช็คความถูกต้องของข้อมูลก็จะมีการรับข้อมูลขยะมาประมวลผลได้

โปรโตคอลรับ/ส่ง

ผมใช้วิธีแบบง่ายๆและได้ผลคือส่ง Start byte ไปก่อน แล้วตามด้วยข้อมูล แล้วจบด้วย CRLF เมื่อฝั่งรับเจอ Start byte ก็จะทำการรับข้อมูลไปเรื่อยๆ จนกระทั่ง buffer ของฝั่งรับเต็มหรือเจอ CRLF ถ้าเจอ CRLF ก็จะนำข้อมูลไปตรวจสอบความถูกต้อง เช่น ฝั่งส่งส่ง :CMD01<CR> ถ้าฝั่งรับรับได้ข้อมูล “CMD01″ ก็จะ enable การทำงานนั่น

สำหรับโปรโตคอลที่ซับซ้อนขึ้นเราจำเป็นต้องมี Error Checking ตรวจสอบข้อมูลเช่น Check Sum หรือ CRC16 แต่จากการทดลองรับส่งการใช้ Check Sum ก็เพียงพอ และยังใช้ Cycle ในการคำนวณไม่มากเท่า CRC16

การสร้าง

สำหรับการสร้าง จะมีฝั่งรับ/ฝั่งส่ง ทางฝั่งส่งผมออกแบบให้ใช้กับถ่าน 9V แล้วมี IC 7805 แปลงเป็นไฟ 5V เพื่อเอาไปเลี้ยงวงจร ทางฝั่งส่งไม่ค่อยจะมีปัญหาเท่าไหร่ เนื่องจากไม่จำกัดเรื่องขนาด และไฟเลี้ยง

เพื่อให้ง่ายต่อการสร้าง ผมเลยใช้แผ่นปริ๊นอเนกประสงค์แล้ว wire สายเอา

รูปที่ 3 วงจรภาคส่ง (คล๊กเพื่อดูภาพใหญ่)

รูปที่ 4 วงจรภาครับ (คล๊กเพื่อดูภาพใหญ่)

หลังจากหลังขดหลังแข็ง wire สายมาก็จะได้ชุดรีโมทภาคส่งมาทดลองกัน สำหรับกล่องที่ใส่ก็เป็นกล่องอเนกประสงค์ทั่วไปครับ อย่าลืมต่อสายไฟทำเป็นเสาอากาศด้วยนะครับเพือเพิ่มระยะทางการส่ง

รูปที่ 5 ภาคส่ง

ส่วนของภาครับ ผมจะใช้่ฝาของกล่องอเนกประสงค์ ทำเป็นฐานรองแผ่นปริ๊นแล้วใช้สายไฟต่อเป็นเสาอากาศ

รูปที่ 6 ภาครับ

Source Code

Compiler : Hi-tech 8.02 + MPLAB V7.0

ถ้าต้องการ Compiler มาทดลองใช้สามารถ Download ตัว Demo ได้ที่นี่ครับ

Download Code สื่อสารข้อมูลแบบไร้สายด้วยโมดูล TLP434/RLP434