|
|
 |
|
| |

การสร้างต้นแบบฮาร์ดแวร์ควบคุมความร้อนระดับแรงดันไฟฟ้ากระแสสลับด้วย
PIC 16F877 / CCS
เขียนโดย อ.จักรกฤษณ์ แสงแก้ว สาขาสารสนเทศศาสตร์ คณะวิทยาการสารสนเทศ มหาวิทยาลัยมหาสารคาม
บทความนี้จะนำท่านสร้างต้นแบบฮาร์ดแวร์ สำหรับเครื่องควบคุมระดับแรงดันไฟฟ้ากระแสสลับในย่าน
0-220 Volte AC โดยควบคุมด้วยไมโครคอนโทรเลอร์ เบอร์ 16F877 ของบริษัทไมโครชิพ
โดยใช้ภาษาซีของค่าย CCS ในการเขียนโปรแกรมเพื่อควบคุมการทำงานทั้งหมดของฮาร์ดแวร์ชุดนี้
เครื่องมือและอุปกรณ์
- Protel
- CCSc
- เครื่องโปรแกรม PIC 16F877
- Triac , Opto, Transformer, Pic 16F877 , Transistor 458
หลักการ
โดยปกติกระแสไฟฟ้าสลับที่จ่ายมาจากการไฟฟ้าส่วนภูมิภาค เป็นไฟฟ้ากระแสสลับมีระดับแรงดันที่
220 volte และมีความถี่ 50 Hz (กระแสไฟฟ้าไหล 50 ไซน์เคิลในหนึ่งวินาที)
ดังนั้น หลักการทำงานคือต้องจับให้ได้ว่า ณ เวลาใด ที่มีระดับแรงดันไฟฟ้าเป็น
0 ขอให้พิจารณาภาพต่อไปนี้

รูปที่ 1 แสดงจุดตัดที่ระดับ 0 โวลท์ (เรียกอีกอย่างหนึ่งว่า Zero Crossing)
ตัวอย่างด้านบนพล็อตกราฟด้วย Matlab โดยมีไซด์เวฟเพียง 5 ลูกเท่านั้น เพื่อให้ท่านสามารถเห็นขนาดลูกคลื่นได้อย่างพอเหมาะ
หลักการของเราคือต้องจับให้ได้ว่า Zero Crossing เกิดขึ้นเมื่อไร (0 Volte)
เมื่อได้รับสัญญาณ Zero Crossing แล้วให้หน่วงไประยะเวลาหนึ่ง
เวลาที่หน่วงคำนวณได้จากสูตร

ดังนั้น เมื่อ f = 50 ดังนั้น t = 20 ms
ท่านต้องหน่วงเวลาในช่วง 0 ถึง 10 ไมโครวินาทีซึ่งเป็นคาบเวลาซึ่งมีผลต่อระดับแรงดันซึ่งแปลผันในช่วง
0 ถึง 220 volte และจะต้องหน่วงเวลาให้คงที่ทุก ๆ รอบของการเกิด Zero Crossing
ดังนั้น MicroController ที่ใช้งานจะต้องมีความเร็วมากกว่า 50 Hz ขึ้นไป
ซึ่งตัวอย่างนี้เราใช้ Pic877 และ Crystal 20 MHz ซึ่งเร็วพอและเร็วเกินด้วย
ดังนั้นสามารถอิมพลิเมนต์โปรเจ็คนี้ได้ !!
เมื่อหน่วงเวลาสักระยะ ให้ท่านเขียนดึงสัญญาณลงมาเป็น 0 volte เป็นเวลา 10
ไมโครวินาที เมื่อหน่วงแล้วให้กลับเป็น 5 volte ตามเดิม สัญญาณนี้จะถูกป้อนให้กับ
อ็อปโต้ เพื่อเหนี่ยวนำทางแสงให้ไตรแอคทำงาน หลักการทำงานของ อ็อปโต้และไตรแอค
ศึกษาได้ในคู่มือทางอิเล็กทรอนิกส์
นอกจากนั้นแอพลิเคชั่นนี้ยังมีปุ่มให้กดเลือกโหมดการทำงานอีก 5 ปุ่ม
1. กำหนดระดับแรงดันของชุดจ่ายที่ 1
2. กำหนดระดับแรงดันของชุดจ่ายที่ 2
3. ปุ่มตั้งเวลาการหยุดทำงาน
4. ปุ่มบันทึกสถานะการทำงานปัจจุบัน ถูกใช้เมื่อผู้ใช้ต้องการกลับมายังสถานะปัจจุบันที่เคยตั้งไว้
5. ปุ่มเปิด/ปิด
ออกแบบ Schematic
การออกแบบแบ่งออกเป็นสองส่วน
1. ชุดกำเนิด Zero Crossing โดยใช้หม้อแปลง (Transformer) จากนั้นเชื่อมผ่านไดโอด
และส่งเข้าให้ทรานซีสเตอร์ 458 เพื่อตรวจจับระดับ 0 volte จึงปล่อยให้กระแสไฟฟ้าไหลผ่านไปจ่ายให้ชุดคอนโทรลเลอร์
2. เมื่อขา B0 ได้รับสัญญาณ Zero Crossing ให้หน่วงเวลาตามที่ต้องการเพื่อปรับระดับแรงดันไฟฟ้า
(รายละเอียดได้กล่าวในตอนต้นแล้ว)
3. นำสัญญาณไปกระตุ้นให้กับ Opto ซึ่งอ็อปโต้จะเหนี่ยวนำทางแสงไปกระตุ้นขาเกต
(Gate) ของไตรแอค

รูปที่ 2 การออกแบบ Schematic
ออกแบบ PCB
เมื่อได้ Schematic เรียบร้อยแล้วลำดับถัดไปคือการออกแบบ PCB ก่อนที่จะออกแบบต้องทำการจัดตำแหน่งของอุปกรณ์คร่าว
ๆ ว่าต้องการวางอุปกรณ์แต่ละตัวไว้ที่ไหน จากนั้นเดินสายเชื่อมต่อระหว่างอุปกรณ์ต่าง
ๆ เหล่านั้นเข้าด้วยกัน เมื่อออกแบบ PCB เสร็จแล้วจึงส่งไปให้บริษัททำแผ่นพรินต์ต่อไป
รูปที่ 3 ผลลัพธ์จากการออกแบบ PCB
การนำอุปกรณ์อิเ็ล็กทรอนิกส์ประกอบเป็นชิ้นงานสำเร็จ
เมื่อได้แผ่น PCB แล้วจากนั้นเป็นการประกอบอุปกรณ์อิเล็กทรอนิกส์ต่าง ๆ ลงบนบอร์ด
ผลลัพธ์แสดงได้ดังภาพต่อไปนี้
รูปที่ 4 แสดงการประกอบอุปกรณ์อิเล็กทรอนิกส์ลงบนแผ่น PCB
เขียนโปรแกรมด้วยภาษาซี
ในการเขียนโปรแกรมด้วยภาษาซีช่วยให้ท่านสามารถเขียนควบคุมไมโครคอนโทรลเลอร์ได้อย่างสะดวก
และมีประสิทธิภาพ ในตัวอย่างนี้ผู้เขียนได้ทดสอบโปรแกรมแล้ว และสามารถใช้งานได้อย่างสมบูรณ์
มีรายละเอียดซอร์สโค๊ดดังต่อไปนี้
ซอร์สโค๊ดภาษาซีแสดงได้ดังนี้ !!
/* -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- */
/* DEFINITIONS */
/* This Program Written by Mr.Chakrit Saengkaew. */
/* King Mongkut's University of Technology Thonburi. */
/* The current date is: Fri 01/21/2005 */
/* The current time is: 7:33:42.43 */
/* -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- */
#include <18F458.h>
#fuses HS,NOLVP, NOWDT,NOPROTECT
#use delay (clock=20000000)
#use fast_io(B)
/* -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- */
/* DEFINITIONS */
/* -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- -==- */
#define Mind_mode PIN_B5
#define Power PIN_B6
#define Time PIN_B7
#define Temp2 PIN_B4
#define Temp1 PIN_B3
#define HEATER1 PIN_B1
#define HEATER2 PIN_B2
#define HEATER3 PIN_A5
#define HEATER4 PIN_A3
#define HEATER5 PIN_A2
#define ZERO PIN_B0
#define CLK PIN_C2
#define LATCH PIN_C0
#define DATA PIN_C1
#define SEGMENT2 PIN_A0
#define SEGMENT1 PIN_A1
#define Temp1_LED PIN_D0
#define High1_LED PIN_D1
#define Mid1_LED PIN_D2
#define Low1_LED PIN_D3
#define Temp2_LED PIN_D4
#define High2_LED PIN_D5
#define Mid2_LED PIN_D6
#define Low2_LED PIN_D7
#define Power_LED PIN_E1
#define Mind_Mode_LED PIN_E0
#define SP PIN_E2
// 5500 = 110 volte
// 5600 = 115 volte
#define HI 5500
#define MID 6000 // 6000 = 90 volte
#define LOW 6500 // 6500 = 75 volte
#define INTERVAL_INCREMENT 3000 //3000 // 50 = 1 sec (50 Hz) : (50Hz * 60sec) = 1 minute
#define TIME_INTERVAL 30 // 30 minute
/*=========================================================
small
40 degree 55-60v 0.31 A-0.34 A
60 85-90 0.4-0.51A
80 105-110 0.59-0.62 A
///////////////////////////////
medium
40 degree 55-60v 0.5-0.54 A
60 85-90 0.77-0.82A
80 105-110 0.95-0.99 A
//////////////////////////////
large
40 degree 55-60v 1.62-1.76 A
60 85-90 2.5-2.65A
80 105-110 3.09-3.24 A
========================================================= */
char num_led7[10] = {0x3f,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7f,0x6f};
int Temp2_Status = 0, Temp1_Status=0, us = 0;
int1 Zero_Crossing = 0, mm_clk = 0 , power_flag = 0 , one_minute_flag = 0, passed_one_minute = 0;
int8 counter = 0 ,original_counter = 0 , mm_counter = 0, incremental_counter=0;
int16 second = 0 , Mind_Mode_Counter = 0;
// -==============================================================-
#INT_EXT
ZERO_CROSSING_SERVICE(){Zero_Crossing = 1;}
// -==============================================================-
set_all_unit(int1 status)
{
switch(status){
case 1:
output_high(Temp1_LED);
output_high(High1_LED);
output_high(Mid1_LED);
output_high(Low1_LED);
output_high(Temp2_LED);
output_high(High2_LED);
output_high(Mid2_LED);
output_high(Low2_LED);
output_high(SP);
output_high(Mind_Mode_LED);
output_c(0xFF);
break;
case 0:
output_low(Temp1_LED);
output_low(High1_LED);
output_low(Mid1_LED);
output_low(Low1_LED);
output_low(Temp2_LED);
output_low(High2_LED);
output_low(Mid2_LED);
output_low(Low2_LED);
output_low(SP);
output_low(Mind_Mode_LED);
output_c(0x00);
}
}
// -==============================================================-
beep(int sec)
{
output_high(SP);
delay_ms(sec);
output_low(SP);
}
// -==============================================================-
out_hc595(byte ds1){
BYTE i,DIS[1];
DIS[0] = ds1;
output_low(CLK);
output_low(LATCH);
for(i=1;i<=8;++i) {
if((*DIS&0x80)==0)
output_low(DATA);
else
output_high(DATA);
shift_left(DIS,1,0);
output_high(CLK);
output_low(CLK);
}
output_high(LATCH);
}
led7(BYTE m)
{
BYTE c1,c2;
if(power_flag){
c2 = (BYTE)m/10;
c1 = (BYTE)(m%10)%10;
out_hc595(num_led7[(int)c1]); output_high(SEGMENT1);delay_ms(5);output_low(SEGMENT1); // Left digit c1
out_hc595(num_led7[(int)c2]); output_high(SEGMENT2);delay_ms(5);output_low(SEGMENT2); // Right digit c2
}
}
// -==============================================================-
led_Temp1_Status(int status)
{
output_high(Temp1_LED);
switch(status)
{
case 0:
output_low(High1_LED);
output_low(Mid1_LED);
output_low(Low1_LED);
output_low(Temp1_LED);
break;
case 1:
output_low(High1_LED);
output_low(Mid1_LED);
output_high(Low1_LED);
break;
case 2:
output_low(High1_LED);
output_high(Mid1_LED);
output_low(Low1_LED);
break;
case 3:
output_high(High1_LED);
output_low(Mid1_LED);
output_low(Low1_LED);
break;
}
}
// -==============================================================-
led_Temp2_Status(int status)
{
output_high(Temp2_LED);
switch(status)
{
case 0:
output_low(High2_LED);
output_low(Mid2_LED);
output_low(Low2_LED);
output_low(Temp2_LED);
break;
case 1:
output_low(High2_LED);
output_low(Mid2_LED);
output_high(Low2_LED);
break;
case 2:
output_low(High2_LED);
output_high(Mid2_LED);
output_low(Low2_LED);
break;
case 3:
output_high(High2_LED);
output_low(Mid2_LED);
output_low(Low2_LED);
break;
}
}
main() {
set_tris_b(0xF9);
set_all_unit(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
delay_ms(500);
set_all_unit(1);beep(2000);set_all_unit(0);set_all_unit(1);beep(2000);set_all_unit(0);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);output_high(HEATER4);output_high(HEATER5);
while(1)
{
// ========== Start Interrupt Zero Crossing
if(Zero_Crossing){
second+=1;
led7(counter);
led_Temp1_Status(Temp1_Status);
led_Temp2_Status(Temp2_Status);
if(counter==0){us=0;}else{us=10;}
if((second>=INTERVAL_INCREMENT)&&(counter>0)){counter-=1;incremental_counter+=1;second=0;}
if((counter==1) && (one_minute_flag==0)) {passed_one_minute = 1;beep(400);delay_ms(100);beep(400);one_minute_flag=1;}
if((counter==0)&& (passed_one_minute==1)){ reset_cpu(); }
// ==============================================
if((Temp1_Status == 3)&&(Temp2_Status == 3)){
delay_us(HI);
if(us == 10){us = 5;}
output_low(heater1);output_low(heater2);output_low(heater3);
delay_us(us);
output_high(heater1);output_high(heater2);output_high(heater3);
output_low(heater4);output_low(heater5);
delay_us(us);
output_high(heater4);output_high(heater5);
}
// ==============================================
if((Temp1_Status ==1)&&(Temp2_Status ==1)){
delay_us(LOW);
if(us == 10){us = 5;}
output_low(heater1);
delay_us(us);
output_high(heater1);
output_low(heater2);
delay_us(us);
output_high(heater2);
output_low(heater3);
delay_us(us);
output_high(heater3);
output_low(heater4);
delay_us(us);
output_high(heater4);
output_low(heater5);
delay_us(us);
output_high(heater5);
}
// ==============================================
if((Temp1_Status ==2)&&(Temp2_Status ==2)){
delay_us(MID); if(us == 10){us = 5;}
output_low(heater1);output_low(heater2);output_low(heater3);
delay_us(us);
output_high(heater1);output_high(heater2);output_high(heater3);
output_low(heater4);output_low(heater5);
delay_us(us);
output_high(heater4);output_high(heater5);
}
if((Temp2_Status ==1) && (Temp1_Status == 0))
{
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(LOW);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
if((Temp2_Status ==2) && (Temp1_Status == 0))
{
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(MID);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
if((Temp2_Status ==3) && (Temp1_Status == 0))
{
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(HI);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
// ===========================================================
if((Temp1_Status ==1) && (Temp2_Status == 0))
{
output_high(HEATER4);output_high(HEATER5);
delay_us(LOW);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
if((Temp1_Status ==2) && (Temp2_Status == 0))
{
output_high(HEATER4);output_high(HEATER5);
delay_us(MID);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
if((Temp1_Status ==3) && (Temp2_Status == 0))
{
output_high(HEATER4);output_high(HEATER5);
delay_us(HI);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
// ===========================================================
if((Temp1_Status == 2) && (Temp2_Status == 1))
{
delay_us(MID);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(LOW-MID);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
if((Temp1_Status ==3) && (Temp2_Status == 2))
{
delay_us(HI);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(MID-HI);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
if((Temp1_Status ==3) && (Temp2_Status == 1))
{
delay_us(Hi);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
delay_us(LOW-HI);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
}
// ===========================================================
if((Temp2_Status == 2) && (Temp1_Status == 1))
{
delay_us(MID);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
delay_us(LOW-MID);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
if((Temp2_Status ==3) && (Temp1_Status == 2))
{
delay_us(HI);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
delay_us(MID-HI);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
if((Temp2_Status ==3) && (Temp1_Status == 1))
{
delay_us(HI);
output_low(HEATER4);output_low(HEATER5);
delay_us(us);
output_high(HEATER4);output_high(HEATER5);
delay_us(LOW-HI);
output_low(HEATER1);output_low(HEATER2);output_low(HEATER3);
delay_us(us);
output_high(HEATER1);output_high(HEATER2);output_high(HEATER3);
}
// ==============================================
Zero_Crossing = 0;}
// ========== End Interrupt Zero Crossing
//=======================================
// On Temp1 ::
//=======================================
if(!input(Temp1)) {
if(power_flag == 1) {beep(50);}
// =========== OLD METHOD 1 2 3 1 2 3 1 2 3 ..
//if(Temp1_Status>=4){
// Temp1_Status=0;
//}
//Temp1_Status+=1;
// ============================================
switch(Temp1_Status){
case 0:
Temp1_Status+=1;
break;
case 1:
Temp1_Status+=1;
break;
case 2:
Temp1_Status+=1;
break;
case 3:
Temp1_Status=0;
break;
default:
break;
}
}
do{}while(!input(Temp1));
//=======================================
// On Temp2 ::
//=======================================
if(!input(Temp2)) {
if(power_flag == 1) {beep(50);}
// =========== OLD METHOD 1 2 3 1 2 3 1 2 3 ..
// if(Temp2_Status>=4){
// Temp2_Status=0;}
// Temp2_Status+=1;
// if(Temp2_Status == 4){
// Temp2_Status = 0;}
// ===========================================
switch(Temp2_Status){
case 0:
Temp2_Status+=1;
break;
case 1:
Temp2_Status+=1;
break;
case 2:
Temp2_Status+=1;
break;
case 3:
Temp2_Status=0;
break;
default:
break;
}
}
do{}while(!input(Temp2));
//=======================================
// On Time ::
//=======================================
if(!input(Time)){
if(power_flag == 1) {beep(50);}
counter+=5;
if(counter>TIME_INTERVAL){
counter=0;}
second=0;
original_counter = counter;
}
do{}while(!input(Time));
//=======================================
// On MindMode ::
//=======================================
if(!input(Mind_mode)) {mm_counter=0;output_high(Mind_Mode_LED);}
while(!input(Mind_mode)){
mm_clk ^=1;
delay_ms(16);
if(mm_clk){mm_counter+=1;}
if((mm_counter>50) && (mm_counter<150)) {beep(200); delay_ms(100); beep(200);}
};
output_low(Mind_mode_LED);
if((mm_counter>0) && (mm_counter<20)) {
/*Read EEPROM*/
beep(100);
counter = read_eeprom(0x00);
Temp1_Status = read_eeprom(0x01);
Temp2_Status = read_eeprom(0x02);
mm_counter=0; }
if((mm_counter>50) && (mm_counter<150)){
/*Write EEPROM*/
beep(1000);
write_eeprom(0x00,counter);
write_eeprom(0x01,Temp1_Status);
write_eeprom(0x02,Temp2_Status);
mm_counter=0; }
//=======================================
// On Power ::
//=======================================
if(!input(Power)){
power_flag ^=1;
beep(200);}
do{}while(!input(Power));
if(power_flag == 0) { output_low(POWER_LED);Temp1_Status = 0;Temp2_Status=0;set_all_unit(0);counter=0;}
if(power_flag == 1) { output_high(POWER_LED);}
}
}
ดาวน์โหลดซอร์สโค๊ดและเอกสารต่าง ๆ
- Schematic
และ PCB
- Source
Code
ทดสอบการทำงานของฮาร์ดแวร์และไมโครคอนโทรลเลอร์
เมื่อเขียนโปรแกรมด้วยภาษาซีเรียบร้อยแล้วจะนำเอาผลลัพธ์ที่ได้จากการคอมไพล์
(ไฟล์ .HEX) โหลดเข้าสู่ไอซีไมโครคอนโทรลเลอร์ และป้อนไฟให้กับวงจรดิจิตอลเพื่อทดสอบการทำงานต่อไป
ภาพต่อไปนี้แสดงการทดสอบการทำงานของฮาร์ดแวร์และคอนโทรลเลอร์
รูปที่ 5 ภาพต่อไปนี้แสดงการทดสอบการทำงานของฮาร์ดแวร์และคอนโทรลเลอร์
สรุป
บทความนี้ทำให้ท่านเห็นว่าภาษาซี ถูกนำไปใช้อย่างกว้างขวางหลากหลายสาขา หลากหลายอาชีพ
ตัวอย่างนี้เป็นการประยุกต์ใช้ภาษาซีในการเขียนควบคุมอุปกรณ์ไมโครคอนโทรลเลอร์
ได้อย่างสะดวกรวดเร็วและมีประสิทธิภาพ หวังว่าบทความนี้จะเป็นประโยชน์ต่อเพื่อน
ๆ ทุก ๆ ท่านที่กำลังสนใจภาษาซีและงานไมโครคอนโทรลเลอร์
|
|
|

|
|