/*
 * 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;

}
ATTINY8520PU
Loading chip...chip-scope