Multiplexación de matriz RGB LED 10x10 con modulación de ángulo de bits de registros de desplazamiento

0

He construido una matriz de LED de 10x10 RGB. Los LEDs están conectados en filas y columnas. Eso es 40 pines (30 para RGB, 10 para GND). Conseguí 5 74CH595 IC's y soldé todo juntos. También agregué un BJT 1A al frente de cada fila / columna para proteger el Arduino + del IC y poder usar una fuente de alimentación externa. Los 3 pines (Data, Clock, latch) de los IC están conectados a mi micro arduino.

Todo funciona muy bien (incluso con multiplexación) cuando no uso la Modulación de Ángulo de Bit.

Palabras que probablemente. no sé:

  

BAM = Modulación de ángulo de bits

     

En los comentarios "... (Datos) una" significa que el pin ... (Datos) está activado.       "... (Datos) aus" significa que el pin de Datos está desactivado.

¿Por qué utilizo el código de la biblioteca FastLED:

  

Lo uso porque hay un software de animación muy bueno para eso       Libary / Tipo de LED.

El Código utiliza el 10% de la memoria del programa y el 21% de la memoria dinámica.

Aquí está mi código (Arduino IDE 1.6.7, no Lib)

class FLED {
private:
bool b;

public:
FLED();
void show();
};

FLED::FLED() : b(false) {

}

void FLED::show() {

}


class LED {
  private:
uint8_t LEDname;
uint8_t R;
uint8_t G;
uint8_t B;

 public:
LED();
uint8_t getR();
uint8_t getG();
uint8_t getB();
void setR(uint8_t _R);
void setG(uint8_t _G);
void setB(uint8_t _B);
};

LED::LED() : R(0), G(0), B(0) {

}

uint8_t LED::getR() {
  return R;
}
uint8_t LED::getG() {
  return G;
}
uint8_t LED::getB() {
  return B;
}

void LED::setR(uint8_t _R) {
  R = _R;
}
void LED::setG(uint8_t _G) {
  G = _G;
}
void LED::setB(uint8_t _B) {
  B = _B;
}

LED leds[100];
FLED FastLED;


void setup() {
  //set pins to output so you can control the shift register
  pinMode(2, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  //Serial.begin(1000000);


}

uint8_t BitMapR1[10] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};
uint8_t BitMapR2[10] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
 B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};
uint8_t BitMapR3[10] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};

uint8_t BitMapR4[10] = {
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000,
  B00000000
};

LED CRGB(byte _R, byte _G, byte _B) {
  LED _LED = LED();
  _LED.setR(constrain(_R / 16, 0, 15));
  _LED.setG(constrain(_G / 16, 0, 15));
  _LED.setB(constrain(_B / 16, 0, 15));
  return _LED;
}

void loop() {
  //Serial.print(micros()); Serial.println(" Start");

  leds[0] = CRGB(0, 0, 0);
  leds[1] = CRGB(0, 0, 0);
  leds[2] = CRGB(0, 0, 0);
  leds[3] = CRGB(0, 0, 0);
  leds[4] = CRGB(0, 0, 0);
  leds[5] = CRGB(0, 0, 0);
  leds[6] = CRGB(0, 0, 0);
  leds[7] = CRGB(0, 0, 0);
  leds[8] = CRGB(0, 0, 0);
  leds[9] = CRGB(0, 0, 0);
  leds[10] = CRGB(0, 0, 0);
  leds[11] = CRGB(0, 0, 0);
  leds[12] = CRGB(0, 0, 0);
  leds[13] = CRGB(0, 0, 0);
  leds[14] = CRGB(0, 0, 0);
  leds[15] = CRGB(0, 0, 0);
  leds[16] = CRGB(0, 0, 0);
  leds[17] = CRGB(0, 0, 0);
  leds[18] = CRGB(0, 0, 0);
  leds[19] = CRGB(0, 0, 0);
  leds[20] = CRGB(0, 0, 0);
  leds[21] = CRGB(0, 0, 0);
  leds[22] = CRGB(0, 0, 0);
  leds[23] = CRGB(0, 0, 0);
  leds[24] = CRGB(0, 0, 0);
  leds[25] = CRGB(0, 0, 0);
  leds[26] = CRGB(0, 0, 0);
  leds[27] = CRGB(0, 0, 0);
  leds[28] = CRGB(0, 0, 0);
  leds[29] = CRGB(0, 0, 0);
  leds[30] = CRGB(16, 0, 0);
  leds[31] = CRGB(32, 0, 0);
  leds[32] = CRGB(48, 0, 0);
  leds[33] = CRGB(64, 0, 0);
  leds[34] = CRGB(96, 0, 0);
  leds[35] = CRGB(128, 0, 0);
  leds[36] = CRGB(180, 0, 0);
  leds[37] = CRGB(200, 0, 0);
  leds[38] = CRGB(255, 0, 0);
  leds[39] = CRGB(0, 0, 0);
  leds[40] = CRGB(0, 0, 0);
  leds[41] = CRGB(0, 0, 0);
  leds[42] = CRGB(0, 0, 0);
  leds[43] = CRGB(0, 0, 0);
  leds[44] = CRGB(0, 0, 0);
  leds[45] = CRGB(0, 0, 0);
  leds[46] = CRGB(0, 0, 0);
  leds[47] = CRGB(0, 0, 0);
  leds[48] = CRGB(0, 0, 0);
  leds[49] = CRGB(0, 0, 0);
  leds[50] = CRGB(16, 0, 0);
  leds[51] = CRGB(32, 0, 0);
  leds[52] = CRGB(48, 0, 0);
  leds[53] = CRGB(64, 0, 0);
  leds[54] = CRGB(96, 0, 0);
  leds[55] = CRGB(128, 0, 0);
  leds[56] = CRGB(180, 0, 0);
  leds[57] = CRGB(200, 0, 0);
  leds[58] = CRGB(255, 0, 0);
  leds[59] = CRGB(0, 0, 0);
  leds[60] = CRGB(0, 0, 0);
  leds[61] = CRGB(0, 0, 0);
  leds[62] = CRGB(0, 0, 0);
  leds[63] = CRGB(0, 0, 0);
  leds[64] = CRGB(0, 0, 0);
  leds[65] = CRGB(0, 0, 0);
  leds[66] = CRGB(0, 0, 0);
  leds[67] = CRGB(0, 0, 0);
  leds[68] = CRGB(0, 0, 0);
  leds[69] = CRGB(0, 0, 0);
  leds[70] = CRGB(0, 0, 0);
  leds[71] = CRGB(0, 0, 0);
  leds[72] = CRGB(0, 0, 0);
  leds[73] = CRGB(0, 0, 0);
  leds[74] = CRGB(0, 0, 0);
  leds[75] = CRGB(0, 0, 0);
  leds[76] = CRGB(0, 0, 0);
  leds[77] = CRGB(0, 0, 0);
  leds[78] = CRGB(0, 0, 0);
  leds[79] = CRGB(0, 0, 0);
  leds[80] = CRGB(0, 0, 0);
  leds[81] = CRGB(0, 0, 0);
  leds[82] = CRGB(0, 0, 0);
  leds[83] = CRGB(0, 0, 0);
  leds[84] = CRGB(0, 0, 0);
  leds[85] = CRGB(0, 0, 0);
  leds[86] = CRGB(0, 0, 0);
  leds[87] = CRGB(0, 0, 0);
  leds[88] = CRGB(0, 0, 0);
  leds[89] = CRGB(0, 0, 0);
  leds[90] = CRGB(0, 0, 0);
  leds[91] = CRGB(0, 0, 0);
  leds[92] = CRGB(0, 0, 0);
  leds[93] = CRGB(0, 0, 0);
  leds[94] = CRGB(0, 0, 0);
  leds[95] = CRGB(0, 0, 0);
  leds[96] = CRGB(0, 0, 0);
  leds[97] = CRGB(0, 0, 0);
  leds[98] = CRGB(0, 0, 0);
  leds[99] = CRGB(0, 0, 0);
  //Serial.print(micros()); Serial.println(" Objekte");
  FastLED.show();
  //setBitMaps();
  //myloop();
  while(true) {
    BAM();

  }

  //Serial.print(micros()); Serial.println(" BAM");

}

void BAM() {
  for (int cycle = 1; cycle <= 15; cycle++) {
setBitMaps(cycle, 1);
myloop();


  }
}

void setBitMaps(int cycle, int pos) {


  //Register 1
  for (byte intLayerSel = 0; intLayerSel < 100; intLayerSel += 10) { 

byte _byte = 0;
for (byte i = intLayerSel; i < intLayerSel + 8; i++) {
  if (cycle == 1 && (leds[i].getR() & (1 << pos - 1)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if ((cycle == 2 || cycle == 3) && (leds[i].getR() & (1 << pos)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 4 && cycle <= 7 && (leds[i].getR() & (1 << pos + 1 )) != 0)  {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else if (cycle >= 8 && cycle <= 15 && (leds[i].getR() & (1 << pos + 2)) != 0) {
    _byte = _byte << 1;
    _byte = _byte + B00000001;
  }
  else {
    _byte = _byte << 1;
    _byte = _byte + B00000000;
  }
}
BitMapR1[intLayerSel / 10] = _byte;
  }
}



void myloop() {
  byte bLayerA;
  byte bLayerB;

  for (byte bLayerTop = 1; bLayerTop <= 10; bLayerTop++) {
bLayerA = B00000000;
bLayerB = B00000000;
if (bLayerTop == 1) {
  bLayerA = B10000000;
} else if (bLayerTop == 2) {
  bLayerA = B01000000;
} else if (bLayerTop == 3) {
  bLayerA = B00100000;
} else if (bLayerTop == 4) {
  bLayerA = B00010000;
} else if (bLayerTop == 5) {
  bLayerA = B00001000;
} else if (bLayerTop == 6) {
  bLayerA = B00000100;
} else if (bLayerTop == 7) {
  bLayerA = B00000010;
} else if (bLayerTop == 8) {
  bLayerA = B00000001;
} else if (bLayerTop == 9) {
  bLayerB = B00000010;
} else if (bLayerTop == 10) {
  bLayerB = B00000001;
}




// take the latchPin low so
// the LEDs don't change while you're sending in bits:
// shift out the bits:
/*
  shiftOut(dataPin, clockPin, MSBFIRST, bLayerA);
  shiftOut(dataPin, clockPin, MSBFIRST, bLayerB + B00111111);
  shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
  shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
  shiftOut(dataPin, clockPin, MSBFIRST, B11111111);


  PORTD &= ~_BV(PORTD2);
  delayMicroseconds(35);//delay < 35 flackert
  PORTD |= _BV(PORTD2);

*/



PORTD &= ~_BV(PORTD2);
byte bLayer = bLayerTop - 1;
ShiftOut(bLayerA);
ShiftOut(bLayerB + BitMapR4[bLayer]);
ShiftOut(BitMapR3[bLayer]);
ShiftOut(BitMapR2[bLayer]);
//ShiftOut(B11111111);
ShiftOut(BitMapR1[bLayer]);

//take the latch pin high so the LEDs will light up:
PORTD |= _BV(PORTD2);//LatchPin

// pause before next value:

//delay(1);
delayMicroseconds(100);

  }
}

void ShiftOut(byte myDataOut) {
  // This shifts 8 bits out MSB first,
  //on the rising edge of the clock,
  //clock idles low

  //internal function setup
  byte i = 0;

  //clear everything out just in case to
  //prepare shift register for bit shifting
  PORTD &= ~_BV(PORTD3);//Data aus
  PORTD &= ~_BV(PORTD4);//Clock aus

  //for each bit in the byte myDataOutï
  //NOTICE THAT WE ARE COUNTING DOWN in our for loop
  //This means that %00000001 or "1" will go through such
  //that it will be pin Q0 that lights.
  for (i = 0; i <= 7; i++)  {
    PORTD &= ~_BV(PORTD4);//Clock aus

    //if the value passed to myDataOut and a bitmask result
    // true then... so if we are at i=6 and our value is
    // %11010100 it would the code compares it to %01000000
    // and proceeds to set pinState to 1.
    if ( myDataOut & (1 << i) ) {
  PORTD |= _BV(PORTD3);//Data an
} else {
  PORTD &= ~_BV(PORTD3);//Data aus
}
//register shifts bits on upstroke of clock pin
PORTD |= _BV(PORTD4);//Clock an
//zero the data pin after shift to prevent bleed through
PORTD &= ~_BV(PORTD3);//Data aus
  }
}

Mi primer problema es que la última fila (2 o 10) es más brillante que las otras filas. Creo que este es el momento en que el bucle se reinicia y rellena los Objetos (led en leds) con datos nuevos.

  1. Creo que mi código es lento porque todavía tengo algunos parpadeo cuando hago BAM. Si alguien tiene un consejo para mí sobre cómo obtener el código más rápido, sería muy bueno si me lo dijera :)

Si lo necesitas, puedo subir un esquema, pero mi Internet es muy lento, así que no lo hago ahora.

Aquí hay una simulación hecha para probar el código. Es solo 1 color y 8x8 pero funciona de la misma manera: enlace

    
pregunta Tom Stein

1 respuesta

1

Creo que sus problemas no son de hardware sino del software que utiliza. La razón por la que obtiene una luz intermitente periódica o un brillo incoherente entre las filas mientras multiplexa una matriz de LED es que el tiempo de encendido de cada fila no es consistente. A pesar de que su ojo no puede ver cómo la fila se enciende y se apaga porque está sucediendo más rápido de lo que permite su persistencia de visión, su ojo puede detectar las diferencias en total a tiempo. Este es el principio básico detrás de la habilitación de la escala de grises basada en PWM en los LED. Para arreglar las cosas, debe asegurarse de que el tiempo en cada fila sea consistente.

El problema principal es que el retraso de 100 microsegundos entre filas no es lo mismo que actualizar cada fila cada 100 microsegundos. La cantidad de tiempo para actualizar una fila con su código puede variar. Por ejemplo, si actualiza la fila 1, luego demora 100 microsegundos, entonces se necesitan 200 microsegundos para actualizar la fila 2, la fila 1 ha estado activa por un total de 300 microsegundos. Si se necesitan 50 microsegundos para actualizar la fila 3, la fila 2 habría estado activada durante 150 microsegundos. A continuación, puede ver cómo el uso de un retraso entre cada actualización de fila puede llevar a tiempos inconsistentes si los cálculos de cada fila son inconsistentes.

En su código, hay varias cosas que podrían llevar a una incoherencia en el tiempo entre las filas. Primero, usa un bloque de 10 niveles de if-then para determinar los bits de control de fila. Eso tomará más tiempo evaluar en la fila 10 que en la fila 1 y es probable que las filas inferiores sean más brillantes que las filas superiores. Segundo, un efecto similar se emitirá en su función setBitMaps() al evaluar las diferencias de comportamiento entre ciclos. Sospecho que esto amplifica el brillo de la última fila. Finalmente, está creando efectivamente su propio bucle dentro del bucle AVR general. Cuando salga de su propio bucle y vuelva a hacer el bucle AVR principal, volverá a calcular completamente el mapa de bits para sus LED. Sospecho que esto está causando apuñalamientos ocasionales, ya que tomará más tiempo antes de que vuelva a ingresar a sus bucles internos que realizan las exploraciones de ciclo, lo que significa que mientras está recalculando el mapa de bits, los LED quedan en la última configuración , de ahí un destello momentáneo de brillo (estroboscópico).

Hice una matriz de 8x8 LED de diseño similar y escribí un controlador que está disponible en GitHub aquí . Mi controlador es capaz de crear una imagen estable (sin flash). Si bien mi controlador es un poco más robusto que el suyo, la diferencia clave es que estoy usando una interrupción de temporizador en el microcontrolador AVR. Fuera de la interrupción, hago todos los cálculos necesarios para determinar cuáles deben ser los bits para cada fila, y cuando la interrupción se dispara, todo lo que hago es eliminar los bits de las siguientes filas en los registros de desplazamiento. Utilizo SPI en lugar de golpear los bits, pero el concepto general sigue siendo el mismo. Lo que proporciona la interrupción del temporizador es un tiempo de inicio consistente para cada actualización de la fila, y solo hacer la transmisión de bits durante la interrupción hace que el trabajo se haga muy consistente, por lo que las actualizaciones de la fila (cuando se dispara el pin de cierre) se cronometran de manera muy consistente, lo que resulta en Una imagen suave.

Otro elemento clave de mi diseño es que tengo dos buffers de bits que contienen los bits de fila para un cuadro de imagen dado. El volcado de bits fila por fila se produce desde un búfer, mientras que el cálculo para el siguiente cuadro de imagen se realiza en el otro búfer. Cuando el siguiente marco de imagen está listo y el escaneo de la fila se está reiniciando, simplemente cambio los búferes. Esto ayuda a enfocar el trabajo necesario durante las interrupciones del temporizador a solo ser la transmisión de los bits de fila a los registros de desplazamiento.

    
respondido por el Kamprath

Lea otras preguntas en las etiquetas