Ich möchte die Erfahrung mit der Erstellung eines 8x8-Pixel-LED-Displays, 262k-Farbkombinationen (18 Bit), einer Bildrate von 180 FPS und einer USB-Verbindung teilen. Ich bin auch bereit, Vorschläge zur Optimierung und Verfeinerung anzuhören. In Zukunft plane ich, die Best Practices zu verwenden, um eine Anzeige der Heimwetterstation zu erstellen.Vorwort
Alles begann mit dem einfachsten Steuerungsschema für eine Reihe von 8 LEDs über einen LPT-Port. Die nächste Version war eine 5x8-Karte mit dreifarbigen LEDs, die ebenfalls mit dem LPT verbunden war, und tatsächlich eine Anordnung von fünfzehn 8-Bit-Puffern mit einem Decoder für ihre Adressierung. Später, nachdem ich mich mit Mikrocontrollern getroffen hatte, machte ich mich daran, ein ähnliches Display zu erstellen, jedoch mit einer USB-Verbindung. Zunächst werden voraussichtlich nur 8 Farben verwendet. Anschließend fand er einen Weg, die Helligkeit jeder Diode mithilfe eines Timers in Analogie zu PWM zu steuern, und nach Abschluss des Softwareteils stellte sich das aktuelle Gerät heraus. Theoretisch können Sie mit 16 Millionen Farben arbeiten, aber herkömmliche LEDs sind für diesen Modus hinsichtlich Farbwiedergabe und Wiederholbarkeit nicht geeignet. Außerdem sind in der aktuellen Konfiguration bereits Probleme mit der Farbe verschiedener Dioden sichtbar.Stellenbeschreibung
Das Gerät basiert auf dem Mikrocontroller PIC18F4550, der mit einer Frequenz von 48 MHz arbeitet. Es werden ein eingebauter USB-Controller und eine vorgefertigte Bibliothek zum Arbeiten verwendet, Timer0 im 8-Bit-Modus, der die dynamische Anzeige implementiert. Um drei Farben in einer Spalte zu speichern, wurden drei 8-Bit-Trigger auf 74F374 verwendet. Durch die Verwendung eines solchen Puffers kann die Anzeigezeit eines Frames um das Dreifache reduziert werden. Hinweis: Bei der Auswahl des 74F374-Puffers habe ich nicht auf die Verkabelung der Beine geachtet, sondern dies nur am Montageständer verstanden, sodass ich die Platine erheblich komplizieren musste. Es ist besser, bequemere Analoga zu verwenden. Zum Beispiel 74HC574. Die LEDs werden über die Tasten ULN2803 und UDN2982 angeschlossen. Strombegrenzungswiderstände liegen nur im roten Kanal, weil Ihre Versorgungsspannung liegt unter blau und grün. Für Blau und Grün sind keine Widerstände installiert, weil genug Spannungsabfall an den Tasten. Hinweis: Für eine genauere Farbwiedergabe ist es besser, in jedem Kanal genauere Strombegrenzungswiderstände auszuwählen. Der Mikrocontroller fragt in einem Endloszyklus den USB-Status ab und startet / stoppt die Anzeige, wenn ein Datenpaket ankommt, abhängig vom Befehl oder bereitet die Daten für die Anzeige vor. Aufgrund der Begrenzung der Größe eines Pakets auf 64 Bytes werden die Daten für jede Farbe in einem separaten Paket von 48 Bytes übertragen - 6 Bytes für jede der 8 Spalten, wobei die Helligkeit jeder LED in der Spalte codiert wird. Nach Erhalt jedes Pakets wird es vom USB-Speicher in ein Array seiner Farbe kopiert. Nachdem der Anzeigestartbefehl empfangen wurde, aktiviert der MK den Timer im 8-Bit-Modus und einen Divisor um 128. Der Timer verwendet die Betriebsfrequenz des Mikrocontrollers als Taktimpulse. Eine Erhöhung des Timer-Zählers erfolgt alle 4 Takte. Die minimale Zeitdauer beträgt 10,6 μs (1/48 * 4 * 128), was ungefähr dem 2,8-fachen der Interrupt-Verarbeitungszeit entspricht (46 Operationen gegenüber 128 Zeitgeber-Abtastwerten). Wenn der Timer überläuft, wird ein Interrupt mit hohem Vektor ausgeführt. Der Interrupt-Handler deaktiviert die Anzeige, aktualisiert die Daten in den Puffern, überträgt 1 Byte von jedem Farbarray entsprechend dem Cursor und schaltet dann die Anzeige ein. Gibt einen neuen Wert aus dem temporären Puffer in den Timer ein, dekrementiert den Cursor und verschiebt den temporären Puffer für den Timer. Wenn der Zeitgeberpuffer den Maximalwert überschreitet, d.h. Mehr als fünfmal verschoben, wird der Timer-Puffer auf den Minimalwert zurückgesetzt und der Zeiger der ausgewählten Spalte verschoben.Als Ergebnis wird der folgende dynamische Anzeigealgorithmus erhalten:- Wir nehmen die erste Gruppe von 3 Bytes aus drei Arrays und legen sie in die Puffer jeder Farbe in der Spalte.
- Wir aktivieren den Timer mit einer minimalen Verzögerungszeit von 128 Ticks.
- Wir nehmen die nächste Gruppe von 3 Bytes aus drei Arrays und legen sie in die Puffer jeder Farbe in der Spalte.
- Wir aktivieren den Timer mit einer doppelten Verzögerung gegenüber dem vorherigen Schritt.
- Wiederholen Sie die Probe noch 4 Mal und verdoppeln Sie die Verzögerungszeit jedes Mal.
- Wir setzen den Timer zurück und beginnen mit der Verarbeitung der nächsten Spalte ab Schritt 1.
Somit können wir für jede Diode in der Spalte 2 ^ 6 = 64 Helligkeitsoptionen einstellen. Wenn wir die Helligkeit jeder der drei Grundfarben kombinieren, erhalten wir 64 * 64 * 64 = 262144 Farben. Die Verarbeitungszeit für eine Spalte beträgt (2 ^ 6-1) * 10,6 μs = 672 μs. Die Zeit pro Frame von 8 Spalten beträgt 672 * 8 = 5,4 ms, was ungefähr 186 Frames pro Sekunde entspricht.Verwendete Komponenten
Schema
Schema im DSN-Format - DownloadGebühr
Lay6 Zeichnungen - herunterladenGrafikHauptmodulseite 1
Hauptmodulseite 2
LED-Modul (Beachten Sie, dass das Überbrückungskabel, das die Säulen verbindet, blau markiert ist)
LED-Montagematrix
Firmware
Quellen und zusammengesetztes HEX in MPLABX X IDE v2.30 - herunterladenHauptcode#ifndef MAIN_C
#define MAIN_C
#include "config.h"
#include "usb.h"
#include "HardwareProfile.h"
#include "usb_function_hid.h"
#include "genericHID.h"
#define UdnOn LATA&=0b11111110
#define UdnOff LATA|=0b00000001
#define UlnOn LATD
#define UlnOff LATD =0b00000000
#define LineBufer LATB
#define WriteR LATE|=0b00000001
#define WriteG LATE|=0b00000010
#define WriteB LATE|=0b00000100
#define WriteRst LATE =0b00000000
#define Columns 8
#define BrightLevels 6
#define BlockSize (Columns*BrightLevels)
#define MinBright 0b11111111
unsigned char cursor;
unsigned char bright;
unsigned char column;
unsigned char dataR[BlockSize];
unsigned char dataG[BlockSize];
unsigned char dataB[BlockSize];
void ProcessIO(void) {
unsigned char temp = BlockSize + 1;
if ((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1)) return;
if (!HIDRxHandleBusy(USBOutHandle))
{
switch (ReceivedDataBuffer[0])
{
case 0x80:
while (--temp) dataR[temp-1] = ReceivedDataBuffer[temp];
break;
case 0x81:
while (--temp) dataG[temp-1] = ReceivedDataBuffer[temp];
break;
case 0x82:
while (--temp) dataB[temp-1] = ReceivedDataBuffer[temp];
break;
case 0x90:
column = 0b00000001;
cursor = BlockSize;
bright = MinBright;
TMR0ON = 1;
SWDTEN = 0;
break;
case 0x91:
UdnOff;
UlnOff;
TMR0ON = 0;
SWDTEN = 0;
break;
case 0x92:
UdnOff;
UlnOff;
TMR0ON = 0;
SWDTEN = 0;
SLEEP();
break;
}
USBOutHandle = HIDRxPacket(HID_EP, (BYTE*) & ReceivedDataBuffer, 64);
}
}
void main(void)
{
PCFG3 = 1;
PORTA = 0b00000000;
PORTB = 0b00000000;
PORTC = 0b00000000;
PORTD = 0b00000000;
PORTE = 0b00000000;
TRISA = 0b00000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
TRISD = 0b00000000;
TRISE = 0b00000000;
INTCON = 0b10100000;
T0CON = 0b01000110;
USBDeviceInit();
while(1)
{
USBDeviceTasks();
ProcessIO();
};
}
void interrupt tc_int()
{
UdnOff;
UlnOff;
LineBufer = dataR[cursor-1]; WriteR;
LineBufer = dataG[cursor-1]; WriteG;
LineBufer = dataB[cursor-1]; WriteB;
UdnOn;
UlnOn = column;
WriteRst;
TMR0L = bright;
if (!--cursor) cursor = BlockSize;
bright <<= 1;
asm("BTFSS _bright, 5, 0"); asm("RLNCF _column, 1, 0");
asm("BTFSS _bright, 5, 0"); bright = MinBright;
TMR0IF = 0;
}
#endif
Gerät in Betrieb
Zur Steuerung verwende ich einen in C geschriebenen Internetradio-Player, der auf der BASS.DLL-Bibliothek basiert. Eine Verlaufsdemo über die gesamte verfügbare Farbpalette funktioniert während einer Pause. Die Aktualisierungsrate der Frames (an das Gerät übertragene Pakete) beträgt 20 Hz. Bei der Musikwiedergabe arbeitet ein Visualizer mit dem von BASS.DLL erhaltenen FFT-Array. Die Bildwiederholfrequenz von Frames (an das Gerät übertragene Pakete) beträgt in diesem Modus 29 Hz.Visualizer
Musik: Tape Five - Soulsalicious
: ( ) ( ). .. , .- ( UDN)
- USB
- smd
- 74F374 74HC574,
- 74F374
- 74HC138,
- 3 ULN, UDN