Prototipe 262.144 kombinasi warna LED dan 64 piksel

    Saya ingin berbagi pengalaman membuat tampilan LED 8x8 piksel, kombinasi warna 262k (18 bit), frame rate 180 FPS dan koneksi USB. Saya juga siap mendengarkan saran untuk pengoptimalan dan penyempurnaan. Di masa depan saya berencana untuk menggunakan praktik terbaik untuk membuat tampilan stasiun cuaca rumah.

Kata Pengantar


    Semuanya dimulai dengan skema kontrol paling sederhana untuk garis 8 LED melalui port LPT. Versi berikutnya adalah papan 5x8 LED tiga warna, yang juga terhubung ke LPT dan, pada kenyataannya, adalah array lima belas buffer 8-bit dengan decoder untuk pengalamatan mereka.
    Kemudian, setelah bertemu dengan mikrokontroler, saya berangkat untuk membuat tampilan yang serupa, tetapi dengan koneksi USB. Awalnya diperkirakan hanya menggunakan 8 warna. Selanjutnya, ia menemukan cara untuk mengontrol kecerahan masing-masing dioda menggunakan timer dengan analogi dengan PWM, dan setelah menyelesaikan bagian perangkat lunak, perangkat saat ini ternyata. Secara teoritis, Anda dapat bekerja dengan 16 juta warna, tetapi LED konvensional tidak cocok untuk mode ini dalam hal reproduksi warna dan pengulangan. Selain itu, masalah dengan warna dioda yang berbeda sudah terlihat pada konfigurasi saat ini.

Deskripsi pekerjaan


    Perangkat ini didasarkan pada mikrokontroler PIC18F4550 yang beroperasi pada frekuensi 48 MHz. Pengontrol USB bawaan dan pustaka siap pakai untuk bekerja dengannya digunakan, Timer0 dalam mode 8-bit, yang mengimplementasikan indikasi dinamis. Untuk menyimpan tiga warna dalam satu kolom, digunakan tiga pemicu 8-bit pada 74F374. Menggunakan buffer semacam itu memungkinkan untuk mengurangi waktu tampilan satu frame sebanyak 3 kali. Catatan: Ketika saya memilih buffer 74F374, saya tidak memperhatikan kabel kakinya, tapi saya mengerti ini hanya pada dudukan pemasangan, jadi saya harus menyulitkan papan secara signifikan. Lebih baik menggunakan analog yang lebih nyaman. Misalnya, 74HC574.
    LED terhubung melalui tombol ULN2803 dan UDN2982. Tahanan yang membatasi saat ini hanya ada di saluran merah, karena tegangan suplai mereka di bawah biru dan hijau. Untuk resistensi biru dan hijau tidak diinstal, karena cukup drop tegangan pada tombol. Catatan: Untuk reproduksi warna yang lebih akurat, lebih baik untuk memilih resistensi pembatas arus yang lebih akurat di setiap saluran.
    Mikrokontroler dalam siklus tanpa akhir menyurvei status USB dan, ketika sebuah paket data tiba, tergantung pada perintahnya, memulai / menghentikan tampilan atau menyiapkan data untuk ditampilkan. Karena keterbatasan ukuran satu paket hingga 64 byte, data untuk setiap warna ditransmisikan dalam paket terpisah 48 byte - 6 byte untuk masing-masing 8 kolom, yang menyandikan kecerahan setiap LED dalam kolom. Setelah menerima setiap paket, itu disalin dari memori USB ke array warnanya.
    Setelah perintah mulai indikasi diterima, MK mengaktifkan timer dalam mode 8-bit dan pembagi dengan 128. Timer menggunakan frekuensi operasi mikrokontroler sebagai pulsa clock. Peningkatan penghitung waktu terjadi setiap 4 langkah. Periode timer minimum adalah 10,6 μs (1/48 * 4 * 128), yang kira-kira 2,8 kali waktu pemrosesan interupsi (46 operasi, terhadap 128 sampel timer).
    Ketika timer meluap, interupsi vektor tinggi dilakukan. Interrupt handler menonaktifkan indikasi, memperbarui data dalam buffer, mentransfer 1 byte dari setiap array warna sesuai dengan kursor, kemudian menyalakan indikasi. Memasukkan nilai baru ke timer dari buffer sementara, menurunkan kursor, menggeser buffer sementara untuk timer. Jika buffer waktu melebihi nilai maksimum, mis. bergeser lebih dari 5 kali, buffer waktu diatur ulang ke nilai minimum dan penunjuk kolom yang dipilih digeser.
Hasilnya, algoritma indikasi dinamis berikut diperoleh:
  1. Kami mengambil kelompok pertama 3 byte dari tiga array dan dimasukkan ke dalam buffer setiap warna di kolom.
  2. Kami mengaktifkan timer dengan waktu tunda minimum 128 kutu.
  3. Kami mengambil kelompok berikutnya 3 byte dari tiga array dan dimasukkan ke dalam buffer masing-masing warna di kolom.
  4. Kami mengaktifkan timer dengan penundaan ganda relatif terhadap langkah sebelumnya.
  5. Ulangi sampel 4 kali lebih banyak dan gandakan waktu tunda setiap kali.
  6. Kami mengatur ulang timer dan mulai memproses kolom berikutnya dari langkah 1.

    Dengan demikian, kita dapat mengatur 2 ^ 6 = 64 opsi kecerahan untuk setiap dioda dalam kolom. Menggabungkan kecerahan dari masing-masing tiga warna dasar, kita mendapatkan 64 * 64 * 64 = 262144 warna. Waktu pemrosesan untuk satu kolom adalah (2 ^ 6-1) * 10,6 μs = 672 μs. Waktu per frame dari 8 kolom adalah 672 * 8 = 5.4ms, yang kira-kira sama dengan 186 frame per detik.

Komponen yang Digunakan


  • PIC18F4550 - Mikrokontroler
  • 74F374 - Pemicu untuk memegang nilai kolom saat ini
  • ULN2803 - Kunci untuk kontrol katoda
  • UDN2982 - Kunci untuk mengendalikan anoda
  • LED RGB 4-pin dengan katoda umum (LED apa saja dapat digunakan)

Skema


Skema dalam format dsn - unduh
Grafik


Biaya


Gambar Lay6 - unduh
Grafik
1


2


( , , )





Firmware


Sumber dan rakitan HEX dalam MPLABX X IDE v2.30 - unduh
Kode utama
#ifndef MAIN_C
#define MAIN_C

// Local includes
#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 we are not in the configured state just return
    if ((USBDeviceState < CONFIGURED_STATE) || (USBSuspendControl == 1)) return;

    //Check if data was received from the host.
    if (!HIDRxHandleBusy(USBOutHandle))
    {
        switch (ReceivedDataBuffer[0])
        {
            case 0x80: // get red packet
                while (--temp) dataR[temp-1] = ReceivedDataBuffer[temp];
                break;

            case 0x81: // get green packet
                while (--temp) dataG[temp-1] = ReceivedDataBuffer[temp];
                break;

            case 0x82: // get blue packet
                while (--temp) dataB[temp-1] = ReceivedDataBuffer[temp];
                break;

            case 0x90: // start
                column = 0b00000001;
                cursor = BlockSize;
                bright = MinBright;
                TMR0ON = 1;
                SWDTEN = 0;
                break;

            case 0x91: // stop
                UdnOff;
                UlnOff;
                TMR0ON = 0;
                SWDTEN = 0;
                break;

            case 0x92: // power off
                UdnOff;
                UlnOff;
                TMR0ON = 0;
                SWDTEN = 0;
                SLEEP();
                break;
        }

        // Re-arm the OUT endpoint for the next packet
        USBOutHandle = HIDRxPacket(HID_EP, (BYTE*) & ReceivedDataBuffer, 64);
    }
}

void main(void)
{
    // Set all port as digital input/output
    PCFG3   = 1;

    // Clear all ports
    //          76543210
    PORTA   = 0b00000000;
    PORTB   = 0b00000000;
    PORTC   = 0b00000000;
    PORTD   = 0b00000000;
    PORTE   = 0b00000000;

    // Configure ports (1 - inputs; 0 - outputs)
    //          76543210
    TRISA   = 0b00000000;
    TRISB   = 0b00000000;
    TRISC   = 0b00000000;
    TRISD   = 0b00000000;
    TRISE   = 0b00000000;

    // Configure interrupts for Timer0
    //          76543210
    INTCON  = 0b10100000;

    // Configure Timer0 as 8bit and 128 prescaler
    //          76543210
    T0CON   = 0b01000110;

    USBDeviceInit();

    while(1)
    {
        // Check bus status and service USB interrupts.
        USBDeviceTasks();

        // Application-specific tasks.
        ProcessIO();
    };
}

void interrupt tc_int() // High priority interrupt
{
    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



Perangkat sedang beroperasi


    Untuk kontrol, saya menggunakan pemutar radio Internet yang ditulis dalam C, yang didasarkan pada perpustakaan BASS.DLL. Demo gradien di seluruh palet warna yang tersedia berfungsi selama jeda, kecepatan refresh frame (paket yang dikirim ke perangkat) adalah 20 Hz. Saat memutar musik, visualisator bekerja menggunakan array FFT yang diperoleh BASS.DLL, kecepatan refresh frame (paket yang dikirimkan ke perangkat) dalam mode ini adalah 29 Hz.

Gradien


Visualizer

: Tape Five — Soulsalicious

: ( ) ( ). .. , .







  • ( UDN)
  • USB
  • smd
  • 74F374 74HC574,
  • 74F374
  • 74HC138,
  • 3 ULN, UDN

Source: https://habr.com/ru/post/id392815/


All Articles