Interrupt Frequency (audio, no PWM) generation?

Hi,

I am currently experimenting with audio generation in the Arduino. I already did some funny sounds (very retro!) and wanted now to use an interrupt to do the sound and beeing able to alter the frequency with a low frequency filter during play.

With the interrupt tutorial I was able to get some sound (nice sqare waves):

// http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/

#define TIMER_CLOCK_FREQ 2000000.0 //2MHz for /8 prescale from 16MHz
#define TOGGLE_IO 13 //Arduino pin to toggle in timer ISR

long  latencySum, latency,sampleCount,timerLoadValue;
volatile long count;
volatile int pitch=2;

//Setup Timer2.
//Configures the ATMega168 8-Bit Timer2 to generate an interrupt
//at the specified frequency.
//Returns the timer load value which must be loaded into TCNT2
//inside your ISR routine.
//See the example usage below.

unsigned char SetupTimer2(float timeoutFrequency){
  unsigned char result; //The timer load value.

  //Calculate the timer load value
  result=(int)((257.0-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5);
  //The 257 really should be 256 but I get better results with 257.

  //Timer2 Settings: Timer Prescaler /8, mode 0
  //Timer clock = 16MHz/8 = 2Mhz or 0.5us
  //The /8 prescale gives us a good range to work with
  //so we just hard code this for now.
  TCCR2A = 0;
  TCCR2B = 0<<CS22 | 1<<CS21 | 0<<CS20;

  //Timer2 Overflow Interrupt Enable
  TIMSK2 = 1<<TOIE2;

  //load the timer for its first cycle
  TCNT2=result;

  return(result);
}


//Timer2 overflow interrupt vector handler
ISR(TIMER2_OVF_vect) {
  //Toggle the IO pin to the other state.
  count++;
  if (count<=pitch/2)
  {
    digitalWrite(TOGGLE_IO,HIGH);
  }
  else
  {
    digitalWrite(TOGGLE_IO,LOW);
  }
  if (count>=pitch)
  {
    count=0;
  }
  //Capture the current timer value. This is how much error we
  //have due to interrupt latency and the work in this function
  latency=TCNT2;

  //Reload the timer and correct for latency.
  TCNT2=latency+timerLoadValue;
}


void setup(void) {
  //Set the pin we want the ISR to toggle for output.
  pinMode(TOGGLE_IO,OUTPUT);

  //Start up the serial port
  Serial.begin(115200);

  //Signal the program start
  Serial.println("Timer2 Test");

  //Start the timer and get the timer reload value.
  timerLoadValue=SetupTimer2(4);

  //Output the timer reload value
  Serial.print("Timer2 Load:");
  Serial.println(timerLoadValue,HEX);
}


void loop(void) {
  //Accumulate ISR latency every 10ms.
  delay(10);
  //Accumulate the current latency value from the ISR and increment
  //the sample counter
  latencySum+=latency;
  sampleCount++;

  //Once we have 100 samples, calculate and output the measurements
  if(sampleCount>99) {
    float latencyAverage;
    float loadPercent;

    pitch++;

    //Calculate the average latency
    latencyAverage=latencySum/100.0;

    //zero the accumulator values
    sampleCount=0;
    latencySum=0;

    //Calculate the Percentage processor load estimate
    loadPercent=latencyAverage/(float)timerLoadValue;
    loadPercent*=100; //Scale up from ratio to percentage;

    //Output the average Latency
    Serial.print("Latency Average:");
    Serial.print((int)latencyAverage);
    Serial.print(".");
    latencyAverage-=(int)latencyAverage;
    Serial.print((int)(latencyAverage*100));

    //Output the load percentage estimate
    Serial.print(" Load:");
    Serial.print((int)loadPercent);
    Serial.print("%");
    Serial.print("  Pitch:");
    Serial.print(pitch);
    Serial.println();
  }
}

You can see I left all the educational functions in for now. Using a software-soundcard scope on my pc I can see the waves and the frequency.

My problem: I can generate frequencies up to some kHz but the steps between the single frequencies are just too big. So I guess I need to call the timer isr more often so that the range of my pitch value is maybe in a range of some hundred counts which may be enough for a untrained ear not to hear the steps.

I tried some things with the prescaler, but never got smaller steps.

Carsten

Hrm.

Was my question to complicated or stupid? :(

Carsten

My guess is that you’re simply running out of horsepower. I see lots of math, calls through Serial, and the ISR.

Create a new Sketch with the ISR on a fast rate (generating a high frequency sound). If that works, slowly add more bits until it stops working. If it does stop working, you’re going to need a faster processor or less code.

Good luck,
Brian

Looking at it again after some time has passed your guess makes very much sense.

Thanks! Carsten

Check out some of my audio code. It might help.

#include <MIDI.h>

//variables setup
  byte note;
  byte velocity;
  byte OPTO_PIN = 7;
  byte noteBuf[5]={255,255,255,255,255};  // set up keyboard buffer for 5 notes
  int squareout = 9;  // sound is output on pin 9.  Just connect a speaker to it and gnd.
  int channel = 1; // MIDI channel to respond to (in this case channel 1)

// setup midi note value for timer 1 (16bit resolution)
 unsigned int note_val[]={
34321,32395,30577,28860,27240,25711,24268,22906,21620,20407,19261,18180,17160,16197,15288,14429,13619,12855,12133,11452,10809,10203,9630
,9089,8579,8098,7643,7214,6809,6427,6066,5725,5404,5101,4814,4544,4289,4048,3821,3606,3404,3213,3032,2862,2701,2550,2406,2271,2144,2023,1910,1802,1701
,1606,1515,1430,1350,1274,1202,1135,1071,1011,954,900,850,802,757,714,674,636,600,567,535,505,476
};



//setup: declaring iputs and outputs and begin serial
void setup() {

  pinMode(squareout, INPUT); // silence the squarewave out until we get our first note.

// now set up timer1
  TCCR1A = _BV(COM1A0)
         | _BV(COM1B0)      // toggle OC1B on compare match
         | _BV(WGM10)
         | _BV(WGM11);
  TCCR1B = _BV(WGM12)
         | _BV(WGM13);      // Fast PWM mode, OCR1A as TOP
  OCR1B = 0;            // toggle when the counter is zero
  OCR1A = 34321;      // default timer value (could be anything)
  TCCR1B |= _BV(CS11);      // set prescale to div 8 and start the timer
  
  MIDI_Class MIDI;  // instance the midi class
  MIDI.begin (OPTO_PIN); // not sure I need this
  MIDI.useExternalPowerPin(); // use different 5 volt supply for this implementation

}

//loop: wait for serial data, and interpret the message
void loop () {

      if (MIDI.read(channel) > 0) // must be a real midi message
      {
            if (MIDI.getType() == NoteOn) // get midi not on message
            {
                  note = MIDI.getData1();
                  velocity = MIDI.getData2();
                        if (velocity!=0)
                        {
                    note_insert(note);
                        }
                        else if (velocity==0)  // this will be a note off message
                        {
                          note_delete(note);
                        }
            }
            if (MIDI.getType() == NoteOff) // my midi keyboard never sends this.  It's alway noteon with velocity ==0
            {
                  note = MIDI.getData1();
                  velocity = MIDI.getData2();
                  note_delete(note);
            }
                playNote();
      }
}

void playNote()  // play the note
{  
  int ploop;
    if (noteBuf[0]!=255)
    {
      pinMode (squareout, OUTPUT);
      OCR1A = note_val[noteBuf[ploop]-22];
    }
    else
    {
      pinMode (squareout, INPUT);
    }    
}

// insertion note into note_buff
void note_insert(byte note)
{
      int nloop;
      for(int nloop=4; nloop>0;nloop--)
      {
              noteBuf[nloop]=noteBuf[nloop-1];
      }
   noteBuf[0]=note;  
}
    
// delete note into note_buff.  It should first find the notes
// position and then delete it.
void note_delete(byte note)
{
  int nloop, pos;
  
  for (nloop=0; nloop<=4;nloop++)
  {
      if (noteBuf[nloop] == note) {
          pos=nloop;
          break;
      }
   }  
   for(nloop=pos; nloop<=4;nloop++)
   {
         noteBuf[nloop]=noteBuf[nloop+1];
   }
   noteBuf[nloop-1]=255;
}

Hi Guys,

I’m completely new to arduino… I found a code online for a project to read in the current and voltage readings and in order to factor in the power factor i need to used to interrupt function. However when i run the code in arduino i keep getting and error saying TIM0_COMP not declared in global scope… sorry if this isnt where i’m supposed to post my question could you kindly guide me as to where i should post it?

Here is the code:

  /*
  *
  * Voltage on A0
  * Current on A1
  *
  * Serial commands:
  * TIME <long seconds>
  * RELAY <0/1>
  * THRESHOLD <watts>
  */
  
 #include <WProgram.h>
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
  
 #define SAMPLES 1000
 #define t1 1000 // 1000 ms.
 #define t2 1 // 1 ms
 #define t3 1 // 1 ms
 #define R_SENSE 0.2
 #define Vref 5.0
   
 char *cmds[] = {"TIME", "RELAY", "THRESHOLD"};
 #define TIME 0
 #define RELAY 1
 #define THRESHOLD 2
  
 long FP_ADC_CONV, FP_OFFSET; 
  
 ////// 20:12 fixed point macros
 #define int2fix(a)   (((long)(a))<<12)    //Convert char to fix. a is a char
 #define float2fix(a) ((long)((a)*4096.0)) //Convert float to fix. a is a float
 #define fix2float(a) ((float)(a)/4096.0)  //Convert fix to float. a is an int
 #define multfix(a,b) ((long)((((long)(a))*((long)(b)))>>12))
  
 long fpVSquareSum;
 long fpISquareSum;
 long fpPowerSum;
 float rPower, aPower;
 float powerFactor;
  
 float iScaleFactor, vScaleFactor, rpScaleFactor;
  
 ///// Periods //////
  long fpVLastValue;
  unsigned long vPeriodSum;
  int vLastZeroMsec;
  unsigned int vPeriodCount;
    
     
  ///// Watt Hour Stuff ////
  float kWattHrs;
    
  unsigned char r_index, r_buffer[40], r_ready, r_char;
  unsigned char t_index, t_buffer[350], t_ready, t_char;
  void gets_init();
  void puts_init();
   
  char time0, time1, time2, time3;
  unsigned int sample;
   
  // seconds since January 1, 1970 (UNIX time)
  unsigned long unixtime;
  unsigned int msecs;
  unsigned long offTime;
  unsigned long onTime;
    
  long threshold; // power limit
  char shutdown; // whether to shut down the relay
    
  void task1();
  void task2();
  void task3();
  void initialize();
   
  void main() {
  initialize();
   
  // launch tasks if necessary
  while(1) {
    if (time1 == 0) task1();
    if (time2 == 0) task2();
    if (time3 == 0) task3();
    }
  }
   
  void task3() { 
    
   int int_param, i;
     char cmd;
     char cmdStr[50];
     char param[50];
     char *space;
     int spaceIndex;
    
   time3 = t3;
    
   // return if not ready yet
   if (r_ready != 1) return;
   
   // try to find space
   space = strchr(r_buffer, ' ');
   
   if (space != NULL) {
    // space was found, extract param
     spaceIndex = space - r_buffer;
     strncpy(cmdStr, r_buffer, spaceIndex);
     cmdStr[spaceIndex] = '\0';
     strcpy(param, space + 1);     
    }
   else
    {
     // space not found, just copy over
     strcpy(cmdStr, r_buffer);
    }
     
     // cmd will be -1 if no command
      cmd = -1;
      for (i = 0; i < 3; i++) {
        if (!strcmp(cmdStr, cmds[i]))
        {
          cmd = i;
          break;
        }
      }
      
      switch(cmd) {
        case TIME:
          sscanf(param, "%ld", &unixtime);
          msecs = 0;
          break;
          case RELAY:
          sscanf(param, "%d", &int_param);
          if (int_param) shutdown = 0;
          else shutdown = 1;
          break;
        case THRESHOLD:
          sscanf(param, "%ld", &threshold);
          break;
      }
      
      //printf("CMD OK\n\r");
      gets_init();
  }
   
  void task1() {
    time1 = t1;
    PORTD.2 = ~PORTD.2;
  }
   
  void task2() {
    char Ain0, Ain1;
    long fpVin0, fpVin1, fpVin, fpIin;
    long fpAin0, fpAin1;
    float vAvg, iAvg;
    int vPeriod;
  
    time2 = t2;
   
    // start conversion for channel 0
    ADMUX.0 = 0;
    ADCSR.6 = 1;
   
    // wait for conversion to finish
    while (ADCSR.6);
   
    // read Ain0
    Ain0 = ADCH;
   
    // start conversion for channel 1
    ADMUX.0 = 1;
    ADCSR.6 = 1;
   
    // wait for conversion to finish
    while (ADCSR.6);
   
    // read Ain1
    Ain1 = ADCH;
   
    // go to 20:12 fixed point
    fpAin0 = (long)Ain0 << 12;
    fpAin1 = (long)Ain1 << 12;
   
    // calculate Vin of the ADC
    fpVin0 = multfix(fpAin0, FP_ADC_CONV) - FP_OFFSET;
    fpVin1 = multfix(fpAin1, FP_ADC_CONV) - FP_OFFSET;
   
    // sum up power or squares
    fpPowerSum += multfix(fpVin0, fpVin1);
    fpVSquareSum += multfix(fpVin0, fpVin0);
    fpISquareSum += multfix(fpVin1, fpVin1);
   
    ///////// FREQUENCY CALCULATION //////
    if (fpVLastValue < 0 && fpVin0 >= 0) {
      // found a zero crossing from neg. to pos.!
      vPeriod = msecs - vLastZeroMsec;
   
      // make sure it's not an edge
      if (vPeriod > 0) {
      vPeriodSum += vPeriod;
      vPeriodCount++;
      }
   
     vLastZeroMsec = msecs;
   
    }
   
    fpVLastValue = fpVin0;
    ///////////////////////////////////
   
    sample++;
   
    if (sample == SAMPLES) {
      // this only happens once a second,
      // so floating point mults should be okay
      vAvg = (float) sqrt(vScaleFactor * fpVSquareSum);
      iAvg = (float) sqrt(iScaleFactor * fpISquareSum);
      rPower = (float) rpScaleFactor * fpPowerSum; // watts
      aPower = vAvg * iAvg; // VA
      powerFactor = rPower / aPower;
      kWattHrs += rPower / 3600000.0;
 
      sprintf(t_buffer, "%ld:P%3.2f,S%3.2f,I%3.2f,V%3.2f,F%3.2f,E%f,R%3.2f\n\r",
        unixtime, rPower, aPower, iAvg, vAvg, 1000.0 * (float)vPeriodCount
        / (float)vPeriodSum, kWattHrs, powerFactor);
       puts_init();
      
      if (rPower > threshold) shutdown = 1;
      
      if (shutdown) PORTD.3 = 0; // turn relay off
      else PORTD.3 = 1;
 
     // reset for next sample
      fpVSquareSum = 0;
      fpISquareSum = 0;
      fpPowerSum = 0;
      vPeriodSum = 0;
      vPeriodCount = 0;
      sample = 0;
     }
   }
  
  // compare match interrupt
  interrupt [TIM0_COMP] void timer0_compare(void) {
    if (time1 > 0) --time1;
    if (time2 > 0) --time2;
    if (time3 > 0) --time3;
   
    // update wall clock
    msecs++;
    if (msecs == 1000)
    {
      msecs = 0;
      unixtime++;
    }
  }
  
   void initialize() {
    long t;
   
    /////////////// TIMER 0 ///////////////////////
    TIMSK = 2; // turn on timer 0 compare match ISR
    OCR0 = 250; // sets compare to 250 ticks
    TCCR0 = 0b00001011; // sets prescalar to 64
   
    //set up UART
    UCSRB = 0x18;
    UBRRL = 103;
   
    unixtime = 0;
    msecs = 0;
   
    DDRD = 0xFF; // output
    PORTD.2 = 0;
    PORTD.3 = 1; // turn relay on
   
    threshold = 1000;
    shutdown = 0;
   
    kWattHrs = 0;
    time1 = t1;
    time2 = t2;
   
    vScaleFactor = 1002001.0 / (4096.0 * SAMPLES);
    iScaleFactor = 1 / (R_SENSE * R_SENSE) / (4096.0 * SAMPLES);
    rpScaleFactor = 1001.0 / R_SENSE / (4096.0 * SAMPLES);
   
    // internal Aref = Vcc, left adjust result
    ADMUX = 0b01100000;
    //enable ADC and set prescaler to 1/128*16MHz=125,000
    //and clear interupt enable
    ADCSR = 0b11000111;
   
    // calculate conversion factor
    //FP_ADC_CONV = float2fix(Vref / 256.0);
    FP_ADC_CONV = float2fix(0.512 / 256.0); // opto
    //FP_I_CONV = float2fix(1 / R_SENSE);
   
    FP_OFFSET = float2fix(0.256);
    #asm("sei")
    
    gets_init();
  }
   
  //**********************************************************
  //UART character-ready ISR
  interrupt [USART_RXC] void uart_rec() {
      r_char=UDR;    //get a char
      //build the input string
      if (r_char != '\r') r_buffer[r_index++]=r_char;
      else {
          putchar('\n');              //use putchar to avoid overwrite
          r_buffer[r_index]=0x00;        //zero terminate
          r_ready=1;                       //signal cmd processor
          UCSRB.7=0;                   //stop rec ISR
      }
  }
   
  /**********************************************************/
  //UART xmit-empty ISR
  interrupt [USART_DRE] void uart_send() {
      t_char = t_buffer[++t_index];
      if (t_char == 0) {
          UCSRB.5=0; //kill isr
          t_ready=1; //transmit done
      }
      else UDR = t_char ;     //send the char
  }
   
  //**********************************************************
  //  -- non-blocking keyboard check initializes ISR-driven
  // receive. This routine merely sets up the ISR, which then
  //does all the work of getting a command.
  void gets_init() {
    r_ready=0;
    r_index=0;
    UCSRB.7=1;
  }
   
  //**********************************************************
  //  -- nonblocking print: initializes ISR-driven
  // transmit. This routine merely sets up the ISR, then
  //send one character, The ISR does all the work.
  void puts_init()  {
    t_ready=0;
    t_index=0;
    if (t_buffer[0]>0) {
        putchar(t_buffer[0]);
        UCSRB.5=1;
    }
 }

thank you!

When you're posting code, can you please use the "code" (#) button in the editor?

You can edit your post - just click on "modify", then hhighlight all your code, and click on the "#" button in the editor.

You've got more work to do on that sketch before it's Arduino-compatible - you're going to find that you've got two "main"s.

Hi AWOL thanks so much…

any bit of a lead on how and which parts i need to work on would be great…

thanks again

  /*
  *
  * Voltage on A0
  * Current on A1
  *
  * Serial commands:
  * TIME <long seconds>
  * RELAY <0/1>
  * THRESHOLD <watts>
  */
  
 #include <WProgram.h>
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
  
 #define SAMPLES 1000
 #define t1 1000 // 1000 ms.
 #define t2 1 // 1 ms
 #define t3 1 // 1 ms
 #define R_SENSE 0.2
 #define Vref 5.0
   
 char *cmds[] = {"TIME", "RELAY", "THRESHOLD"};
 #define TIME 0
 #define RELAY 1
 #define THRESHOLD 2
  
 long FP_ADC_CONV, FP_OFFSET; 
  
 ////// 20:12 fixed point macros
 #define int2fix(a)   (((long)(a))<<12)    //Convert char to fix. a is a char
 #define float2fix(a) ((long)((a)*4096.0)) //Convert float to fix. a is a float
 #define fix2float(a) ((float)(a)/4096.0)  //Convert fix to float. a is an int
 #define multfix(a,b) ((long)((((long)(a))*((long)(b)))>>12))
  
 long fpVSquareSum;
 long fpISquareSum;
 long fpPowerSum;
 float rPower, aPower;
 float powerFactor;
  
 float iScaleFactor, vScaleFactor, rpScaleFactor;
  
 ///// Periods //////
  long fpVLastValue;
  unsigned long vPeriodSum;
  int vLastZeroMsec;
  unsigned int vPeriodCount;
    
     
  ///// Watt Hour Stuff ////
  float kWattHrs;
    
  unsigned char r_index, r_buffer[40], r_ready, r_char;
  unsigned char t_index, t_buffer[350], t_ready, t_char;
  void gets_init();
  void puts_init();
   
  char time0, time1, time2, time3;
  unsigned int sample;
   
  // seconds since January 1, 1970 (UNIX time)
  unsigned long unixtime;
  unsigned int msecs;
  unsigned long offTime;
  unsigned long onTime;
    
  long threshold; // power limit
  char shutdown; // whether to shut down the relay
    
  void task1();
  void task2();
  void task3();
  void initialize();
   
  void main() {
  initialize();
   
  // launch tasks if necessary
  while(1) {
    if (time1 == 0) task1();
    if (time2 == 0) task2();
    if (time3 == 0) task3();
    }
  }
   
  void task3() { 
    
   int int_param, i;
     char cmd;
     char cmdStr[50];
     char param[50];
     char *space;
     int spaceIndex;
    
   time3 = t3;
    
   // return if not ready yet
   if (r_ready != 1) return;
   
   // try to find space
   space = strchr(r_buffer, ' ');
   
   if (space != NULL) {
    // space was found, extract param
     spaceIndex = space - r_buffer;
     strncpy(cmdStr, r_buffer, spaceIndex);
     cmdStr[spaceIndex] = '\0';
     strcpy(param, space + 1);     
    }
   else
    {
     // space not found, just copy over
     strcpy(cmdStr, r_buffer);
    }
     
     // cmd will be -1 if no command
      cmd = -1;
      for (i = 0; i < 3; i++) {
        if (!strcmp(cmdStr, cmds[i]))
        {
          cmd = i;
          break;
        }
      }
      
      switch(cmd) {
        case TIME:
          sscanf(param, "%ld", &unixtime);
          msecs = 0;
          break;
          case RELAY:
          sscanf(param, "%d", &int_param);
          if (int_param) shutdown = 0;
          else shutdown = 1;
          break;
        case THRESHOLD:
          sscanf(param, "%ld", &threshold);
          break;
      }
      
      //printf("CMD OK\n\r");
      gets_init();
  }
   
  void task1() {
    time1 = t1;
    PORTD.2 = ~PORTD.2;
  }
   
  void task2() {
    char Ain0, Ain1;
    long fpVin0, fpVin1, fpVin, fpIin;
    long fpAin0, fpAin1;
    float vAvg, iAvg;
    int vPeriod;
  
    time2 = t2;
   
    // start conversion for channel 0
    ADMUX.0 = 0;
    ADCSR.6 = 1;
   
    // wait for conversion to finish
    while (ADCSR.6);
   
    // read Ain0
    Ain0 = ADCH;
   
    // start conversion for channel 1
    ADMUX.0 = 1;
    ADCSR.6 = 1;
   
    // wait for conversion to finish
    while (ADCSR.6);
   
    // read Ain1
    Ain1 = ADCH;
   
    // go to 20:12 fixed point
    fpAin0 = (long)Ain0 << 12;
    fpAin1 = (long)Ain1 << 12;
   
    // calculate Vin of the ADC
    fpVin0 = multfix(fpAin0, FP_ADC_CONV) - FP_OFFSET;
    fpVin1 = multfix(fpAin1, FP_ADC_CONV) - FP_OFFSET;
   
    // sum up power or squares
    fpPowerSum += multfix(fpVin0, fpVin1);
    fpVSquareSum += multfix(fpVin0, fpVin0);
    fpISquareSum += multfix(fpVin1, fpVin1);
   
    ///////// FREQUENCY CALCULATION //////
    if (fpVLastValue < 0 && fpVin0 >= 0) {
      // found a zero crossing from neg. to pos.!
      vPeriod = msecs - vLastZeroMsec;
   
      // make sure it's not an edge
      if (vPeriod > 0) {
      vPeriodSum += vPeriod;
      vPeriodCount++;
      }
   
     vLastZeroMsec = msecs;
   
    }
   
    fpVLastValue = fpVin0;
    ///////////////////////////////////
   
    sample++;
   
    if (sample == SAMPLES) {
      // this only happens once a second,
      // so floating point mults should be okay
      vAvg = (float) sqrt(vScaleFactor * fpVSquareSum);
      iAvg = (float) sqrt(iScaleFactor * fpISquareSum);
      rPower = (float) rpScaleFactor * fpPowerSum; // watts
      aPower = vAvg * iAvg; // VA
      powerFactor = rPower / aPower;
      kWattHrs += rPower / 3600000.0;
 
      sprintf(t_buffer, "%ld:P%3.2f,S%3.2f,I%3.2f,V%3.2f,F%3.2f,E%f,R%3.2f\n\r",
        unixtime, rPower, aPower, iAvg, vAvg, 1000.0 * (float)vPeriodCount
        / (float)vPeriodSum, kWattHrs, powerFactor);
       puts_init();
      
      if (rPower > threshold) shutdown = 1;
      
      if (shutdown) PORTD.3 = 0; // turn relay off
      else PORTD.3 = 1;
 
     // reset for next sample
      fpVSquareSum = 0;
      fpISquareSum = 0;
      fpPowerSum = 0;
      vPeriodSum = 0;
      vPeriodCount = 0;
      sample = 0;
     }
   }
  
  // compare match interrupt
  interrupt [TIM0_COMP] void timer0_compare(void) {
    if (time1 > 0) --time1;
    if (time2 > 0) --time2;
    if (time3 > 0) --time3;
   
    // update wall clock
    msecs++;
    if (msecs == 1000)
    {
      msecs = 0;
      unixtime++;
    }
  }
  
   void initialize() {
    long t;
   
    /////////////// TIMER 0 ///////////////////////
    TIMSK = 2; // turn on timer 0 compare match ISR
    OCR0 = 250; // sets compare to 250 ticks
    TCCR0 = 0b00001011; // sets prescalar to 64
   
    //set up UART
    UCSRB = 0x18;
    UBRRL = 103;
   
    unixtime = 0;
    msecs = 0;
   
    DDRD = 0xFF; // output
    PORTD.2 = 0;
    PORTD.3 = 1; // turn relay on
   
    threshold = 1000;
    shutdown = 0;
   
    kWattHrs = 0;
    time1 = t1;
    time2 = t2;
   
    vScaleFactor = 1002001.0 / (4096.0 * SAMPLES);
    iScaleFactor = 1 / (R_SENSE * R_SENSE) / (4096.0 * SAMPLES);
    rpScaleFactor = 1001.0 / R_SENSE / (4096.0 * SAMPLES);
   
    // internal Aref = Vcc, left adjust result
    ADMUX = 0b01100000;
    //enable ADC and set prescaler to 1/128*16MHz=125,000
    //and clear interupt enable
    ADCSR = 0b11000111;
   
    // calculate conversion factor
    //FP_ADC_CONV = float2fix(Vref / 256.0);
    FP_ADC_CONV = float2fix(0.512 / 256.0); // opto
    //FP_I_CONV = float2fix(1 / R_SENSE);
   
    FP_OFFSET = float2fix(0.256);
    #asm("sei")
    
    gets_init();
  }
   
  //**********************************************************
  //UART character-ready ISR
  interrupt [USART_RXC] void uart_rec() {
      r_char=UDR;    //get a char
      //build the input string
      if (r_char != '\r') r_buffer[r_index++]=r_char;
      else {
          putchar('\n');              //use putchar to avoid overwrite
          r_buffer[r_index]=0x00;        //zero terminate
          r_ready=1;                       //signal cmd processor
          UCSRB.7=0;                   //stop rec ISR
      }
  }
   
  /**********************************************************/
  //UART xmit-empty ISR
  interrupt [USART_DRE] void uart_send() {
      t_char = t_buffer[++t_index];
      if (t_char == 0) {
          UCSRB.5=0; //kill isr
          t_ready=1; //transmit done
      }
      else UDR = t_char ;     //send the char
  }
   
  //**********************************************************
  //  -- non-blocking keyboard check initializes ISR-driven
  // receive. This routine merely sets up the ISR, which then
  //does all the work of getting a command.
  void gets_init() {
    r_ready=0;
    r_index=0;
    UCSRB.7=1;
  }
   
  //**********************************************************
  //  -- nonblocking print: initializes ISR-driven
  // transmit. This routine merely sets up the ISR, then
  //send one character, The ISR does all the work.
  void puts_init()  {
    t_ready=0;
    t_index=0;
    if (t_buffer[0]>0) {
        putchar(t_buffer[0]);
        UCSRB.5=1;
    }
 }

Well, an Arduino sketch has no "main", so the stuff you've got in "initialize" probably needs to go into "setup", and the rest of the stuff in "main" goes into "loop". Your assembler issue is probably covered by "sei()"