Cómo cambiar 16 bits rápido en la placa arduino

Estoy codificando un sistema que necesita cambiar 16 bits rápidamente desde una variable uint16_t a dos registros de desplazamiento emparejados 74HC595. Estoy ejecutando el código en un Arduino (atmega328@16Mhz) y shiftOut en el Arduino es demasiado lento. La función digitalWrite de las bibliotecas también es lenta.

La mejor idea que se me ocurrió es un ciclo for que recorre los 16 bits de la variable y escribe 1/0 en el pin de datos, configura el bit de reloj lo más alto posible y luego pasa al siguiente bit de la variable.

¿Es esta la solución más rápida y, de ser así, cómo hago un bucle a través de bits de variables uint16_t en c ++?

Hice algunas pruebas con SRAM, puede encontrar los resultados interesantes: arduino.stackexchange.com/questions/36871/… Conclusión: un digitalRead/WriteFast es insignificante, sin embargo, un shiftOut cuesta 120 us.

Respuestas (4)

Esto es bastante simple con la biblioteca SPI.

Conecte su entrada de registro de desplazamiento al pin MOSI (Master Out, Slave In) - pin digital 11 - y tendrá transferencias rápidas y agradables.

Habrá un retraso muy leve entre los 8 bits superior e inferior de cada palabra transmitida.

Por ejemplo:

#include <SPI.h>

void begin()
{
    SPI.begin();
}

void loop()
{
    unsigned int val;

    val = rand()%0xFFFF; // Generate a random 16 bit number

    SPI.transfer(val >> 8);  // Output the MSB first
    SPI.transder(val & 0xFF); // Followed by the LSB

    delay(1000);  // Wait a sec...
}
¿Qué pasa con los pasadores de cierre? Esto parece estar simplemente alternando la línea de datos en serie, pero no veo cómo algo se engancha en el registro.
Nunca he usado uno de los registros de desplazamiento en cuestión, por lo que no sé qué se requiere. Por lo general, envuelve el SPI en un digitalWrite (x, BAJO) y digitalWrite (x, ALTO) para alternar una línea de E/S digital de su elección como "selección de chip" o "alternar pestillo" o lo que sea (obviamente invierta el alternar para alto activo ). Usa el pin que quieras.

Si está buscando usar una transferencia de datos de software, no quiere usar las funciones digitalWrite. Son muy lentos, esto se debe a que necesitan traducir el número de pin a través de una tabla a un registro real (PORTx), enmascarar el bit correcto y cambiarlo. Todos los pines en arduino están asignados a números, mientras que debajo pueden pertenecer al puerto A, B, C e incluso más en la versión MEGA de Arduino.

Es mucho más rápido modificar directamente los registros AVR. Como PORTB y similares. De hecho, necesita pasar por cada bit. Crearía un bucle for de 0 a 15 y cambiaría y enmascararía un poco.

Como no conozco la configuración de fijación, no puedo dar un ejemplo exacto. Sin embargo, probablemente se verá muy cerca de esto. Con 'muy cerca' quiero decir que esto no se ha probado.

void ShiftOut(UI16_t data)
{
 // Initialize (you may want to set CLK to low) - as we're toggling later on.

// step from bit 0 to 15
 for(UI08_t i = 0; i < 15; i++)
 {
  // Check the content of this data bit
  // Shift data so this bit is LSB, and mask it with 1 so we only look at this bit.
  if ((data >> i) & 0x1 == 1)
  {
    // set data pin high, like PORTB |= 1<<4;
    // when pin 4 of portB is your data pin
    // Doing an OR will make pin B4 always high
  }
  else
  {
    // set data pin low, like PORTB &= ~(1<<4);
    // Doing an AND with the inverse means all pins except B4 will be unchanged
  }

// Generate clk to 'transfer' the bit:
  // This can likely be done by using PORTB ^= 1 << 5; (pin B5 in this example)
  // ^= toggle 
  // Do this TWICE, so CLK goes high/low
 }

// as you're using a shift register, you may want to toggle LATCH pin as well..
}
Para averiguar qué número de pin de hardware (¡no asuma que el pin 4 es el pin B4 o A4!), Debe mirar el esquema de Arduino.

Ejecuté un código similar en un PIC32 (funciona a 80 MHz). El PIC32 pudo hacer esto a aproximadamente 1,5 MHz, pero se estaban ejecutando algunas líneas adicionales de código en main() para calcular una nueva salida. Sin embargo, se puede hacer muy rápidamente.

Gracias por la respuesta detallada, probaré primero el enfoque SPI, ya que parece más rápido. También encontré más ejemplos del enfoque de software en bildr.org/2011/02/74hc595

Debe usar el periférico SPI en lugar de hacer el cambio en el software. Nunca he usado un Arduino, pero la referencia en línea sugiere que hay una biblioteca SPI que puedes usar. Si eso no se ajusta a sus necesidades, puede buscar el periférico SPI en la hoja de datos de ATMega. Los periféricos SPI suelen ser bastante fáciles de configurar y usar.

Soy de la vieja escuela, he estado codificando desde procesadores de 100 kHz. Use código en línea para la manipulación de bits directamente en el puerto, en lugar de un bucle. Loop requiere gastos generales, en línea es más rápido aunque ocupa más espacio de programa. Consulte AVR035: Codificación C eficiente para AVR para la manipulación de bits de los puertos.