Ayuda con proyecto de audio arduino y xbee

#1
Hola qué tal.
El proyecto que estoy realizando es reproducir voz humana con el PWM encontrado en el Playground de ejemplos de arduino, con la diferencia de que debe recibir los datos de una comunicación serial.
El problema principal aqui es que si el Arduino recibe los datos de una conexión USB, el sonido se escucha entendible, pero si lo hace desde un XBEE, se escucha puro ruido y no se logra entender ni una sola palabra del sonido a reproducir.

Por favor, ayúdenme, ya he estado intentando en esto como más de dos meses, y no encuentro solución. Mil gracias :)
Código:
int a = 0;
int ledPin = 13;
int speakerPin = 11;
char inData[3];
char numero[3]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character
long arraySize = 999999;
byte num;

/*
 * speaker_pcm
 *
 * Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
 * For Arduino with Atmega168 at 16 MHz.
 *
 * Uses two timers. The first changes the sample value 8000 times a second.
 * The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
 * depending on sample value. The second timer repeats 62500 times per second
 * (16000000 / 256), much faster than the playback rate (8000 Hz), so
 * it almost sounds halfway decent, just really quiet on a PC speaker.
 *
 * Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
 * (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
 * for the pulse width modulation, breaking PWM for pins 11 & 3.
 *
 * References:
 *     http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
 *     http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
 *     http://www.evilmadscientist.com/article.php/avrdac
 *     http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
 *     http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
 *     http://www.gamedev.net/reference/articles/article442.asp
 *
 * Michael Smith <michael@hurts.ca>
 */

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000  //8KHz sample rate

/*
 * The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
 * to fit in flash. 10000-13000 samples is about the limit.
 *
 * sounddata.h should look like this:
 *     const int sounddata_length=10000;
 *     const unsigned char sounddata_data[] PROGMEM = { ..... };
 *
 * You can use wav2c from GBA CSS:
 *     http://thieumsweb.free.fr/english/gbacss.html
 * Then add "PROGMEM" in the right place. I hacked it up to dump the samples
 * as unsigned rather than signed, but it shouldn't matter.
 *
 * http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
 * mplayer -ao pcm macstartup.mp3
 * sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
 * sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
 * wav2c macstartup-cut.wav sounddata.h sounddata
 */

//#include "sounddata.h"

#define SAMPLEINDEX_MASK 0x0FFF

//Used to implement phase increment resampling
uint16_t sampleStep;  //The step size for each sample. All 16 bits are used.
			    //The lower 12 are fractional steps. A step size of 0x01000 is equal to one step
			    //per sample. Also, this means that playback can be done at a maximum of 16X the
			    //orignal rate.
volatile unsigned long sampleIndex; //Keeps the current sample index.

//Used by the ISR and initalizaiton methods
uint16_t samplePoint;
unsigned int sampleValue;

//Prototype for DAC output function
//The idea is to abstract the type of DAC used. It is assumed that the DAC would never have more then
//16 bits of resolution so an unsigned int is used. If you intened to have 8-Bits of resolution then you
//need to upshift the input (value<<8). This does add some time/hassel but it support the concept of
//differnet resolutions independent of the applicaiton code.
//The second parameter is the DAC channel. For the inital test code one is used for the PWM DAC and
//and the other is for the R2R DAC. In a future version I want to have Left and Right channels
//
#define DAC_PWM 1
#define DAC_R2R 2
void SetDAC(unsigned int outputValue, unsigned int channel);

//Lower level funcitons to actualy set the specific DAC type. Used only by the SetDAC funciton.
void SetDAC_PWM(unsigned int outputValue);
void SetDAC_R2R(unsigned int outputValue);

ISR(TIMER1_COMPA_vect) {
}

void startPlayback() {

    pinMode(speakerPin, OUTPUT);
    sampleStep=0x2000; //Set to orignal sample rate.

    // Set up Timer 2 to do pulse width modulation on the speaker
    // pin.

    // Use internal clock (datasheet p.160)
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));

    // Set fast PWM mode  (p.157)
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);

    // Do non-inverting PWM on pin OC2A (p.155)
    // On the Arduino this is pin 11.
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set initial pulse width to the first sample.
    //sampleValue=pgm_read_byte(&sounddata_data[0])<<8;
    //sampleValue = num;
//    SetPWMDAC(sampleValue);
//    SetR2RDAC(sampleValue);


    // Set up Timer 1 to send a sample every interrupt.
 //   cli();

    // Set CTC mode (Clear Timer on Compare Match) (p.133)
    // Have to set OCR1A *after*, otherwise it gets reset to 0!
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

    // No prescaler (p.134)
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set the compare register (OCR1A).
    // OCR1A is a 16-bit register, so we have to do this with
    // interrupts disabled to be safe.
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

    // Enable interrupt when TCNT1 == OCR1A (p.136)
    TIMSK1 |= _BV(OCIE1A);

//    lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
    //sampleIndex = 0;
//    sei();
}

void SetDAC(unsigned int outputValue, unsigned int channel) {
  switch(channel) {
    case DAC_PWM :
	SetDAC_PWM(outputValue);
	break;
    case DAC_R2R :
	SetDAC_R2R(outputValue);
	break;
  }
}

//Set the PWM D/A converter output
void SetDAC_PWM(unsigned int outputValue){
  //This implementation uses PWM in 8 bit mode.
  //Load the upper 8 bits into the PWM control register
  OCR2A = (outputValue>>8)&0xFF;
}

//Set the R2R D/A converter output.
void SetDAC_R2R(unsigned int outputValue){
  //We are using port D bits 2-7 for a 6-bit D/A.
  //Bits 0 and 1 are serial which we dont want to disturb
  PORTD=(PIND&0x03)|((outputValue>>8)&0xFC);
}

#define MAX_STEP 0x05000
#define MIN_STEP 0x00400

void setup() {
  //Set the LED pin mode to output.
  pinMode(ledPin, OUTPUT);
  //Iniciar el serial a 115200 bps
  Serial.begin(142500);
  //2 bits de paro / 2 stop bits
 // UCSR0C = UCSR0C | B00001000;
 // UCSR0C |= (1 << USBS0); // right after calling Serial.begin ();

  pinMode(speakerPin, OUTPUT);
  //Setup the hardware for the D/A converter
  //We are using port D bits 2-7 for a 6-bit D/A.
  //Bits 0 and 1 are serial which we dont want to disturb
 // DDRD|=B11111110; //Set upper 6 as ouput, lower are TX and RX

  //Set an inital phase step size.
  sampleStep=MIN_STEP;

  //Setup the timers for the ISR and PCM generation
  startPlayback();

  //Parpadear LED para indicar que funciona correctamente
  for (int i = 0; i<3; i++){
    digitalWrite(ledPin,HIGH);
    delay(250);
    digitalWrite(ledPin,LOW);
    delay(250);
  }
}

void loop() {
  //To demonstrate the phase steping feature set the phase step as a function
  //of the A/D input on input 0. Hook up a pot to vary the phase step and resample the
  //sound at diffenret frequencies.
  //for(int i = 0; i<255;i++)
    //sampleStep=MIN_STEP+(analogRead(0)<<3);
    //sampleStep=MIN_STEP+i;

 while(Serial.available() > 0) // Don't read unless you know there is data
   {
     digitalWrite(ledPin,HIGH);
	 if(index < arraySize) // One less than the size of the array
	 {
		inChar = Serial.read(); // Read a character
		//Que reciba caracteres hasta que llegue una coma
		  if (inChar!=','){
			  inData[index] = inChar; // Store it
		    index++; // Increment where to write next
		    inData[index] = '\0'; // Null terminate the string
		  }
		  //Si el caracter es coma, que lo mande a numero
		  if(inChar==','){
		    for(int i = 0; i<3;i++){
			numero[i]='\0';//Borrar cada caracter de numero para poder escribir en el de nuevo
			if(inData[i]!='\0')
			  numero[i] = inData[i];
		    }
		    //Ahora en entero
		    char * thisChar = numero;
		    a = atoi(thisChar);
		    num = a;
		    index = 0;
		  }
	}
	  //delay(10);
	  OCR2A = num;//QUe lo saque por el pwm
    //SetDAC(a, DAC_PWM);
    digitalWrite(ledPin,LOW);
   }
}
 
#2
Ya encontre el error, no es de programación, es con interferencia de los Xbee... por favor si saben como cambiarles el canal o la frecuencia, se los agradecería mucho. Saludos
 

Angelu29

Bovino adolescente
#4
Hola amigo que tal???, tan solo es una opinion ya que yo he realizado un proyecto semejante y tubimos esl mismo problema, te describo mi proyecto y espero explicarlo bien y encuentres la semejansa. El proyecto trata basicamente de obtener audio, mediante un microfono electred (osea voz o musica) y almacenarlo en una memoria MMC y despues reproducirla con un DAC conectado a un Amplificador en el momento que uno desee obteniendo los datos desde la memoria. Nosotros obteniamos los datos con el ADC de un microcontrolador y un amplificador, luego esos datos eran empaquetados en un buffer y enviados a la memoria. Lamentablemente el micro no tiene la suficiente velocidad para muestrear correctamente el audio debido a que realiza varias tareas. El detalle importante de esto es que, el muestreo (la entrada de datos) requeria un tiempo ya que la informacion se empaquetaba y luego se enviaba y eso requeria tiempo, osea que teniamos tiempo muerto, lo que hacia que en el audio se escuchara un click contante. (osea el tiempo muerto). Al momento de reproducir el audio, no se entendia ni idea , NADA se escuchaba puro ruido, pura basura. Por que???? Bueno es sencillo, anteriormente te explique que el muestreo tenia un tiempo muerto, y que requeria tiempo debido al mepaquetado. Cuando regresas los datos de la memoria al microcontrolador, la obtienes mas rapido y sin perdidas de tiempo ya que puedes realizar dos tareas al mismo tiempo debido al tipo de obtencion de datos, bueno, ese hecho elimina el tiempo muerto y el tiempo requerido para empaquetar los datos. Paara resolverlo, solo integramos un retardo entre cada dato que se sacaba al DAC para que se escuchara o al menos eso alucinabamos jaja debido a la baja calidad del audio solo se escuchaban murmullos. Bueno para comprobar que al menos la velocidad del micro puede realizar una tarea o al menos algo aproximado, nosotros utilizando el mismo circuito, omitimos el almacenamiento de datos a la memoria y pasaba directamente la informacion de la entrada a la salida sin psar por nada. Y comprobamos que el audio que muestreabamos era de buena calidad, comenzamos a probar retardando la salida de la informacion con respecto a la salida, y teniamos que el audio perdia forma y solo se escuchaba ruido, hicimos lo contrario, intercalando informacion y lo mismo ocurria.
A lo que voy es que por medio del puerto USB supongo yo que la informacion fluye con mas velocidad y no tiene ningun problema al ser transportada y recibida. Pero por el XBee hasta donde yo se la informacion la transporta como un puerto Serie y tiene una menor velocidad de transporte de datos, toma en cuenta las diferencias de transmision de datos. Todo lo que te digo esta limitado a lo que yo sé y solo eso, si lo que te digo no te suena coherente pues estoy seguro que hay algo que aun no se jaja. De cualquier modo, esta es mi ayuda y espero que te ayude en algo o al menos espero no haberte confundido mas. Saludos.
 

mcpiebot

Bovino adicto
#6
Hola, que tal?

Necesitas revisar la velocidad de transmisión de modulo, y considerar la frecuencia de muestreo que estas usando y la velocidad a la cual puede transmitir el modulo, ya que los Xbee están diseñados para control, no para transmisión de audio.

Una manera en la que se puede superar ese problema es mandar por bloques de audio y almacenarlo antes de reproducirlo.

Saludos!
 
Arriba