That pll_drv.h file should be in the original AVR495 package.
// *untried, probably will blow up*
// space vector vfd from IAR thing
//
// 50hz PWM from 'front end' controller comes in on PD6
// Copyright (c) 2004 Atmel.
// author raubree
#include <stdio.h>
#include <math.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
//#include "lib_mcu/dac/dac_drv.h"
//#include "lib_mcu/adc/adc_drv.h"
#include "lib_mcu/pll/pll_drv.h"
//#include "table_sin120.h" // table_sin120.h : no third harmonic
#include "table_sin81.h" // space vector
#define MAX_PWM 2666 // 64MHz (PLL frequency) / 2666 / 2 = 12 kHz (PWM frequency)
#define MAX_THETA 80 // one sixth of the circle
#define K_scal 16 // used for the angle integrator
volatile uint16_t runtimer=0;
volatile uint16_t control=0; // control pwm pulse width
volatile uint16_t adtbl[12]; // a/d reading array
volatile uint8_t Flag_IT_timer0=0;
volatile uint8_t Flag_IT_ADC=0 ;
volatile uint16_t Softcounter = 0 ;
volatile int Omega_meas;
volatile int Omega_ref = -160;
volatile int Command = 0;
volatile uint16_t theta1=0, theta2=160, theta3=320 ;
volatile uint16_t amplitude , OmegaTe = 64 ;
volatile uint8_t direction = 0 ;
volatile uint16_t PWM0, PWM1, PWM2;
volatile uint16_t Counter_PE1; // changed to int from byte
//volatile uint16_t DACoutput;
volatile uint16_t tau1, tau2 ; // space vector stuff
volatile uint16_t tau1bis, tau2bis;
volatile uint16_t Thetai = 0, Thetai_1 = 0;
volatile uint8_t Sector_number = 1;
volatile int speed_error=0; //"mc_control" !<Error calculation
volatile int speed_integral = 0;
volatile int speed_integ = 0;
volatile int speed_proportional = 0;
const uint8_t PROGMEM adsetup[]= {0x40,0x42,0x48,0x49,0x4a}; // Thermistor,IU, IW, IV, Pot, Vcc ref
#define DeadTime 32 // 32 => temps mort = 0.5 µs
#define MAX_AMPLITUDE ((MAX_PWM / 2) - DeadTime)
#define BRREG_VALUE 100 // 4800 baud
//#define BRREG_VALUE 25 // 19200 baud
//#define BRREG_VALUE 12 // 38400 baud
#define Itrip 200 // overcurrent
#define Thermtrip 1023 // overtemp
#define Vtherm adtbl[0] // Thermistor
#define IU adtbl[1] // Phase U current
#define IV adtbl[2] // Phase V current
#define IW adtbl[3] // Phase W current
#define Vpot adtbl[4] // Potentiometer setting
#define BAUD_RATE_LOW_REG UBRRL // definitions for UART control
#define UART_CONTROL_REG UCSRB
#define ENABLE_TRANSMITTER_BIT TXEN
#define ENABLE_RECEIVER_BIT RXEN
#define UART_STATUS_REG UCSRA
#define TRANSMIT_COMPLETE_BIT TXC
#define RECEIVE_COMPLETE_BIT RXC
#define UART_DATA_REG UDR
#define Set_PC7() PORTC |= (1<<PC7) // SOME USEFUL MACROINSTRUCTIONS
#define Clear_PC7() PORTC &= ~(1<<PC7)
#define Toggle_PC7() PINC |= (1<<PINC7)
#define Set_PC3() PORTC |= (1<<PC3)
#define Clear_PC3() PORTC &= ~(1<<PC3)
#define Toggle_PC3() PINC |= (1<<PINC3)
#define Set_PE1() PORTE |= (1<<PE1)
#define Clear_PE1() PORTE &= ~(1<<PE1)
#define Toggle_PE1() PINE |= (1<<PINE1)
#define Vf_SLOPE 67 // "control v/f" defines
#define OMEGA_TS_MAX 192
//#define OMEGA_TS_MIN 32
#define OMEGA_TS_MIN 64
ISR(INT0_vect) // ext int0 control pwm interrupt
{ // any change generates interrupt
static uint16_t startcount; // 8us/count (6250==50ms)
if(PIND & 0x40) // hi? pulse has ended
{
control=(TCNT1-startcount)/8;
}
else // low? pulse has started
{
startcount=TCNT1;
}
runtimer=1000; // reset runtimer 500ms
}
ISR(TIMER0_COMPA_vect) // Timer0 500 usec
{
Flag_IT_timer0=1;
if(runtimer)--runtimer;
else control=0; // speed zero if no pulses for 500ms
}
ISR(ADC_vect) // 8mhz/32/13/5 = ~3846 scans/second
{ // 64 steps/cycle
static uint8_t row;
adtbl[row]=ADC; // save voltage sample
if(++row>4) // bump pointers
{ // as needed
row=0;
}
ADMUX=pgm_read_byte(adsetup+row); // and set A/D mux address for next reading
ADCSRA = 0xce; // start next conversion,
Flag_IT_ADC=1; // set scan complete flag
}
void init(void)
{
ADMUX = 0x40; // use external vref & right adjust result
ADCSRA = 0xcd; // start adc with interrupt, ck/32 (250khz)
DIDR0 = 0x04; // disable digital on adc2
DIDR1 = 0x07; // disable digital on adc8,adc9,adc10
DDRB = 0xC3;
DDRC = 0x89;
DDRD = 0x01;
DDRE = 0x02;
PORTC = 0x06; // enable pull up on buttons
PORTD = 0x42; // enable pullup on "fault" and PWM inputs
TCCR0A = (1<<WGM01); // mode CTC : Clear Timer on Compare
TCCR0B = (1<<CS02); // f_quartz = 8 MHz / 256 = 32 kHz
OCR0A = 0x10; // one interruption every 0.5ms
TIMSK0 = (1<<OCIE0A); // allow interruption when timer=compare
TCCR1A = 0x00; // T1 normal mode
TCCR1B = 0x03; // clk/64 (8us/tick)
EICRA = 0x01; // configure INT0 to trigger both edges
EIMSK = 0x01; // enable INT0
SREG |= 0x80; // allow interruptions,
}
/*
void DAC_Init(void)
{
Enable_dac();
Right_adjust_dac_result(); // 10 bits resolution
Output_dac_enable();
}
*/
void PSC_Init(uint16_t ot0, uint16_t ot1)
{
Start_pll_64_mega(); // start the PLL at 64 MHz
Wait_pll_ready();
OCR0RA = ot0;
OCR0RB = ot1;
PCNF0 = (1<<POP0)|(1<<PMODE01)|(1<<PMODE00)|(1<<PCLKSEL0); // TP
PFRC0A = (1<<PFLTE0A)|(0<<PRFM0A3)|(1<<PRFM0A2)|(1<<PRFM0A1)|(1<<PRFM0A0);
// input noise cancel, fault mode 7 (halt psc and wait for software action)
// falling edge pscin trigger (PD1)
// PFRC0A = 0; // TP test
PFRC0B = 0;
PCTL0 = (1<<PARUN0)|(1<<PCCYC0);
OCR1RA = ot0;
OCR1RB = ot1;
PCNF1 = (1<<POP1)|(1<<PMODE11)|(1<<PMODE10)|(1<<PCLKSEL1); // TP
PFRC1A = 0;
PFRC1B = 0;
PCTL1 = (1<<PARUN1)|(1<<PCCYC1);
OCR2RA = ot0;
OCR2RB = ot1;
PCNF2 = (1<<POP2)|(1<<PMODE21)|(1<<PMODE20)|(1<<PCLKSEL2); // TP
PFRC2A = 0;
PFRC2B = 0;
PCTL2 = (1<<PCCYC2)|(1<<PRUN2);
PSOC0 = (1<<POEN0B)|(1<<POEN0A); // connect the PSC waveform generator outputs to the port outputs
PSOC1 = (1<<POEN1B)|(1<<POEN1A);
PSOC2 = (1<<POEN2B)|(1<<POEN2A);
}
void PSC_Load (uint16_t dt0a, uint16_t dt1a, // load all pscs
uint16_t dt0b, uint16_t dt1b,
uint16_t dt0c, uint16_t dt1c)
{
PCNF0 = (1<<POP0)|(1<<PLOCK0)|(1<<PMODE01)|(1<<PMODE00)|(1<<PCLKSEL0);
PCNF1 = (1<<POP1)|(1<<PLOCK1)|(1<<PMODE11)|(1<<PMODE10)|(1<<PCLKSEL1);
PCNF2 = (1<<POP2)|(1<<PLOCK2)|(1<<PMODE21)|(1<<PMODE20)|(1<<PCLKSEL2);
OCR0SA = dt0a;
OCR0SB = dt1a;
OCR1SA = dt0b;
OCR1SB = dt1b;
OCR2SA = dt0c;
OCR2SB = dt1c;
PCNF0 = (1<<POP0)|(1<<PMODE01)|(1<<PMODE00)|(1<<PCLKSEL0);
PCNF1 = (1<<POP1)|(1<<PMODE11)|(1<<PMODE10)|(1<<PCLKSEL1);
PCNF2 = (1<<POP2)|(1<<PMODE21)|(1<<PMODE20)|(1<<PCLKSEL2);
}
uint16_t controlVF(uint16_t wTs) // V/f law
{
uint16_t amp;
if(wTs <= OMEGA_TS_MIN) // boost frequency
{
amp = (Vf_SLOPE * OMEGA_TS_MIN) / 10; // boost voltage
}
else
{
if ((wTs > OMEGA_TS_MIN) & (wTs < OMEGA_TS_MAX))
{
amp = (Vf_SLOPE * wTs)/10; // V/f law
}
else
{
amp = (Vf_SLOPE * OMEGA_TS_MAX)/10; // rated value
}
}
return amp;
}
void SVPWM(uint16_t amp, uint16_t Omega)
{
Thetai_1 = ((long)K_scal*Thetai_1 + Omega) / K_scal ;
if (Thetai_1 >= MAX_THETA)
{
Thetai_1 -= MAX_THETA ;
Sector_number = Sector_number + 1 ;
if (Sector_number > 6)
{
Sector_number = 1 ;
}
}
theta2 = (uint8_t)Thetai_1 ;
theta1 = (uint8_t)(MAX_THETA - Thetai_1) ;
tau1 = ((long)amp * tab_sin[theta1]) / 128 ; // 128
tau2 = ((long)amp * tab_sin[theta2]) / 128 ; // 128
switch(Sector_number)
{
case 1 :
PWM0 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 + tau1 - tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ; break ;
case 2 :
PWM0 = (uint16_t) (MAX_PWM/2 - tau1 + tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ; break ;
case 3 :
PWM0 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 + tau1 - tau2) ; break ;
case 4 :
PWM0 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 - tau1 + tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ; break ;
case 5 :
PWM0 = (uint16_t) (MAX_PWM/2 + tau1 - tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ; break ;
case 6 :
PWM0 = (uint16_t) (MAX_PWM/2 - tau1 - tau2) ;
PWM1 = (uint16_t) (MAX_PWM/2 + tau1 + tau2) ;
PWM2 = (uint16_t) (MAX_PWM/2 - tau1 + tau2) ; break ;
default :
PWM0 = (uint16_t) (MAX_PWM/2) ;
PWM1 = (uint16_t) (MAX_PWM/2) ;
PWM2 = (uint16_t) (MAX_PWM/2) ; break ;
}
}
int main(void)
{
CLKPR = 0x80;
CLKPR = 0x00;
init();
// DAC_Init(); // do not init DAC if you want to use PC7 as I/O
// ADC_Init();
PSC_Init(0x00, MAX_PWM);
while(1)
{
if (Flag_IT_timer0) // .5ms yields 2khz
{
// ADC_start_conv();
if(Counter_PE1 != 0) // 125 ms
{ // this just blinks a LED
Counter_PE1--;
}
else
{
Toggle_PE1();
Counter_PE1 = 1000; // was 250, calmed it down to 1000
}
Flag_IT_timer0=0;
}
if (Flag_IT_ADC) // adc channel scan complete?
{
// Command=control; // command from 'front end' controller pwm
// Command=((512 - Vpot)*20) / 10; // command with the on board pot
Command=(Vpot/5)+20;
if (-1)//Command > (int)(0)) // direction management : extract sign and absolute value
{
direction = 0 ;
OmegaTe = Command;
}
else
{
direction = 1 ;
OmegaTe = (~Command) + 1;
}
amplitude = controlVF(OmegaTe);// V/f law
amplitude=1000;
if (amplitude > MAX_AMPLITUDE)
{
amplitude = MAX_AMPLITUDE ;
}
SVPWM(amplitude, OmegaTe) ; // space vector PWN algorithm
if (direction==0) // load the PSCs with the new duty cycles
{
PSC_Load (PWM0, PWM0+DeadTime, PWM1, PWM1+DeadTime, PWM2, PWM2+DeadTime);
}
else
{
PSC_Load (PWM0, PWM0+DeadTime, PWM2, PWM2+DeadTime, PWM1, PWM1+DeadTime);
}
Flag_IT_ADC=0;
}
// if (( PIFR0 & (1<<PEV0A)) !=0 ) // test the overcurrent input
if ((IU>Itrip)||(IV>Itrip)||(IW>Itrip)||(Vtherm>Thermtrip)) // test for overcurrent and overtemp
{ // and shut it down
Set_PC7();
Set_PC3();
Clear_PE1();
while (1) ;
}
}
}
วันอังคารที่ 10 ตุลาคม พ.ศ. 2560
Arduino 3 phase induction motor variable frequency
Try this, this is a mangled AVR495 which should compile with avr-gcc. I added some odds and ends such as the external control scheme, and *other* changes from the original files, so beware 8) There may be signals or inputs that if missing may shut the outputs down making it appear dead. Look at the fault checks near the end of 'main', you may need to override them.
สมัครสมาชิก:
ส่งความคิดเห็น (Atom)
ไม่มีความคิดเห็น:
แสดงความคิดเห็น