miércoles, 8 de mayo de 2013

Analizador lógico (analógico) | Logic analyzer (analog)

Para leer un canal analógico la cosa cambia. No podemos leer el puerto completo, tenemos que leer un pin analógico y esperar a que el microcontrolador haga la conversión del voltaje de entrada a un valor numérico legible. Por defecto, Arduino utiliza el prescaler del reloj del conversor analógico-digital con un valor de 128, que significa que el reloj ADC trabajará a una frecuencia de 125KHz.

    16 MHz / 128 = 125 KHz

Esto lo podemos ver en el archivo "Arduino \hardware\arduino\cores\arduino\wiring.c"
To read an analog channel things change. We can't read the full port, we have to read an analog pin and wait for the microcontroller do the conversion of the input voltage to a numerical value. By default, Arduino uses ADC clock prescaler with a value of 128, which means that the ADC clock work at a frequency of 125KHz.

    16 MHz / 128 = 125 KHz

This can be seen in the "Arduino\hardware\arduino\cores\arduino\wiring.c"

#if defined(ADCSRA)
 // set a2d prescale factor to 128
 // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
 // XXX: this will not work properly for other clock speeds, and
 // this code should use F_CPU to determine the prescale factor.
 sbi(ADCSRA, ADPS2);
 sbi(ADCSRA, ADPS1);
 sbi(ADCSRA, ADPS0);

 // enable a2d conversions
 sbi(ADCSRA, ADEN);
#endif


Si miramos el datasheet de ATmega328, en la página 263, en el punto 23.9.2 podemos ver la siguiente tabla:
Looking at ATmega328 datasheet, on page 263, in section 23.9.2 we can see the following table:


7 6 5 4 3 2 1 0
ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0


Donde ADPSx son los 3 bits que corresponden al valor del prescaler del reloj. En la página siguiente (264), en la tabla 23-5, podemos ver qué valor debemos asignar a cada bit para establecer el factor de división:
Where ADPSx are 3 bits corresponding to the clock prescaler value. On the next page (264), Table 23-5, we can see what value we have to assign each bit to set the division factor:


ADPS2 ADPS1 ADPS0 Division factor
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128


Una lectura ADC tarda aproximadamente 13 ciclos (pag 263), necesitamos un valor de prescaler que nos asegure velocidad a la vez que fiabilidad en el resultado. Si usamos un prescaler de 16, tenemos 76923 lecturas por segundo:
ADC read takes about 13 cycles (p 263), we need a prescaler value that assures us speed and reliability in the result. If we use a prescaler of 16, we have 76923 scans per second:


    16000000 / 16 = 1000000
    1000000 / 13 = 76923

 sbi(ADCSRA, ADPS2);
 cbi(ADCSRA, ADPS1);
 cbi(ADCSRA, ADPS0);


El tiempo total de la ejecución de lectura puede ser variable, así que lo mejor es leer el tiempo total y enviarlo también por puerto serie. Como en el modo digital hemos utilizado un buffer de 1800 bytes y sabiendo que la lectura analógica retorna un valor entero de 2 bytes y que el tiempo en microsegundos es un entero largo sin signo, sabemos que podremos llegar a leer 898 valores:
The total execution time for reading can be variable, so the best is to read the total spend time and send it also via serial port. As digital mode we used a buffer of 1800 bytes and knowing that analog reading returns a 2-byte integer value and the time in microseconds is an unsigned long, we know we can get to read 898 values:


    1800 - 4 = 1796
    1796 / 2 = 898


#define DATA 1800
#define DATAA 1796

byte _data[DATA];
unsigned long t;

void setup()
{

  sbi(ADCSRA, ADPS2);
  cbi(ADCSRA, ADPS1);
  cbi(ADCSRA, ADPS0);

  // DEFAULT Analog reference + A0 input pin
  ADMUX = (DEFAULT << 6); // | (pin & 0x07);

}

void ReadAnalog()
{

  t = micros();

  for(i=0; i<DATAA; i+=2)
  {

    /*** From wiring_analog.c ***/

    // start the conversion
    sbi(ADCSRA, ADSC);

    // ADSC is cleared when the conversion finishes
    while (bit_is_set(ADCSRA, ADSC));

    // we have to read ADCL first; doing so locks both ADCL
    // and ADCH until ADCH is read.  reading ADCL second would
    // cause the results of each conversion to be discarded,
    // as ADCL and ADCH would be locked when it completed.
    _data[i+1] = ADCL;
    _data[i]   = ADCH;

    /****************************/
    
  }

  t = micros() - t;
  _data[DATA-4] = (byte)(t >> 24);
  _data[DATA-3] = (byte)(t >> 16);
  _data[DATA-2] = (byte)(t >> 8);
  _data[DATA-1] = (byte)(t);

}







PRUEBAS:
TESTS:


Al igual que en el artículo anterior, he programado otra placa Arduino para que genere los datos a leer. Se trata de una onda sinusoidal que oscila entre 0 y 5V.

Si miramos el enlace de la Wikipedia podemos ver la siguiente expresión. Tomamos la fase inicial como 0 (φ). Sabemos que si utilizamos una salida PWM para generar la onda podemos representar 256 valores de 0V a 5V. Así que la amplitud (A) corresponderá a la mitad, 128 (2.5V) y el periodo (T) a 255:
As in the previous article, I have programed another Arduino to generate the data to read. It is a sine wave ranging between 0 and 5V.

If we look at the Wikipedia link we can see the following expression. We take the initial phase as 0 (φ). We know that if we use a PWM output to generate the wave we can represent 256 values from 0V to 5V. So that the amplitude (A) correspond to half, 128 (2.5V) and the period (T) of 255:





Ahora tenemos un valor entre -2.5V y 2.5V, para obtener un valor entre 0V y 5V debemos sumar 2.5V al resultado final. Sabemos que el valor numérico en bytes para 2.5V es 128.
Now we have a value between -2.5V and 2.5V, to obtain a value between 0V and 5V, must add 2.5V to the final result. We know that the numeric value in bytes is 128 for 2.5V.




Para convertir la señal PWM en una señal analógica se utiliza un filtro RC, yo he elegido unos valores un poco a ojo, 1K y 0.47uF.
To convert the PWM signal into an analog signal, must use an RC filter, I have chosen values a little by eye, 1K and 0.47uF.


Ejemplo de conexiones
Example of connections

Esquema
Schematic

Onda sinusoidal
Sene wave
Cambiando 1K por 10K
Changing 1K for 10K





Descargas:
Downloads:

LogicAnalyzer.zip




Enlaces:
Links:

8-bit AVR® Instruction Set (EN): http://www.atmel.com/Images/doc0856.pdf
ATmega 328 (EN): http://www.atmel.com/Images/doc8161.pdf
Sinusoide (ES): https://es.wikipedia.org/wiki/Sinusoide
Sine wave (EN): http://en.wikipedia.org/wiki/Sine_wave




No hay comentarios:

Publicar un comentario