16F628A & DFPlayer
16F628A & DFPlayer & I2CLCD & IR SENSOR & kütüphanesiz DFPlayer. Hepsi bir arada.
Devremiz NEC protokolü kullanan kumandaların kodlarını çözüyor, kodları LCD ekranda gösteriyor, DFPlayer çalıştırıyor. Bu arada I2C ve RS232 protokollerini kullanıyor. Yani çoklu bir çalışma:
1- IR kod çözme
2- IR kod gösterme
3- Checksum hesaplama, alçak ve yüksek baytları bulma
4- DFPlayer'e komut gönderme
nec_remote_read() fonksiyonunu internet üzerinden ccspicc.blogspot.com adresinden buldum. Bu fonksiyon projemin kalbi oldu. İkinci önemli fonksiyon da hesap() fonksiyonu. Bu fonksiyon DFPlayer'e komut gönderiyor. Komutların alçak bayt'ını (high byte) ve yüksek bayt'ını (high byte) hesaplayıp putc komutu ile DFPayer gönderiyor.
I2C_LCD.c kütüphanesini de internetten buldum. İşin geri kalanı biraz montaj biraz kopyala yapıştır...:)
Malzeme listesini ayrıntılı olarak devre şemasında görebilirsiniz.
2) Beleme devrenizi güzel bir 5v regüle devre kullanın. LM7805'le kurduğum besleme devresini kullandım. Devrede en fazla akım çeken parça LCD.
3) DFPlayer'in sd kart bölümünün üst metali her ne kadar eksi pinlere bağlı olsa da ben özellikle ayrı bir kablo ile şaseledim.
4) Devre çalışınca hoparörden parazit gürültüler gelmeye başladı. Bunu da pic'in RB2'den DFPlayer'in TX pinine giden bağlantı arasına 1k direnç koydum, parazit kesildi. Hem RX hem de TX'e giden bağlantılarda 1k dirençler var. DFPlayer'in datasheets dosyasında yalnızca RX'e direnç bağlanmış.
5) Derleyici olarak PIC C Compiler (CCS C Compiler) kullanıyorum. Programı yazdıkça 16F628A'ın belleği yetersiz gelmeye başlıyor ve kodda ekonomiye gitmeye başlıyorum.
6) Uzaktan kumanda tuşlarına bastığınızda kodu alması-çözmesi derken bazen sapıtabiliyor. İkinci farklı tuş basışta bir önceki kodu sürdürebiliyor. Tuş basışları arası yavaş olmak lazım. Benzer protokol kullanan kumanda kodlarını da çalıştırıyor.
7) Gelen sinyal ve sinyalin çözülmesi sırasında kod kontrolleri iyileştirilebilir diye düşünüyorum.
8) Kumanda üzerinde info tuşuna bastığımızda ekranın ikinci satırında kumandadan gelen kodu gösteriyor, aynı tuşa tekrar basınca eski gösterimine dönüyor. Yani kod okuma da yapabiliyor.
9) Bence kodlar daha da geliştirilip kusursuz hale getirilebilir. Ben bu işlerle amatörce, boş vakitlerimi değerlendirmek amaçlı uğraşıyorum.
10) Mutlaka 8Mhz kristal kullanın. Çünkü nec_remote_read() fonksiyonundaki bütün değişkenler buna göre hesaplanmış. Farklı bir kristal kullanırsanız bu değerleri yeniden hesaplamanız gerekir. bu kod programın ana iskeleti oldu.
11) LCD üşüyünce ekran parlaklığı değişiyor. Isınınca dengeli çalışıyor.
12) Dibinde masa lambası açılınca ateşleme paraziti şarkı atlatabiliyor.
13) Ama her şeye rağmen oldukça zevkli ve gayet güzel çalıyor.
14) NEXT ve PREV komutlarını gönderdiğinizde, bir sonraki veya bir önceki şarkı çalıyor ve bitince duruyor. Bu sorunu daha önce gerçekleştirdiğim Arduino'lu projemde BUSY portunu dinleyerek gidermiştim. Benzer çalışma burada da yapılabilir. O yazıma da bakabilirsiniz.
15) Projemizin geliştirilmesi artık sizin hayalinize kalmış
Çalışmalarınızda yararlı olması dileklerimle.
main.c dosyası:
/* KODLA GİTSİN KODLA
-------Developed by Kodla Gitsin-----
DFPlayer MP3 PLAYER UYGULAMASI
Malzemeler:
16F628A, DFPlayer Modülü, IR alıcı,
I2C modüllü 16X2 LCD
Herhangi bir NEC Protokou kullanan uzaktan kumanda
Ben Next UK-660 uydu alıcısı (Next Minix Punto Plus) kumandasını kullandım
(kodlarını öğrenebildiğiniz NEC Protokol kullanan her kumandayı kullanabilirsiniz)
https://ccspicc.blogspot.com/2016/07/nec-ir-remote-control-decoder-pic16f84a-microcontroller-ccs-c-code.html?m=1
*/
#include <16f628A.H> //kullanılacak pic
//sigorta ayarları ----------------------------------------------
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT //pic sigorta ayarları
#fuses nomclr //mclr devre dışı
//---------------------------------------------------------------
#include <stdio.h>
#include <stdint.h>
//#include <stdbool.h>
//bool Playing=false; //<stdbool.h> kütüphanesi ile..... (kullanmadığım için kapattım)
#use delay (clock=8000000) // kesinlikle 8 MHz kullanın. Çünkü nec_remote_read() fonksiyonu 8Mhz'e göre yazılmış
//#use I2C(master, I2C1, FAST = 100000, STREAM = I2C_LCD)
#use i2c(Master,Fast,sda=PIN_B4,scl=PIN_B5,STREAM = I2C_LCD) //LCD ile haberleşmek için I2C protokolü
#include <I2C_LCD.c> //I2C LCD sürücü kaynak kodu
//#bit RCIF=0xF9E.5
//#include <UART.h>
//#include <DFPlayer.h>
#use RS232 (baud = 9600, bits = 8, parity = N, xmit = pin_B2, rcv = pin_B1) //DFPlayer ile haberleşmek için RS232 protokulü
//#use fast_io(B)
//-------------------------------------------------------------------------------------------------------------------------
#define led1 pin_A2 // 1 nolu pin
//buton kullanırsanız:
//#define buton1 pin_A3 // 2 nolu pin (1K...4K7 direnç ile gnd'ye) ---buton +5v dan tetiklemeli
//#define buton2 pin_A4 // 3 nolu pin (1K...4K7 direnç ile gnd'ye) ---buton +5v dan tetiklemeli
//#define DFPlayer_BUSY PIN=A1; // DFPlayer BUSY portu bağlantısı---
#define IR_sensor pin_B0 // IR receiver IIR alıcının bağlı olduğu pin)
//#define BUSY pin_B3 // DFPlayer BUSY port dinleme pini
//DFPlayer-----------------------------------------------------------------------------------------------------------------
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00
//--------NEXT KUMANDA KODLARI----NEC protocol----Next UK-660 uydu alıcısı (Next Minix Punto Plus) kumandası-----NEC protocol ------
// kullanmadıklarımı pasivize ettim
# define t_play 0x80BF1BE4 // play
# define t_p_inc 0x80BF53AC // p+
# define t_p_dec 0x80BF4BB4 // p-
# define t_vol_inc 0x80BF837C // vol +
# define t_vol_dec 0x80BF9966 // vol -
# define t_equalizer 0x80BF6B94 // equaliser //epg
# define t_info 0x80BF0BF4 // info
# define t_usb 0x80BF4AB5 // USB
# define t_sd 0x80BF8B74 // SHIFT
# define t_pause 0x80BFE31C // pause
//# define t_next 0x80BFAB54 // next
//# define t_prev 0x80BF639C // prev
//# define t_mute 0x80BF39C6 // mute
//# define t_ok 0x80BF738C // ok
//# define t_stop 0x80BF2BD4 // stop
//# define t_apps 0x80BF817E // APPs
//# define t_pic 0x80BFC13E // PICTURE
//# define t_menu 0x80BFA956 // MENU
//# define t_exit 0x80BFA3C5 // EXIT
//# define t_pr 0x80BF41BE // PR
//# define t_tvrad 0x80BF9B64 // TV/RADYO
//# define rak0 0x80BFE11E // 0
//# define rak1 0x80BF49B6 // 1
//# define rak2 0x80BFC936 // 2
//# define rak3 0x80BF33CC // 3
//# define rak4 0x80BF718E // 4
//# define rak5 0x80BFF10E // 5
//# define rak6 0x80BF13EC // 6
//# define rak7 0x80BF51AE // 7
//# define rak8 0x80BFD12E // 8
//# define rak9 0x80BF23DC // 9
//--------------------------------------------------------------------------------------
int i=1; // equalizer seçimlerinde kullandığımız değişken
int volume = 10; // başlangıç volüm seviyesi
int gosterge=1; // ekran durum - basılı tuşa göre ilgili ekran görüntüsüne yollar - ekran() fonksiyonunca kullanılır
int kaynak=0; //
unsigned int32 ir_code;
unsigned int16 address;
unsigned int8 command, inv_command;
//-------------------------------------------------------------------------------------
// IR sensörden aldığı kodu çözüyor bu bölüm 8 Mhz kristale göre düzenlenmiştir
short nec_remote_read(){
unsigned int8 count = 0, i;
// Check 9ms pulse (remote control sends logic high)
while((input(IR_sensor) == 0) && (count < 200)){
count++;
delay_us(50);}
if( (count > 199) || (count < 160)) // NEC protocol?
return FALSE;
count = 0;
// Check 4.5ms space (remote control sends logic low)
while((input(IR_sensor)) && (count < 100)){
count++;
delay_us(50);}
if( (count > 99) || (count < 60)) // NEC protocol?
return FALSE;
for(i = 0; i < 32; i++){
count = 0;
while((input(IR_sensor) == 0) && (count < 14)){
count++;
delay_us(50);}
if( (count > 13) || (count < 8)) // NEC protocol?
return FALSE;
count = 0;
while((input(IR_sensor)) && (count < 40)){
count++;
delay_us(50);}
if( (count > 39) || (count < 8)) // NEC protocol?
return FALSE;
if( count > 20) // If space width > 1ms
bit_set(ir_code, (31 - i)); // Write 1 to bit (31 - i)
else // If space width < 1ms
bit_clear(ir_code, (31 - i)); // Write 0 to bit (31 - i)
}
return TRUE;
}
//-------------------------------------------------------------------------------------
// DFPlayer'e komut gönderimi:
// komutların alçak bayt'ını (high byte) ve yüksek baytını(high byte) hesaplayıp
// putc komutu ile DFPayer' komut gönderiyor
void hesap(int CMD,int Par1,int Par2) {
delay_ms(100);
uint16_t checksum=(65535-(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2))+1;
unsigned char hi=(checksum >>8);
unsigned char lo=checksum & 0x00FF;
int high=hi;
int low=lo;
// komutu gönderiyoruz.---------------------------------------------
putc(Start_Byte);
putc(Version_Byte);
putc(Command_Length);
putc(CMD);
putc(Acknowledge);
putc(Par1);
putc(Par2);
putc(high);
putc(low);
putc(End_Byte);
}
//-------------------------------------------------------------------------------------
void LCD_Yaz()
{
LCD_Begin(0x4E); // LCD modülünü I2C ile başlat address = 0x4E
delay_ms(1000);
}
void ekran()
{
switch (gosterge) { //seçimlere göre ekrandaki mesajlar
case 1:
//LCD_Goto(0, 2);
// LCD_Out("Kodla Gitsin");
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sağ ok
delay_ms(100);
break;
case 2:
address = ir_code >> 16;
command = ir_code >> 8;
inv_command = ir_code;
LCD_Goto(1, 2);
LCD_Out("irCod:");
printf(LCD_Out,"%4LX %2X %2X ",address,command,inv_command);
delay_ms(50);
break;
case 3:
LCD_Goto(1, 1);
LCD_Out("Next");
LCD_Goto(5, 1);
printf(LCD_Out,"%c%c",0x7E,0x7E); //sağ ok
delay_ms(1000);
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c ",0x7E); //sağ ok
//LCD_Goto(6, 1);
// LCD_Out(" ");
break;
case 4:
LCD_Goto(7, 1);
LCD_Out("Volum: ");
LCD_Goto(13, 1);
if (volume<10){
LCD_Out("0"); printf(LCD_Out,"%i",volume);}
else {printf(LCD_Out,"%i",volume);}
break;
case 5:
LCD_Goto(1, 1);
printf(LCD_Out,"%c%c",0x7F,0x7F); //sol ok
LCD_Goto(3, 1);
LCD_Out("Prev");
delay_ms(1000);
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sol ok
LCD_Goto(6, 1);
LCD_Out(" ");
break;
case 6:
LCD_Goto(1, 2);
LCD_Out("***");
break;
case 7:
LCD_Goto(1, 2);
LCD_Out("SD ");
break;
case 8:
LCD_Goto(1, 2);
LCD_Out("USB");
break;
case 9: // ilk açılışta ekran değerleri
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sol
LCD_Goto(7, 1);
LCD_Out("Volum: ");
LCD_Goto(13, 1);
if (volume<10){
//LCD_Out("0");
printf(LCD_Out,"%i 0",volume);}
else {printf(LCD_Out,"%i",volume);}
LCD_Goto(1, 2);
LCD_Out(" ");
LCD_Goto(1, 2);
if (kaynak==1) {LCD_Out("SD ");}
else if (kaynak==2) {LCD_Out("USB");}
else{ LCD_Out("***");}
LCD_Goto(7, 2);
LCD_Out("Normal ");
break;
}
}
//-------------------------------------------------------------------------------------
void eqAyarla()
// equalizer modları fonksiyonu switch case ile seçiyoruz.
{ gosterge=0;
switch (i) {
case 1: // normal
hesap(0x07,0,0);
LCD_Goto(7, 2);
LCD_Out("Normal ");
i=2;
break;
case 2: // pop
hesap(0x07,0,1);
LCD_Goto(7, 2);
LCD_Out("Pop ");
i=3;
break;
case 3: // rock
hesap(0x07,0,2);
LCD_Goto(7, 2);
LCD_Out("Rock ");
i=4;
break;
case 4: // jazz
hesap(0x07,0,3);
LCD_Goto(7, 2);
LCD_Out("Jazz ");
i=5;
break;
case 5: // classic
hesap(0x07,0,4);
LCD_Goto(7, 2);
LCD_Out("Classic");
i=6;
break;
case 6: // bass
hesap(0x07,0,5);
LCD_Goto(7, 2);
LCD_Out("Bass ");
i=1;
break;
}
}
//-------------------------------------------------------------------------------------
void volumeINC() // volüm + fonksiyonu
{
volume = volume+1;
if(volume==31)
{
volume=30;
}
hesap(0x06, 0, volume);
gosterge=4;
}
//-------------------------------------------------------------------------------------
void volumeDEC() // volüm - fonksiyonu
{
volume = volume-1;
if(volume==-1)
{
volume=0;
}
hesap(0x06, 0, volume);
gosterge=4;
}
//-------------------------------------------------------------------------------------
void main(void)
{
LCD_Yaz();
set_tris_b(1);
gosterge=9;
ekran();
delay_ms(1000); //uzaktan kumanda komutlarının düzgün çalışması için ilk açılıta bekletiyor.
hesap(0x11,0,1); // FIRST --- ilk şarkıdan çalmaya başlıyor
hesap(0x06, 0, volume); //ilk açılış volümü
while(TRUE){
while(input(IR_sensor)); // RB0 pinini (IR sensör girişi) dinliyor
nec_remote_read(); // RB0 giriş alırsa kodu çözmeye gidiyor
{
output_high(led1); // görsel amaçlı LED'i yakıyoruz
if (ir_code==t_p_inc){
hesap(0x01,0,1); // next
gosterge=3;
}
if (ir_code==t_p_dec){
hesap(0x02,0,1); // prev
gosterge=5;
}
if (ir_code==t_equalizer){
eqAyarla(); // equalizer
}
if (ir_code==t_vol_inc){
volumeINC(); // volum +++
}
if (ir_code==t_vol_dec){
volumeDEC(); // volum ---
}
if (ir_code==t_info){ // player modu- IR kod okuma modu arasında geçiş yapar
// ekran 2.satırda kumandadan gelen kodu yazar
// aynı tuşu kullanarak iki durum arasıda geçiş yapıyoruz
if (gosterge>2) gosterge=1;
gosterge=gosterge+1;
if (gosterge==3)
gosterge=9;
}
if (ir_code==t_pause) {
hesap(0x0E,0,0); // pause
}
/*
if (ir_code==t_play){
hesap(0x11,0,1); // FIRST
//Playing=true;
}
*/
if (ir_code==t_play){
hesap(0x0D,0,0); // play - pause'den devam -
}
if (ir_code==t_usb){ // usb modu
//hesap(0x3F, 0, 1); //sıfırla
hesap(0x09,0,1); //usb
hesap(0x11,0,1); // FIRST
kaynak=2;
gosterge=8;
}
if (ir_code==t_sd){ // sd kart modu
// hesap(0x3F, 0, 0); //sıfırla
hesap(0x09,0,0); //sd
hesap(0x11,0,1); // FIRST
kaynak=1;
gosterge=7;
}
delay_ms(250); // kumandadan gelen kodları kararlı yakalaması için alt bekleme sınırı
ekran();
output_low(led1); //görsel amaçlı yakdığımız LED'i söndürüyoruz
}
}
}
//-------------------------------------------------------
I2C_LCD dosyası:
// CCS C driver code for I2C LCDs (HD44780 compliant controllers)
// https://simple-circuit.com/
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define LCD_FIRST_ROW 0x80
#define LCD_SECOND_ROW 0xC0
#define LCD_THIRD_ROW 0x94
#define LCD_FOURTH_ROW 0xD4
#define LCD_CLEAR 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04
#define LCD_CURSOR_OFF 0x0C
#define LCD_UNDERLINE_ON 0x0E
#define LCD_BLINK_CURSOR_ON 0x0F
#define LCD_MOVE_CURSOR_LEFT 0x10
#define LCD_MOVE_CURSOR_RIGHT 0x14
#define LCD_TURN_ON 0x0C
#define LCD_TURN_OFF 0x08
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1E
#ifndef LCD_TYPE
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#endif
int1 RS;
unsigned int8 i2c_addr, backlight_val = LCD_BACKLIGHT;
void LCD_Write_Nibble(unsigned int8 n);
void LCD_Cmd(unsigned int8 Command);
void LCD_Goto(unsigned int8 col, unsigned int8 row);
void LCD_Out(unsigned int8 LCD_Char);
void LCD_Begin(unsigned int8 _i2c_addr);
void Backlight();
void noBacklight();
void Expander_Write(unsigned int8 value);
void LCD_Write_Nibble(unsigned int8 n) {
n |= RS;
Expander_Write(n);
Expander_Write(n | 0x04);
delay_us(1);
Expander_Write(n & 0xFB);
delay_us(50);
}
void LCD_Cmd(unsigned int8 Command) {
RS = 0;
LCD_Write_Nibble(Command & 0xF0);
LCD_Write_Nibble((Command << 4) & 0xF0);
}
void LCD_Goto(unsigned int8 col, unsigned int8 row) {
switch(row) {
case 2:
LCD_Cmd(0xC0 + col-1);
break;
case 3:
LCD_Cmd(0x94 + col-1);
break;
case 4:
LCD_Cmd(0xD4 + col-1);
break;
default: // case 1:
LCD_Cmd(0x80 + col-1);
}
}
void LCD_Out(unsigned int8 LCD_Char){
RS = 1;
LCD_Write_Nibble(LCD_Char & 0xF0);
LCD_Write_Nibble((LCD_Char << 4) & 0xF0);
}
void LCD_Begin(unsigned int8 _i2c_addr) {
i2c_addr = _i2c_addr;
Expander_Write(0);
delay_ms(40);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(LCD_RETURN_HOME);
delay_ms(5);
LCD_Cmd(0x20 | (LCD_TYPE << 2));
delay_ms(50);
LCD_Cmd(LCD_TURN_ON);
delay_ms(50);
LCD_Cmd(LCD_CLEAR);
delay_ms(50);
LCD_Cmd(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
delay_ms(50);
}
void Backlight() {
backlight_val = LCD_BACKLIGHT;
Expander_Write(0);
}
void noBacklight() {
backlight_val = LCD_NOBACKLIGHT;
Expander_Write(0);
}
void Expander_Write(unsigned int8 value) {
I2C_Start(I2C_LCD);
I2C_Write(I2C_LCD, i2c_addr);
I2C_Write(I2C_LCD, value | backlight_val);
I2C_Stop(I2C_LCD);
}
PROGRAM DOSYALARINI İNDİR
KULLANILAN PROGRAMLAR: PIC C Compiler (CCS C Compiler 5.015), microbrn,
KULLANILAN PROGRAMLAYICI: k150_pic_programmer
Devremiz NEC protokolü kullanan kumandaların kodlarını çözüyor, kodları LCD ekranda gösteriyor, DFPlayer çalıştırıyor. Bu arada I2C ve RS232 protokollerini kullanıyor. Yani çoklu bir çalışma:
1- IR kod çözme
2- IR kod gösterme
3- Checksum hesaplama, alçak ve yüksek baytları bulma
4- DFPlayer'e komut gönderme
Bu projeyi Arduino Uno ile yapmıştım. PIC'e de uygulamak istedim.Elimde iki adet atıl durumda bulunan 16F628A'yı kullanmak istedim.Ama uygulamaya geçince öncelikle PIC'e göndereceğim komut yapısını, checksum hesaplamayı öğrenmek durumunda kaldım. DFPLayer ile ilgili mikrobotik.com adresindeki yazı zaten ana başvuru kaynağım. Bunları yaparken C dilinin biraz daha ayrıntısına girdim. Bu arada değişkenler hakkında da eksiklerim tamamlamak durumunda kaldım. C konusunda en önemli kaynağım: Gökhan DÖKMETAŞ'ın Temel C Programlama notları oldu.
nec_remote_read() fonksiyonunu internet üzerinden ccspicc.blogspot.com adresinden buldum. Bu fonksiyon projemin kalbi oldu. İkinci önemli fonksiyon da hesap() fonksiyonu. Bu fonksiyon DFPlayer'e komut gönderiyor. Komutların alçak bayt'ını (high byte) ve yüksek bayt'ını (high byte) hesaplayıp putc komutu ile DFPayer gönderiyor.
I2C_LCD.c kütüphanesini de internetten buldum. İşin geri kalanı biraz montaj biraz kopyala yapıştır...:)
Malzeme listesini ayrıntılı olarak devre şemasında görebilirsiniz.
Denemelerde özellikle karşılaştığım sorunlar ve çözümleri:
1) Devrenizi baskı devre kartı kullanmadan sadece delikli pertinaksa kuracaksanız, bağlantıları kısa tutun.2) Beleme devrenizi güzel bir 5v regüle devre kullanın. LM7805'le kurduğum besleme devresini kullandım. Devrede en fazla akım çeken parça LCD.
3) DFPlayer'in sd kart bölümünün üst metali her ne kadar eksi pinlere bağlı olsa da ben özellikle ayrı bir kablo ile şaseledim.
4) Devre çalışınca hoparörden parazit gürültüler gelmeye başladı. Bunu da pic'in RB2'den DFPlayer'in TX pinine giden bağlantı arasına 1k direnç koydum, parazit kesildi. Hem RX hem de TX'e giden bağlantılarda 1k dirençler var. DFPlayer'in datasheets dosyasında yalnızca RX'e direnç bağlanmış.
5) Derleyici olarak PIC C Compiler (CCS C Compiler) kullanıyorum. Programı yazdıkça 16F628A'ın belleği yetersiz gelmeye başlıyor ve kodda ekonomiye gitmeye başlıyorum.
6) Uzaktan kumanda tuşlarına bastığınızda kodu alması-çözmesi derken bazen sapıtabiliyor. İkinci farklı tuş basışta bir önceki kodu sürdürebiliyor. Tuş basışları arası yavaş olmak lazım. Benzer protokol kullanan kumanda kodlarını da çalıştırıyor.
7) Gelen sinyal ve sinyalin çözülmesi sırasında kod kontrolleri iyileştirilebilir diye düşünüyorum.
8) Kumanda üzerinde info tuşuna bastığımızda ekranın ikinci satırında kumandadan gelen kodu gösteriyor, aynı tuşa tekrar basınca eski gösterimine dönüyor. Yani kod okuma da yapabiliyor.
9) Bence kodlar daha da geliştirilip kusursuz hale getirilebilir. Ben bu işlerle amatörce, boş vakitlerimi değerlendirmek amaçlı uğraşıyorum.
10) Mutlaka 8Mhz kristal kullanın. Çünkü nec_remote_read() fonksiyonundaki bütün değişkenler buna göre hesaplanmış. Farklı bir kristal kullanırsanız bu değerleri yeniden hesaplamanız gerekir. bu kod programın ana iskeleti oldu.
11) LCD üşüyünce ekran parlaklığı değişiyor. Isınınca dengeli çalışıyor.
12) Dibinde masa lambası açılınca ateşleme paraziti şarkı atlatabiliyor.
13) Ama her şeye rağmen oldukça zevkli ve gayet güzel çalıyor.
14) NEXT ve PREV komutlarını gönderdiğinizde, bir sonraki veya bir önceki şarkı çalıyor ve bitince duruyor. Bu sorunu daha önce gerçekleştirdiğim Arduino'lu projemde BUSY portunu dinleyerek gidermiştim. Benzer çalışma burada da yapılabilir. O yazıma da bakabilirsiniz.
15) Projemizin geliştirilmesi artık sizin hayalinize kalmış
Çalışmalarınızda yararlı olması dileklerimle.
/* KODLA GİTSİN KODLA
-------Developed by Kodla Gitsin-----
DFPlayer MP3 PLAYER UYGULAMASI
Malzemeler:
16F628A, DFPlayer Modülü, IR alıcı,
I2C modüllü 16X2 LCD
Herhangi bir NEC Protokou kullanan uzaktan kumanda
Ben Next UK-660 uydu alıcısı (Next Minix Punto Plus) kumandasını kullandım
(kodlarını öğrenebildiğiniz NEC Protokol kullanan her kumandayı kullanabilirsiniz)
https://ccspicc.blogspot.com/2016/07/nec-ir-remote-control-decoder-pic16f84a-microcontroller-ccs-c-code.html?m=1
*/
#include <16f628A.H> //kullanılacak pic
//sigorta ayarları ----------------------------------------------
#fuses XT,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT //pic sigorta ayarları
#fuses nomclr //mclr devre dışı
//---------------------------------------------------------------
#include <stdio.h>
#include <stdint.h>
//#include <stdbool.h>
//bool Playing=false; //<stdbool.h> kütüphanesi ile..... (kullanmadığım için kapattım)
#use delay (clock=8000000) // kesinlikle 8 MHz kullanın. Çünkü nec_remote_read() fonksiyonu 8Mhz'e göre yazılmış
//#use I2C(master, I2C1, FAST = 100000, STREAM = I2C_LCD)
#use i2c(Master,Fast,sda=PIN_B4,scl=PIN_B5,STREAM = I2C_LCD) //LCD ile haberleşmek için I2C protokolü
#include <I2C_LCD.c> //I2C LCD sürücü kaynak kodu
//#bit RCIF=0xF9E.5
//#include <UART.h>
//#include <DFPlayer.h>
#use RS232 (baud = 9600, bits = 8, parity = N, xmit = pin_B2, rcv = pin_B1) //DFPlayer ile haberleşmek için RS232 protokulü
//#use fast_io(B)
//-------------------------------------------------------------------------------------------------------------------------
#define led1 pin_A2 // 1 nolu pin
//buton kullanırsanız:
//#define buton1 pin_A3 // 2 nolu pin (1K...4K7 direnç ile gnd'ye) ---buton +5v dan tetiklemeli
//#define buton2 pin_A4 // 3 nolu pin (1K...4K7 direnç ile gnd'ye) ---buton +5v dan tetiklemeli
//#define DFPlayer_BUSY PIN=A1; // DFPlayer BUSY portu bağlantısı---
#define IR_sensor pin_B0 // IR receiver IIR alıcının bağlı olduğu pin)
//#define BUSY pin_B3 // DFPlayer BUSY port dinleme pini
//DFPlayer-----------------------------------------------------------------------------------------------------------------
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00
//--------NEXT KUMANDA KODLARI----NEC protocol----Next UK-660 uydu alıcısı (Next Minix Punto Plus) kumandası-----NEC protocol ------
// kullanmadıklarımı pasivize ettim
# define t_play 0x80BF1BE4 // play
# define t_p_inc 0x80BF53AC // p+
# define t_p_dec 0x80BF4BB4 // p-
# define t_vol_inc 0x80BF837C // vol +
# define t_vol_dec 0x80BF9966 // vol -
# define t_equalizer 0x80BF6B94 // equaliser //epg
# define t_info 0x80BF0BF4 // info
# define t_usb 0x80BF4AB5 // USB
# define t_sd 0x80BF8B74 // SHIFT
# define t_pause 0x80BFE31C // pause
//# define t_next 0x80BFAB54 // next
//# define t_prev 0x80BF639C // prev
//# define t_mute 0x80BF39C6 // mute
//# define t_ok 0x80BF738C // ok
//# define t_stop 0x80BF2BD4 // stop
//# define t_apps 0x80BF817E // APPs
//# define t_pic 0x80BFC13E // PICTURE
//# define t_menu 0x80BFA956 // MENU
//# define t_exit 0x80BFA3C5 // EXIT
//# define t_pr 0x80BF41BE // PR
//# define t_tvrad 0x80BF9B64 // TV/RADYO
//# define rak0 0x80BFE11E // 0
//# define rak1 0x80BF49B6 // 1
//# define rak2 0x80BFC936 // 2
//# define rak3 0x80BF33CC // 3
//# define rak4 0x80BF718E // 4
//# define rak5 0x80BFF10E // 5
//# define rak6 0x80BF13EC // 6
//# define rak7 0x80BF51AE // 7
//# define rak8 0x80BFD12E // 8
//# define rak9 0x80BF23DC // 9
//--------------------------------------------------------------------------------------
int i=1; // equalizer seçimlerinde kullandığımız değişken
int volume = 10; // başlangıç volüm seviyesi
int gosterge=1; // ekran durum - basılı tuşa göre ilgili ekran görüntüsüne yollar - ekran() fonksiyonunca kullanılır
int kaynak=0; //
unsigned int32 ir_code;
unsigned int16 address;
unsigned int8 command, inv_command;
//-------------------------------------------------------------------------------------
// IR sensörden aldığı kodu çözüyor bu bölüm 8 Mhz kristale göre düzenlenmiştir
short nec_remote_read(){
unsigned int8 count = 0, i;
// Check 9ms pulse (remote control sends logic high)
while((input(IR_sensor) == 0) && (count < 200)){
count++;
delay_us(50);}
if( (count > 199) || (count < 160)) // NEC protocol?
return FALSE;
count = 0;
// Check 4.5ms space (remote control sends logic low)
while((input(IR_sensor)) && (count < 100)){
count++;
delay_us(50);}
if( (count > 99) || (count < 60)) // NEC protocol?
return FALSE;
for(i = 0; i < 32; i++){
count = 0;
while((input(IR_sensor) == 0) && (count < 14)){
count++;
delay_us(50);}
if( (count > 13) || (count < 8)) // NEC protocol?
return FALSE;
count = 0;
while((input(IR_sensor)) && (count < 40)){
count++;
delay_us(50);}
if( (count > 39) || (count < 8)) // NEC protocol?
return FALSE;
if( count > 20) // If space width > 1ms
bit_set(ir_code, (31 - i)); // Write 1 to bit (31 - i)
else // If space width < 1ms
bit_clear(ir_code, (31 - i)); // Write 0 to bit (31 - i)
}
return TRUE;
}
//-------------------------------------------------------------------------------------
// DFPlayer'e komut gönderimi:
// komutların alçak bayt'ını (high byte) ve yüksek baytını(high byte) hesaplayıp
// putc komutu ile DFPayer' komut gönderiyor
void hesap(int CMD,int Par1,int Par2) {
delay_ms(100);
uint16_t checksum=(65535-(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2))+1;
unsigned char hi=(checksum >>8);
unsigned char lo=checksum & 0x00FF;
int high=hi;
int low=lo;
// komutu gönderiyoruz.---------------------------------------------
putc(Start_Byte);
putc(Version_Byte);
putc(Command_Length);
putc(CMD);
putc(Acknowledge);
putc(Par1);
putc(Par2);
putc(high);
putc(low);
putc(End_Byte);
}
//-------------------------------------------------------------------------------------
void LCD_Yaz()
{
LCD_Begin(0x4E); // LCD modülünü I2C ile başlat address = 0x4E
delay_ms(1000);
}
void ekran()
{
switch (gosterge) { //seçimlere göre ekrandaki mesajlar
case 1:
//LCD_Goto(0, 2);
// LCD_Out("Kodla Gitsin");
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sağ ok
delay_ms(100);
break;
case 2:
address = ir_code >> 16;
command = ir_code >> 8;
inv_command = ir_code;
LCD_Goto(1, 2);
LCD_Out("irCod:");
printf(LCD_Out,"%4LX %2X %2X ",address,command,inv_command);
delay_ms(50);
break;
case 3:
LCD_Goto(1, 1);
LCD_Out("Next");
LCD_Goto(5, 1);
printf(LCD_Out,"%c%c",0x7E,0x7E); //sağ ok
delay_ms(1000);
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c ",0x7E); //sağ ok
//LCD_Goto(6, 1);
// LCD_Out(" ");
break;
case 4:
LCD_Goto(7, 1);
LCD_Out("Volum: ");
LCD_Goto(13, 1);
if (volume<10){
LCD_Out("0"); printf(LCD_Out,"%i",volume);}
else {printf(LCD_Out,"%i",volume);}
break;
case 5:
LCD_Goto(1, 1);
printf(LCD_Out,"%c%c",0x7F,0x7F); //sol ok
LCD_Goto(3, 1);
LCD_Out("Prev");
delay_ms(1000);
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sol ok
LCD_Goto(6, 1);
LCD_Out(" ");
break;
case 6:
LCD_Goto(1, 2);
LCD_Out("***");
break;
case 7:
LCD_Goto(1, 2);
LCD_Out("SD ");
break;
case 8:
LCD_Goto(1, 2);
LCD_Out("USB");
break;
case 9: // ilk açılışta ekran değerleri
LCD_Goto(1, 1);
LCD_Out("Play ");
LCD_Goto(5, 1);
printf(LCD_Out,"%c",0x7E); //sol
LCD_Goto(7, 1);
LCD_Out("Volum: ");
LCD_Goto(13, 1);
if (volume<10){
//LCD_Out("0");
printf(LCD_Out,"%i 0",volume);}
else {printf(LCD_Out,"%i",volume);}
LCD_Goto(1, 2);
LCD_Out(" ");
LCD_Goto(1, 2);
if (kaynak==1) {LCD_Out("SD ");}
else if (kaynak==2) {LCD_Out("USB");}
else{ LCD_Out("***");}
LCD_Goto(7, 2);
LCD_Out("Normal ");
break;
}
}
//-------------------------------------------------------------------------------------
void eqAyarla()
// equalizer modları fonksiyonu switch case ile seçiyoruz.
{ gosterge=0;
switch (i) {
case 1: // normal
hesap(0x07,0,0);
LCD_Goto(7, 2);
LCD_Out("Normal ");
i=2;
break;
case 2: // pop
hesap(0x07,0,1);
LCD_Goto(7, 2);
LCD_Out("Pop ");
i=3;
break;
case 3: // rock
hesap(0x07,0,2);
LCD_Goto(7, 2);
LCD_Out("Rock ");
i=4;
break;
case 4: // jazz
hesap(0x07,0,3);
LCD_Goto(7, 2);
LCD_Out("Jazz ");
i=5;
break;
case 5: // classic
hesap(0x07,0,4);
LCD_Goto(7, 2);
LCD_Out("Classic");
i=6;
break;
case 6: // bass
hesap(0x07,0,5);
LCD_Goto(7, 2);
LCD_Out("Bass ");
i=1;
break;
}
}
//-------------------------------------------------------------------------------------
void volumeINC() // volüm + fonksiyonu
{
volume = volume+1;
if(volume==31)
{
volume=30;
}
hesap(0x06, 0, volume);
gosterge=4;
}
//-------------------------------------------------------------------------------------
void volumeDEC() // volüm - fonksiyonu
{
volume = volume-1;
if(volume==-1)
{
volume=0;
}
hesap(0x06, 0, volume);
gosterge=4;
}
//-------------------------------------------------------------------------------------
void main(void)
{
LCD_Yaz();
set_tris_b(1);
gosterge=9;
ekran();
delay_ms(1000); //uzaktan kumanda komutlarının düzgün çalışması için ilk açılıta bekletiyor.
hesap(0x11,0,1); // FIRST --- ilk şarkıdan çalmaya başlıyor
hesap(0x06, 0, volume); //ilk açılış volümü
while(TRUE){
while(input(IR_sensor)); // RB0 pinini (IR sensör girişi) dinliyor
nec_remote_read(); // RB0 giriş alırsa kodu çözmeye gidiyor
{
output_high(led1); // görsel amaçlı LED'i yakıyoruz
if (ir_code==t_p_inc){
hesap(0x01,0,1); // next
gosterge=3;
}
if (ir_code==t_p_dec){
hesap(0x02,0,1); // prev
gosterge=5;
}
if (ir_code==t_equalizer){
eqAyarla(); // equalizer
}
if (ir_code==t_vol_inc){
volumeINC(); // volum +++
}
if (ir_code==t_vol_dec){
volumeDEC(); // volum ---
}
if (ir_code==t_info){ // player modu- IR kod okuma modu arasında geçiş yapar
// ekran 2.satırda kumandadan gelen kodu yazar
// aynı tuşu kullanarak iki durum arasıda geçiş yapıyoruz
if (gosterge>2) gosterge=1;
gosterge=gosterge+1;
if (gosterge==3)
gosterge=9;
}
if (ir_code==t_pause) {
hesap(0x0E,0,0); // pause
}
/*
if (ir_code==t_play){
hesap(0x11,0,1); // FIRST
//Playing=true;
}
*/
if (ir_code==t_play){
hesap(0x0D,0,0); // play - pause'den devam -
}
if (ir_code==t_usb){ // usb modu
//hesap(0x3F, 0, 1); //sıfırla
hesap(0x09,0,1); //usb
hesap(0x11,0,1); // FIRST
kaynak=2;
gosterge=8;
}
if (ir_code==t_sd){ // sd kart modu
// hesap(0x3F, 0, 0); //sıfırla
hesap(0x09,0,0); //sd
hesap(0x11,0,1); // FIRST
kaynak=1;
gosterge=7;
}
delay_ms(250); // kumandadan gelen kodları kararlı yakalaması için alt bekleme sınırı
ekran();
output_low(led1); //görsel amaçlı yakdığımız LED'i söndürüyoruz
}
}
}
//-------------------------------------------------------
I2C_LCD dosyası:
// CCS C driver code for I2C LCDs (HD44780 compliant controllers)
// https://simple-circuit.com/
#define LCD_BACKLIGHT 0x08
#define LCD_NOBACKLIGHT 0x00
#define LCD_FIRST_ROW 0x80
#define LCD_SECOND_ROW 0xC0
#define LCD_THIRD_ROW 0x94
#define LCD_FOURTH_ROW 0xD4
#define LCD_CLEAR 0x01
#define LCD_RETURN_HOME 0x02
#define LCD_ENTRY_MODE_SET 0x04
#define LCD_CURSOR_OFF 0x0C
#define LCD_UNDERLINE_ON 0x0E
#define LCD_BLINK_CURSOR_ON 0x0F
#define LCD_MOVE_CURSOR_LEFT 0x10
#define LCD_MOVE_CURSOR_RIGHT 0x14
#define LCD_TURN_ON 0x0C
#define LCD_TURN_OFF 0x08
#define LCD_SHIFT_LEFT 0x18
#define LCD_SHIFT_RIGHT 0x1E
#ifndef LCD_TYPE
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#endif
int1 RS;
unsigned int8 i2c_addr, backlight_val = LCD_BACKLIGHT;
void LCD_Write_Nibble(unsigned int8 n);
void LCD_Cmd(unsigned int8 Command);
void LCD_Goto(unsigned int8 col, unsigned int8 row);
void LCD_Out(unsigned int8 LCD_Char);
void LCD_Begin(unsigned int8 _i2c_addr);
void Backlight();
void noBacklight();
void Expander_Write(unsigned int8 value);
void LCD_Write_Nibble(unsigned int8 n) {
n |= RS;
Expander_Write(n);
Expander_Write(n | 0x04);
delay_us(1);
Expander_Write(n & 0xFB);
delay_us(50);
}
void LCD_Cmd(unsigned int8 Command) {
RS = 0;
LCD_Write_Nibble(Command & 0xF0);
LCD_Write_Nibble((Command << 4) & 0xF0);
}
void LCD_Goto(unsigned int8 col, unsigned int8 row) {
switch(row) {
case 2:
LCD_Cmd(0xC0 + col-1);
break;
case 3:
LCD_Cmd(0x94 + col-1);
break;
case 4:
LCD_Cmd(0xD4 + col-1);
break;
default: // case 1:
LCD_Cmd(0x80 + col-1);
}
}
void LCD_Out(unsigned int8 LCD_Char){
RS = 1;
LCD_Write_Nibble(LCD_Char & 0xF0);
LCD_Write_Nibble((LCD_Char << 4) & 0xF0);
}
void LCD_Begin(unsigned int8 _i2c_addr) {
i2c_addr = _i2c_addr;
Expander_Write(0);
delay_ms(40);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(3);
delay_ms(5);
LCD_Cmd(LCD_RETURN_HOME);
delay_ms(5);
LCD_Cmd(0x20 | (LCD_TYPE << 2));
delay_ms(50);
LCD_Cmd(LCD_TURN_ON);
delay_ms(50);
LCD_Cmd(LCD_CLEAR);
delay_ms(50);
LCD_Cmd(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
delay_ms(50);
}
void Backlight() {
backlight_val = LCD_BACKLIGHT;
Expander_Write(0);
}
void noBacklight() {
backlight_val = LCD_NOBACKLIGHT;
Expander_Write(0);
}
void Expander_Write(unsigned int8 value) {
I2C_Start(I2C_LCD);
I2C_Write(I2C_LCD, i2c_addr);
I2C_Write(I2C_LCD, value | backlight_val);
I2C_Stop(I2C_LCD);
}
//----------------------------------------------------------
KULLANILAN PROGRAMLAR: PIC C Compiler (CCS C Compiler 5.015), microbrn,
KULLANILAN PROGRAMLAYICI: k150_pic_programmer
Yorumlar
Yorum Gönder