Interrupciones vs delay(),while(), for(),etc

Estimada comunidad estoy realizando con harto entusiasmo un proyecto para poder emitir señales PSK31 por radio ya que hay muchos programas en Windows y Android para decodificar. He googleado por un montón de partes y encontre uno que me pareció excelente porque no requiere de mucho hardware adicional, solo una adaptación de impedancias del Arduino Diecimilia al micrófono de una radio.
Lo principal es que el programa funciona con PWM con interrupciones propias del ATMega168 para poder mantener la cronometría de cada bit.
El problema con el que me topo es que genera una señal continua de una palabra (definida por mi), pero quiero hacer que se genere la cantidad de veces que yo desee. Esto es porque no domino bien el tema de las interrupciones vs los distintos comandos del código Arduino como delay(), while(),etc. Lo que quiereo conseguir es mantener un control en el loop() para que no sea continua sino algo como (int i=0; i <= 10; i++). Alguien sabe como poder controlar sin desestabilizar las interrupciones?
Desde ya agradecido por cualquier ayuda y por supuesto una vez que resuelva estos inconvenientes, mantendré actualizado el proyecto. :slight_smile:

#include "avr/pgmspace.h"

// Tabla de 256 valores para construir una onda senoidal almacenada en memoriaflash
PROGMEM  prog_uchar sine256[]  = {
  127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,217,219,221,223,225,227,229,231,233,234,236,238,239,240,
  242,243,244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,244,243,242,240,239,238,236,234,233,231,229,227,225,223,
  221,219,217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,127,124,121,118,115,111,108,105,102,99,96,93,90,87,84,81,78,
  76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,10,11,12,14,15,16,18,20,21,23,25,27,29,31,
  33,35,37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124

};
// Palabra "MAFARI" codificada en Varicode
PROGMEM prog_uchar msg[] = {1,0,1,1,1,0,1,1, 0,0, 1,1,1,1,1,0,1, 0,0, 1,1,0,1,1,0,1,1, 0,0, 1,1,1,1,1,0,1, 0,0, 1,0,1,0,1,1,1,1, 0,0, 1,1,1,1,1,1,1, 0,0, 0,0, 1, 0,0};  //Mauricio
byte ptr = 0;

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31335.6;      // medido

// variables usadas dentro del servicio de interrupcion declaradas como volatile
volatile byte icnt;              // variable dentro de interrupcion
volatile byte icnt1;             // variable dentro de interrupcion
volatile byte c4ms;              // countador incrementado todo 4ms
volatile unsigned long phaccu;   // Acumulador de fase
volatile unsigned long tword_m;  // dds tuning word m
volatile byte offset;

void setup()
{
  pinMode(11, OUTPUT);     // pin 11= Salida PWM   / frequencia de salida
  Setup_timer2();
  // disabilita interrupciones para evitar distorsion por temporizacion
  cbi (TIMSK0,TOIE0);              // desabilita Timer0 !!! delay() no esta disponible
  sbi (TIMSK2,TOIE2);              // habilita interrupcione Timer2

  dfreq=1000.0;                    // Frequencia Incial de Tx = 1000 Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word 
}


void loop()
{
//Es aqui donde quiero poner un control para emitir mi mensaje la cant. de veces que yo desee y no en forma continua.
  byte sig; // Byte para asignar el valor del bit de la letra que se esta enviando
  if (c4ms >= 8) {      // timer / wait for 32ms = 31.25 baud
      c4ms=0;
      sig = pgm_read_byte_near(msg + ptr); //Aqui se rescata el bit de la letra que esta enviando
      ptr++;
      if (ptr > 62)  ptr=0;
      if (sig == 0) { //Aqui se analiza si el valor del bit es cero o no
          offset = offset + 128; //Si el valor del bit es cero entonces cambia de fase para producir el efecto PSK
    }
  }
} 
//******************************************************************
// timer2 setup
// set prscaler to 1, PWM mode to phase correct PWM,  16000000/510 = 31372.55 Hz clock
void Setup_timer2() {

// Timer2 Clock Prescaler to : 1
  TCCR2B = 0<<CS22 | 0<<CS21 | 1<<CS20;

// Timer2 PWM Mode set to Phase Correct PWM
  TCCR2A = 1<<COM2A1 | 0<<COM2A0;

    sbi (TCCR2A, WGM20);  // Mode 1  / Phase Correct PWM
    cbi (TCCR2A, WGM21);
    cbi (TCCR2B, WGM22);
}

//******************************************************************
// Timer2 Interrupt Service at 31372,550 KHz = 32uSec
// this is the timebase REFCLOCK for the DDS generator
// FOUT = (M (REFCLK)) / (2 exp 32)
// runtime : 8 microseconds ( inclusive push and pop)
ISR(TIMER2_OVF_vect) {

  phaccu=phaccu+tword_m; // soft DDS, phase accu with 32 bits
  icnt=phaccu >> 24;     // use upper 8 bits for phase accu as frequency information
  icnt = icnt + offset;  
  OCR2A=pgm_read_byte_near(sine256 + icnt); // read value from ROM sine table and send to PWM DAC    

  if(icnt1++ == 125) {  // increment variable c4ms all 4 milliseconds (125)
    c4ms++;
    icnt1=0;
   }
}

Muy buenas... no sé si has solucionado tus problemas. Pero te voy a adjuntar un código para que un led realice un parpadeo durante un periodo determinado. Utilizo 2 interrupciones. La externa para configurar la temporización (interrupcion timer) y la propia de la temporización. El parpadeo se configura para 2 segundos (2s encendido y 2s apagado) y esto se realiza 10 veces (5 veces encendido y 5 veces apagado.

Espero que te aclare algo. Cualquier cosa me preguntas (Y)

PD: Olvidate de la parte del loop() que como ves es sólo para encender un led via serie.

const byte LED = 13;
int boton = 3;
int led_int = 9;
int state = LOW;
int estado = LOW;
int contador = 0;
int lectura;

ISR(TIMER1_COMPA_vect)
{
  estado = !estado;  // toggle
  if (contador%2)  Serial.println("\tFin periodo");
  digitalWrite (led_int, estado ? HIGH : LOW);
  contador++;
  if (contador == 10){
    cli();                                             // Desabilitamos interrupciones
    TIMSK1 = 0;                                        // Anulamos interrupción
    TCNT1 = 0;                                         // Contador a 0
    TCCR1B = 0;                                        // Paramos temporizador
    sei();                                             // Habilitamos interrupciones
    estado = 0;
    Serial.println("\tFin ciclo parpadeo");
    contador = 0;                                      // Reset ciclo parpadeo
    digitalWrite(LED, HIGH);
  }
}

void interrupcion_externa()
{
  digitalWrite (LED, LOW);
  digitalWrite (LED, HIGH);
  state = !state;
  estado = LOW;
  contador = 0;
  cli();                                               // Deshabilitamos interrupciones
  TIFR1 = 0;                                           // Borramos flag
  TCCR1A = 0;                                          // normal operation
  TCCR1B = bit(WGM12) | bit(CS10) | bit(CS12);         // Modo CTC y prescaler 1024
  OCR1A =  31249;                                      //  2s (PR/16MHz)*(OCR1A+1)
  TCNT1 = 0;                                           // Contador a cero
  TIMSK1 = bit (OCIE1A);                               // interrupt on Compare A Match
  sei();                                               // Habilitamos interrupciones
  Serial.println("\tInicia ciclo parpadeo");
  digitalWrite (LED, LOW);
}

void setup() 
{
  // CONFIGURACION I/O PORT
  pinMode(LED, OUTPUT);
  pinMode(boton, INPUT);
  pinMode(led_int, OUTPUT);
  pinMode(6, OUTPUT);
  
  // CONFIGURACION Timer 1
  TIFR1 = 0;
  TCCR1A = 0;
  TIMSK1 = 0;
  TCCR1B = 0;                                           // Paramos temporizador
  
  //CONFIGURACIÓN INTERRUPCION EXTERNA1 Y RUTINA
  attachInterrupt(1, interrupcion_externa, RISING);
  
  //ARRANCAMOS SERIAL 9600Baudios
  Serial.begin(9600);
}  

void loop() 
{
 digitalWrite (led_int, estado);
 if (Serial.available()) {         
     lectura = Serial.read();
     
     if(lectura == 53){          //ACTIVAMOS LED ENVIANDO 5 POR SERIAL MONITOR (ASCII 53)
        digitalWrite(6, HIGH);
        Serial.println("\tLed verde encendido");
     }
     if(lectura == 51){          //ACTIVAMOS LED ENVIANDO 3 POR SERIAL MONITOR (ASCII 51)
        digitalWrite(6, LOW);
        Serial.println("\tLed verde apgado");
     }    
 }

}