martes, 6 de mayo de 2014

Arduino-Transmisor temperatura y humedad 433MHz -mx-fs-03v

Página principal


Arduino
Transmisor temperatura y humedad
433MHz - mx-fs-03v
xsetaseta@gmail.com

Navegando por la red,http://www.hobbycomponents.com/, encontré un kit de transmisión y recepción para el arduino en la frecuencia de 433MHz.
Es sencillo de programar y se puede obtener por menos de 2€.
Dicho y hecho, lo pedí y en menos de 15 días lo tenía en casa.
El montaje lo he separado en dos artículos, transmisor y receptor, en este primer montaje voy a explicar como he hecho el transmisor.


Kit transmisor
Esquema del transmisor


Esquema del montaje en la placa arduino.


Esquema del montaje en el ATMEGA328.

Para poder medir el consumo del circuito por partes y quitar el consumo de los componentes de la placa arduino, he sacado el Atmega en un modulo board. También he añadido un conversor USM->rs232 para poder programar el microcontrolador.


Montaje del circuito.

Para entender este circuito conviene ver mis dos anteriores artículos:
Reduciendo consumo.Parte 2. Reloj - DS1302. ardurab
Reduciendo consumo.Parte 1. Reloj - DS1302. arduraa

El consumo total del circuito quitado el adaptador usb-to-TTL es de 0.08 mA a 4.2V.
Cuando transmite el circuito consume 15mA ,el tiempo de transmisión dura aproximadamente 1 segundo.
Mediante un interruptor podemos indicarle al circuito que transmita cada  1 segundo o cada 60 segundos.
Una pila AA pude tener una capacidad entre 1100mAh(Zinc–carbono)
y 2900mAh (NiMH).
Si hacemos cálculos con un consumo de 15mA cada 60 segundos, con una pila de 1100mAh , tendremos para aproximadamente 4400 horas, 183 días.
Si utilizaríamos pilas alcalinas con poca autodescarga y cambiaríamos el programa para que transmitiera cada mas tiempo, duraría años el circuito transmitiendo.


Todo esto es bastante teórico, las baterías se autodescargan con el tiempo.

Programa
//-------------
// SETA43
// 06/05/2014
//-------------

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

#include <avr/sleep.h>

#include <Wire.h>
#include <VirtualWire.h>
#include "DHT.h"

#define DHTPIN 3     // what pin we're connected to

// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

unsigned int ih,it;
int sensorValue1, sensorValue2;

DHT dht(DHTPIN, DHTTYPE);

const int TX_DIO_Pin = 2;

int z,contador;

void setup() {
  
  pinMode(13, OUTPUT);
  pinMode(12, INPUT);

  vw_set_tx_pin(TX_DIO_Pin);
  vw_set_ptt_inverted(true);
  vw_setup(2000);

  Serial.begin(9600);
  Serial.println("DHTxx test!");
 
  dht.begin();
  
  watchdogOn(); // Turn on the watch dog timer.
  //Desactiva conversor A/D
  ADCSRA = ADCSRA & B01111111;
  ACSR = B10000000;
 
  contador=0;
}

void loop() {
 unsigned int Data;
 byte TxBuffer[2];
 
  float h = dht.readHumidity();
  float t = dht.readTemperature();


  if (isnan(t) || isnan(h))
    {
    Serial.println("Failed to read from DHT");
    }
  else
    {
    
    ih=h*100;
    it=t*100;
 
    sensorValue1=222;
    sensorValue2=contador;
    
    digitalWrite(13, HIGH);
    
    TxBuffer[0] = 33333 >> 8;
    TxBuffer[1] = 33333;
    vw_send((byte *)TxBuffer, 2);
    vw_wait_tx();
    
    TxBuffer[0] = ih >> 8;
    TxBuffer[1] = ih;
    vw_send((byte *)TxBuffer, 2);
    vw_wait_tx();
    
    TxBuffer[0] = it >> 8;
    TxBuffer[1] = it;
    vw_send((byte *)TxBuffer, 2);
    vw_wait_tx();
    
    TxBuffer[0] = sensorValue1 >> 8;
    TxBuffer[1] = sensorValue1;
    vw_send((byte *)TxBuffer, 2);
    vw_wait_tx();
    
    TxBuffer[0] = sensorValue2 >> 8;
    TxBuffer[1] = sensorValue2;
    vw_send((byte *)TxBuffer, 2);
    vw_wait_tx();
        
    Serial.print(ih); Serial.print(" %  ");
    Serial.print(it); Serial.print(" C  ");
    Serial.println(contador);  
    
    delay(500);
    digitalWrite(13, LOW);
    
    for(z=0;z<60 && HIGH==digitalRead(12) ;z++)goToSleep();
    contador++;
    if(contador>100) contador=0;
    delay(100);

    digitalWrite(13, HIGH);

    }
  
}

void goToSleep()   
{    
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep mode.
  sleep_enable(); // Enable sleep mode.
  sleep_mode(); // Enter sleep mode.
  sleep_disable(); // Disable sleep mode after waking.                     
}

void watchdogOn()
{
  //Fuente http://www.fiz-ix.com/2012/11/low-power-arduino-using-the-watchdog-timer/
  // Clear the reset flag, the WDRF bit (bit 3) of MCUSR.
  MCUSR = MCUSR & B11110111;
  WDTCSR = WDTCSR | B00011000;
  //WDTCSR = B00000101; //0.5S
  WDTCSR = B00000110; //1S
  //WDTCSR = B00100001; //8S

  // Enable the watchdog timer interupt.
  WDTCSR = WDTCSR | B01000000;
  MCUSR = MCUSR & B11110111;
}


ISR(WDT_vect)
{
  //No hace nada
  
}



Hasta pronto.
JUAN GALAZ

Bibliografía:
http://forum.hobbycomponents.com/viewtopic.php?f=39&t=1324
http://seta43.duckdns.org/ardurab.html
http://playground.arduino.cc/Main/DHTLib
http://www.pjrc.com/teensy/td_libs_VirtualWire.html

lunes, 14 de abril de 2014

Arduino Reloj con Nokia 3310

Página principal


Arduino
Reloj con Nokia 3310
xsetaseta@gmail.com

Recién adquirido un LCD 3310, que llevaban los modelos de Nokia, me he dispuesto a pasar los montajes de relojes que hice con un lcd de 16x2, artime.html , arduds.html ,  al LCD 3310.
Existen una librerías: Adafruit_GFX y  Adafruit_PCD8544 para manejar el LCD, pero tienen un problema, no funcionan con versión 1.0.5, que es la que tengo instalada, por lo que he utilizado otra forma. En la página oficial de arduino existe un ejemplo, http://playground.arduino.cc/Code/PCD8544 , el cual le he adaptado a mi programa.
Como podemos observar en las características del LCD 3310, debe funcionar a 3.3V, y las salidas del arduino funcionan a 5V. He visto varios montajes utilizando resistencias, pero  en uno  decía que el LCD podía funcionar a 5V, pero el Led de iluminación solo se podía poner a 3.3V, y eso es lo que he hecho. A pesar de lo que dice el fabricante funciona a 5V, no se por cuanto tiempo. Hemos de pensar que el ATMega328 funciona perfectamente a 3V, por lo cual podemos alimentar todo el conjunto con baterías de 3V.

Programa


Datos técnicos del LCD.



Esquema reloj simple mediante interrupciones.


Montaje
reloj simple mediante interrupciones.


Esquema de reloj mediante DS1302


Montaje
de reloj mediante DS1302



Los dos modos que tiene de tamaño de hora.

He hecho una modificación en el montaje con el DS1302 , para poderlo desbloquear la primera vez que se pone en marcha. Manteniendo pulsados a la vez los dos pulsadores mientras se resetea o se inicia, se desbloquea el
DS1302 , poniendo una fecha determinada.


Hasta pronto.
JUAN GALAZ

Bibliografía:
 http://playground.arduino.cc/Main/DS1302
 http://playground.arduino.cc/Code/PCD8544
 http://www.microsyl.com/index.php/2010/03/24/nokia-lcd-library/
 http://seta43.duckdns.org/electro.html


jueves, 3 de abril de 2014

Viejos montajes Grabador de EPROM - Puerto paralelo LPT1

Página principal

Viejos montajes
Grabador de EPROM
Puerto paralelo LPT1
xsetaseta@gmail.com

 http://seta43.duckdns.org/graba.html
Removiendo papeles en la estantería, he encontrado un viejo montaje de un grabador de memorias EPROM. Este es un montaje desarrollado enteramente por mi, es una utilidad a un anterior circuito,  CONTROLADOR DE 8255 MEDIANTE PUERTO PARALELO, STANDARD O BIDIRECCIONAL, port.htm.
A finales de los años 80 realice un montaje para el Spectrum que venía en un revista, pedí la placa por correo, y lo monté, en algún cajon aún existe, en aquel tiempo me sirvió para hacer montajes con el Z80.
El borrado era mediante rayos ultravioletas, también me compre un tubo de rayos ultravioletas. Los rayos ultravioletas se utilizan en algunas peluquerías para matar bichos, y son peligrosos si se miran directamente, puedes perder vista.
Ya con los años las memorias EPROM que tenían diferentes voltajes de programación, se fueron sustituyendo por las EEPROM que se podían borrar eléctricamente, ya no hacía falta la pequeña ventanilla para borrarlos mediante (UV).
Pero eso es otra historía, el montaje se quedo en programador EPROM, con visos de hacer un programador de EEPROM.
Realice varios programas en Turbo C, para las diferentes modelos de EPROM 2K, 4K, 8K, etc...
Existen muchos tipos de EPROM, para programar un tipo de memoria debemos mirar la hoja del fabricando y ajustar el voltaje de programación.

Aquí muestro todos los planos, imágenes y programas.

Programas

Pulsar para zoom.
Grabador montado con alguna modificación.

.
Pulsar para zoom.
Esquema

.
Pulsar para zoom.
Segundo prototipo

.
Pulsar para zoom.
Primer prototipo

.
Pulsar para zoom.
Tipos de memoria


Saludos
Juan Galaz



lunes, 17 de marzo de 2014

Frecuencímetro 16f648. Interface serie-usb. Programación Basic.

Página principal

Frecuencímetro 16f648.

Interface serie-usb.

Programación Basic.

xsetaseta@gmail.com

Estamos otra vez aquí con otro frecuencímetro, este es una continuación del frecupl2.html, esta vez la visualización se realiza en el PC.
El 16F648 se configura como un medidor de frecuencia con autorango, y la medida se manda a través de un interface serie-usb, donde en el PC se visualiza la frecuencia.
La diferencia entre el montaje original y este, aparte de la eliminación del LCD y la eliminación del pulsador de cambio de escala, es la utilización de un cristal de 16MHz. La alimentación de 5V la toma del  propio USB, con lo cual solo es pinchar y usar.
Para las diferentes pruebas he utilizado como medida el propio reloj del PIC a 16MHz.
La programación esta hecha en C mediante el compilador CCS. Se utiliza la emulación por software de la interface serie.
En principio la programación en el lado del PIC no fue difícil se hizo relativamente rápido. Para la visualización se utilizó en un principio un terminal de serie como el cutecom en linux. El funcionamiento era correcto pero poco vistoso, por lo que decidí hacer un programa especifico. Aquí tuve la disyuntiva de hacerlo en C que era lo lógico, o retornar al pasado, y volver mis inicios en la programación, el Basic.
Navegando por la red encontré la página http://basic.mindteq.com donde  hace una recopilación de los diferentes interpretes y compiladores de Basic que existen.
Probando uno y probando otro he realizado varios programas de visualización de frecuencia con diferentes compiladores de Basic. Por lo que este montaje se a convertido en un ejercicio de programación Basic.


Esquema del circuito y su simulación



Montaje del circuito en placa Board.



Adaptador Serie-Usb.  En mi caso es un PL2303 Serial Port.
En windows hace falta drivers, linux ya los tiene.

Programa del PIC


Programación en Basic

El primer basic que probé fue el Freebasic  , es un programa que compila programas hechos en Basic, Puede tener un alto nivel de compatibilidad con QuickBASIC. Existen versiones para Windows y Linux y está bastante bien documentado y extendido. He realizado dos programas uno para consola y otro con interface gtk.

Programa en Freebasic consola.


Programa en Freebasic gtk.

Rapidq
Es un buen programa de compilación de basic, existe versiones para Windows y Linux, en este caso el programa lo he hecho para Windows. Es muy fácil de utilizar con entorno ide.

Programa en Rapidq para windows.

Purebasic
Es el único programa propietario usado, tiene versiones para diferentes plataformas.
Te permite usarlo gratis para un numero bajo de líneas de programa, suficiente para nuestro propósito.
Completo y fácil de usar.


Gambas_3
Es un entorno de desarrollo de basic, muy completo, bastante parecido a Vbasic, muy bueno, para hacer programas de todo tipo, bases de datos, juegos, etc... El único pero,  es que debes tener instalado las librerías para su funcionamiento, y que de unas versiones a otras debes de recopilar los programas.


Todos los programas en basic



Saludos
SETA43

Juan Galaz


Bibliografía:

http://basic.mindteq.com
Freebasic 
http://gambas.sourceforge.net/en/main.html
http://rapidq.phatcode.net/download/
http://www.purebasic.com/



sábado, 1 de febrero de 2014

Arduino reproductor de voz mediante tarjeta SD - Interface LCD

Página principal

Arduino reproductor de voz mediante tarjeta SD

Interface LCD

wav - 8bits -11KHz

xsetaseta@gmail.com

Continuando con mi anterior montaje  Arduino reproductor de voz mediante SD, ahora realizo un interface mediante 2 botones, un potenciómetro y un LCD.
La elección del potenciómetro para seleccionar las canciones es un motivo práctico, de fácil realización y sencillo.
Mediante el potenciómetro seleccionamos las canciones que deben estar creadas en la SD como números del 0 al 63 y con la extensión wav , ejemplo: 1.wav . Para su reproducción pulsamos el botón PLAY y para parar el botón STOP.
Las canciones tienen que estar en formato wav, mono , resolución 8bits y con una frecuencia de 11KHz.
En este formato cada minuto ocupa 0.65M, con lo cual con una tarjeta de 4G  tendremos 6153 minutos, unas 102 horas.
La tasa de frecuencia de muestreo de 11KHz es suficiente para la reproducción de voz .

Esquema del circuito.


Montaje del circuito.

Vídeo del funcionamiento



Muestra de una señal de 500Hz.


//SETA43
//xsetaseta@gmail.com
//arduvoc  Reproductor de audio con arduino
//01/02/2014


#include <LiquidCrystal.h>

LiquidCrystal lcd(7,6,5,4,3,2);

int sensorValue ;
int oldsensorValue=-1;

#include <SD.h>
File dataFile;

String inputString = ""; 
char fileplay[20] ;
boolean stringComplete = false; 

byte valor;
byte bufer0[100];
byte bufer1[100];
int din=0;
int dout=0;
byte nf=0;
byte vacio=1;
byte fin=1;

byte e1Pin=18;
byte e2Pin=19;

void setup()
{
  lcd.begin(16, 2);
  pinMode(9, OUTPUT); //Salida audio

 // pinMode(4, OUTPUT);    // si utilizamos la salida 4 como CS de la tarjeta SD
 // if(!SD.begin(4)){    // 
   pinMode(10, OUTPUT);    // si utilizamos la salida 4 como CS de la tarjeta SD
  if(!SD.begin(10))
  {
    lcd.print("ERROR Tarjeta ");    // Texto informativo
    return;
  }
  else
  {
    lcd.print("Tarjeta OK ");    // Texto informativo
  }   
  delay(900);
  lcd.clear();
  lcd.print("Arduino VOC");
  delay(500);
  lcd.clear();
   
 cli();//stop interrupts

  //timer1 PWM 31KHz
  TCCR1A = 0x81;
  TCCR1B = 0x01;
  OCR1A = 255;
  TIMSK1=0;

  //set timer2 interrupt at 11kHz
  TCCR2A = 0;
  TCCR2B = 0;
  TCNT2  = 0;
  OCR2A = 182;
  TCCR2A =2;
  TCCR2B =2;     
  TIMSK2=2;
 
sei();//allow interrupts
 
}
//end setup


ISR(TIMER2_COMPA_vect)  //timer1 interrupt 11kHz toggles
{
 if(fin==0)
  {
  if(nf==0)
    valor=bufer1[dout];
   else
    valor=bufer0[dout];
   
  dout++;
  if(dout>99)
    {
     vacio=1;
     dout=0;
     if(nf==1)
       nf=0;
      else
       nf=1;      
    } 
  OCR1AH = 0;
  OCR1AL = valor;    
  }
}


void loop()
{
    if(!digitalRead(e2Pin))
        {
         clearBuffer();        
         lcd.clear();
         lcd.setCursor(0, 0); lcd.print("PLAY WAV "); lcd.print(inputString);
         inputString.toCharArray(fileplay,19);
         dataFile.close();
         dataFile = SD.open(fileplay,FILE_READ);
         //dataFile = SD.open("11.wav",FILE_READ);
         while(!digitalRead(e2Pin));
         if (dataFile)
          {          
           for(din=0;din<200;din++) dataFile.read(); //quita 200 bytes del wav
           fillBuffer(); 
           fin=0;         
          }
          else
          {
           lcd.setCursor(0, 0); lcd.print("NO   WAV ");          
          }                           
        }
       
    if(!digitalRead(e1Pin))
        {           
         clearBuffer();
         dataFile.close(); 
         lcd.setCursor(0, 0); lcd.print("STOP WAV ");  
         while(!digitalRead(e1Pin));        
        }

  sensorValue = analogRead(A0)>>4;
  if(oldsensorValue != sensorValue)
    {
    inputString=String(sensorValue,DEC);
    inputString+=".wav";
    lcd.setCursor(0, 1);
    lcd.print(inputString);
    lcd.print("    ");
    }
  oldsensorValue = sensorValue;
  fillBuffer();
}


//Borrar buffer
void clearBuffer()
{
   fin=1;
   for(din=0;din<100;din++){ bufer0[din]=128;  bufer1[din]=128;} //vacia bufer
}

//llenado de buffer
void fillBuffer()
{  
  if(vacio == 1 && fin == 0)
    {    
     if(nf==0)
       for(din=0;din<100;din++) bufer0[din] = dataFile.read();
      else
       for(din=0;din<100;din++) bufer1[din] = dataFile.read();
      
     vacio=0;
     if(!dataFile.available())
       {
         lcd.setCursor(0, 0); lcd.print("END  WAV ");
         fin=1;
         for(din=0;din<100;din++){ bufer0[din]=128;  bufer1[din]=128;} //vacia bufer        
       }
    }  
}

Código fuente.




Saludos
Juan Galaz



Bibliografía:
http://ravc00cs.blogspot.com.es/2012/07/pwm.html
https://github.com/TMRh20/TMRpcm/wiki
http://apcmag.com/arduino-project-5-digital-audio-player.htm
http://arduino-info.wikispaces.com/Arduino-PWM-Frequency
http://hykrion.com/?q=node/153
http://arduino.cc/es/Tutorial/SecretsOfArduinoPWM



lunes, 27 de enero de 2014

Arduino reproductor audio



Arduino reproductor de voz mediante tarjeta SD

wav - 8bits -11KHz

xsetaseta@gmail.com

El arduino da muchas satisfaciones, la documentación que tiene y sus librerías le hacen totalmente manejable para distintos montajes, es camaleónico. Creo que su secreto es la documentación de su microcontrolador y la facilidad de programación de su entorno. Su entorno de programación basado en java es  un  tanto simple, y quizas sea esa la base de su éxito.
En este montaje realizo un reproductor de voz. En una tarjeta SD almaceno ficheros wav en un formato de 8bits y con  una frecuencia de 11KHz. Mediante la consola serie escribo el nombre del fichero a reproducir, y el arduino lo reproduce si existe.
Una de las pocas cosas que no dispone el arduino es un conversor de D/A de serie, no conozco el motivo, los  micros PIC tampoco lo llevan, debe ser un  problema de fabricación para rebajar costes. Lo mas fácil para hacer un conversor D/A sería mediante una serie de resistencias, esto implica un circuito de 16 resistencia.

Como queremos hacer un circuito lo mas sencillo posible, utilizaremos la técnica de modulación por anchura de pulso PWM (Pulse-Width Modulation) .  Consiste como dice el hombre, modular el ancho del pulso para conseguir un voltage de salida dependiendo de la anchura del pulso. En la salida colocamos un condensador a modo de filtro para conseguir una salida analógica mas real.


Una vez explicada la teoría del conversor D/A por ancho de pulso, vamos a implementarlo mediante el microcontrolador ATMEGA328.
Existen varias librerías que realizan la reproducción de un fichero wav mediante el arduino como por ejemplo TMRpcm. Pero resultó que funcionaba en el arduino mega pero no en el  arduino diecimila, no se el motivo.
 Ante esta situación decidí realizar toda la programación, y de esta forma aprender un poco de PWM.

Para la generación de la frecuencia patrón del  PWM he utilizado el timer1 con salida al Pin 9 de arduino.
Se genera una frecuencia de 31KHz por medio del timer1. Viene muy bien explicado en la página web:
http://ravc00cs.blogspot.com.es/2012/07/pwm.html

Página 134 ATmega328
Se colocan los registros del timer1 con los siguientes valores:
TCCR1A = 0x81; // seleccion del contador. PWM, Phase Correct, 8-bit  
TCCR1B = 0x01; // prescaler = 1, clkI/O/1 (No prescaling)

TIMSK1=0;      //habilita cualquier interrupción.
Ahora ya tenemos una señal de 31KHz en la salida 9 del arduino que podemos modificar el ancho del pulso cambiando el valor del registro   OCR1A .

Para poder generar en tiempo real sonido a una tasa de muestras de 11KHz, debemos modificar el registro OCR1A 11000 veces por segundo. Esto lo realizamos generando una interrupción  11000 veces por segundo, esto lo conseguimos mediante el timer2 del ATMEGA328.
Página 158 ATmega328
Se colocan los registros del timer2 con los siguientes valores:
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  OCR2A = 182;// = (16*10^6) / (11000*8) - 1 (must be <256)  11khz 
  TCCR2A |= (1 << WGM21);
// turn on CTC mode 
  TCCR2B |= (1 << CS21); 
// Set CS21 bit for 8 prescaler    
  TIMSK2 |= (1 << OCIE2A);
// enable timer compare interrupt

En el vector de interrupción ISR(TIMER2_COMPA_vect) colocamos el programa que modifica el registro OCR1A, según el valor que nos proporciona en cada instante el fichero wav.

Como la lectura de la SD requiere un tiempo, y los datos para actualizar el registro OCR1A deben ser inmediatos, debemos crear un doble buffer donde almacenar los datos para que su disponibilidad sea inmediata.

//SETA43 21/01/2014
// xsetaseta@gmail.com
// reproductor de wav desde tarjeta SD
// wav 11kHz mono
// Arduino Diecimila

#include <SD.h>
File dataFile;

String inputString = "";  
char fileplay[20] ;
boolean stringComplete = false;  

byte valor;
byte bufer0[100];
byte bufer1[100];
int din=0;
int dout=0;
byte nf=0;
byte vacio=1;
byte fin=1;

void setup()
{
  
  Serial.begin(9600);  
  inputString.reserve(50);
  
  pinMode(9, OUTPUT);
 
 // pinMode(4, OUTPUT);    // si utilizamos la salida 4 como CS de la tarjeta SD
 // if(!SD.begin(4)){    //  
   pinMode(10, OUTPUT);    // si utilizamos la salida 4 como CS de la tarjeta SD
  if(!SD.begin(10))
  {
    Serial.println("Tarjeta erronea o no insertada");    // Texto informativo
    return;
  }
  else
  {
    Serial.println("Tarjeta OK");    // Texto informativo
  }
  
cli();//stop interrupts

TCCR1A = 0x81;
TCCR1B = 0x01;
OCR1A = 255;
TIMSK1=0;

//timer interrupts
//by Amanda Ghassaei
//set timer2 interrupt at 11kHz
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  OCR2A = 182;// = (16*10^6) / (11000*8) - 1 (must be <256)  11khz
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);      
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
}//end setup


ISR(TIMER2_COMPA_vect)
{
  //timer1 interrupt 11kHz toggles
  if(nf==0) valor=bufer1[dout];
  if(nf==1) valor=bufer0[dout];
  dout++;
  if(dout>99)
    {
     vacio=1;
     dout=0;
     if(nf==1)
       nf=0;
      else
       nf=1;       
    }  
  OCR1AH = 0;
  OCR1AL = valor;     
  //PORTC= valor;
}

void loop()
{
  
  if(vacio == 1 && fin == 0)
    {     
     if(nf==0) for(din=0;din<100;din++) bufer0[din] = dataFile.read();
     if(nf==1) for(din=0;din<100;din++) bufer1[din] = dataFile.read();
     vacio=0;
     if(!dataFile.available())
       {
         Serial.println("Fin de cancion");
         for(din=0;din<100;din++){ bufer0[din]=128;  bufer1[din]=128;} //vacia bufer
         fin=1;
       }
    }
    
  if (stringComplete)
    {
     inputString.toCharArray(fileplay,19);
     fileplay[inputString.length()-1]=0; //clear \n
     if(strcmp(fileplay, "stop")  == 0)
       {
         Serial.println("Stop cancion");
         for(din=0;din<100;din++){ bufer0[din]=128;  bufer1[din]=128;} //vacia bufer
         dataFile.close();
         fin=1;         
       }
       else
       {
        inputString.toCharArray(fileplay,19);
        fileplay[inputString.length()-1]=0;
        dataFile.close();
        dataFile = SD.open(fileplay,FILE_READ);
        if (dataFile)
          {
           Serial.print("OK ");
           for(din=0;din<1000;din++) dataFile.read(); //quita 1000 bytes del wav
           fin=0;
          }
          else
          {
           Serial.print("Error ");
          }
          Serial.println(fileplay);
       }      
    inputString = "";
    stringComplete = false;
   }    
}

void serialEvent()
{
  while (Serial.available())
   {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n')   stringComplete = true;
   }
}

El código fuente no está optimizado ni nada, es un ejercicio de programación rápida que funciona.
El programa no hace ninguna comprobación de tipo de fichero wav, ni de tasa de muestreo  ni de resolución de bits, solo toma el fichero de la SD, quita los 1000 primeros bytes y los vuelca en el conversor D/A a una tasa de muestreo de 11KHz.

En la salida, pin 9 del arduino,  sale la señal de audio que se filtra mediante un condensador.

La tarjeta SD funciona a 3,3V, y como el arduino funciona a 5V debemos hacer adaptar la entradas y salidas. Para no complicar el circuito y no gastarnos dinero en un adaptador, lo realizo con resistencias.
Es fácil y normalmente funciona bien.


Esquema eléctrico.


Circuito eléctrico montado en un adaptador de SD a MicroSD.


Diagrama del filtro de audio.




Circuito montado y funcionando.

Video del funcionamiento



Para la conversión y edición  de ficheros wav, utilizo el programa audacity.


Conversor de audio con audacity.

En el siguiente circuito crearé un interface desde el arduino para manejar los ficheros wav.

Saludos
Juan Galaz



Bibliografía:
http://ravc00cs.blogspot.com.es/2012/07/pwm.html
https://github.com/TMRh20/TMRpcm/wiki
http://apcmag.com/arduino-project-5-digital-audio-player.htm
http://arduino-info.wikispaces.com/Arduino-PWM-Frequency
http://hykrion.com/?q=node/153
http://arduino.cc/es/Tutorial/SecretsOfArduinoPWM