วันจันทร์ที่ 13 กุมภาพันธ์ พ.ศ. 2560

การสร้างเครื่องควบคุมความเร็ว direct drive motor



//a simple demo software for small 3-phase inverter

//Danijel Gorupec, 2015



#include <avr/io.h>

#include <avr/interrupt.h>



char sin_table[64]=

{

0,  3,  6,  9,  12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45,

48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 82, 85, 87,

89, 91, 94, 96, 98, 100,102,103,105,107,108,110,112,113,114,116,

117,118,119,120,121,122,123,123,124,125,125,126,126,126,126,126,

};



unsigned char pwm_table[256]; //holds V-F curve adjusted PWM outputs



unsigned char speed; //output frequency (uint: 0.25Hz)

unsigned char direction; //rotation direction (0 forwared, 1 reverse)

unsigned int phase; //the phase of output sine signal





//some handy macros

#define LED_ON {SREG&=0x7F;PORTC|=0x10;SREG|=0x80;}

#define LED_OFF {SREG&=0x7F;PORTC&=0xEF;SREG|=0x80;}

#define INVERTOR_ENABLE {PORTC|=0x20;PORTD|=0x03;}

#define INVERTOR_DISABLE {PORTC&=0xDF;PORTD&=0xFC;}

#define INPUT_JOG ((PINC&0x02)==0)

#define INPUT_RUN ((PINC&0x04)==0)

#define INPUT_DIR ((PINC&0x08)==0)

#define JOG_SPEED 20





//timer interrupt routing

//It is called in fixed intervals. It advances sine wave phase.

ISR (TIMER0_OVF_vect)

{

if (direction==0)

phase+=speed; //phase: 0...16384 equals 0...2*pi

else

phase-=speed;



unsigned int p=phase/64;

unsigned char p1=p%256;

unsigned char p2=p1+85;

unsigned char p3=p1+171;



OCR1A=pwm_table[p1];

OCR1B=pwm_table[p2];

OCR2=pwm_table[p3];



//adjust the next timer interrupt time

TCNT0=256-240;

}





//this function makes a short pause

//time uint: about 10 microseconds (100 = 1 millisecond)

void WaitLoop(unsigned int time)

{

unsigned int i,j;

for (j=0;j<time;j++)

{

for (i=0;i<8;i++) //the ATmega is runs at 8MHz

if (PORTC==0xFF) DDRB|=0x02; //just a dummy instruction

}

}







char analog_channel=0;

void ReadAnalogs(void)

{

if (ADCSRA&(1<<ADSC)) {return;} //the conversion still not finished



if (analog_channel==0)

{

//ADCH is the speed reference (but inverted!!! - 255=min speed, 0=max speed)

unsigned char spd_ref=255-ADCH;



if (INPUT_JOG) spd_ref=JOG_SPEED;



if (INPUT_DIR)

{

if (direction==0) spd_ref=10;

if (speed==10) direction=1; //only allow direction change at minimum speed

}

else

{

if (direction==1) spd_ref=10;

if (speed==10) direction=0; //only alow direction change at minimum speed

}



if (spd_ref>speed) speed++;

if (spd_ref<speed) speed--;

if (speed<10) speed=10; //the minimum speed



//in next reading we again read this channel because there are no other analog channels used

analog_channel=0;

ADMUX=0x60;

}



ADCSRA|=(1<<ADSC);

}







int main()

{

//Set ATmega8 fuses to 8MHz, internal RC

//Hardware cosist of ATMega8 microcontroller, 6xIRF840 MOSFET (3 halfbridges)



//wait a bit, cca 300ms, for easier programming

//(otherwise programmer has problems downloading)

WaitLoop(30000);





//program IO pins of the ATMega8 microcontroller

//D0 - reset hold (can be kept high to ensure high level on reset pin C6)

//D1 - not used

//D2 - not used

//D3 - not used

//D4 - not used

//D5 - not used

//D6 - not used

//D7 - not used

DDRD=(unsigned char)0x00;

//B0 - not used (ICR1 is modified if this bit is changed)

//B1 - PWM_R

//B2 - PWM_S

//B3 - PWM_T (MOSI SPI)

//B4 - not used (MISO SPI)

//B5 - not used (SCK SPI)

//B6 - not used (always +5V)

//B7 - not used

DDRB=(unsigned char)0x0E;

//C0 - programable input 1 (speed reference - inverted analog input, +5V=min speed, 0V=max speed)

//C1 - programable input 2 (jog - digital input, active low)

//C2 - programable input 3 (run signal - digital input, active low)

//C3 - programable input 4 (rotation direction - digital input, active low)

//C4 - LED output

//C5 - enable output

//C6 - RESET

DDRC=(unsigned char)0x30;





//enable pull-up resistors on inputs 1, 2, 3 & 4

//note: this is nasty, it would be better if we have external pull-down resistors for analog inputs

//    because now we have to use analog input in inverted way (+5V=min speed, 0V=max speed) so that

//      the motor slows down if the wire disconnects

PORTC|=0x0F;



INVERTOR_DISABLE;



//LED test (0.3 sec)

LED_ON;

WaitLoop(30000);

LED_OFF;





//configuring ADC (trigger mode)

ADMUX=0x60; //AVcc for reference, right aligned, mux=ADC0

ADCSRA=0xC7; //ADC frequency (62.5kHz), results in 4.8kHz sampling rate



//wait one more milisecond

WaitLoop(100);



//Programming PWM_R and PWM_S

OCR1A=0x00;

OCR1B=0x00;

TCCR1A=0xA1; //OC1A and OC1B used, phase correct PWM, 8bit

TCCR1B=0x01; //1:1 prescaller - 15kHz PWM



//Programming PWM_T

OCR2=0x00;

TCCR2=0x61; //phase correct PWM, no prescaller - 15kHz PWM





//configuring timer 0

TCNT0=0x00; //timer set to start value

TCCR0|=0x02; //timer/counter 0 input frequency divider set to /8 (that is, 1MHz)

TIMSK|=0x01; //timer/counter 0 interrupt enabled

SREG|=0x80; //global interrupt enabled





speed=10; //2.5 Hz



//OCR1A=128;

//OCR1B=128;

//OCR2=128;



unsigned char led_cntr=0;



while (1)

{

int i;



if ((INPUT_RUN) || (INPUT_JOG))

{

if (led_cntr>16) LED_OFF else LED_ON //we just make short blinks to save power

led_cntr++;



//The VFfactor defines VF curve (how V depends on speed)

int VFfactor=(int)speed+18; //This setting is for asynchronous motor in delta connection (230VAC delta / 400VAC star)

//int VFfactor=speed/4+15; //this settign is for 200VAC servo motor with permanent magnet

if (VFfactor>255) VFfactor=255;



//computing PWM ratios (as we have nothing else to do, this is not optimized)

for (i=0;i<64;i++)

{

int A=sin_table[i];

if (A>127) A=-256+A; //wow! how come I cannot cast char to int?



A=A*VFfactor;

A=A/256;



A+=128+6;

if (A>250) A=250; //because signal delay, we cannot actually create very short impulses



SREG&=0x7F;

pwm_table[i]=A;

pwm_table[127-i]=A;

SREG|=0x80;

A=255-A;

SREG&=0x7F;

pwm_table[i+128]=A;

pwm_table[255-i]=A;

SREG|=0x80;

}



INVERTOR_ENABLE;

}

else

{

INVERTOR_DISABLE;

OCR1A=128;

OCR1B=128;

OCR2=128;

for (i=0;i<255;i++)

{

SREG&=0x7F;

pwm_table[i]=128;

SREG|=0x80;

}

led_cntr=0;

LED_OFF;

speed=10;

}



ReadAnalogs();



}



}


ไม่มีความคิดเห็น:

แสดงความคิดเห็น