viernes, 20 de enero de 2012

Viejos montajes - Boot loader Z80

Página principal


Viejos montajes - Boot loader Z80

Abriendo un cajón me he encontrado con un viejo montaje que hice en el siglo pasado, sobre 1989. Era la época del Z80, era el micro que llevaba el spectrum, MSX1 y algún otro modelo, fue el rey de los 80. Yo tenía un spectrum donde hacía montajes, controladores PIO, grabadores de EPROM y otros muchos.
Un día me animé  hacer una placa donde incorporaba un Z80,un  Z80PIO, dos memorias  2114 que en total sumaban 1K, y una EPROM 2716 de 2K. Era una placa para hacer unas practicas de programación del Z80. Mi primera práctica era la mas clásica de todas, hacer parpadear un LED colocado en el PIOZ80.

Los pasos para pasar los programas a la EPROM eran los siguientes:
-Realizaba el programa ensamblador en el spectrum.
-Programaba la EPROM en el spectrum mediante un programador casero que me hice.
-Lo quitabas del programador y lo insertaba en la placa.
-Si con suerte te funcionaba bien.
-Pero si no te funcionaba tenías quitar la EPROM de la placa, borrarla mediante una lampara ultravioleta  y volver al primer paso.

Como podéis imaginar se tardaba muchísimo, era todo tedioso.
A la cuarta vez de hacer lo mismo, se te quitaba las ganas de hacer mas prácticas.
Pensando una forma mas fácil de trabajar, llegue a la conclusión, que grabar los programas que querías ejecutar en la EPROM era un atraso. Lo mas fácil era ejecutarlos en la RAM. ¿Pero como poner los programas a ejecutar en la RAM?. Encontré la solución, hacer un programa cargador en la EPROM y que pusiese el programa en la RAM y lo ejecutase. El programa en la EPROM era fijo, no debería volver a tocar la EPROM servía para todos los programas que hiciera.
Retoque un código de un programa que emulaba RS232  y lo adapte al PIOZ80. Era de una revista llamada Micromanía, muchos montajes para el spectrum los saque de allí.
Por aquel entonces tenía un PC con monitor verde. Entre los programas que tenía, había un programa ensamblador cruzado para el Z80. Este lo utilice para crear el fichero binario, y mediante la conexión serie lo mandaba a la placa que lo ejecutaba. Era muy fácil hacer prácticas y los resultados eran casi inmediatos.
Como veréis en el montaje, no existe adaptador RS232 a la entrada PIOZ80, el caso es que en el caso de aquel PC con monitor verde funcionaba sin problemas, cosa que con otros ordenadores no llegó a funcionar.
Imagen del circuito.


Pulsa en el esquema para ampliar.

CODIGO FUENTE DE LA PLACA Z80
CARGA PROGRAMAS DEL RS232-1200BAUDIOS A LA POSICION 8000 Y LO EJECUTA.
0379 3E00                             ld      a, 0                            
037B D33F                             out     (3Fh), a                        
037D D32F                             out     (2Fh), a                        
037F 3EFF                             ld      a, 0FFh ; <void>                
0381 D37F                             out     (7Fh), a                        
0383 3EFE                             ld      a, 0FEh ; '_' ; <void>          
0385 D37F                             out     (7Fh), a                        
0387 3EFF                             ld      a, 0FFh ; <void>                
0389 D36F                             out     (6Fh), a                        
038B 3E00                             ld      a, 0                            
038D D36F                             out     (6Fh), a                        
038F 210080                           ld      hl, 8000h                       
0392 110004                           ld      de, 400h ; <void>               
0395 F3                               di                                     
0396                  loc_0_396: ; <void>                                     
0396                                                          ; CODE XREF: 03C
0396 0E3F                             ld      c, 3Fh ; '?' ; <void>           
0398 0601                             ld      b, 1                            
039A ED41                             out     (c), b                          
039C                  loc_0_39C:
039C                                                          ; CODE XREF: 03A
039C ED78                             in      a, (c)
039E FE03                             cp      3
03A0 20FA                             jr      nz, loc_0_39C
03A2 3E06                             ld      a, 6
03A4                  loc_0_3A4:
03A4                                                          ; CODE XREF: 03A
03A4 3D                               dec     a
03A5 20FD                             jr      nz, loc_0_3A4
03A7 3E00                             ld      a, 0
03A9 ED79                             out     (c), a
03AB 0680                             ld      b, 80h ; 'Ç' ; <void>
03AD                  loc_0_3AD:
03AD                                                          ; CODE XREF: 03B
03AD 3E16                             ld      a, 16h
03AF                  loc_0_3AF:
03AF                                                          ; CODE XREF:
03AF 3D                               dec     a
03B0 20FD                             jr      nz, loc_0_3AF
03B2 ED78                             in      a, (c)
03B4 1F                               rra
03B5 1F                               rra
03B6 CB18                             rr      b
03B8 30F3                             jr      nc, loc_0_3AD
03BA 3E14                             ld      a, 14h
03BC                  loc_0_3BC:
03BC                                                          ; CODE XREF:
03BC 3D                               dec     a
03BD 20FD                             jr      nz, loc_0_3BC
03BF 3EFF                             ld      a, 0FFh ; <void>
03C1 90                               sub     b
03C2 D32F                             out     (2Fh), a
03C4 77                               ld      (hl), a
03C5 23                               inc     hl
03C6 1B                               dec     de
03C7 7A                               ld      a, d
03C8 B3                               or      e
03C9 20CB                             jr      nz, loc_0_396
03CB FB                               ei
03CC 00                               nop
03CD C30080                           jp      unk_0_7CF+7831h
Programa Boot loader grabado en la EPROM

Un saludo.
SETA43

jueves, 19 de enero de 2012

ARDUINO - Grabar el boot loader

ARDUINO - Grabar el boot loader

El otro día me llegaron dos Atmega328, los había pedido para colocarlos en el arduino. El caso es que venían sin el cargador de arduino, normal si son nuevos. ¿Como grabar el boot loader en el Atmega328?. Tengo varios grabadores de ATMEGA, entre ellos uno conectado al USB llamado usbasp de la página:
 http://www.fischl.de/usbasp/
Este montaje lo he construido yo también, y mis experiencias las comente hace unos años en mi página:
 http://seta43.duckdns.org/miATp.html
Como la versión que tengo de Arduino IDE no soporta mi grabador usbasp he tenido que buscar gente que le pasa lo mismo y encontré la página:
http://wolfpaulus.com/tag/atmega168
Explica bastante bien los comandos que tienes que dar al avrdude para grabar el boot loader.
Yo los he cambiado para que me sirvan al mio y aquí los expongo.

avrdude -p m328p  -c usbasp  -V -e -U lock:w:0x3F:m -U hfuse:w:0xD8:m -U lfuse:w:0xFF:m -U efuse:w:0x03:m

avrdude -p m328p  -c usbasp   -V -D -U flash:w:ATmegaBOOT_168_atmega328.hex:i

avrdude -p m328p  -c usbasp  -V -U lock:w:0x0F:m


También expongo el resultado de la consola de avrdude.


root@debian6:/home/seta# avrdude -p m328p  -c usbasp  -V -e -U lock:w:0x3F:m -U hfuse:w:0xD8:m -U lfuse:w:0xFF:m -U efuse:w:0x03:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: erasing chip
avrdude: reading input file "0x3F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lock written
avrdude: reading input file "0xD8"
avrdude: writing hfuse (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of hfuse written
avrdude: reading input file "0xFF"
avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of lfuse written
avrdude: reading input file "0x03"
avrdude: writing efuse (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of efuse written

avrdude: safemode: Fuses OK

avrdude done.  Thank you.



__________________GRABACION DE CODIGO________________


root@debian6:/home/seta# avrdude -p m328p  -c usbasp   -V -D -U flash:w:ATmegaBOOT_168_atmega328.hex:i

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: reading input file "ATmegaBOOT_168_atmega328.hex"
avrdude: writing flash (32670 bytes):

Writing | ################################################## | 100% 154.37s



avrdude: 32670 bytes of flash written

avrdude: safemode: Fuses OK

avrdude done.  Thank you.




__________________VERIFICACION DE CODIGO________________

root@debian6:/home/seta# avrdude -p m328p  -c usbasp   -V -D -U flash:v:ATmegaBOOT_168_atmega328.hex:i

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: verifying flash memory against ATmegaBOOT_168_atmega328.hex:
avrdude: load data flash data from input file ATmegaBOOT_168_atmega328.hex:
avrdude: input file ATmegaBOOT_168_atmega328.hex contains 32670 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 140.54s



avrdude: verifying ...
avrdude: 32670 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done.  Thank you.





root@debian6:/home/seta# avrdude -p m328p  -c usbasp  -V -U lock:w:0x0F:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x1e950f
avrdude: reading input file "0x0F"
avrdude: writing lock (1 bytes):

Writing | ################################################## | 100% 0.02s

avrdude: 1 bytes of lock written

avrdude: safemode: Fuses OK

avrdude done.  Thank you.



Espero que os sirva.
Un saludo.
SETA43

ARDUINO-LLAVE PARA PEUGEOT 306

ARDUINO-LLAVE PARA PEUGEOT 306
El otro día me comento un amigo que tenía que hacer una llave nueva para el coche, era un Megane y le costaba la dichosa llave 100€. A mi me parecía un tanto cara, y me dio  que pensar lo que me costaría la llave de mi coche un Peugeot 306. Mirando por internet vi que mi llave con mando estaba entre 80 y 100€. Desde luego debería tener una gran tecnología para el precio que pedían.
Manos a la obra, vamos a investigar la llave de mi coche.
Abierta la llave podemos ver que tiene un CI de ocho patilla OM1058T, unas resistencias, un transistor y un diodo emisor de infrarrojos.
Bajado las características del OM1058T poco podemos sacar de como programarlo, o de las formas de ondas que emite.
Mediante un osciloscopio podemos averiguar las formas de onda y las características de la señal.
Vemos como existen 72 pulsos a 2 mS y de vez en cuando un pulso a 0,5mS del pulso de 2mS.
Interpreto que si solo existen los pulsos de 2mS es un -0- y si existe un pulso intermedio a 0,5mS es un -1-



Figura donde podemos ver los dos tipos de pulsos.

Figura donde podemos ver un byte de pulsos.
Ahora lo primero es hacer un programa donde nos lea los 72 valores, que corresponde a 9 bytes.

Figura donde podemos observar los 72 bits y los 9 bytes correspondientes.
He borrado mis códigos por seguridad.
Podemos observar que realmente solo son 3 bytes repetidos 3 veces.

Figura donde vemos el circuito receptor de infrarrojos.
El programa realizado en arduino lee los códigos de la llave y los manda por el puerto serie al ordenador.
Debido a que los ladrones pueden utilizar el circuito para robar coches, y ese no es mi propósito, he quitado el código correspondiente a receptor.
En el circuito emisor he montado un pulsador para la emisión del código, un led que hace de piloto de emisión, y un diodo emisor de infrarrojos. Para conseguir distancia en el mando he tenido que utilizar dos transistores en montaje darlintong que proporciona bastante intensidad para los pulsos.

Figura donde podemos ver el circuito emisor de infrarrojos.
Aquí vemos el código fuente del emisor donde debemos poner los códigos de la llave.
// seta - Telemando peugeot 306
//18-12-2011
//xsetaseta@gmail.com

// En la variable datos debemos poner los códigos de la llave
// Deben ser tres bytes repetidos 3 veces
  byte datos[100]={0x00,0x11,0x22,0x00,0x11,0x22,0x00,0x11,0x22};
  byte coche[9];
   
  byte x;
  byte x1;
  byte x2;
  int xx;
  int xx1;
  int xx3;
  int retardo;

void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
 
  pinMode(11, INPUT);
   pinMode(12, INPUT); //devolver codigo  
}

void loop() {
  //Emisor  peugeot
   if (digitalRead(12)==LOW)
    {
      digitalWrite(3, HIGH);    
      for(x=0;x<9;x++)
       {
        x1=datos[x];
        for(x2=0;x2<8;x2++)
          {              
              digitalWrite(6, HIGH);
              for(xx=0;xx<100;xx++);
              digitalWrite(6, LOW);               
            if((x1 & 128))
             {
              for(xx=0;xx<1127;xx++);
              digitalWrite(6, HIGH);
              for(xx=0;xx<100;xx++);
              digitalWrite(6, LOW);              
              for(xx=0;xx<3290;xx++);
             }
             else
             {
              for(xx=0;xx<4526;xx++);
             } 
          x1= x1 << 1; 
         }
      }
      delay(500);
      digitalWrite(3, LOW);
    } 
 }



Conclusión:
El querer cobrar una media de 90 € por una llave es un atraco. La electrónica del mando como mucho 7€, se podría emular con un micro de 8 patillas ATtiny y utilizar el própio reloj interno. Hasta creo que el OM1058T realmente sea un microcontrolador barato, pero eso solo es una suposición.


Circuito de pruebas.

Un saludo.
SETA43

ARDUINO - MANDO A DISTANCIA POR INFRARROJOS

ARDUINO - MANDO A DISTANCIA POR INFRARROJOS

Ya tenemos creado circuitos receptores de infrarrojos, ahora me toca crear un mando a distancia por infrarrojos.
El protocolo utilizado es el SIRCS, utilizado en la mayoría de la televisiones SONY, para las pruebas solo voy a poner un pulsador de subir volumen(código 18). El que quiera ampliar el circuito para gobernar mas cosas deberá modificar el circuito colocando pulsadores para las diferentes funciones.
Para consultar los códigos de las televisiones SONY ver la página http://www.hifi-remote.com/sony/Sony_tv.htm.
El formato que debemos generar es el siguiente:


Además debemos poner los datos en una portadora de 40KHz.
En un principio iba a utilizar un 555 para generar la portadora de 40KHz, pero después de visitar la página http://tthheessiiss.wordpress.com/2009/08/05/dirt-cheap-wireless/, vi que era posible generar los 40KHz mediante los contadores del ATMEGA.
En la siguiente  circuito  podemos ver como hago la mezcla de la portadora y los datos. También pongo un diodo LED de piloto de indicación visible de emisión de datos.
Hemos colocado un pulsador para la función de subir volumen, en un principio utilice la función de PWR, pero después de encender y apagar varias veces la TV, creí conveniente cambiar de función para no cargarme la TV.
Una cosa que no figura en el circuito y que debemos colocar, es un condensador de 50uF en la alimentación, cerca de los transistores.



Código fuente.
// seta - Emisor de infrarrojos
//Código SIRCS de SONY
//1-12-2011
//xsetaseta@gmail.com


  byte datos[20];
  byte x;
  byte x1;
  byte comando;
  byte direccion;
  int xx;
  int xx1;
 

void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);

  pinMode(11, INPUT);
  pinMode(12, INPUT); //devolver codigo
 
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);

  // Clear Timer on Compare Match (CTC) Mode
  bitWrite(TCCR1A, WGM10, 0);
  bitWrite(TCCR1A, WGM11, 0);
  bitWrite(TCCR1B, WGM12, 1);
  bitWrite(TCCR1B, WGM13, 0);

  // Toggle OC1A and OC1B on Compare Match.
  bitWrite(TCCR1A, COM1A0, 1);
  bitWrite(TCCR1A, COM1A1, 0);
  bitWrite(TCCR1A, COM1B0, 1);
  bitWrite(TCCR1A, COM1B1, 0);

  // No prescaling
  bitWrite(TCCR1B, CS10, 1);
  bitWrite(TCCR1B, CS11, 0);
  bitWrite(TCCR1B, CS12, 0);

  OCR1A = 200;    // 40KHz
  OCR1B = 200;
}

void loop()
{
 
if (digitalRead(12)==LOW)
    {   
      x=WriteIR(18,1);  //repetición de 3 veces el dato
      delay(24);
      x=WriteIR(18,1);
      delay(24);
      x=WriteIR(18,1);
      delay(100);
    }
}


int WriteIR(byte com,byte dir)
{
      digitalWrite(3, HIGH);
      digitalWrite(2, HIGH);
      for(xx=0;xx<5500;xx++);
      digitalWrite(2, LOW);
      for(x=0;x<7;x++)
          {
           for(xx=0;xx<1375;xx++);
           digitalWrite(2, HIGH);
           if(com & 1)
               for(xx=0;xx<2750;xx++);
             else
               for(xx=0;xx<1375;xx++);
           digitalWrite(2, LOW);
           com = (com >> 1);          
          }
      for(x=0;x<5;x++)
          {
           for(xx=0;xx<1375;xx++);
           digitalWrite(2, HIGH);
           if(dir & 1)
               for(xx=0;xx<2750;xx++);
             else
               for(xx=0;xx<1375;xx++);
           digitalWrite(2, LOW);
           dir = (dir >> 1);          
          }   
      digitalWrite(3, LOW);
}

ARDUINO - RECEPTOR INFRARROJOS-2

ARDUINO - RECEPTOR INFRARROJOS-2
Creando rutina propia
Después de mi anterior circuito de receptor de infrarrojos mediante librería IRremote, he decidido hacer mi propia rutina.
Utilizo el mismo circuito de Receptor de infrarrojos por lo que conviene ver el mismo.
El protocolo utilizado es el SIRCS utilizado en la mayoría de la televisiones SONY.
En la siguiente imagen podemos ver el formato del mensaje con los diferentes tiempos.




Formato visto en osciloscopio.


Las tres tramas iguales de la pulsación de una tecla.

Código fuente del programa, donde podemos ver que mediante el puerto serie se mandan los códigos al ordenador. Mediante las teclas 1-2 , 4-5 , 7-8 , se encienden y apagan los LED.
No se hace una comprobación de que las tres tramas iguales de cada tecla de el mismo resultado, solo se lee la primera trama de datos. Es raro que exista diferencia entre las tres tramas pero puede ocurrir, por lo que el que quiera asegurarse deberá modificar el programa.
// seta detector infrarojos
//Código SIRCS de SONY
//28-11-2011
//xsetaseta@gmail.com

// 1Logico=110      0Logico=60
#define xT4  190
#define xT5  240
#define xT3  140
#define xT15  75

  byte datos[20];
  byte x;
  byte x1;
  byte comando;
  byte direccion;
  int xx;
 

void setup()
{
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
 
  pinMode(11, INPUT);
  pinMode(12, INPUT); //devolver codigo

}

void loop() {
 
      if((x=ReadIR())==0)
        {
          if(comando==0) digitalWrite(2, HIGH);
          if(comando==1) digitalWrite(2, LOW);
   
          if(comando==3) digitalWrite(3, HIGH);
          if(comando==4) digitalWrite(3, LOW);
   
          if(comando==6) digitalWrite(4, HIGH);
          if(comando==7) digitalWrite(4, LOW);
         
          Serial.println("--");      
          Serial.print("-Comando=");
          Serial.print(comando,DEC);
          Serial.print("-Direccion=");
          Serial.print(direccion,DEC);          
        }
        else
        {
         if(x!=1)Serial.print("E");
        }           
}



//Valor retornado en comando y direccion
//Si existe error retorna mayor de 0, y valor correcto retorna 0
//si retorna 1 significa tiempo de espera excesivo
int ReadIR()
 {
  xx=400;
  while(xx>1)
   {  
   xx--; 
   if (digitalRead(11)==LOW)
    {
      x1=0; 
      while(digitalRead(11)==LOW)
          {
            x1++;
            for(xx=0;xx<15;xx++);
          }
      if(x1<xT4 || x1>xT5) goto error;
      datos[0]=x1;
      for(x=1;x<13;x++)
          {
           x1=0;
           while(digitalRead(11)==HIGH)
              {
                x1++;
                for(xx=0;xx<15;xx++);
              }
           x1=0;
           while(digitalRead(11)==LOW)
              {
                x1++;
                for(xx=0;xx<15;xx++);
                if(x1>xT3)goto error;                    
              }
           datos[x]=x1;
          }
         
      comando=0;
      for(x=7;x>0;x--)
          if(datos[x]>xT15)
            comando = (comando << 1) | 1;
           else
             comando <<= 1;
      direccion=0;
      for(x=12;x>7;x--)
          if(datos[x]>xT15)
            direccion = (direccion << 1) | 1;
           else
             direccion <<= 1;
//      for(x=0;x<13;x++) Serial.println(datos[x], DEC);    
      goto salto;
  error:
      //Serial.print("E-");
      //Serial.print(x1,DEC);
      return x1;
  salto:
      return 0;
    }
    return 1;
   }
}


Lugares donde he sacado información:

http://users.telenet.be/davshomepage/index.htm
http://www.fullcustom.es/guias/control-remoto-infrarrojo-software-usb-serie
http://www.sharatronica.com/decodificador_infrarrojo_sony.html
http://www.hifi-remote.com/sony/Sony_tv.htm

Saludos.
SETA43

ARDUINO - RECEPTOR INFRARROJOS

ARDUINO - RECEPTOR INFRARROJOS

Me apareció en el cajón de los desguaces un diodo receptor de infrarrojos, de algún televisor o vídeo desarmado.
Buscándole una utilidad, he realizando un receptor de mando a distancia que encienda y apague 3 diodos led .
Como no tengo mucha idea de mandos a distancias, he navegado por la red buscando ayuda.
He encontrado la librería IRremote que facilita en gran medida la realización del circuito.
Como mando a distancia he utilizado uno universal programado para que funcione como de TV Sony, los códigos son fáciles y cortos.

Códigos de las diferentes teclas
1->10
2->810

4->C10
5->210

7->610
8->E10

Los códigos son en Hexadecimal.

El diodo receptor de infrarrojos utilizado es TSOP-1730 corresponde al patillaje siguiente.

Bodigo fuente
// seta prueba infrarrojos
//30-10-2011
//xsetaseta@gmail.com

#include <IRremote.h>

int RECV_PIN = 11;

IRrecv irrecv(RECV_PIN);

decode_results results;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  if (irrecv.decode(&results)) {
 
    Serial.println(results.value, HEX);
       
    if(results.value==0x10) digitalWrite(2, HIGH);
    if(results.value==0x810) digitalWrite(2, LOW);
   
    if(results.value==0xc10) digitalWrite(3, HIGH);
    if(results.value==0x210) digitalWrite(3, LOW);
   
    if(results.value==0x610) digitalWrite(4, HIGH);
    if(results.value==0xe10) digitalWrite(4, LOW);
   
    irrecv.resume(); // Receive the next value
  }
}



Fotos del circuito montado


Esquema

Es muy fácil de montar y da mucho juego.

Controlando aparatos de 220V
Una utilidad que se le puede dar  a este mando de infrarrojos puede ser el encender o apagar luces.
Para utilizarlo como interruptor de aparatos de 220V se necesita un relé o un dispositivo de estado solido.
Yo dispongo  una caja con 4 dispositivos de estado solido para encender o apagar mediante señales lógicas de 5V, aislados eléctricamente mediante optoacopladores.
En la imagen siguiente se puede ver la conexión.



Un saludo.
seta43

ARDUINO - OSCILOSCOPIO 66K MUESTRAS

ARDUINO - OSCILOSCOPIO 66K MUESTRAS

Quizás el título puede ser un poco pretencioso, mejor hubiera sido digitalizador de 66418 muestras/segundo.
La idea original la he sacado de:
 http://real2electronics.blogspot.com/2011/09/arduino-adc-muestreo-alta-velocidad.html
 siempre me gusta poner las fuentes, hay que reconocer los méritos de cada uno.
En la mencionada página explica como se puede aumentar la velocidad de muestreo bajando la resolución a 8 bits.
Modificando el registro ADCSRA – ADC Control and Status Register A  , se modifica la velocidad de muestreo.
He utilizado el divisor 16 para la conversión, dando un muestreo de 66418 muestras /segundo.



A continuación se muestra el código fuente del arduino.

 //seta43
//17/01/2012
 

byte datos[800];
  int x;
  int z;
  int zz;
  int analogValue;
  byte xx;
  int retardo;


 void setup() {
  Serial.begin(115200);
 
  bitWrite(ADCSRA,ADPS2,1);
  bitWrite(ADCSRA,ADPS1,0);
  bitWrite(ADCSRA,ADPS0,0);
 
  //Analog Input A0
  ADMUX=(1<<ADLAR)|(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
 
 }

 void loop() {

 if (Serial.available() > 0)
     { 
      xx = Serial.read();
       switch (xx)
       {
// 1  1ms   
         case 49:
           retardo=27;
           break;     
// 2ms          
         case 50:
           retardo=80;
           break;                 
// 4ms
         case 51:
           retardo=185;
           break;            
//10ms          
         case 52:
           retardo=520;
           break; 
//50ms                      
         case 54:
           retardo=2650;
           break;          
//100ms                     
         case 55:
           retardo=5300;
           break;          
           
//9
        //a
         case 97:
             Serial.println(analogReadFast());  
             break;                
         //s  
         case 115:
            for (x=0;x<800;x++) datos[x]=analogReadFast(); 
            for (x=0;x<800;x++)
             {
               analogValue=datos[x];
               Serial.println(analogValue);
             }
             break;
         //t
         case 116:         
             for (x=0;x<800;x++)
               {
                 datos[x]=analogReadFast(); 
                 for(z=0;z<retardo;z++)zz=0;
               }
            for (x=0;x<800;x++)
             {
               analogValue=datos[x];
               Serial.println(analogValue);
             }            
         break;
        
       }
    
     }

 }

 
 //Read ADC
int analogReadFast()
{
 ADCSRA|=(1<<ADSC);
 // ADSC is cleared when the conversion finishes
 while (bit_is_set(ADCSRA, ADSC));
        return ADCH;
}



El programa en Arduino funciona bajo demanda de otro programa hecho en gambas. Gambas es una especie de Visual Basic para Linux.
El programa en gambas manda a través del puerto serie una orden mediante un carácter. Una vez recibido el carácter la placa Arduino, lo procesa y según sea el carácter hace una cosa u otra, mandando las muestras a través del puerto serie al PC. En el PC se dibuja en una gráfica la onda digitalizada.
Programa en Gambas ardu_os.zip 
Programa para Gambas3 osciv1G3.zip


Seleccionamos el puerto serie donde tenemos colocado el Arduino.


Vemos una onda de 4 KHz.


También podemos utilizarlo de voltímetro con registro de variaciones de voltaje.

Como experiencia también he hecho prueba modificando el registro ADCSRA – ADC Control and Status Register A a otros divisores, 8 y 4, estos son los resultados. También probé el divisor por 2, pero a esa velocidad el conversor no funcionaba.

 123200 muestras/s

198000 muestras/s

Saludos.
SETA43