Transmitir y recibir a traves de Modulacion PSK.

Hola a todos,

soy nuevo en este foro, antes que nada quiero decir que he leido el apartado de “Consejos para hacer un correcto uso de los foros” y he seguido los consejos, sobre todo el de buscar en internet antes de hacer prguntas, si escribo aqui ahora, es por varios motivos entre ellos y el mas importante es que de electronica no se casi nada, soy programador y estoy tratando de desarrollar una app en Android usando como apoyo un Arduino para transmitir datos, expongo mi problema:

Basicamente lo que que quiero hacer es transmitir texto de un arduino a otro a traves de modulacion PSK.

He encontrado varios ejemplos en internet que me han ayudado a aprender y a entender un poco sobre esto, y de todos el que mejor funciona para mi es este https://github.com/Cesco1/ArduModem/tree/master/ArduModemPSK.

Y se preguntaran, ¿cual es el problema?

El problemas es que en este codigo tenemos uno para transmitir (TX) y otro para recibir (RX).

Esto me obliga a tener dos arduino de cada lado, osea, de un lado un Arduino para recibir y otro para transmitir, y del otro lado lo mismo.

H estado tratando de cambiar el codigo para que un mismo Arduino pueda transmitir y recibir.

Por lo que veo en el codigo, si al principio del mismo ponemos “#define TX” o #define RX, este trabajara de una forma o de otra.

He intentado hacer una combinacion de ambos codigos definiendo ambos parametros “#define TX” y “#define RX”, pero entran en conflicto unas variables que por lo que entiendo estan relacionadas con el Timer2.

Para intentar resolver esto, he cambido el nombre de las variables que entraban en conflicto y resulto bien, pero no del todo, creo que el problema ahora esta en que ambos procesoso TX y RX usan el mismo Timer2 configurado de forma diferente.

He pensado que la solucion seria usar otro Timer para el TX pero aqui es donde peor lo estoy pasando porque no entiendo nada de configurar los Timer, he leido mucho sobre como configurarlos pero no termino de entender, desde mi punto de vista hay que tener conocimiento de como trabaja internamente el ATMEGA 128P.

Estoy utilizando para esto dos Arduinos UNO para TX y RX.

Adjunto los archivos del proyecto, el archvio llamado ArduModemPSK.zip es del proyecto orginal, este funciona bien, el otro adjunto llamado ArduModemPSK_TXRX.zip es mi intento por unificar los dos codigo para tratar de conseguir que se pueda enviar y recibir datos desde el mismo Arduino.

Estoy agradecido por su ayuda de antemano, y repito, no tengo conocimientos de electronica solo cosas muy basicas.

ArduModemPSK.zip (8.66 KB)

ArduModemPSK_TXRX.zip (4.64 KB)

Hola. Por irnos centrando en el objetivo. ¿La finalidad sería hacer una transmisión full duplex o semiduplex?

noter:
Hola.
Por irnos centrando en el objetivo. ¿La finalidad sería hacer una transmisión full duplex o semiduplex?

Hola noter, gracias por contestar y por tu tiempo.

Entiendo que con full duplex y semi duplex te refieres a si debe transmitir y recibir al mismo tiempo o transmitir y luego recibir por ejemplo.

Me valdría con enviar y luego recibir, podría estar a la escucha y cuando tuviera que transmitir puede parar de escuchar, pero claro está que si puede hacerlo al mismo tiempo perfecto.

Espero que esto responda a tu pregunta.

Sí. Me refería exactamente a eso. ¿Por qué? Pues porque la parte dedicada al psk está compuesta por, digamos, dos programas (uno establece el arduino en modo transmisión y el otro en modo recepción). Tal como está, sólo carga la parte del programa dedicada a transmisión o recepción dependiendo del define que pongas. El problema es que, si bien cada configuración usa un pin distinto, ambas utilizan para sus fines el timer2. Pienso que una transmisión semiduplex sería posible, modificando la librería para hacer alternativamente llamadas a unas funciones que llamaríamos, por ejemplo initPskTx e initPskRx justo antes de hacer la transmisión o la recepción. Habría que controlar, claro está, cómo hacer el cambio de modo una vez enviados o recibidos todos los datos. En cuanto a adaptar la librería para realizar full duplex, primero necesitaríamos adaptar una de las funciones para utilizar otro timer distinto al 2. En el arduino uno disponemos, creo, de tres timers: timer0 y timer2 de 8 bit y timer1 de 16 bits. Aparentemente lo más sencillo sería utilizar timer0 para una de las rutinas, pero creo que se vería alterado el funcionamiento de arduino (creo que el conteo de millis() depende de ese timer. Aparte, todavía quedaría por probar si disponemos de suficiente potencia de cómputo para realizar las dos funciones simultáneamente.

noter:
Sí. Me refería exactamente a eso. ¿Por qué?
Pues porque la parte dedicada al psk está compuesta por, digamos, dos programas (uno establece el arduino en modo transmisión y el otro en modo recepción). Tal como está, sólo carga la parte del programa dedicada a transmisión o recepción dependiendo del define que pongas. El problema es que, si bien cada configuración usa un pin distinto, ambas utilizan para sus fines el timer2.
Pienso que una transmisión semiduplex sería posible, modificando la librería para hacer alternativamente llamadas a unas funciones que llamaríamos, por ejemplo initPskTx e initPskRx justo antes de hacer la transmisión o la recepción. Habría que controlar, claro está, cómo hacer el cambio de modo una vez enviados o recibidos todos los datos.
En cuanto a adaptar la librería para realizar full duplex, primero necesitaríamos adaptar una de las funciones para utilizar otro timer distinto al 2. En el arduino uno disponemos, creo, de tres timers: timer0 y timer2 de 8 bit y timer1 de 16 bits. Aparentemente lo más sencillo sería utilizar timer0 para una de las rutinas, pero creo que se vería alterado el funcionamiento de arduino (creo que el conteo de millis() depende de ese timer. Aparte, todavía quedaría por probar si disponemos de suficiente potencia de cómputo para realizar las dos funciones simultáneamente.

Vale, supongamos que quiero utilizar el Timer1 para transmitir, digo esto porque teniendo configurado un timer para TX y otro para RX, luego podria hacer cada operacion por separado en cualquier momento.

Para empezar y para no liarme demasiado, he cogido el programa que solo transmite “ArduModemPSK_TX” y he modificado la libreria para cambiar lo relacionado con el Timer2 por el Timer1. Como no se como se configura un Timer, lo que he echo es substituir lo que entiendo esta relacionado con el Timer2 de la siguiente manera:

void initPsk()
{
#if defined (TX)
pinMode(9,OUTPUT); // Timer2 11 or 3 = output, Timer1 10 or 9 = output.
OCR1A = 128;
TCCR1B = (1<<CS20); //run at 64khz
TCCR1A = _BV(COM1A1) | _BV(WGM20)| _BV(WGM21); // connect pin 11 to timer 2 channel A
TIMSK1 |= (1<<TOIE1); // enable tim2 interrupt
#endif

#if defined (RX)
// AD part
OCR2A = 128; // pin 11
TCCR2B = (1<<CS21); // run at 8khz
TCCR2A = 0; // normal mode
TIMSK2 |= (1<<TOIE2); // enable tim2 interrupt

pinMode(12, OUTPUT); // pin = output
DIDR0 = 0x3F; // digital inputs disabled
#if defined (INTVREF)
ADMUX = 0xE3; // measuring on ADC3, use 1.1V reference, left adjust
#else
ADMUX = 0x63; // measuring on ADC3, use VCC reference, left adjust
#endif
ADCSRA = 0x87; // AD-converter on, interrupt disabled, prescaler = 128
ADCSRB = 0x00; // AD channels MUX on
#endif

sei(); // set interrupt flag
}

#if defined (TX)
byte phase = 0;
boolean is_change = true;
boolean is_invert = false;
byte oddcycle = 0;
byte bitct = 0;
byte data;

ISR(TIMER1_OVF_vect) // this runs at 64khz
{
if (oddcycle < 1) oddcycle++;
else
{
oddcycle = 0;
// this runs at 32 khz
if (is_change)
{
byte sinval = sin_table_change[phase];
if (is_invert) OCR1A = sinval ^ 0xFF;
else OCR1A = sinval;
}
else
{
byte sinval = sin_table_same[phase%SINTABLEN];
if (is_invert) OCR1A = sinval ^ 0xFF;
else OCR1A = sinval;
}
phase++;
if (phase >= mydelay)
{…

Estoy seguro que hay algo mal, porque el resultado de la modificacion no es igual que antes de modificar, ¿como se esto?, porque poniendo un pequeño altavoz a la salida (pin 9), no suena igual que antes de modificar (antes pin 11).

La cuestion es, ¿como configuro el Timer1 con las mismas caractericas en las que esta configurado el Timer2?

Ahí me pillas también en pañales. Deberías leer detalladamente la documentación sobre los timers, pues, como te dije, timer1 es de 16 bit, mientras timer2 es de 8, con lo que los debe de existir alguna diferencia en sus registros de control (además de que están asignados a pines diferentes). Si en lugar de timer1 usas timer0, probablemente la configuración sí te valdría, pero se verían afectadas funciones que hacen uso del mismo (delay, millis, micros...), así que coincido contigo en que lo ideal sería tirar de timer1. Todo esto, si estás pensando en full-duplex (transmitir y recibir a la vez), porque para half duplex, podrías alternar la configuración del timer2 (y la ISR) para ser utilizado alternativamente como TX o RX.

noter: Ahí me pillas también en pañales. Deberías leer detalladamente la documentación sobre los timers, pues, como te dije, timer1 es de 16 bit, mientras timer2 es de 8, con lo que los debe de existir alguna diferencia en sus registros de control (además de que están asignados a pines diferentes). Si en lugar de timer1 usas timer0, probablemente la configuración sí te valdría, pero se verían afectadas funciones que hacen uso del mismo (delay, millis, micros...), así que coincido contigo en que lo ideal sería tirar de timer1. Todo esto, si estás pensando en full-duplex (transmitir y recibir a la vez), porque para half duplex, podrías alternar la configuración del timer2 (y la ISR) para ser utilizado alternativamente como TX o RX.

He leido y sigo haciendolo, la hoja de datos de atmel pero sigo sin entender demasiado, me parece que hay que tener mucho conocimiento sobre el funcionamiento interno del ATmega328P, cosa que no tengo.

Seguire intentadolo y sin importar lo que tarde en averiguarlo, pondre mis resultados aqui.

gracias por tu tiempo.

Seguramente que hay algún forero que conoce mejor que yo los entresijos de los timers; no obstante, ando yo también curioseando, pues es un tema en el que me apetece empaparme con más detalle, a pesar del jaleo de registros que implican. Si veo algo que pueda ayudarte, lo publico por aquí.

Estoy aún pegando un poco palos de ciego, pero prueba a ver si la transmisión suena mejor con el siguiente código psk. Es muy similar al tuyo, pero con algún matiz:

#define PSK_BUFFER_SIZE 64
volatile uint8_t inBufPt,outBufPt;
volatile uint8_t serialPSKBuffer[PSK_BUFFER_SIZE];

// 32khz sampling , 64khz / 2
// 128 samples per cycle 
// 32000 / 128 = 250 baud
// 4 cycles per bit, 250 * 4 = 1000hz
#define mydelay 128
static const uint8_t sin_table_same[mydelay] =
{
  151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
  103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127, 
  151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
  103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127, 
  151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
  103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127, 
  151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
  103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127,
};
static const uint8_t sin_table_change[mydelay] = 
{
  151, 174, 195, 214, 229, 240, 246, 248, 245, 238, 226, 210, 192, 171, 149, 127, 
  105, 85, 66, 50, 38, 29, 25, 24, 28, 35, 46, 60, 75, 92, 110, 127, 
  143, 158, 171, 182, 190, 195, 197, 195, 192, 185, 177, 168, 157, 147, 136, 127, 
  119, 112, 106, 102, 100, 100, 101, 103, 107, 111, 115, 119, 122, 125, 127, 127, 
  127, 125, 122, 119, 115, 111, 107, 103, 101, 100, 100, 102, 106, 112, 119, 127, 
  136, 147, 157, 168, 177, 185, 192, 195, 197, 195, 190, 182, 171, 158, 143, 127, 
  110, 92, 75, 60, 46, 35, 28, 24, 25, 29, 38, 50, 66, 85, 105, 127, 
  149, 171, 192, 210, 226, 238, 245, 248, 246, 240, 229, 214, 195, 174, 151, 127,
};
void initPsk() 
{
  pinMode(9,OUTPUT);    // 11 or 3 = output
  cli();
  OCR1AH = 0;
  OCR1AL = 128;
  TCCR1B =  (1<<CS10);   //run at 64khz
  TCCR1A = _BV(COM1A1) | _BV(WGM10)| _BV(WGM11); // connect pin 11 to timer 2 channel A
  TIMSK1 |= (1<<TOIE1);  // enable tim2 interrupt
  sei();                   // set interrupt flag
}

byte phase = 0;
boolean is_change = true;
boolean is_invert = false;
byte oddcycle = 0;
byte bitct = 0;
byte data;

ISR(TIMER1_OVF_vect) // this runs at 64khz
{
  if (oddcycle < 1) oddcycle++;
  else
  {  
    oddcycle = 0;    
    // this runs at 32 khz
    if (is_change) 
    {
      byte sinval = sin_table_change[phase];
      cli();
      OCR1AH=0;
      if (is_invert) OCR1AL = sinval ^ 0xFF;
      else           OCR1AL = sinval; 
      sei();
    }  
    else 
    {
      byte sinval = sin_table_same[phase];
      if (is_invert) OCR1A = sinval ^ 0xFF;
      else           OCR1A = sinval; 
    }
    phase++;
    if (phase >= mydelay) 
    {
      if (is_change) is_invert = !is_invert;
      phase = 0; 
      // bitcounter 0..7 data / 8 stopbit / 9 idle, else startbit
      if (bitct <= 7) // databit
      {
        // get next bit 
        is_change = (data & (1<<bitct));
        bitct++;
      }
      else if (bitct == 8)
      {
        //stopbit 1000 hz
        is_change = true;
        bitct++;
      }
      else if (bitct == 9)
      {
        if ((uint8_t)(inBufPt - outBufPt)%PSK_BUFFER_SIZE > 0) 
        {
          outBufPt++; 
          if (outBufPt >= PSK_BUFFER_SIZE) outBufPt = 0;
          data = serialPSKBuffer[outBufPt];  
          // startbit no_change
          bitct = 0;
          is_change = false;
        }
        else is_change = true;        
      }
    }
  }
}

void writePSK(uint8_t a) 
{
  uint8_t t = inBufPt;
  if (++t >= PSK_BUFFER_SIZE) t = 0;
  serialPSKBuffer[t] = a;
  inBufPt = t;
}
void writePSK16(int32_t a) 
{
  writePSK(a & 0xFF);
  writePSK((a>>8) & 0xFF);
}
void writePSK32(int32_t a) 
{
  writePSK(a & 0xFF);
  writePSK((a>>8) & 0xFF);
  writePSK((a>>16) & 0xFF);
  writePSK((a>>24) & 0xFF);
}

Básicamente varía en que escribo el OCR1A en dos pasos (OCR1AH y OCR1AL), dado que es un registro de 16 bit (previamente desactivo interrupciones por si acaso). También he cambiado los nombres de algunos bits que hacían aún referencia al timer2, aunque probablemente el número de pin sea el mismo, pero también por si acaso
Prueba y me cuentas.

He probado tu codigo pero no funciona como beberia, aun asi voy a seguir probando cosas con el, por mi parte he modificado los registro tratando de hacer concidir los del timer1 con los del timr2, y quedo asi:

// out pin 11
// in pin A3

#define PSK_BUFFER_SIZE 64
volatile uint8_t inBufPt,outBufPt;
volatile uint8_t serialPSKBuffer[PSK_BUFFER_SIZE];

// 32khz sampling , 64khz / 2
// 128 samples per cycle 
// 32000 / 128 = 250 baud
// 4 cycles per bit, 250 * 4 = 1000hz

#if defined (TX)
  #define mydelay 128
  #define SINTABLEN 32
  static const uint8_t sin_table_same[SINTABLEN] =
  {
    151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
    103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127, 
  };
  static const uint8_t sin_table_change[mydelay] = 
  {
    151, 174, 195, 214, 229, 240, 246, 248, 245, 238, 226, 210, 192, 171, 149, 127, 
    105, 85, 66, 50, 38, 29, 25, 24, 28, 35, 46, 60, 75, 92, 110, 127, 
    143, 158, 171, 182, 190, 195, 197, 195, 192, 185, 177, 168, 157, 147, 136, 127, 
    119, 112, 106, 102, 100, 100, 101, 103, 107, 111, 115, 119, 122, 125, 127, 127, 
    127, 125, 122, 119, 115, 111, 107, 103, 101, 100, 100, 102, 106, 112, 119, 127, 
    136, 147, 157, 168, 177, 185, 192, 195, 197, 195, 190, 182, 171, 158, 143, 127, 
    110, 92, 75, 60, 46, 35, 28, 24, 25, 29, 38, 50, 66, 85, 105, 127, 
    149, 171, 192, 210, 226, 238, 245, 248, 246, 240, 229, 214, 195, 174, 151, 127,
  };
#endif

#if defined (RX)
  #define offs (128)
  #define mydelay 32  //bittime = 4ms -> 250 baud
#endif

void initPsk() 
{    
  #if defined (TX)
    pinMode(9,OUTPUT);    // Timer2 11 or 3 = output, Timer1 10 or 9 = output.
    OCR1A = 128;  
    TCCR1B =  (1<<CS10);   //run at 64khz (No prescaling)
    TCCR1A = _BV(COM1A1) | _BV(WGM10); // connect pin 9 to timer1 channel A
    TIMSK1 |= (1<<TOIE1);  // enable tim2 interrupt
  #endif
  
  #if defined (RX)
  // AD part
    OCR2A = 128; // pin 11
    TCCR2B =  (1<<CS21);   // run at 8khz
    TCCR2A =  0;           // normal mode
    TIMSK2 |= (1<<TOIE2);  // enable tim2 interrupt
    
    pinMode(12, OUTPUT);   // pin = output  
    DIDR0 = 0x3F;          // digital inputs disabled
    #if defined (INTVREF)
      ADMUX = 0xE3;          // measuring on ADC3, use 1.1V reference, left adjust
    #else
      ADMUX = 0x63;          // measuring on ADC3, use VCC reference, left adjust
    #endif
    ADCSRA = 0x87;         // AD-converter on, interrupt disabled, prescaler = 128
    ADCSRB = 0x00;         // AD channels MUX on
  #endif

  sei();                   // set interrupt flag
}

#if defined (TX)
  byte phase = 0;
  boolean is_change = true;
  boolean is_invert = false;
  byte oddcycle = 0;
  byte bitct = 0;
  byte data;
  
  ISR(TIMER1_OVF_vect) // this runs at 64khz
  {
    if (oddcycle < 1) oddcycle++;
    else
    {  
      oddcycle = 0;    
      // this runs at 32 khz
      if (is_change) 
      {
        byte sinval = sin_table_change[phase];
        if (is_invert) OCR1A = sinval ^ 0xFF;
        else           OCR1A = sinval; 
      }  
      else 
      {
        byte sinval = sin_table_same[phase%SINTABLEN];
        if (is_invert) OCR1A = sinval ^ 0xFF;
        else           OCR1A = sinval; 
      }
      phase++;
      if (phase >= mydelay) 
      {
        if (is_change) is_invert = !is_invert;
        phase = 0; 
      
        // bitcounter 0..7 data / 8 stopbit / 9 idle, else startbit
        if (bitct <= 7) // databit
        {
          // get next bit 
          is_change = (data & (1<<bitct));
          bitct++;
        }
        else if (bitct == 8)
        {
          //stopbit 1000 hz
          is_change = true;
          bitct++;
        }
        else if (bitct == 9)
        {
          if ((uint8_t)(inBufPt - outBufPt)%PSK_BUFFER_SIZE > 0) 
          {
            outBufPt++; 
            if (outBufPt >= PSK_BUFFER_SIZE) outBufPt = 0;
            data = serialPSKBuffer[outBufPt];  
            // startbit no_change
            bitct = 0;
            is_change = false;
          }
          else is_change = true;        
        }
      }
    }
  }
   
  void writePSK(uint8_t a) 
  {
    uint8_t t = inBufPt;
    if (++t >= PSK_BUFFER_SIZE) t = 0;
    serialPSKBuffer[t] = a;
    inBufPt = t;
  }
  void writePSK16(int32_t a) 
  {
    writePSK(a & 0xFF);
    writePSK((a>>8) & 0xFF);
  }
  void writePSK32(int32_t a) 
  {
    writePSK(a & 0xFF);
    writePSK((a>>8) & 0xFF);
    writePSK((a>>16) & 0xFF);
    writePSK((a>>24) & 0xFF);
  }
#endif

#if defined (RX)

  int8_t fifo[mydelay];
  uint8_t fifopt = 0;
  
  #define LOWRES
  
  int16_t sum = 0;
  #if defined (LOWRES)
    int8_t rfifo[mydelay]; // 8 bit variant, low dynamic range, 8us
  #else
    int16_t rfifo[mydelay]; // 16 bit variant, 9-12 us all 125us
  #endif
  
  byte history = 0;
  byte bitct = 0;
  byte data;
  byte decimationct = 0;

  ISR(TIMER2_OVF_vect) // this runs at 8khz
  {
    uint8_t ad_byte;
    int8_t currentSample;
    int8_t oldestSample;
    int16_t result;
    boolean is_space;
    
    ad_byte = ADCH;   
    
    #if defined(TESTRXLEVEL)
      SerialWrite(ad_byte);
      ADCH = 127;
      ADCSRA = 0xC7; // start AD conversion
    #else
    
    currentSample = ad_byte - offs;
    ADCSRA = 0xC7; // start AD conversion
    oldestSample = fifo[fifopt];
    fifo[fifopt] = currentSample;
    // incrase the thing later
    
    #if defined (LOWRES)
      // may be 127 * 127 = +-16300>>7 = +-64 
      result = (currentSample * oldestSample) >> 8;
    
      // summed over 32 samples = 64 * 32 = 2016
      sum -= rfifo[fifopt];
      sum += result;
      rfifo[fifopt] = result;
    #else
      // may be 127 * 127 = +-16300>>3 = +-2000 
      result = (currentSample * oldestSample) >> 3; 
    
      // summed over 32 samples = 2000 * 32 = 64000 
      sum -= rfifo[fifopt];
      sum += result;
      rfifo[fifopt] = result;
    #endif
    
    fifopt = (fifopt + 1)%mydelay;
    
    is_space = (sum <= 0);
    
    // fix me. 32 bits / symbol to 4 bits/symbol
    decimationct++; //counts 1,2,3,4 from here on
    //bitphase := bitphase + (early - late) / (early + late);
    if (decimationct == 4)
    {
      decimationct = 0;
            
      history <<= 1;  // history should be 64 bits long ....
      if (is_space) history |= 0x01;
    
      if (bitct == 0)  
      {
        if (history == 0xF0) bitct = 1; // waiting for startbit 11110000
        else if ((history == 0x70) || (history == 0xB0) || (history == 0xD0)) bitct = 1;
        else if ((history == 0xF4) || (history == 0xF2) || (history == 0xF1)) bitct = 1;
      }
      else
      {    
        // bitct advances every half ms. 250 baud = 4ms / bit + 1 start + 1 stop 
        if      (bitct ==  8) data  = (is_space << 0);
        else if (bitct == 16) data |= (is_space << 1);
        else if (bitct == 24) data |= (is_space << 2);
        else if (bitct == 32) data |= (is_space << 3);
        else if (bitct == 40) data |= (is_space << 4);
        else if (bitct == 48) data |= (is_space << 5);
        else if (bitct == 56) data |= (is_space << 6);
        else if (bitct == 64) data |= (is_space << 7);
      
        //if (bitct%8 == 0) digitalWrite(12, HIGH); //middle of bit check
        //if (bitct%8 == 1) digitalWrite(12, LOW);
      
        bitct++;
        if (bitct >= 72)
        {
          uint8_t t = inBufPt;
          if (++t >= PSK_BUFFER_SIZE) t = 0;
          serialPSKBuffer[t] = data;
          inBufPt = t;
          bitct = 0;  
        }      
      }
    
      if (is_space) digitalWrite(12, HIGH); // marker low
      else digitalWrite(12, LOW); // marker high
    }
    #endif //TESTRXLEVEL    
  }; 

  uint8_t readPSK()
  {
    uint8_t t = outBufPt;
    if (inBufPt != t) 
    {
      uint8_t r;
      if (++t >= PSK_BUFFER_SIZE) t = 0;
      outBufPt = t;
      r = serialPSKBuffer[t];
      return r;
    }
    return 0;
  }

  uint16_t readPSK16() {
    uint16_t t = readPSK();
    t+= (uint16_t)readPSK()<<8;
    return t;
  }
  uint32_t readPSK32() {
    uint32_t t = readPSK16();
    t+= (uint32_t)readPSK16()<<16;
    return t;
  }

  uint8_t PskAvailable() 
  {
    return ((uint8_t)(inBufPt - outBufPt))%PSK_BUFFER_SIZE;
  }
#endif

En principio parece funcionar pero con un problema, y es que la frecuencia o tono es mas baja o grave que la del codigo original con el Timer2.

Osea, la modulacion del sonido lo hace coreccto pero en un tono mas bajo, creo que ahora habria que buscar la manera de subir el tono del la onda.

¿Por qué en tu último código te comes uno de los bits?

TCCR1A = _BV(COM1A1) | _BV(WGM10)| _BV(WGM11);

Sólo tienes la parte en negrita.

Porque si lo pongo, la frecuencia aumenta mucho, esto es lo que no entiendo del todo.

Probando al azar quiete este bit, y empezo a trabjar muy parecido a como deberia, solo que como te decia antes, en un tono bajo.

Hola de nuevo. Prueba a ver configurando así:

TCCR1B = _BV(CS10) | _BV(WGM12); //run at 64khz (No prescaling) TCCR1A = _BV(COM1A1) | _BV(WGM10); // connect pin 9 to timer1 channel A

Y me cuentas.

Hola noter,

con esta untima configuracion me has puesto funciona perfecto la transmision con Timer1, ahora queda juntar los dos codigos para que trabajen al mismo tiempo.

Ya hice una primera prueba y no se porque cuando habilito RX y TX al mismo tiempo, empieza a producir un sonido continuo.

Si solo habilito TX, transmite bien.

Si solo habilito RX recibe bien.

Tetengo el codigo con el Timer1 para TX y Timer2 para RX.

Bueno, he resuelto parte del problema, cuando habilito ambos modos RX/TX, en la definicion de la libreria hay una variable llamada mydelay, que en RX esta definido con un valor 32 y en TX esta con valor 128.

Solo renombre la variable en TX como mydelay1 en todos los sitios en que se utiliza.

Aun asi para poder untilizar el codigo con ambos modos habilitados, en el bucle void loop(), debo utilizarlo uno a la vez, en otras palabras, llamar a cada funcion dentro del blucle una a la vez, lo que seria semi duplex, ya que si hago la llamada a las dos, produce un tono continuo.

A lo mejor, si sigo separando las variables de todo el codigo podria llegar a funcionar en full duplex.

De momento, probare tal y como esta entre dos Arduinos con el mismo codigo a ver que pasa, ya comentare los resultados.

ArduModemPSK_TXRX.zip (4.67 KB)

De momento podemos partir de este código de Psk, si te parece. Intentaremos buscar posibles fallos. De momento compila.

// out pin 11
// in pin A3

#define PSK_BUFFER_SIZE 64
volatile uint8_t inBufPt,outBufPt;
volatile uint8_t serialPSKBuffer[PSK_BUFFER_SIZE];

// 32khz sampling , 64khz / 2
// 128 samples per cycle 
// 32000 / 128 = 250 baud
// 4 cycles per bit, 250 * 4 = 1000hz

#if defined (TX)
  #define mydelaytx 128
  #define SINTABLEN 32
  static const uint8_t sin_table_same[SINTABLEN] =
  {
    151, 174, 195, 214, 230, 241, 248, 251, 248, 241, 230, 214, 195, 174, 151, 127, 
    103, 80, 59, 40, 24, 13, 6, 3, 6, 13, 24, 40, 59, 80, 103, 127, 
  };
  static const uint8_t sin_table_change[mydelaytx] = 
  {
    151, 174, 195, 214, 229, 240, 246, 248, 245, 238, 226, 210, 192, 171, 149, 127, 
    105, 85, 66, 50, 38, 29, 25, 24, 28, 35, 46, 60, 75, 92, 110, 127, 
    143, 158, 171, 182, 190, 195, 197, 195, 192, 185, 177, 168, 157, 147, 136, 127, 
    119, 112, 106, 102, 100, 100, 101, 103, 107, 111, 115, 119, 122, 125, 127, 127, 
    127, 125, 122, 119, 115, 111, 107, 103, 101, 100, 100, 102, 106, 112, 119, 127, 
    136, 147, 157, 168, 177, 185, 192, 195, 197, 195, 190, 182, 171, 158, 143, 127, 
    110, 92, 75, 60, 46, 35, 28, 24, 25, 29, 38, 50, 66, 85, 105, 127, 
    149, 171, 192, 210, 226, 238, 245, 248, 246, 240, 229, 214, 195, 174, 151, 127,
  };
#endif

#if defined (RX)
  #define offsrx (128)
  #define mydelayrx 32  //bittime = 4ms -> 250 baud
#endif

void initPsk() 
{    
  #if defined (TX)
    pinMode(9,OUTPUT);    // 9 or 10 = output
    OCR1A = 128;  
    _BV(CS10) | _BV(WGM12);   //run at 64khz (No prescaling)
    TCCR1A = _BV(COM1A1) | _BV(WGM10); // connect pin 9 to timer 1 channel A
    TIMSK1 |= (1<<TOIE1);  // enable tim1 interrupt
  #endif
  
  #if defined (RX)
  // AD part
    OCR2A = 128; // pin 11
    TCCR2B =  (1<<CS21);   // run at 8khz
    TCCR2A =  0;           // normal mode
    TIMSK2 |= (1<<TOIE2);  // enable tim2 interrupt
    
    pinMode(12, OUTPUT);   // pin = output  
    DIDR0 = 0x3F;          // digital inputs disabled
    #if defined (INTVREF)
      ADMUX = 0xE3;          // measuring on ADC3, use 1.1V reference, left adjust
    #else
      ADMUX = 0x63;          // measuring on ADC3, use VCC reference, left adjust
    #endif
    ADCSRA = 0x87;         // AD-converter on, interrupt disabled, prescaler = 128
    ADCSRB = 0x00;         // AD channels MUX on
  #endif

  sei();                   // set interrupt flag
}

#if defined (TX)
  byte phase = 0;
  boolean is_change = true;
  boolean is_invert = false;
  byte oddcycle = 0;
  byte bitcttx = 0;
  byte datatx;
  
  ISR(TIMER1_OVF_vect) // this runs at 64khz
  {
    if (oddcycle < 1) oddcycle++;
    else
    {  
      oddcycle = 0;    
      // this runs at 32 khz
      if (is_change) 
      {
        byte sinval = sin_table_change[phase];
        if (is_invert) OCR2A = sinval ^ 0xFF;
        else           OCR2A = sinval; 
      }  
      else 
      {
        byte sinval = sin_table_same[phase%SINTABLEN];
        if (is_invert) OCR2A = sinval ^ 0xFF;
        else           OCR2A = sinval; 
      }
      phase++;
      if (phase >= mydelaytx) 
      {
        if (is_change) is_invert = !is_invert;
        phase = 0; 
      
        // bitcounter 0..7 datatx / 8 stopbit / 9 idle, else startbit
        if (bitcttx <= 7) // databit
        {
          // get next bit 
          is_change = (datatx & (1<<bitcttx));
          bitcttx++;
        }
        else if (bitcttx == 8)
        {
          //stopbit 1000 hz
          is_change = true;
          bitcttx++;
        }
        else if (bitcttx == 9)
        {
          if ((uint8_t)(inBufPt - outBufPt)%PSK_BUFFER_SIZE > 0) 
          {
            outBufPt++; 
            if (outBufPt >= PSK_BUFFER_SIZE) outBufPt = 0;
            datatx = serialPSKBuffer[outBufPt];  
            // startbit no_change
            bitcttx = 0;
            is_change = false;
          }
          else is_change = true;        
        }
      }
    }
  }
   
  void writePSK(uint8_t a) 
  {
    uint8_t t = inBufPt;
    if (++t >= PSK_BUFFER_SIZE) t = 0;
    serialPSKBuffer[t] = a;
    inBufPt = t;
  }
  void writePSK16(int32_t a) 
  {
    writePSK(a & 0xFF);
    writePSK((a>>8) & 0xFF);
  }
  void writePSK32(int32_t a) 
  {
    writePSK(a & 0xFF);
    writePSK((a>>8) & 0xFF);
    writePSK((a>>16) & 0xFF);
    writePSK((a>>24) & 0xFF);
  }
#endif

#if defined (RX)

  int8_t fifo[mydelayrx];
  uint8_t fifopt = 0;
  
  #define LOWRES
  
  int16_t sum = 0;
  #if defined (LOWRES)
    int8_t rfifo[mydelayrx]; // 8 bit variant, low dynamic range, 8us
  #else
    int16_t rfifo[mydelayrx]; // 16 bit variant, 9-12 us all 125us
  #endif
  
  byte history = 0;
  byte bitctrx = 0;
  byte datarx;
  byte decimationct = 0;

  ISR(TIMER2_OVF_vect) // this runs at 8khz
  {
    uint8_t ad_byte;
    int8_t currentSample;
    int8_t oldestSample;
    int16_t result;
    boolean is_space;
    
    ad_byte = ADCH;   
    
    #if defined(TESTRXLEVEL)
      SerialWrite(ad_byte);
      ADCH = 127;
      ADCSRA = 0xC7; // start AD conversion
    #else
    
    currentSample = ad_byte - offsrx;
    ADCSRA = 0xC7; // start AD conversion
    oldestSample = fifo[fifopt];
    fifo[fifopt] = currentSample;
    // incrase the thing later
    
    #if defined (LOWRES)
      // may be 127 * 127 = +-16300>>7 = +-64 
      result = (currentSample * oldestSample) >> 8;
    
      // summed over 32 samples = 64 * 32 = 2016
      sum -= rfifo[fifopt];
      sum += result;
      rfifo[fifopt] = result;
    #else
      // may be 127 * 127 = +-16300>>3 = +-2000 
      result = (currentSample * oldestSample) >> 3; 
    
      // summed over 32 samples = 2000 * 32 = 64000 
      sum -= rfifo[fifopt];
      sum += result;
      rfifo[fifopt] = result;
    #endif
    
    fifopt = (fifopt + 1)%mydelayrx;
    
    is_space = (sum <= 0);
    
    // fix me. 32 bits / symbol to 4 bits/symbol
    decimationct++; //counts 1,2,3,4 from here on
    //bitphase := bitphase + (early - late) / (early + late);
    if (decimationct == 4)
    {
      decimationct = 0;
            
      history <<= 1;  // history should be 64 bits long ....
      if (is_space) history |= 0x01;
    
      if (bitctrx == 0)  
      {
        if (history == 0xF0) bitctrx = 1; // waiting for startbit 11110000
        else if ((history == 0x70) || (history == 0xB0) || (history == 0xD0)) bitctrx = 1;
        else if ((history == 0xF4) || (history == 0xF2) || (history == 0xF1)) bitctrx = 1;
      }
      else
      {    
        // bitctrx advances every half ms. 250 baud = 4ms / bit + 1 start + 1 stop 
        if      (bitctrx ==  8) datarx  = (is_space << 0);
        else if (bitctrx == 16) datarx |= (is_space << 1);
        else if (bitctrx == 24) datarx |= (is_space << 2);
        else if (bitctrx == 32) datarx |= (is_space << 3);
        else if (bitctrx == 40) datarx |= (is_space << 4);
        else if (bitctrx == 48) datarx |= (is_space << 5);
        else if (bitctrx == 56) datarx |= (is_space << 6);
        else if (bitctrx == 64) datarx |= (is_space << 7);
      
        //if (bitctrx%8 == 0) digitalWrite(12, HIGH); //middle of bit check
        //if (bitctrx%8 == 1) digitalWrite(12, LOW);
      
        bitctrx++;
        if (bitctrx >= 72)
        {
          uint8_t t = inBufPt;
          if (++t >= PSK_BUFFER_SIZE) t = 0;
          serialPSKBuffer[t] = datarx;
          inBufPt = t;
          bitctrx = 0;  
        }      
      }
    
      if (is_space) digitalWrite(12, HIGH); // marker low
      else digitalWrite(12, LOW); // marker high
    }
    #endif //TESTRXLEVEL    
  }; 

  uint8_t readPSK()
  {
    uint8_t t = outBufPt;
    if (inBufPt != t) 
    {
      uint8_t r;
      if (++t >= PSK_BUFFER_SIZE) t = 0;
      outBufPt = t;
      r = serialPSKBuffer[t];
      return r;
    }
    return 0;
  }

  uint16_t readPSK16() {
    uint16_t t = readPSK();
    t+= (uint16_t)readPSK()<<8;
    return t;
  }
  uint32_t readPSK32() {
    uint32_t t = readPSK16();
    t+= (uint32_t)readPSK16()<<16;
    return t;
  }

  uint8_t PskAvailable() 
  {
    return ((uint8_t)(inBufPt - outBufPt))%PSK_BUFFER_SIZE;
  }
#endif

Veo que nos hemos pisado, pero básicamente he hecho lo mismo que tú, osea evitar dobles declaraciones (si no se nos ha escapado ninguna). Ahora echo un vistazo a tu programa principal.

Prueba a ver así en el programa principal a ver qué hace.

#define RX  // TX or RX firmware
#define TX  // TX or RX firmware
#define INTVREF  // use internal 1.1V ref for AD
#define LED 13
#define BAUDRATE 115200
//#define TESTRXLEVEL

// PWM out is pin 9 and 10
// AFSK out is pin 11
// AFSK in is pin A3

uint16_t time, lasttime;
uint16_t timediff;

void setup() 
{  
  pinMode (LED, OUTPUT);  
  SerialOpen(BAUDRATE);
  initPsk();
  digitalWrite(LED, 1);
  lasttime = millis();
}
  
void loop() 
{
  time = millis();
  timediff = time - lasttime;
  if (timediff > 1500) {
    lasttime = time;
    writePSK('

);     writePSK('T');     writePSK('G');     writePSK('H');     writePSK('H');     writePSK('O');     writePSK('L');     writePSK('A');

  }   if (PskAvailable())   {     SerialWrite(readPSK());   } } ```

Ya he probado este ultimo codigo que has puesto, en principio funciona bien recibiendo, pero no transmite, si en el loop comento "SerialWrite(readPSK());", transmite bien, pero desde que lo descomento deja de enviar, el pitido queda en solo tono, osea si hago esto:

void loop() { time = millis(); timediff = time - lasttime; if (timediff > 1500) { lasttime = time; writePSK('$'); writePSK('T'); writePSK('G'); writePSK('H'); writePSK('H'); writePSK('O'); writePSK('L'); writePSK('A');

} if (PskAvailable()) { // SerialWrite(readPSK()); } }

Tiene que haber algo dentro de readPSK() que este interfiriendo con el writePSK(), he estado haciendo cambios pero no doy con el problema, seguire probando.

Otra cosa, he visto que no pones:

uint16_t missedframes = 0; uint16_t goodframes = 0; uint8_t c;

Es por algun motivo en particular?, porque veo que sin estas lineas tambien funciona, que se supone que hace esto?

Hola. He quitado esas declaraciones sencillamente porque no las estoy utilizando en el código. Si te fijas, he hecho otra sutil modificación, definiendo todas las variables te timer como uint16_t en lugar de como uint32_t. Realmente eso no suele ser lo correcto, aunque para temporizados de menos de un minuto funciona, y ahorras unos ciclos de reloj en las operaciones (16 cifras, en lugar de 32). En cuanto a lo del pitido continuo, salvo error no detectado, me temo que lo que puede ocurrir es que el arduino no da de sí para satisfacer las tres interrupciones que se implementan (timer1, timer2 y serial). Por ello ando intentando "escatimar" ciclos de reloj al programa. Intenta hacer la siguiente prueba, para ver si funciona. En lugar de comentar el SerialWrite readPsk, comenta todos los writePSK, excepto uno. Si funcionara de forma estable, descomenta uno más, y así hasta que empiece a fallar, y me dices resultado.