Go Down

Topic: Creación de Audiómetro con Arduino UNO  (Read 2973 times) previous topic - next topic

surbyte

Cuando me refiero a las tablas hablo de algo asi.

Aca una tabla con 256 valores para un dac de 8 bits.
Esto esta pensado para una salida PWM que genera una senoide por filtrado. No es tu caso!!!
Pero sirve para que veas como hacerlo.
Modifica este código usando tu DAC, y aprovecha el uso del TIMER que en este caso corre a 31k que por 256 te dara 32us x 256 = 8192 useg o sea 8.192 mseg = 122 Hz

Code: [Select]
// table of 256 sine values / one sine period / stored in flash memory
const byte sine256[] PROGMEM = {
  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

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

int ledPin  = 13;                 // LED pin 7
int testPin = 7;
int t2Pin   = 6;
byte bb;

double dfreq;
// const double refclk=31372.549;  // =16MHz / 510
const double refclk=31376.6;      // measured

// variables used inside interrupt service declared as voilatile
volatile byte icnt;              // var inside interrupt
volatile byte icnt1;             // var inside interrupt
volatile byte c4ms;              // counter incremented all 4ms
volatile unsigned long phaccu;   // pahse accumulator
volatile unsigned long tword_m;  // dds tuning word m

void setup()
{
  pinMode(ledPin, OUTPUT);      // sets the digital pin as output
  Serial.begin(115200);        // connect to the serial port
  Serial.println("DDS Test");

  pinMode(6, OUTPUT);      // sets the digital pin as output
  pinMode(7, OUTPUT);      // sets the digital pin as output
  pinMode(11, OUTPUT);     // pin11= PWM  output / frequency output

  Setup_timer2();

  // disable interrupts to avoid timing distortion
  cbi (TIMSK0,TOIE0);              // disable Timer0 !!! delay() is now not available
  sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

  dfreq=1000.0;                    // initial output frequency = 1000.o Hz
  tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word

}
void loop()
{
  while(1) {
     if (c4ms > 250) {                 // timer / wait fou a full second
      c4ms=0;
      dfreq=analogRead(0);             // read Poti on analog pin 0 to adjust output frequency from 0..1023 Hz

      cbi (TIMSK2,TOIE2);              // disble Timer2 Interrupt
      tword_m=pow(2,32)*dfreq/refclk;  // calulate DDS new tuning word
      sbi (TIMSK2,TOIE2);              // enable Timer2 Interrupt

      Serial.print(dfreq);
      Serial.print("  ");
      Serial.println(tword_m);
    }

   sbi(PORTD,6); // Test / set PORTD,7 high to observe timing with a scope
   cbi(PORTD,6); // Test /reset PORTD,7 high to observe timing with a scope
  }
 }
//******************************************************************
// 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
  sbi (TCCR2B, CS20);
  cbi (TCCR2B, CS21);
  cbi (TCCR2B, CS22);

  // Timer2 PWM Mode set to Phase Correct PWM
  cbi (TCCR2A, COM2A0);  // clear Compare Match
  sbi (TCCR2A, COM2A1);

  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) {

  sbi(PORTD,7);          // Test / set PORTD,7 high to observe timing with a oscope

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

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

  cbi(PORTD,7);            // reset PORTD,7
}


Todo lo que sea PORTD y su pin 7 debes reemplazarlo por tu dac

Referencia Arduino DDS Sinewave Generator

Arduino DDS Sinewave Generator

BryannLuna

¡Perfecto!, intentaré realizar la adaptación al DAC.

Una duda, con el AD9850,  ¿es posible modelar la amplitud de la onda mediante código para suplir al potenciometro?. Si es posible y estoy entendiendo bien, se tendría que dividir el número de puntos que otorga el potenciometro (1024) entre la máxima amplitud de la onda en volts verdad?. Para ir indicando en código cuanto sería la máxima amplitud (1024 = 5v), etc. Saludos!

BryannLuna

¡Hola buen día!, como bien dice el título, busco una de manera controlar la amplitud (volumen o ganancia) de una señal senoidal generada a través de un DDS AD9850 mediante Arduino. Recientemente adquirí el DDS y con la documentación y ejemplos que encontré en internet logré representar las frecuencias deseadas pero me topé con el problema de la amplitud. Se me ocurría utilizar algún tipo de amplificador operacional pero lo que quiero es controlar el volumen mediante programación sin necesidad de utilizar potenciometros.


EDIT: Utilizo la conexión serial del computador por lo que mi máxima amplitud rms generada es aproximadamente 3.7v de salida del arduino, pero el AD9850 solo maneja un voltaje pk-pk de 1v y genera en rms 700mv aproximadamente si mal no leí. Tendría que amplificar el voltaje de salida y posteriormente manipularlo digitalmente.

Adjunto las imágenes del proyecto.








attiny128

#18
Oct 23, 2018, 01:38 am Last Edit: Oct 23, 2018, 07:45 am by attiny128
Quote
Tendría que amplificar el voltaje de salida y posteriormente manipularlo digitalmente.
Hazlo como tu quieras.

BryannLuna

#19
Oct 23, 2018, 07:14 am Last Edit: Oct 23, 2018, 07:18 am by BryannLuna
No.  Lo que deberías hacer es colocar el control de volumen entre el generador de señal y el amplificador.

Si no quieres usar un control manual puedes usar unpotenciómetro digital, en tu caso dos, X9C103P con su librería llamada DigiPotX9Cxxx y usar sus funciones pot.reset, pot.set, pot.get, pot.increase, pot.decrease. Saludos
¿No sería mejor amplificar primero la señal y después modificar la amplitud de la señal misma amplificada?.

Ya que el voltaje de salida del DDS es de máximo 2v (1v pk-pk), el amplificador que pienso utilizar (LM386) no lee potencias tan bajas, si regulo la potencia antes de amplificarla puede ser que ni se escuche (según mi razonamiento). En base a lo que me comentaste, lo intenté replicar gráficamente para darnos una idea de lo que se planea.


attiny128

#20
Oct 23, 2018, 07:53 am Last Edit: Oct 23, 2018, 09:06 am by attiny128
Quote
el amplificador que pienso utilizar (LM386) no lee potencias tan bajas.
Tienes razón y Sony, Aiwa, Philips, Pioneer se equivocan al poner el potenciómetro antes del amplificador.

No debe ser una exageración si digo que debe haber en el mundo 200 millones de parlantes de computadoras de escritorio con el LM386 y el potenciómetro va antes del amplificador.

surbyte

#21
Oct 23, 2018, 03:54 pm Last Edit: Oct 23, 2018, 03:56 pm by surbyte
Ademas de lo que te dice @attiny128, vamos a la lógica.
El LM386 esta preparado para la impedancia de carga de algo como parlantes/Auriculares pero en cambio el X9C103P es un divisor digital resistivo, tu crees que puede manejar cualquier tensión y cualquier impedancia de carga? Claro que no.

Fueron diseñados para las etapas preamplificadoras, tensiones de entrada hasta cierto nivel y no mas.
No para cualquier situación. Todos los elementos electrónicos tienen restricciones.

La hoja de datos siempre responde estas preguntas con mucha facilidad.
Es un buen ejercicio, lucirá abrumador al comienzo pero con paciencia se encuentra la respuesta seas o no electrónico.

BryannLuna

#22
Oct 25, 2018, 03:58 am Last Edit: Oct 25, 2018, 04:05 am by BryannLuna
Bueno chicos, me dí a la tarea de implementar el amplificador LM386N-1 con un potenciometro de 10k (aún no consigo el digital) y aquí les dejo mis resultados.

(La señal azul proviene del DDS y la amarilla del Amp)

En esta imagen se puede apreciar poca amplitud ya que manipulaba valores bajos desde el potenciometro:



En esta imagen se puede apreciar mayor amplitud en la onda pero se percibe una pequeña deformación en la senoidal (aún busco la razón, en esta imagen no se tenía conectado el potenciometro):



En esta última imagen se aprecia ruido en la señal (y aumento de frecuencia debido al ruido) al conectarlo a un speaker de 8ohm 0.5w, quiero suponer que el ruido es debido a la impedancia que el altavoz está manejando:



Cabe recalcar que la configuración del LM386 está a x20 y no a x200 de ganancia.

Como les comenté, sigo en busca del potenciometro digital y @attiny128 tenías razón, el mismo datasheet del LM386 solicita el potenciometro antes de la etapa amplificadora, te pido una disculpa si insulté tu razonamiento pero gracias por aclararme las ideas. Un saludo a todos!, en un par de horas o días subo el esquema de conexiones para futuras consultas una ves solucione lo del ruido a la impedancia y sobre todo, modifique el amplificador para aumentar a x200.

BryannLuna

¡Hola buen día chicos!, he vuelto, ésta vez con un problema en el X9C103P que me han recomendado para manipular la amplitud de la señal antes de la etapa amplificadora del audiometro.

He seguido el tutorial de Panamahitek al pie de la letra, realicé las conexiones de la salida del AD9850 (+) al X9C103P (Vcc) y al momento de medir la resistividad e intentar variarla mediante código no funciona, inclusive he conectado el voltaje directo desde el Arduino (5v a Vcc) para intentar probar el código haciendo funcionar únicamente el X9C103P pero las pruebas han sido sin éxito. Cabe mencionar que se utiliza la librería Digipot, no se si es falta de actualización o error en las conexiones. ¿Alguien ha tenido un problema similar?. Saludos!

surbyte

Como lo estas probando? montado en un protoboard?
Verifica con el tester/multímetro las conexiones desde el arduino que uses al integrado. Toca el pin del arduino contra el pin del integrado. No compruebes contra alguno de las posibles conexiones del protoboard.

BryannLuna

Así es, lo tengo montado en una protoboard, en la misma donde probé el amplificador LM386. Verifico la salida de la señal del DDS (+) que es de 1v (en el datasheet del X9C103P se indica que soporta voltajes mínimos de 0.4v hasta 7v pero este no es el caso ya que aun que conecte la salida de 5v del Arduino igual no funciona) y la que entra por el pin 8 del X9C103P (Vcc) y el voltaje entra correctamente, existe una salida pero esta salida no mantiene la forma senoidal y mucho menos la resistividad, pues la resistividad al medirla con el multimetro es nula, igual montando una instalación limpia y única del X9C la falla continúa, algo me dice que va mas por el tema del código que físico ya que aunque la resistividad sea nula al intentar manipularla, su origen me marca 0.30kOhms (tomando en cuenta que es de 10k) y los pasos que doy con el Arduino no logran manipular la señal.


surbyte

#26
Nov 26, 2018, 04:24 pm Last Edit: Nov 26, 2018, 04:25 pm by surbyte
No funciona como un potenciometro resistivo asi que no esperes lecturas de continuidad como cuando mides los 3 contactos de un potenciómetro.

Algo anda mal con la librería.
Usas la del enlace que has comentado?

Prueba esta Arduino-X9C a ver cmo se comporta

BryannLuna

#27
Nov 26, 2018, 06:58 pm Last Edit: Nov 26, 2018, 07:03 pm by BryannLuna Reason: Imagenes
Al parecer teníamos razón, la librería parece estar desactualizada y no manda órdenes correctamente al X9C. Ahora he logrado medir mediante el multimetro los valores que el X9C arroja en los pines 3, 5 y 6 respectivamente.

Te muestro el diagrama que llevo hasta el momento, pues he conectado de la siguiente manera el equipo no logrando que la amplitud se vea modificada por el potenciometro. Creo que me he hecho un poco bolas al leer el datasheet del pot. Adjunto el código y la imágen que he desarrollado hasta el momento.



Code: [Select]
#include <X9C.h>

//X9C
#define INC 2   // D1 Mini D4 - pulled up in H/W (10k) ->  chip pin 1
#define UD 3   // D1 Mini D8                          ->  chip pin 2
#define CS 4   // D1 Mini D0 - pulled up in H/W (10k) ->  2nd chip pin 7

//DDS
#define W_CLK 8       // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9       // Pin 9 - connect to freq update pin (FQ)
#define DATA 10       // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11      // Pin 11 - connect to reset pin (RST).

#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
X9C pot;

char Caracter;
String Cmd;
int in;

void tfr_byte(byte data)
{
  for (int i = 0; i < 8; i++, data >>= 1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);  
  }
}
void sendFrequency(double frequency) {
  int32_t freq = frequency * 4294967295 / 125000000;
  for (int b = 0; b < 4; b++, freq >>= 8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);
  pulseHigh(FQ_UD);
}

void setup() {
  Serial.begin(9600);

  pot.begin(CS, INC, UD);

  pinMode(FQ_UD, OUTPUT);
  pinMode(W_CLK, OUTPUT);
  pinMode(DATA, OUTPUT);
  pinMode(RESET, OUTPUT);

  pulseHigh(RESET);
  pulseHigh(W_CLK);
  pulseHigh(FQ_UD);
}

void loop() {
  pot.setPot(10, false);
  pot.setPotMin(false);          
  sendFrequency(1000);



Datasheet X9C103P

surbyte

Mi consejo es que separes los tantos.

Primero asegurate que funciona el X9C y luego lo integras al DDS sino doble problema.

Coloca 5V al X9C y verifica con el tester/multimetro que sale lo que se supone debe salir.


BryannLuna

Correcto, está funcionando correctamente el potenciometro! Solo es cuestión de saber jugar con las medidas y los pasos. Ahora sigo enfrentando el mismo problema con la onda senoidal proveniente del DDS

Go Up