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 ++?
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...
}
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.
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.
michel keijzers