Controller
ในส่วนของไมโครคอนโทรลเลอร์ เราใช้ไมโครคอนโทรลตระกูล AVR เราเลือกใช้ ATmega16 ซึ่งมีport ให้เลือกใช้ 4 port และมีฟังก์ชั่นการทำงานหลากหลาย
รูปตัวไมโครคอนโทรลเลอร์ ATmega16
รูปตัว IC 74HC154
รูปตัว IC 74LS48
โค้ดโปรแกรมของกลุ่ม Insanely ซึ่งกลุ่มเราใช้ microcontroller แค่ตัวเดียวนะครับ คือ ATmega16 และสามารถควบคุมการทำงานได้ทั้งหมดของโครงงาน ซึ่งเป็นการใช้ทรัพยากรได้อย่างคุ้มค่า และง่ายดายสำหรับการแก้โปรแกรมควบคุมของงานเพราะแก้ที่ คอนโทรลเลอร์แค่จุดเดียว และยังประหยัดงบประมาณอีกด้วยครับ อิอิ ซึ่งโค้ดโปรแกรมของกลุ่มเรามีรายละเอียดดังต่อไปนี้
/****************************************************************** Includes */
#include <avr/io.h> // AVR device-specific IO definitions
#include <avr/interrupt.h> // Interrupt Service routine
#include <compat/deprecated.h> // Deprecated items
#include <stdio.h> // Standard Input/Output
#define F_CPU 8000000UL // 8 MHz
#include <util/delay.h> // header file implement simple delay loops
#define DSP_DATA_POUT PORTC // DSPx enable (DIGIT PORT)
#define DSP_DATA_DDR DDRC
#define DSP_DATA_POUT1 PORTD // DSPx enable (DIGIT PORT)
#define DSP_DATA_DDR1 DDRD
#define LED_DATA_POUT PORTB // LED Display (DATA_PORT)
#define LED_DATA_DDR DDRB
unsigned int level = 0x00;
unsigned int dc_motor = 0x00;
unsigned int step_motor = 0x00;
unsigned int count_sampling = 0;
unsigned int dl = 0;
unsigned int state=0;
ในส่วนแรกจะเป็นการประกาศ Header และ Global Variable ต่างๆที่ใช้ในโปรแกรมควบคุมทั้งหมด
/********************************************************** Global variables */
const unsigned char num_led[17] = {
0x00, 0x10, 0x20, 0x30, 0x40, //0,1,2,3,4
0x50, 0x60, 0x70, 0x80, 0x90, //5,6,7,8,9
0xA0, 0xB0, 0xC0, 0xD0, 0xE0, //A,b,C,d,E
0xF0 //F,.
};
unsigned char num[9]; // buffer number led
ในส่วนนี้จะเป็นการประกาศ Global Variables ของ ค่าของตัวเลขที่จะแสดงออก 7 segment เพื่อที่จะเรียกใช้ได้ง่ายในรูปแบบ อาร์เรย์
//***************************************************************
uint8_t fs1p[4] = { 0x10,0x20,0x40,0x80 }; //data full step 1 phase
ส่วนนี้จะเป็นการประกาศ Global Variables ของค่าที่จะไปขับ สเต็ปมอเตอร์ ซึ่งในที่นี้จะขับเป็นแบบ 1 เฟส Full step ซึ่งเก็บในรูปแบบของอาร์เรย์เพื่อให้เรียกใช้ได้ง่าย
//***************************************************************
unsigned int a_to_d(unsigned char ch_adc)
{
// AVCC with external capacitor at AREF pin
// ADC Enable & Auto Trigger Disable
ADCSRA = (1<<ADEN)|(0<<ADATE);
ADCSRA |= (0<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // XTAL/8
ADMUX = 0<<REFS1|1<<REFS0|ch_adc;
ADCSRA |= (1<<ADSC);
while(!(ADCSRA &(1<<ADIF))); // wait until finish a2d
return(ADCW);
}
ส่วนนี้จะเป็นฟังก์ชั่นเรียกใช้ ADC Converter จะถูกเรียกใช้จาก main ฟังก์ชั่น และนำค่าที่อ่านได้ไปคำนวณต่อจากนั้นก็ส่งออกจอแสดงผล
/*************************************************************** display_led */
void display_led(unsigned int dly)
{
int i;
for (i=0;i<dly;i++) {
DSP_DATA_POUT = 0x00 ; // 0b1011 (DSP1 enable active)
LED_DATA_POUT = (num_led[num[0]]|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x01; // 0b1101 (DSP2 enable active)
LED_DATA_POUT = (num_led[num[1]]|0x01|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x02; // 0b1110 (DSP3 enable active)
LED_DATA_POUT = (num_led[num[2]]|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x03;
LED_DATA_POUT = (num_led[num[3]]|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x04;
LED_DATA_POUT = (num_led[num[4]]|0x01|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x05;
LED_DATA_POUT = (num_led[num[5]]|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x06;
LED_DATA_POUT = (num_led[num[6]]|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x07;
LED_DATA_POUT = (num_led[num[7]]|0x01|level);
_delay_ms(dl);
DSP_DATA_POUT = 0x08;
LED_DATA_POUT = (num_led[num[8]]|level);
_delay_ms(dl);
}
}
ส่วนของฟังก์ชั่นนี้จะเป็นฟังก์ชั่นของการแสดงผลออกหน้าจอ โดยนำค่าที่คำนวณได้แล้วส่งออกจอ 7 segment เพื่อแสดงค่าอนาล็อกและค่าอุณหภูมิเป้าหมายรวมไปถึงการแสดงสถานะของระดับน้ำในระดับต่างๆอีกด้วย
/************************************************************ Main Functions */
int main(void)
{
unsigned int adc[2];
unsigned int rom=0;
unsigned int rom2=0;
unsigned int count=0;
LED_DATA_DDR = 0xFF; // PORTB All output
DSP_DATA_DDR = 0x0F; // PORT PA0-PA3 Output
DSP_DATA_DDR1 = 0xFF;
num[8] = 0;
num[7] = 0;
num[6] = 0;
num[5] = 0;
num[4] = 0;
num[3] = 0;
num[2] = 0;
num[1] = 0;
num[0] = 0;
ส่วนนี้จะเป็นการ Initial ค่าเริ่มต้นการทำงานของ main function
//*********************************************************
TCCR0 = (1<<CS02)|(0<<CS01)|(1<<CS00); //clk_IO/1024(from prescaler)
TIMSK = (1<<TOIE0); // T/C0 overflow interrupt enable
sei(); //set I-bit global interrupt
ส่วนนี้จะเป็นการเปิดการใช้งาน Interrupt Timer0
//*******************************************************
if((PINC&(1<<PINC7))!=0 && state ==0)
{
unsigned char n = 3;
unsigned int step = 2000;
while(step--) {
step_motor = fs1p[n];
if (n-- == 0)
n = 3;
if((PINC&(1<<PINC7))==0)
step = 0;
DSP_DATA_POUT1 = dc_motor|step_motor;
display_led(1);
_delay_us(100);
}
count_sampling = 0;
}
ส่วนนี้จะเป็นการเซทสถานะของ control valve สเต็ปมอเตอร์ ให้กลับมายังจุดเริ่มต้นหรือทำให้วาล์วสเต็ปมอเตอร์ปิดสนิทก่อน(ถ้ากรณีที่วาล์วเริ่มต้นยังคงเปิดอยู่) ซึ่งส่วนนี้อยู่ใน main function
while (1) {
if((PINC&(1<<PINC4))==0 && count<500){
count++;
_delay_ms(1);
}
if((PINC&(1<<PINC5))==0 && count>0){
count--;
_delay_ms(1);
}
if((PINC&(1<<PINC6))==0 && state == 0){
dc_motor = 0x0F;
state = 1;
_delay_ms(1);
}
if(rom >= 26 && state ==1){ //edit level 30
dc_motor = 0x03;
level = 0x08;
state = 2;
}
if(rom >= 26 && state ==2 && (PINC&(1<<PINC6))==0){
dc_motor = 0x0F;
state = 3;
}
if(rom >= 38 && state ==3){ //edit level 40
dc_motor = 0x03;
level = 0x0C;
state = 4;
}
if(rom >= 38 && state ==4 && (PINC&(1<<PINC6))==0){
state = 5;
}
if(rom >=38 && state ==5){
state = 6;
unsigned char n = 0;
unsigned int step =400;
while(step--) {
step_motor = fs1p[n];
if (n++ == 3)
n = 0;
DSP_DATA_POUT1 = dc_motor|step_motor;
display_led(1);
_delay_us(100);
}
count_sampling =0;
}
if(rom2 <= count+2 && state ==6 && rom >= 38){
level = 0x0E;
state = 7;
unsigned char n = 3;
unsigned int step = 2000;
while(step--) {
step_motor = fs1p[n];
if (n-- == 0)
n = 3;
if((PINC&(1<<PINC7))==0)
step = 0;
DSP_DATA_POUT1 = dc_motor|step_motor;
display_led(1);
_delay_us(100);
}
count_sampling =0;
}
ส่วนนี้จะเป็นส่วนหลักที่ใช้ในการเช็คสถานะของการทำงานว่าให้ทำงานในสถานะใด รวมไปถึงการรับอินพุทสวิทซ์ interface ด้วย และส่วนนี้จะเป็นส่วนที่สั่งการไปยังทุกส่วนให้ทำงานให้ตรงตามเป้าหมายด้วย
//****************************************************************
adc[0] = a_to_d(0x00);
adc[1] = a_to_d(0x01);
if(adc[0]>0 && adc[0] <= 204){
adc[0] = 0;}
if(adc[1]>0 && adc[1] <=204){
adc[1] = 0;}
if(adc[0]>204){
adc[0] = adc[0]-204;}
if(adc[1]>204){
adc[1] = adc[1]-204;}
rom = 0.1221001221*adc[0];
rom2 = 0.6105006105*adc[1];
if(count_sampling == 2)
{
num[8] = (rom2%1000)/100;
num[7] = ((rom2%1000)%100)/10;
num[6] = ((rom2%1000)%100)%10;
num[2] = (rom%1000)/100;
num[1] = ((rom%1000)%100)/10;
num[0] = ((rom%1000)%100)%10;
count_sampling =0;
}
num[5] = (count%1000)/100;
num[4] = ((count%1000)%100)/10;
num[3] = ((count%1000)%100)%10;
DSP_DATA_POUT1 = dc_motor|step_motor;
display_led(8);
}
return 0;
}
ส่วนนี้เป็นส่วนของการคำนวณค่าเพื่อที่จะแสดงผลออกทางหน้าจอแสดงผลทั้งหมด นั่นก็คือ อุณหภูมิที่วัดได้ อุณหภูมิเป้าหมาย ระดับน้ำ สถานะ นอกจากนั้นยังรวมไปถึงการขับวาล์วทั้งสองวาล์วอีกด้วย
//***********************************************************T/C0 Overflow Interrupt
ISR (TIMER0_OVF_vect)
{
count_sampling ++;
}
ส่วนนี้เป็นส่วนของ Interrupt timer0 overflow ซึ่งเมื่อ Timer0 นับขึ้นไปเรื่อย จนเกิด Overflow ตัวแปร count_sampling ก็จะบวกค่าขึ้นไปเรื่อยๆ เพื่อที่จะนำไปใช้ใน main function เป็นตัวกำหนด sampling rate ให้กับโปรแกรม และเงื่อนไขอื่นๆ จากนั้นก็นำไปคำนวณหาค่าเวลาที่ต้องการเอาไปใช้ และนำไปใช้ในส่วนของโปรแกรมที่ต้องการ โดย จะใช้ if, else หรือ while, do while ยังไงก็ได้แล้วแต่เงื่อนไขที่ต้องการเขียนขึ้นมาจากความคิดของเราเอง
หมดแล้วครับ โปรแกรมของเรานี้ ถ้าใครสนใจที่จะนำไป พัฒนาต่อหรือจะเอาไปศึกษาเพื่อความรู้ ทางกลุ่มเรายินดีเป็นอย่างยิ่งครับ ทางเราก็หวังว่าคงจะมีประโยชน์กับท่านไม่มากก็น้อย ขอบคุณครับ
รูปการออกแบบเเละการ Simulation บน Proteus software
รูปการออกแบบลายปริ้นบน ORCAD software