Learning   Examples | Foundations | Hacking | Links

Controlando un Potenciómetro Digital usando SPI

En este tutorial aprenderás como controlar el potenciómetro digital AD5206 usando el bus SPI (Serial Peripheral Interface). Para una explicación del funcionamineto del SPI ver el tutorial SPI EEPROM. Los potenciómetos digitales son útiles cuando se necesita variar la resistencia electrónicamente en un circuito en lugar de manualmente. Ejemplos de aplicaciones son la regulación de LED, acondicionamiento de señal de audio y generación de tono. En este ejemplo se usará un potenciómetro de seis canales para controlar el brillo de seis LEDs. Los pasos que veremos aquí para implementar una comunicación SPI pueden ser fácilmente modificados para su uso con cualquier otro dispositivo SPI.

Materiales necesarios:

  • Circuito integrado AD5206 Potenciómetro Digital
  • Placa Arduino
  • 6 Diodes LEDs
  • Cables de conexionado

Introducción al Potenciómetro Digital AD5206

El AD5206 es un portenciómetro digital de 6 canales. Esto significa que tiene seis resistores variables (potenciómetros) en un circuito integrado. Hay tres pines en el circuito integrado por cada uno de los seis resistores variables internos, y se hace el conexionado como un potenciómetro mecánico. Los pines de cada resistor variable está etiquetado com Ax. Bx y Wx. Ejemplo: A1, B1 y W1

Por ejemplo, en este tutorial usaremos cada resistor variable como un divisor de tensión en un lado se conecta el pin de tensión alta (pin B), en el otra lado el pin de tesnión baja (pin A) y se toma el pin central (pin W) como salida de la tensión variable.

El AD5206 es controlado digitalmente usando SPI. El dispositivo es habilitado poniendo el pin Chip Select (CS)a nivel bajo. Las instrucciones se envían en códigos de operaciones (opcodes) de 10 bits con los tres bits más significativos (10-8) definiendo la dirección del potenciómetro a ajustar y los ocho bits menos significativos (7-0)definiendo que valor poner al potenciómetro entre 0-255. La transferencia del código de operación empieza con el bit más significativo (MSB, Most Significant Bit) en el flanco de subida de la señal de reloj. La señal de reloj es inactiva a nivel bajo, y la velocidad de comunicación del interfaz es mucho más rápida que la velocidad de procesamiento de Arduino, por lo que no es necesario un pre-escaler para adaptarse a la velocidad de transmisión.

Preparando la Placa de prueba

Insertamos el circuito integrado AD5206 en la placa de prueba. Conecta 5V de alimentación y masa de la placa de prueba a 5V de alimentación y masa de la placa de Arduino. Conecte los pines 3, 6, 10, 13, 16, 21 y 24 del AD5206 a +5V y los pines 1, 4, 9, 12, 15, 18, 19 y 22 a masa. Hemos conectado todos los pines A a masa y los pines B a +5V para crear 6 divisores de tensión.

Conectamos el pin 5 de AD5206 al pin 10 de Arduino (Slave Select - SS), el pin 7 de AD5206 al pin 11 de Arduino (Master Out Slave In - MMOSI), y el pin 8 de AD5206 al pin 13 de Arduino (Serial Clock - SCK)

Finalmente, conectamos cada uno de los LEDs entre el pin W (en el AD5206 los pines 2, 11, 14, 17, 20 y 23) y masa, de la siguiente manera: la patilla larga del LED conectada al pin W y la patilla corta, o la cara plana del LED, conectada a masa.

Programando la Arduino

Ahora escribiremos el código en la placa Arduino para realizar el control del AD5206 por comunicación SPI. Este programa activa secuencialmente cada LED y luego se va apagando gradualmente. Esto se hace en la función principal loop() del programa cambiando individualmente el valor de resistencia de cada potenciómetro desde apagado hasta encendido (0-255).

A continuación comentamos el código del programa en pequeñas secciones.

Definimos los pines que se usan para la conexión al SPI: DATAOUT, DATAIN, SPICLOCK y SLAVESELECT. Aunque no se están leyendo datos del AD5206 en este programa, el pin 12 está asignado a la recepción de datos de un dispositivo SPI en otros ejemplos. Por tanto, es mejor no utilizarlo para otras tareas de programación para evitar posibles errores.

#define DATAOUT 11//MOSI
#define DATAIN 12//MISO - no usar, necesario para protocolo SPI
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

A continuación asignamos variables para almacenar el valor de las resistencias y la dirección de los potenciómetros.

byte pot=0;
byte resistance=0;

Primero se configuramos el modo de los pines como entrada y salida y ponemos el pin digital de salida SLAVESELECT a nivel alto para empezar. Esto hace que desactive el dispositivo SPI y evita datos falsos en la transmisión debido a posibles ruidos en el cableado.

void setup()
{
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //dispositivo SPI deshabilitado

Ahora configuramos el registro de control (SPCR) del SPI con el valor binario 01010000. En este registro de control cada bit tiene una función. El bit 7(0) deshabilita la interrupción SPI, el bit 6(1) habilita el SPI, el bit 5(0) elige la transmisión del primer bit al bit más significativo MSB (Most Significant Bit), el bit 4(1) pone a Arduino en modo Maestro en la comunicación, el bit 3(0)ajusta la polaridad de la señal de reloj a nivel bajo, el bit 2(0) pone al SPI para tomar los datos en el flanco de subida de la señal de reloj y el bit 1 y 0 (00) ajusta la velocidad del SPI a la más rápida. Depués de configurar el registro de control se limpia el registro de estado (SPSR) y el registro de dato (SPDR) con la variable clr para eliminar posible datos almacenados anteriormente.

  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  delay(10);

Terminamos la función setup() poniendo todos los potenciómetros con el valor máximo de resistencia, así los LEDs están apagados.

  for (i=0;i<6;i++)
  {
    write_pot(i,255);
  }
}

En la función principal loop() se repite para incrementar el valor de la resistencia (0-255) para cada potenciómetro (0-5). Hay una pausa de 10 milisegunda en cada iteración para hacer visible los pasos. Este código hace que cada LED se encienda y luego se apague poco a poco, de manera secuencial.

void loop()
{
     write_pot(pot,resistance);
     delay(10);
     resistance++;
     if (resistance==255)
     {
       pot++;
     }
     if (pot==6)
     {
       pot=0;
     }
}

La función spi_transfer carga el dato de salida en el registro de transmisión de datos, comenzando la transmisión SPI. Se sondea el bit (SPIF), usando un bit de máscara, del registro de estado (SPSR)del SPI para detectar cuando la transmisión serie se ha completado. Una explicación de bit de máscara se puede encontrar aquí. La función termina devolviendo el dato que se ha registrado en el registro de datos de la EEPROM.

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Empieza la transmisión
  while (!(SPSR & (1<<SPIF)))     // Espera la terminación de la transmisión
  {
  };
  return SPDR;                    // Devuelve el byte recibido
}

La función write_pot permite controlar cada potenciómeto. Ponemos SLAVESELECT (pin 10) a nivel bajo para habilitar el dispositivo. A continuación transferimos el byte de dirección seguido del byte del valor de la resistencia. Por último, ponemos SLAVSELECT a nivel alto de nuevo para liberar el chip y terminar la transferencia del dato.

byte write_pot(int address, int value)
{
  digitalWrite(SLAVESELECT,LOW);
  //2 byte opcode
  spi_transfer(address);
  spi_transfer(value);
  digitalWrite(SLAVESELECT,HIGH); //liberar chip, fin de transmisión
}

Programa completo de LEDs

Para mayor facilidad copiar y pegar el código completo del programa de este tutorial:

#define DATAOUT 11//MOSI
#define DATAIN 12//MISO - no usar, necesario para el protocolo SPI
#define SPICLOCK  13//sck
#define SLAVESELECT 10//ss

byte pot=0;
byte resistance=0;

char spi_transfer(volatile char data)
{
  SPDR = data;                    // Empezar la transmisión
  while (!(SPSR & (1<<SPIF)))     // Espera la terminación de la transmisión
  {
  };
  return SPDR;                    // Devuelve el byte recibido
}

void setup()
{
  byte i;
  byte clr;
  pinMode(DATAOUT, OUTPUT);
  pinMode(DATAIN, INPUT);
  pinMode(SPICLOCK,OUTPUT);
  pinMode(SLAVESELECT,OUTPUT);
  digitalWrite(SLAVESELECT,HIGH); //deshabilita el dispositivo SPI
  // SPCR = 01010000
  //interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
  //sample on leading edge of clk,system clock/4 (fastest)
  SPCR = (1<<SPE)|(1<<MSTR);
  clr=SPSR;
  clr=SPDR;
  delay(10);
  for (i=0;i<6;i++)
  {
    write_pot(i,255);
  }
}

byte write_pot(int address, int value)
{
  digitalWrite(SLAVESELECT,LOW);
  //2 byte opcode
  spi_transfer(address);
  spi_transfer(value);
  digitalWrite(SLAVESELECT,HIGH); //libera el chip, finalización transferencia
}

void loop()
{
     write_pot(pot,resistance);
     delay(10);
     resistance++;
     if (resistance==255)
     {
       pot++;
     }
     if (pot==6)
     {
       pot=0;
     }
}

código, tutorial y fotos por Heather Dewey-Hagborg

Share