martes, 3 de junio de 2014

SD Card Socket Modlue +2.8" Inch TFT Touch Screen Development Board For Arduino


De momento pongo la copia de seguridad del CD que le acompañaba. parece que es elentorno de programación de arduino adaptado para este dispositivo y que solo funciona en windows. Al menos el ejecutable es para windows, deduzco que las librerías que le acompañan son para el mismo sistema operativo y que por lo tanto desde otros sistemas operativos no va a funcionar.

El enlace al fichero es: https://drive.google.com/file/d/0B779vDAuKIBKSWJsMEY0OE0yZ3M/edit?usp=sharing


sábado, 10 de mayo de 2014

2088RGB-5 (Matriz RGB de 8x8 de ánodo común sin resistencias)

Imagen de las conexiones del dispositivo:
Se puede ver que la patilla nº 1 es la de la esquina inferior derecha.
Alguien (https://www.flickr.com/photos/madworm_de/2997547008/sizes/o/in/photostream/) ha puesto esto en internet:
Aunque no son idénticos, es facil comprobar si está bien o mal. Mediante un polímetro se localiza el ánodo y el resto solo es saber de que color es cada grupo.
Lo importante viene ahora. Hay varias soluciones para enviar los datos.
  • Enviar los 32 datos vía serie.
  • Enviar 4 grupos de datos vía serie (uno para cada color y otro para en ánodo).
  • Enviar 4 grupos de 8 bits.
El más lógico parece el último porque sería más rápido, solo serían necesarios 4 buffers (no sería necesario poner registros de desplazamiento). A cambio, se necesitan más salidas: 8 bits para los datos y 4 para las direcciones (que podrían quedarse en 2 si se multiplexan). Lo de multiplexar salidas sería recomendable en caso de que no disponer de suficientes salidas. A cambio, no se podría enviar el mismo dato a todas a la vez (por ejemplo encender o apagar todo a la vez).

En todos los casos se hace necesario fabricar un circuito impreso y eso lleva a una nueva duda. Poner resistencias en los cátodos o en el ánodo.
Ventajas e inconvenientes de cada una de las soluciones (no voy a tener en cuenta la económica porque es una miseria):
  • Más resistencias => Circuito impreso más grande
  • Más resistencias => Mayor facilidad para conectar los dispositivos al poder pasar las pistas por debajo de las resistencias.
  • Más resistencias => Más luz que si tienen una común.
  • Más resistencias => Más control de la corriente de cada led (tienen distintas corrientes/tensiones de funcionamiento).
  • Resistencia común => Es posible que los colores azul y verde no se enciendan si se activan con el rojo porque funciona con menos tensión (no lo he comprobado)
Después de valorar todo, creo que es mejor utilizar 12 salidas del arduino (no multiplexar) y poner 24 resistencias.
Falta localizar los circuitos integrados con 8 básculas tipo D adecuados y calcular las resistencias.
De momento ya he expuesto las ideas. Cuando vuelva a hacer algo lo publicaré.
He encontrado algo que podría valer: 74XX373
  • Tiene un precio razonable.
  • A pesar de ser de la serie 74 es un CMOS.
    • Tiene un consumo reducido.
    • Tiene un buen margen de tensiones de alimentación.
    • Puede suministrar perfectamente la corriente que precisan los LEDs.
  • Cumple sobradamente con las carácterísticas (le sobra la salida triestado pero es facil inhabilitarla poniendo Output Enable a cero)
  • El patillaje es un poco complejo para el circuito impreso porque se llenaría de cruces por la configuración de entradas/salidas.
Hay un datasheet en: http://www.harrisonelectronics.co.uk/datasheets/MC74HC373ADW.pdf
Y en su página principal hay datasheets de muchos componentes corrientes (muy utilizados): Harrison Electronics

Creo que ya está: http://www.fairchildsemi.com/ds/74/74VHC573.pdf
http://pinout-circuits-images.dz863.com/6/CD74HC573.jpg
CD74HC573 pinout from datasheet
Se puede ver que a un lado están  las entradas y a otro las salidas. Lo mismo que en el 373 hay que poner la patilla 1 a masa para que esté siempre activado (no se necesita el triestado).

Para el cálculo de las resistencias he encontrado un problema: potencia máxima 150 mw. Teniendo en cuenta que:

  • LED Rojo: 2,2V/50mA=110mw
  • LED Verde: 3,3V/50mA=165mw
  • LED Azul: 3,3V/50mA=165mw
No se si 150mw se refiere a la potencia máxima que soporta cada conjunto o cada led individual.
En el caso de que sea el primero (lo más probable por la refrigeración) habría que poner una resistencia común o evitar encender los tres a la vez.
Si se hace pasar 15 mA por LED, no se superaría la potencia máxima aunque se activaran los 3 simultáneamente.
Los valores serían:

  • R: (5V-2,2V)/15mA=187 Ohm
  • G: (5V-3,3V)/15mA=113 Ohm
  • B: (5V-3,3V)/15mA=113 Ohm
  • Valores normalizados (E24 - 5%):
    • R: 150-200=> 200 Ohm
    • G=B: 110-130 => 110 Ohm
  • Valores normalizados (E12 - 10%):
    • R: 150-270 => 150 Ohm -> I=2,8V/150=18,7mA
    • G-B: 100-150 => 100 Ohm -> I=1,7/100=17mA
  • Potencias para E12:
    • R: 2,8V*18,7mA=52,36mw
    • G-B:1,7V*17mA=28.9mw
    • Potencia TOTAL=52,36+28,9+28,9=110,16mw
Incluso poniendo resistencias muy distintas a las inicialmente calculadas estaría lejos de la potencia máxima.
Falta diseñar la placa de circuito impreso, a ser posible de una cara. Eso llevará más tiempo...

lunes, 31 de marzo de 2014

Juego de luces sencillo para matriz 16x16

Se va acercando desde las 4 esquinas hacia el centro y cuando llega se enciende entero:

Código fuente:

//salidas que se van a utilizar
int latchPin = 8; //patilla LT
int clockPin = 12; //patilla SK
int dataPin = 11; //patilla RI1
//array en el que se va a contener toda la informacin de filas y columnas
byte dato[4];
byte i;

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  dato[0]=0xFF;
  dato[1]=0xFF;
  dato[2]=0x00;
  dato[3]=0x00;
  envia_datos(dato);
}

void envia_datos(byte *matrix) {
  digitalWrite(latchPin, 0);
  for (byte i=4; i>2; i--) shiftOut(dataPin, clockPin, LSBFIRST, matrix[i-1]);
  for (byte i=2; i>0; i--) shiftOut(dataPin, clockPin, MSBFIRST, matrix[i-1]);
  digitalWrite(latchPin, 1);
  delay(500);
}

void loop() {
  dato[3]=0x01;
  dato[2]=0x80;
  dato[1]=0x7F;
  dato[0]=0xFE;
  envia_datos(dato);
  delay(500);
 
  for (i=0;i<6;i++){
    dato[3]*=2;  
    bitClear(dato[3],7);
    dato[2]/=2;
    bitClear(dato[2],0);
    dato[1]>>=1;
    bitSet(dato[1], 7);
    dato[0]<<=1;
    bitSet(dato[0], 0);
  envia_datos(dato);
  delay(500);  
  }
  dato[0]=0x00;
  dato[1]=0x00;
  dato[2]=0xFF;
  dato[3]=0xFF;
  envia_datos(dato);
 
  delay(500);
 
  dato[0]=0xFF;
  dato[1]=0xFF;
  dato[2]=0x00;
  dato[3]=0x00;
  envia_datos(dato);
 
  delay(500);

}

domingo, 2 de febrero de 2014

Display de 7 segmentos con 8 digitos (MAX7219)_2-Contador pasando de binario a decimal

 Código fuente:

********************************************************
const byte datapin = 12;
const byte latchpin = 11;
const byte clockpin = 10;

void setup() {
  pinMode(datapin, OUTPUT);
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  // set : Normal Mode
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0C );
  shiftOut(datapin, clockpin, MSBFIRST, 0x01 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Normal Operation
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0F );
  shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Intensity
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0A );
  shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Numbers of digits
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
  shiftOut(datapin, clockpin, MSBFIRST, 0x07 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Decode Mode Register
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x09 );
  shiftOut(datapin, clockpin, MSBFIRST, 0xFF );
  digitalWrite(latchpin, HIGH);
}

void loop() {
  unsigned long numero=99988888;
  int i;
  for (i=1;i<9;i++)
  {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, i );
    shiftOut(datapin, clockpin, MSBFIRST, 15 );
    digitalWrite(latchpin, HIGH);
    //delay(5);
  }
  do {
    envDispl(numero);
    numero++;
  } while (numero < 100000000);//unsigned long puede representar hasta: 4.294.967.295 (2^32 - 1) porque tiene 4 bytes (32 bits)
}

void envDispl(unsigned long numero) {
  unsigned long k=10000000;
  int i, j;
  for (i=8; i>0; i--) {
    j=numero/k;
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, i );
    shiftOut(datapin, clockpin, MSBFIRST, j );
    digitalWrite(latchpin, HIGH);
    numero%=k;
    k=k/10;
    //delay (5);
  }
}

Display de 7 segmentos con 8 digitos (MAX7219)_1-Contador utilizando recursividad.

Código fuente:

//*************************************************************************
const byte datapin = 12;
const byte latchpin = 11;
const byte clockpin = 10;

void setup()
{
  pinMode(datapin, OUTPUT);
  pinMode(latchpin, OUTPUT);
  pinMode(clockpin, OUTPUT);
  // set : Normal Mode
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0C );
  shiftOut(datapin, clockpin, MSBFIRST, 0x01 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Normal Operation
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0F );
  shiftOut(datapin, clockpin, MSBFIRST, 0x00 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Intensity
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0A );
  shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Numbers of digits
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x0B );
  shiftOut(datapin, clockpin, MSBFIRST, 0x07 );
  digitalWrite(latchpin, HIGH);
  delay(5);
  // set : Decode Mode Register
  digitalWrite(latchpin, LOW);
  shiftOut(datapin, clockpin, MSBFIRST, 0x09 );
  shiftOut(datapin, clockpin, MSBFIRST, 0xFF );
  digitalWrite(latchpin, HIGH);
}

void loop()
{
  byte j;
  for (int i=1;i<9;i++)
  {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, i );
    shiftOut(datapin, clockpin, MSBFIRST, 15 );
    digitalWrite(latchpin, HIGH);
    delay(5);
  }
  delay(2000);
  contador(8);//funcion recursiva
  delay(2000);
}

void contador (int n) {
  int i;
  i=0;
  do {
    digitalWrite(latchpin, LOW);
    shiftOut(datapin, clockpin, MSBFIRST, n );
    shiftOut(datapin, clockpin, MSBFIRST, i );
    digitalWrite(latchpin, HIGH);
    if (n==1) delay(5);//para que la transicin sea "instantanea" en caso de acarreo
    if (n>1) contador (n-1);
    i++;
    if (i==10) {
      i=0;
      digitalWrite(latchpin, LOW);
      shiftOut(datapin, clockpin, MSBFIRST, n );
      shiftOut(datapin, clockpin, MSBFIRST, i );
      digitalWrite(latchpin, HIGH);
      break;
    }
  }
  while (1);
}

domingo, 19 de enero de 2014

Controlar una matriz barriendo filas y barriendo columnas (74HC595)

 En los dos casos es la misma matriz. La he generado con el ArduinoFrameAnimator.jar y no se parece en nada. Además, genera una matriz de 64 elementos. Tal vez genere las filas y las columnas. Lo pongo aquí por si algún día estoy inspirado y consigo verlo.
código generado por ArduinoFrameAnimator.jar:
int animationFrames = 1;

int animationDelays[] = { 200 };

// Animation is designed for 16x16 pixels
uint8_t animation[][64] = {
  { 0x3, 0x0, 0x0, 0xc0, 0xc, 0x0, 0x0, 0xc0, 0x30, 0x0, 0x0, 0xc0, 0xc0, 0x0, 0x0, 0xc0, 0x0, 0x3, 0x0, 0xc0, 0x0, 0xc, 0x0, 0xc0, 0x0, 0x30, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0xc0, 0x0, 0x0, 0x3, 0xc0, 0x0, 0x0, 0xc, 0xc0, 0x0, 0x0, 0x30, 0xc0, 0x0, 0x0, 0xc0, 0xc0, 0x0, 0x0, 0x0, 0xc3, 0x0, 0x0, 0x0, 0xcc, 0x0, 0x0, 0x0, 0xf0, 0x0, 0x0, 0x0, 0xc0 }
};

CONCLUSION:

Sale mejor barriendo filas porque el led que corresponda a la columna que se enciende lo hará con la máxima intensidad.
Eso tiene la desventaja de que es más dificil escribir la matriz. En este caso la he escrito en positivo y después la he invertido mediante una operación OR EXclusivo a cada uno de los elementos de la matriz.
Pongo primero el código de barrido de columnas por ser más intuitivo. Además, así se puede apreciar el cambio de luminosidad de la última columna.
Para hacer un barrido rápido y continuo basta con comentar la línea delay.

Barriendo columnas

Se muestra el contenido de la matriz que se muestra haciendo un barrido por columnas.

código:
//salidas que se van a utilizar
byte latchPin = 8;
byte clockPin = 12;
byte dataPin = 11;
//array en el que se va a contener toda la informacion de filas
byte dato[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0xFF, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0, 0, 0, 0, 0, 0, 0, 0xff };//informacion de las filas

/*       --
  X00000000000000X
  0X0000000000000X
  00X000000000000X
  000X00000000000X
  0000X0000000000X
  00000X000000000X
  000000X00000000X
- 0000000X0000000X-
- 00000000X000000X-
  000000000X00000X
  0000000000X0000X
  00000000000X000X
  000000000000X00X
  0000000000000X0X
  00000000000000XX
  000000000000000X
         --
*/
byte i;
byte co_L, co_H;

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void loop() {
  muestra (dato);
}

void muestra (byte *matriz) {
  co_L=0xFE;
  co_H=0xFF;
  for (i=0;i<16;i++) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, MSBFIRST, matriz[i+16]);
    shiftOut(dataPin, clockPin, MSBFIRST, matriz[i]);
    shiftOut(dataPin, clockPin, MSBFIRST, co_H);
    shiftOut(dataPin, clockPin, MSBFIRST, co_L);
    digitalWrite(latchPin, 1);
    if (i<8){
      co_L<<=1;
      bitSet(co_L,0);
    }
    else{
      co_H<<=1;
      bitSet(co_H,0);
    }
    if (i==7){
      co_L=0xFF;
      co_H=0xFE;
    }
    delay(250);
  }
}

Barriendo filas


Mismo programa, misma matriz barriendo filas en vez de columnas. Como la columna de la derecha brillaba menos, deduzco que las resistencias de control están en los cátodos. Barriendo por filas se hace que todas brillen igual. Sigo sin ver como se pasa del arduinoframeanimator.jar a una matriz similar a estas que me salen.

código:
//salidas que se van a utilizar
byte latchPin = 8;
byte clockPin = 12;
byte dataPin = 11;
//array en el que se va a contener toda la informacin de filas
byte dato[32] = {
  0x80, 1, 0x40, 1, 0x20, 1, 0x10, 1, 0x08, 1, 0x04, 1, 0x02, 1, 1, 1, 0, 0x81, 0, 0x41, 0, 0x21, 0, 0x11, 0, 0x09, 0, 0x05, 0, 0x3, 0, 1};//informacion de las columnas

/*       --
 X00000000000000X
 0X0000000000000X
 00X000000000000X
 000X00000000000X
 0000X0000000000X
 00000X000000000X
 000000X00000000X
 - 0000000X0000000X-
 - 00000000X000000X-
 000000000X00000X
 0000000000X0000X
 00000000000X000X
 000000000000X00X
 0000000000000X0X
 00000000000000XX
 000000000000000X
 --
 */
byte i;
byte fi_L, fi_H;

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (i=0;i<32;i++) {
    dato[i]^=0xFF;
  }//invierto todos los bits porque las columnas van a los cátodos.
}

void loop() {
  muestra (dato);
}

void muestra (byte *matriz) {
  fi_L=0x01;
  fi_H=0x00;
  for (i=0;i<32;i+=2) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, LSBFIRST, fi_L);
    shiftOut(dataPin, clockPin, LSBFIRST, fi_H);
    shiftOut(dataPin, clockPin, LSBFIRST, matriz[i+1]);
    shiftOut(dataPin, clockPin, LSBFIRST, matriz[i]);
    digitalWrite(latchPin, 1);
    if (i<14){
      fi_L<<=1;
      bitClear(fi_L,0);
    }
    else if (i==14){
      fi_L=0x00;
      fi_H=0x01;
    }
    else{
      fi_H<<=1;
      bitClear(fi_H,0);
    }
    delay(250);
  }
}

viernes, 17 de enero de 2014

arduinoframeanimator.jar

en cuanto consiga decodificar la matriz que genera, lo pondré.

barrido de la matriz (74HC595)

Tiene un pequeño retardo. Se muestran los 32 primeros números expresados en binario 0-31)
código:
//salidas que se van a utilizar
byte latchPin = 8;
byte clockPin = 12;
byte dataPin = 11;
//array en el que se va a contener toda la informacion de filas
byte dato[32];//informacion de las filas
byte i;
byte co_L, co_H;

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  for (i=0;i<32;i++) {
    dato[i]=i;
  }
}

void loop() {
  muestra (dato);
}

void muestra (byte *matriz) {
  co_L=0xFE;
  co_H=0xFF;
  for (i=0;i<16;i++) {
    digitalWrite(latchPin, 0);
    shiftOut(dataPin, clockPin, MSBFIRST, matriz[i+16]);
    shiftOut(dataPin, clockPin, MSBFIRST, matriz[i]);
    shiftOut(dataPin, clockPin, MSBFIRST, co_H);
    shiftOut(dataPin, clockPin, MSBFIRST, co_L);
    digitalWrite(latchPin, 1);
    if (i<8){
      co_L<<=1;
      bitSet(co_L,0);
    }
    else{
      co_H<<=1;
      bitSet(co_H,0);
    }
    if (i==7){
      co_L=0xFF;
      co_H=0xFE;
    }
    delay(5);
  }
}

jueves, 16 de enero de 2014

instalación del programador

La versión que viene por defecto en ubuntu es muy antigua y no tiene al leonardo.
Por suerte está hecho en java y basta con descargarlo y ejecutar el fichero arduino que es un script escrito para /bin/sh y no tiene ninguna complicación.

La versión 1.0.5 funciona.
Me llevó un tiempo descubrir que los menús están ocultos en la parte superior de color gris oscuro (no se ven las letras porque deben haberlas configurado del mismo color) encima de la verde que contiene los iconos.
Para seleccionar el leonardo:

  • Herramientas -> Tarjetas -> Arduino Leonardo.
  • Herramientas -> Puerto Serial -> /dev/ttyACM1 (es necesario que esté conectado)

Control de una matriz led de 16x16 y por extensión a todas (74HC595)

Hay poca información en la web y esa poca cuesta aplicarla a un caso concreto.
El principal detalle es: 74hc595 driver.
Se trata de registros de desplazamiento. En este caso dos de 8 para las filas y 2 de 8 para las columnas.

Pongo códigos que es la forma más sencilla de entenderlos.
Código 1:
//salidas que se van a utilizar
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
//array en el que se va a contener toda la informacin de filas y columnas
byte dato[4];
//i va a variar de 0 a 7 por eso es suficiente con un byte
byte i;

void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  dato[0]=0xFF;//columna mayor peso
  dato[1]=0xFF;//columna menor peso
  dato[2]=0x00;//fila mayor peso
  dato[3]=0x00;//fila menor peso
  envia_datos(dato);
}

/****************************************************************
 * bitWrite()
 * Descripción
 * Escribe un bit de una variable numérica.
 * Sintaxis
 * bitWrite(x, n, b)
 * Parámetros
 * x: la variable numérica en la que vamos a escribir
 * n: en cual de los bits vamos a escribir, empezando en el 0 para el bit menos significativo (el que está más a la derecha)
 * b: el valor a escribir en el bit (0 o 1)
 * 
 * bitRead()
 * Descripción
 * Lee un bit de un número.
 * Sintaxis
 * bitRead(x, n)
 * Parámetros
 * x: el número en el que queremos leer
 * n: cual de los bits queremos leer, empezando por el 0 para el bit menos significativo (el que está más a la derecha)
 * Devuelve
 * el valor del bit (0 o 1). 
 * 
 * bitSet()
 * Descripción
 * Pone a uno un bit de una variable numérica.
 * Sintaxis
 * bitSet(x, n)
 * Parámetros
 * x: la variable numérica en la que está el bit a poner a uno
 * n: cual de los bits queremos poner a uno, empezando en el 0 para el bit menos significativo (el que está más a la derecha) 
 * 
 * bitClear()
 * Descripción
 * Limpia (pone a cero) un bit de una variable numérica.
 * Sintaxis
 * bitClear(x, n)
 * Parámetros
 * x: la variable numérica con el bit a limpiar
 * n: cual de los bits queremos limpiar, empezando en el 0 por el bit menos significativo (el que está más a la derecha) 
 ***************************************************************/

void envia_datos(byte *matrix) {
  digitalWrite(latchPin, 0);
  for (byte i=4; i>2; i--) shiftOut(dataPin, clockPin, LSBFIRST, matrix[i-1]);
  for (byte i=2; i>0; i--) shiftOut(dataPin, clockPin, MSBFIRST, matrix[i-1]);
  digitalWrite(latchPin, 1);
  delay(500);
}

void loop() {
  for (i=0;i<8;i++) {
    dato[2]<<=1;
    bitSet(dato[2], 0);
    envia_datos(dato);

    dato[1]<<=1;
    bitClear(dato[1],0);
    envia_datos(dato);

    dato[3]>>=1;
    bitSet(dato[3],7);
    envia_datos(dato);

    dato[0]>>=1;
    bitClear(dato[0],7);
    envia_datos(dato);
  }//2130
  for (i=0;i<8;i++) {
    dato[2]>>=1;
    bitClear(dato[2],7);
    envia_datos(dato);

    dato[1]>>=1;
    bitSet(dato[1],7);
    envia_datos(dato);

    dato[3]<<=1;
    bitClear(dato[3], 0);
    envia_datos(dato);
    
    dato[0]<<=1;
    bitSet(dato[0],0);
    envia_datos(dato);
  }  

}
Código 2: Para ver cuales son las filas, las columnas, ánodos, cátodos, mayores y menores pesos.
//salidas que se van a utilizar
int latchPin = 8;
int clockPin = 12;
int dataPin = 11;
byte dato[4];
void setup() {
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}
void envia_datos(byte *matrix) {
  digitalWrite(latchPin, 0);
  for (byte i=4; i>2; i--) shiftOut(dataPin, clockPin, LSBFIRST, matrix[i-1]);
  for (byte i=2; i>0; i--) shiftOut(dataPin, clockPin, MSBFIRST, matrix[i-1]);
  digitalWrite(latchPin, 1);
}
void loop() {
  //FILAS
  dato[3]=0x01; //anodo menor peso
  dato[2]=0xA0; //anodo mayor peso
  //COLUMNAS
  dato[1]=0x0F; //catodo mayor peso
  dato[0]=0x73; //catodo menor peso
  envia_datos(dato); //fila (vertical)-anodo 1000 0000 - 0000 0101 + columna (vertical) catodo 11111 0000 - 1100 1110
  /*dato[1]  dato[0]
    F    0    3    7
  0000 1111 0011 0001
  0000 0000 0000 0000
  0000 1111 0011 0001 A
  0000 0000 0000 0000
                      dato[3]
  0000 0000 0000 0000
  0000 0000 0000 0000
  0000 0000 0000 0000 0
  0000 0000 0000 0000
  
  0000 0000 0000 0000
  0000 0000 0000 0000
  0000 0000 0000 0000 0
  0000 0000 0000 0000
                      dato[2]
  0000 0000 0000 0000
  0000 0000 0000 0000
  0000 0000 0000 0000 1
  0000 1111 0011 0001
  */
  delay(100000);//para no hacer uso innecesario de la CPU
}