/*
* ATtiny85 running at 16MHz
*/
const int incrmnts = 130;// # of increments per quarter-sine
static unsigned int sinArry[incrmnts];// Stores the quarter-sine values
const int sinPeak = 255;// Max value for the quarter-sine
const int Vreg = 875;// 223Vrms
const int posOffset = 4;// positive bias for the quarter sine
const int sync = 2;// Offset of the 60Hz squarewave from the quarter-sine array
const int dt = 3;// "dead-time" = # of increments fom incremnt 0 of the quarter-sine where pwm = 0
int quarterSinInc;// advances the sinArry
int quarterCnt;// quarter-cycle counter
int Vfdbk;// Stores the analog feedback value used to regulate amplitude
int pwm;// Stores the value to control the duty-cycle of Timer1
float gain;// a multiplier used to control the amplitude of the half-sine
bool up = true;// flag that controls the direction of the quarterSinInc counter. true increments(++) and false decrements(--)
bool alternate;// flag to control whether Timer1 output is inverted or non-inverted
bool peak = false;// a flag that is set at the peak of the quarter sine
bool strtup = true;// When true a course positive gain increment is applied and the output sinewave increses until Vreg threshold is met.
// This results in a quick controlled startup from 0 after turn-on
void setup()
{
pinMode(0, OUTPUT);// PB0 (Pin 5) 60Hz squarewave
pinMode(1, OUTPUT);// PB1 (Pin 6) PWM Output PWM1B - OC1A
pinMode(A2, INPUT);// PB4 (Pin 3) Voltage feedback input
/* Change the A to D converter prescaler for a faster analogRead */
/* Clear prescaler bits */
ADCSRA &= ~(bit (ADPS0) | bit (ADPS1) | bit (ADPS2));
/* Set prescaler to divide by 16 to obtain an approx 13us read time */
//ADCSRA |= bit (ADPS2);
ADCSRA |= (bit (ADPS1)| bit (ADPS0)); // prescaler = 8 (approx 7us read time)
sei();//Enable Global Interrupts
/* Create the quarter-sine array using the sin function */
for(int i = 0; i < incrmnts; i++)
{
int val = (sin(i*M_PI/(2*(incrmnts-1))) * sinPeak)+ posOffset;//Quarter-sine
sinArry[i] = val;
}
// TIMER0 - Interrupt Counter used to to step through the 180 increment half-sine array
//**************************************************************************
/*COM0A1=0 COM0A0=0 (Normal port operation, OC0A/OC0B disconnected)p.78
*COM0B1=0 and COM0B0=0 (Normal port operation, OC0A/OC0B disconnected)p.78
*WGM01=1 and WGM00=0(CTC) p.79 */
TCCR0A = B00000010;
/*
* WGM02=0 (CTC) p.79
* CS02 = 0, CS01 = 1 and CS00 = 0 (divide by 8) 16MHz / 8 / 64 = 31.25kHz */
TCCR0B = B00000010;
/* Set the compare Match A value for thge proper frequency operation*/
OCR0A = 64;// 31.25kHz for 60Hz operation (.01666 / 520 = 32us)
/* Output Compare Match A Interrupt Enable */
TIMSK = B00010000;
//***************************************************************************
// TIMER1 - PWM running at 62.5kHz
/*
*PWM1A=0(Turn ON PWM OC1A PB1(pin6)) p.89
*COM1A1=1 COM1A0=0(OC1x cleared on compare match. Set when TCNT1 = $00 / OC1A Complimentary not connected.) p.86
*CS13=0 CS12=0 CS11=0 CS10=1(prescaller set to divide by 1) p.89
*/
TCCR1 = B01100001;
/*
*PWM1B=1(Turn OFF PWM) p.90
*COM1B1=0 COM1B0=0 (OC1B and OC1B Complimentary not connected) p.86
*/
GTCCR = B00000000;
OCR1C = sinPeak;
/* OCR1A compare match value controlls the duty-cycle of the pwm */
OCR1A = 0;
}
ISR(TIMER0_COMPA_vect)
{
/* Interrupt occurs every 32us */
/*Advance the quarter-sine array 32us * (incrmnts * 2) = 8.32ms*/
//Count up and down for a full half-sine
if(up == true)
{
quarterSinInc++;
}
else
{
quarterSinInc--;
}
if(quarterSinInc == 0)
{
up = true;
//quarterCnt++;
}
if(quarterSinInc == incrmnts - 1)
{
up = false;
}
// Adjust the phase of the squarewave to the half-sine
if(up && quarterSinInc == sync)
quarterCnt++;
// Quarter count determines when the squarewave toggles/ it will toggle every two quarter counts
if(quarterCnt == 1)
{
quarterCnt = 0;
alternate = !alternate;
}
// Control the alternating modulation
// Timer0 will not fully go to zero on each alternate half-cycle so the output is disconnected to accomplish this
// as a result Timer0 output pin has an external 10kΩ pull-down resistor implemented
if(!alternate)
{
// Non-Invert
PORTB &= B11111110;// set PB0 Low
TCCR1 = B01100001;
}
else
{
// Invert
TCCR1 = B01110001;
PORTB |= B00000001;// Set PB0 High
}
// Set the peak flag when the quarter sine it at 90º
if(alternate && quarterSinInc == incrmnts - 1)
peak = true;
}
void loop() {
// Perform startup and voltage regulation
if(peak)
{
Vfdbk = analogRead(A2);
peak = false;
// Evaluate the output voltage at the 90º peak of sine wave
// Perform a fast start-up until Vreg is reached
// Regulate the output voltage by incrementing or decrementing the gain multiplier
// Constrain the gain to 0 - 0.99
// Fast startup
if(strtup && Vfdbk < Vreg && gain <= .982)
{
gain += .008;
}
else
{
strtup = false;
// Voltage Regulation
if(Vfdbk > Vreg && gain >= .002)
{
gain -= .002;
}
else if(Vfdbk < Vreg && gain <= .988)
{
gain += .002;
}
}
}
// Establish the pwm value
pwm = sinArry[quarterSinInc] * gain;
// Add dead-time to reduce ringing around the zero cross-over
if(quarterSinInc < dt)
OCR1A = 0;
else
OCR1A = pwm;
}