18 Aralık 2015 Cuma
PIC ve EM4102 ile RFID Okuma Devresi
RFID ik çıktığı yıllarda Üniversitedeydim ve bunların birçok alanda kullanılacağı söyleniyordu. Aradan fazla zaman geçmedi ve binaların giriş kapılarının otomatik açılması işlerine kadar girdiler. Şu anda 125KHz ve 13.56MHz olmak üzere iki gruba ayrılmış durumda RFID ürünleri. 125KHz olanı tranceiver kullanmadan basit devrelerle ve yazılımla okumak ve yazmak mümkün ve internette bu konuda birçok örnek uygulama mevcut. Genelde daha yüksek hız ve güvenilirlik istenen uygulamalarda ise 13.56MHz de çalışan RFID'ler tercih ediliyor. Ben de elimdeki PIC16F690 geliştime kartını denemek amaçlı elimdeki EM4102 (RFID tranceiver diyebiliriz) ile bir deneme yaptım. Sonucunu aşağıdaki video dan görebilirsiniz. EM4102'nin çevre elemanlarının boyulandırılmasına ve PCB yerleşimine dikkat etmek gerekiyor. Zira uygulamaların genel karakteristiği icabı 7/24 çalışacak bir entegre ve kötü tasarım durumda ısınmaya çok elverişli ki buda entegre ömrünü azaltacaktır. Bir mühendis olarak hiç tahammül edemediğim şey kötü tasarım sonucu kısa ömürlü olan ürünlerdir. Genelde Çin menşeli ürünlerde söz konusu olan bu bir kere çalışsın yeter mantığı markalaşma bilincini yerleşmemiş olmasından kaynaklanıyor büyük ölçüde. Marka imajı derdinde olan bir şirketin pek kolay kolay tevessül etmeyeceği yollar bunlar ama dediğim gibi markalaşma bilincinin eksik olduğu bizim gibi ülkelerde çok olağan durumlar.
Zilog Z8F6423 ve Wiznet W5100 ile uzaktan kontrol
O zamanlar Wiznet diye Kore'li bir şirket çıkmış ve W5100 diye HW TCP/IP desteği sunan bir çip üreticisi çıkmıştı. Bu W5100 aynı zamanda PHY da barındırıyordu içerisinde ve sadece trafolu bir ETH konnektörü bağlamak yetiyordu en küçük mikrokontrolöre bile. 4 taneye kadar HW socket'e izin veriyordu ve dahili buffer alanı da vardı. Elime bu W5100 geliştime kitinden geçmişti ve Z8 ile uzaktan konrol uygulaması yapıp denemek istedim. Sonuç aşağdaki video da gördüğünüz gibi bir devre oldu. Dahili web server üzerinden 4 röle kontrol edilebiliyor. Sisteme giriş şifre korumalı.
29 Kasım 2015 Pazar
Farklı kernel versiyonu ile derlenmiş modülü yükleme
Embedded veya değil, linux ile uğraşıyorsanız bazen farklı bir kernel
versiyonun da derlenmiş kernel modüllerini yüklemeniz gerekebilir.
Fakat bu durumda “insmod -f “ ile zorlasanız dahi modül
yüklenmez. Bu sorunu aşmanın kolay bir yolu var. Bunun için .ko
dosyasınaki .modinfo kısmını yeniden adlandırmanız yetecektir. Bu
durumda kernel versiyon tanımını bulamayacağı için yükleme sırasında
aşağıdakine benzer bir hata verecektir ama devam da edecektir.
“<modül adı>: no version magic, tainting kernel.”
Böylece modülü yüklemiş olacaksınız.
Son olarakta bu işlemi nasıl yapacağınıza gelince, aslında bunu objcopy ile kolayca yapabilirsiniz, şöyle ki:
objcopy <modül adı>.ko –rename-section .modinfo=.rastgelebirsey
Genelde cross derleyicilerde objcopy’nin önüne işlemciyi belirten bir ön ek de gelir. Umarım işinize yarar.
“<modül adı>: no version magic, tainting kernel.”
Böylece modülü yüklemiş olacaksınız.
Son olarakta bu işlemi nasıl yapacağınıza gelince, aslında bunu objcopy ile kolayca yapabilirsiniz, şöyle ki:
objcopy <modül adı>.ko –rename-section .modinfo=.rastgelebirsey
Genelde cross derleyicilerde objcopy’nin önüne işlemciyi belirten bir ön ek de gelir. Umarım işinize yarar.
27 Kasım 2015 Cuma
P10 Led Paneller
LED göstergelerin yaygınlaşması ile P10 denilen 16 satır ve 32 sütundan oluşan hazır LED paneller piyasayı kaplamış durumda. Bu yazımda bu panellerin çalışma mantığını aktarmaya çalışacağım. Daha sonrasında ise elimdeki PIC18F14K50 ile yaptığım basit bir test devresi ve kodu üzerinden pratikte nasıl kontrol edilir bu P10 paneller onun hakkında da bir fikir vermiş olacağım.
Ö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.
Devre bir giriş ve bir çıkış baglantısına sahip böylece arka arkaya istendiği kadar panel (tabii ki bunun bir sınırı var, zira tarama işlemi bunu sınırlamakta) bağlanabilmesine olanak sağlıyor. Giriş kontrol hatları önce 74HC245 serisi bir buffer'a girilmiş, böylece sinyal zayıflamasına karşı bir önlem alınmış. Devrede toplam 16 tane 74HC595 shift register var. Bunlar birbirlerine bağlı. Yani 16 byte shift edildiğinde ilk byte 16 numaralı entegreye gelmiş oluyor. Bunlara 4'er satırın LED'leri bağlanmış durumda. Yani birinci 74HC595'in pinlerine 1 inci satırın ilk 8 LED'i, 2 inci satırın ilk 8 LED'i, ve yine 3 ve 4 üncü satırların ilk 8 LED'i bağlanmış durumda. Aynı şekilde diğer 74HC595'lerde de her pin 4 ardışık satırdaki ve aynı sütundaki LED'ler bağlanmış durumda. Bu 4 satırdaki LED'lerin anotları ise satır olarak ayrılmış ve farklı MOSFET'lere bağlanmış durumda. Yani MOSFET'lerden istenen iletime geçirilerek istenen satırda shift register çıkışınını görünmesi sağlanabilir. İşin burasında devredeki 74HC138 demultiplekser devreye giriyor, zira onun 2 girişi çıkışına bağlı 4 MOSFET'den birini seçmek için kullanılıyor. Bir de devredeki 74HC04 var ki onun da görevi çıkışları aktif eden sinyalin seviyesini evirmek.
Ş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.
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):
Şimdi test kodunu incelemeye başlayabiliriz. Öncelikle panel ile ilgili işlemlerin yapıldığı ledmatrix.c ve ledmatrix.h dosyalarından başlayalım.
Bir de main.c'yi verirsek kod tamamlanmış olacak.
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.
Ö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.
Kaydol:
Kayıtlar
(
Atom
)