Önce bu P10 panellerin devre şemasını inceleyerek başlamak kontrol işleminin anlaşılması bakımından daha iyi olacaktır. Genel olarak devre şeması Şekil 1'de gösterildiği gibidir.
Şekil 1 - P10 Panel Şematiği |
Şimdi de kontrol etmekte kullanacağımız giriş bağlantılarının neler olduğuna bir bakalım. Giriş bağlantı soketindeki pinler Şekil 2'deki gibidir.
Şekil 2 - Giriş bağlantı soketi |
Burda OE (Output Enable) MOSFET'lerden isteneni seçen 74HC138'in çıkışlarını aktif hale getirmekte kullanılıyor. Bu pine 1 verilirse çıkışlar aktif, 0 verilirse kapalıdır. Böylece istenen bir anda ekran görüntüsü tamamen kapatılabilir.
A ve B pinleri ise 4 MOSFET'den birini, dolayısıyla satır seçimini sağlıyor. Böylece shift register çıkışlarındaki değerler istenen MOSFET'e bağli istenen satır LED'lerinin yanması sağlanmış oluyor.
CKL ve R (isimlendirmeler biraz garip ama orjinal devrede bu şekilde) sırasıyla SPI hattının CLK ve MOSI pinlerinin bağlanacağı pinler. Böylece artık nerdeyse tüm mikrokontrolörlerde bulunan SPI arabirimi kullanılarak tarama işlemi hızlandırılabilir. Hatta artık nerdeyse 8 bit mikrokontrolörlerin yerini almaya başlayan ARM Cortex-Mx ailesi mikrokontrolörlerde standart olarak yer alan DMA ile işlemci zamanını almadan tarama işlemi yapılabilir.
Son kalan SCLK pini ise 74HC595'lere shift edilmiş değerleri çıkışlara aktaran latch pin'i.
PIC18F14K50 İle Örnek Bir Uygulama
Öncelikle hangi pin soketteki hangi pine bağlandı onunla başlayalım. Benim devredeki bağlantılar şu şekilde (P10 panel bağlantı isimlerini daha anlamlı olacak şekilde değiştirdim):
P10(1R)-V706A | PIC18F14K50 |
---|---|
OE | RC5 |
A | RC4 |
B | RC3 |
LATCH | RC6 |
SPI_SCLK | RB6 (SPI) |
SPI_MOSI | RC7 (SPI) |
Şimdi test kodunu incelemeye başlayabiliriz. Öncelikle panel ile ilgili işlemlerin yapıldığı ledmatrix.c ve ledmatrix.h dosyalarından başlayalım.
#include <xc.h> #include <string.h> #include <pic18f14k50.h> #include "ledmatrix.h" #include "8x12_horizontal_MSB_1.h" #define OE LATCbits.LC5 #define A LATCbits.LC4 #define B LATCbits.LC3 #define LATCH LATCbits.LC6 #define FONT_HEIGHT 12 #define FONT_WIDTH 8 #define ROW_BYTE_COUNT 4 #define COLUMN_BYTE_COUNT 16 unsigned char buffer[2][ROW_BYTE_COUNT][COLUMN_BYTE_COUNT]; unsigned int scan_count = 0; unsigned char line = 3; unsigned char active = 0; unsigned char back = 1; unsigned char swap = 0; static void inline LEXMATRIX_SpiSend(unsigned char data) { SSPBUF = data; while(!PIR1bits.SSPIF); PIR1bits.SSPIF = 0; } void interrupt LEDMATRIX_ScanTask(void) { if(TMR0IF) { unsigned char i = 0; unsigned char j = 0; for(j = 0; j < ROW_BYTE_COUNT; j++) { for(i = 0; i < 4; i++) { LEXMATRIX_SpiSend(buffer[active][j][(i*4) + line]); } } LEDMATRIX_Enable(FALSE); switch(line) { case 3: A = B = 0; break; case 2: A = 1; break; case 1: A = 0; B = 1; break; case 0: A = 1; break; } LATCH = 1; LATCH = 0; LEDMATRIX_Enable(TRUE); if(line == 0) { line = 3; ++scan_count; if(swap) { swap = back; back = active; active = swap; swap = 0; scan_count = 0; } } else --line; } TMR0IF = 0; } void LEDMATRIX_Init(void) { unsigned char i; // Used GPIO configuration TRISCbits.TRISC5 = 0; OE = 0; TRISCbits.TRISC3 = 0; TRISCbits.TRISC4 = 0; TRISCbits.TRISC6 = 0; TRISCbits.TRISC7 = 0; TRISBbits.TRISB6 = 0; SLRCONbits.SLRC = 0; SLRCONbits.SLRB = 0; ANSELbits.ANS7 = 0; LATCH = 0; A = 0; B = 1; // SPI configuration PIR1bits.SSPIF = 0; // Clear interrupt flag PIE1bits.SSPIE = 0; // Disable MSSP interrupt INTCONbits.PEIE = 0; // Disable peripheral interrupts SSPSTATbits.CKE = 0; SSPCON1bits.CKP = 0; SSPCON1bits.SSPM = 0; SSPCON1bits.SSPEN = 1; // Timer0 configuration T0CONbits.T0CS = 0; // Transition on instruction clock T0CONbits.PSA = 1; // De-activate pre-scaler T0CONbits.T0PS = 0; // Pre-scaler value 1/2 selected INTCON2bits.TMR0IP = 1; // Timer0 interrupt high priority INTCONbits.T0IF = 0; // Clear Timer0 interrupt flag INTCONbits.T0IE = 1; // Enable Timer0 overflow interrupt T0CONbits.TMR0ON = 1; // Enable Timer0 // Clear the shift register outputs for(i = 0; i < 16; i++) { LEXMATRIX_SpiSend(0xFF); } LATCH = 1; LATCH = 0; A = 1; B = 0; A = 0; B = 1; PR2 = 0b10010101; // Timer2 period value 149 CCP1CON = 0b00001100; // Set PWM mode CCPR1L = 50; // Compare low value } void LEDMATRIX_ShowTime(unsigned char hour1, unsigned char hour2, unsigned char min1, unsigned char min2, unsigned char neg) { unsigned char i = 0; unsigned char k = 0; for(i = 0; i < FONT_HEIGHT; i++) { if(neg) k = font[hour1 + 48][FONT_HEIGHT - i - 1]; else k = ~font[hour1 + 48][FONT_HEIGHT - i - 1]; buffer[back][0][i + 1] = (k >> 1) | 0x80; } for(i = 0; i < FONT_HEIGHT; i++) { if(neg) k = font[hour2 + 48][FONT_HEIGHT - i - 1]; else k = ~font[hour2 + 48][FONT_HEIGHT - i - 1]; buffer[back][1][i + 1] = k; } for(i = 0; i < FONT_HEIGHT; i++) { if(neg) k = font[min1 + 48][FONT_HEIGHT - i - 1]; else k = ~font[min1 + 48][FONT_HEIGHT - i - 1]; buffer[back][2][i + 1] = (k >> 2) | 0xC0; } for(i = 0; i < FONT_HEIGHT; i++) { if(neg) k = font[min2 + 48][FONT_HEIGHT - i - 1]; else k = ~font[min2 + 48][FONT_HEIGHT - i - 1]; buffer[back][3][i + 1] = (k >> 1) | 0x80; } LEDMATRIX_SetPixel(16, 6); LEDMATRIX_SetPixel(15, 6); LEDMATRIX_SetPixel(16, 7); LEDMATRIX_SetPixel(15, 7); LEDMATRIX_SetPixel(16, 9); LEDMATRIX_SetPixel(15, 9); LEDMATRIX_SetPixel(16, 10); LEDMATRIX_SetPixel(15, 10); swap = 1; while(swap); } void LEDMATRIX_ScrollMessage(unsigned char row, unsigned char *msg, unsigned char neg, unsigned int speed) { unsigned char i = 0, j = 0, k = 0; unsigned char current_bit_index = FONT_WIDTH - 1; unsigned char current_index = 0; unsigned char msg_end = 0; while(msg_end < (ROW_BYTE_COUNT * 8)) { for(i = 0; i < (ROW_BYTE_COUNT - 1); i++) { for(j = 0; j < FONT_HEIGHT; j++) { buffer[back][i][row + j] = (buffer[active][i][row + j] << 1) | (buffer[active][i + 1][row + j] >> 7); } } if(!msg_end) { for(j = 0; j < FONT_HEIGHT; j++) { if(neg) k = font[msg[current_index]][FONT_HEIGHT - j - 1]; else k = ~font[msg[current_index]][FONT_HEIGHT - j - 1]; buffer[back][i][row + j] = (buffer[active][i][row + j] << 1) | ((k >> current_bit_index) & 0x01); } if(current_bit_index == 0) { current_bit_index = FONT_WIDTH - 1; if(++current_index == strlen(msg)) { msg_end = 1; } } else { --current_bit_index; } } else { for(j = 0; j < FONT_HEIGHT; j++) { if(neg) buffer[back][i][row + j] = (buffer[active][i][row + j] << 1) & 0xFE; else buffer[back][i][row + j] = (buffer[active][i][row + j] << 1) | 0x01; } ++msg_end; } swap = 1; while(swap); while(scan_count != speed); } } void LEDMATRIX_BufferSet(unsigned char value) { // Set the whole buffer with the provided value memset(buffer, value, ROW_BYTE_COUNT * COLUMN_BYTE_COUNT * 2); } void LEDMATRIX_Enable(unsigned char enable) { if(enable) { T2CON = 0b00000101; //OE = 1; } else { T2CON = 0b00000001; //OE = 0; } } void LEDMATRIX_Dimming(unsigned char dim) { CCPR1L = dim; } void LEDMATRIX_SetPixel(unsigned char x, unsigned char y) { buffer[active][x/8][COLUMN_BYTE_COUNT - 1 - y] = buffer[active][x/8][COLUMN_BYTE_COUNT - 1 - y] & ~(0x80 >> (x % 8)); } void LEDMATRIX_ClearPixel(unsigned char x, unsigned char y) { buffer[active][x/8][COLUMN_BYTE_COUNT - 1 - y] = buffer[active][x/8][COLUMN_BYTE_COUNT - 1 - y] | (0x80 >> (x % 8)); }
#ifndef __LEDMATRIX_H #define __LEDMATRIX_H void LEDMATRIX_Init(void); void LEDMATRIX_ShowTime(unsigned char hour1, unsigned char hour2, unsigned char min1, unsigned char min2, unsigned char neg); void LEDMATRIX_ScrollMessage(unsigned char row, unsigned char *msg, unsigned char neg, unsigned int speed); void LEDMATRIX_BufferSet(unsigned char value); void LEDMATRIX_Enable(unsigned char enable); void LEDMATRIX_Dimming(unsigned char dim); void LEDMATRIX_SetPixel(unsigned char x, unsigned char y); void LEDMATRIX_ClearPixel(unsigned char x, unsigned char y); #endif
Bir de main.c'yi verirsek kod tamamlanmış olacak.
#include "config.h" #include <xc.h> #include <string.h> #include <pic18f14k50.h> #include "ledmatrix.h" void delay(void) { unsigned long i = 0; unsigned long j = 0; for(i = 1; i < 1000; i++) for(j = 1; j < 1; j++) asm("nop"); } int main(void) { const unsigned char msg[] = "CARSI POZCU"; // Initilise all related HW blocks LEDMATRIX_Init(); // Clear the buffer LEDMATRIX_BufferSet(0xFF); // Enable the display now LEDMATRIX_Enable(TRUE); // Enable interrupts globally and start matrix scanning ei(); while(1) { unsigned int h; unsigned char a,b,c,d; unsigned int dim = 0; unsigned char dir = 0; LEDMATRIX_BufferSet(0xFF); LEDMATRIX_Dimming(25); LEDMATRIX_ScrollMessage(1, msg, 0, 150); LEDMATRIX_BufferSet(0xFF); } }
Kod kendini açıklıyor aslında o nedenle çalışma mantığına girmek istemiyorum. Değinmek istediğim bir konu var. Bu paneller oldukça ucuza satıldıklarından kullanılan malzeme kalıtesi de oldukça düşük. LED'ler uzun süre yanık kalırsa bozuluyor, lojik entegreler yine bozulabiliyor. Bunun sonucu olarak da piksel hataları veya yanmayan satır/sütun problemleri ortaya çıkıyor. Benim buna bulduğum çözüm ise LED'leri mümkün olduğu kadar sık tarayıp yandığı süre içerisinde fazla ısınmasına müsade etmemek ve sönük kaldığı sürede de yeterince soğumasını sağlamak. Bunu da tarama frekansını arttırarak sağlamaya çalıştım ki işe de yaradı doğrusu.
Son olarak da yukardaki kodun çalışmasına ait görüntüyü eklersem tamam olacak.
2 yorum :
tebrikler. aynı çalışmanın ccs c örnekleri var mı elinizde?
Bir iki header değişikliği ve kodda bir iki ufak değişiklikle CSS de de derlenebilir yapabilirsiniz.
Yorum Gönder