pcbway

pic16f877a eeprom sorunu

Başlatan eehsyn, 23 Ekim 2012, 15:21:15

eehsyn

Slm arkadaşlar CCS C pic programlamada 4 haneli bir sayıyı \"sifre\" diye bir etikete attım. Daha sonra bunu
write_eeprom(0,sifre);
diye eepromun 0. adresine kaydettim. Fakat ;
x=read_eeprom(0);
printf(lcd_putc,\"%ld\",x);
kodunu yazıyorum ama eepromdan okuduğum veri farklı bir sayı oluyor.Sifre etiketi 16bitlik sayı olarak tanımlandı. Acaba kullandığım picin eeprom hafızası 1byt olduğu için mi böle gösteriyordur. Bir fikri olan var mı??
Ne kadar bilirsin bil söylediklerin karşındakinin anlıyabildiği kadardır.....&&Hz. Mevlana&&

pwm.c

evet dediğin gibi eeprom adrese 8 bit veri kaydedebilirsin. 16bit ve üzeri veriler için sanırım
#include <internal_eeprom.c>Driveri kullanılıyor.

16bit verileri yazmak ve okumak için şu fonksiyonları kullanacaksın:
write_int16_eeprom()
read_int16_eeprom()

bunları bir dene bakalım. olmassa başka yöntemlerde söylerim.
_/\/\/\_ -[ı- -ı>|- -|ı|ı|ı- -ı< -||- -l[]l-

eehsyn

kardeşim çok teşekkür ederim dediğini yaptım oldu ozaman şimdi eepromda bir adresin boyutu 2byte oldu bu kod çok işime yarıyacak çok saol :) peki bunu biz write_int32_eeprom(); diye yazsak 4 bytlık veri kaydedebilirmiyiz acaba ??
Ne kadar bilirsin bil söylediklerin karşındakinin anlıyabildiği kadardır.....&&Hz. Mevlana&&

pwm.c

evet 32 bit tam sayılar için write_int32_eeprom()  fonksiyonu, ondalıklı sayılar için de write_float_eeprom() foksiyonu kullnılır.
_/\/\/\_ -[ı- -ı>|- -|ı|ı|ı- -ı< -||- -l[]l-

eehsyn

peki son bir şey daha. int16 sifre=1234; diye bir etiket tanımladım daha sonra bir pointer tanımlayıp= pointer=&sifre; yaparak sifre değişkenin adresini aldım sonrada =
write_eeprom(0, *(pointer+0));
write_eeprom(1, *(pointer+1));
yaparak sifre değişkeninin içeriğini byt byt eeproma kaydettim şimdi eepromda kayıtlı olan sifre değişkenini okuyup 2bytlık başka bir değişkene nasıl kaydedebilirim??
Ne kadar bilirsin bil söylediklerin karşındakinin anlıyabildiği kadardır.....&&Hz. Mevlana&&

pwm.c

benim anlamadığım nokta, senin 16 bitlik \"sifre\" değişkenin 2 ayrı bellek adresi kullanıyor ise pointer=&sifre; dediğinde bu adreslerden hangisini kaydediyor?
sanırım senin 2 tane pointer kullanman gerekiyor. istersen böyle dene.
_/\/\/\_ -[ı- -ı>|- -|ı|ı|ı- -ı< -||- -l[]l-

yazici67

23 Ekim 2012, 20:13:01 #6 Son düzenlenme: 23 Ekim 2012, 20:14:29 yazici67
CCS Little Endian kullanır. Yani 32-bitlik değişken bellekte şu şekilde tutulur:

16-bit içinde aynı şekilde sadece ilk 0C0D kısmını kullanırız.
Mesela;
int16 degisken = 0x0C0D;

int8 isaretci = &degisken;

int8 byte1 = *(isaretci);
int8 byte2 = *(isaretci + 1);

// Burada byte1 de 0x0D bulunur. byte2 de ise 0x0C var.

write_eeprom(0, *(isaretci));
write_eeprom(1, *(isaretci + 1));

// Eepromda 0.Adres = 0x0D;
//        \'\'         1.Adres = 0x0C olur.

Int16 değişkeni yazmak için şöyle bir metod kullanabilirsiniz:
void write_int16_eeprom(int8 address, int16 data) {
   write_eeprom(address, *(&data));
   write_eeprom(address + 1, *(&data + 1));
}

// veya

void write_int16_eeprom(int8 address, int16 data) {
   write_eeprom(address, data & 0xFF);
   write_eeprom(address + 1, (data >> 8) & 0xFF);
}

Int16 değişkeni okumak için şöyle bir metod kullanabilirsiniz:


// CCS yerlesik make16 metodu ile
int16 read_int16_eeprom(int8 address) {
    int8 a, b;
    a = read_eeprom(address);
    b = read_eeprom(address + 1);
    return make16(a, b);
}

// Bit kaydirma ile
int16 read_int16_eeprom(int8 address) {
    int8 a, b;
    a = read_eeprom(address);
    b = read_eeprom(address + 1);
    return ((a << 8) | (b));
}

Sanırım bu kısım için yeterli... İyi çalışmalar.

Not 1: Şifreyi saklamak için string ( veya char[] ) kullanabilirsiniz. Kaydetme vs. daha kolay olur...
Tüm kodu verirseniz daha kolay yardımcı oluruz...
Not 2: Kod derlerken uyarı verebilir veya yazım yanlışı yapmış olabilirim. Basit hataları düzeltirsiniz...
Not 3: @pwm.c hocam işletim sistemi olmadığı sürece bellek erişim ihlalleri sorun yaratmaz. Tamamen programcı yönetimindedir. Eğer malloc kullanılmışsa sadece veri bozukluğuna neden olabilir.

eehsyn

Bilgilerin için teşekkürler yazici67. Şimdi pwm.c\'nin gösterdiği şekilde yaparak o surunu hallettim ama kafama takılan şu oldu:

int16 *pointer,sifre=1234;   // değişkenler tanımlanıyor
int16 *x,tutucu

pointer=&sifre;   // adres tutacağı ile sifre değişkeninin adresi pointera atanıyor
x=&tutucu       //adres tutacağı ile tutucu değişkeninin adresi x\'e atanıyor

write_eeprom(0, *(pointer + 0));  // 0.adrese sifre değişkeninin 0. bytı atandı
write_eeprom(1, *(pointer + 1));  // 1.adrese sifre değişkeninin 1. bytı atandı
 
*(x  + 0)=read_eeprom(0);    //eepromun 0.adresi okunup tutucu değişkenin 0. adresine atanıyor
*(x  + 1)=read_eeprom(0);    ////eepromun 1.adresi okunup tutucu değişkenin 1. adresine atanıyor


printf(lcd_putc,\"%ld\",tutucu);  //tutucu içindeki değer lcd de 1234 göstermesi gerekirken farklı değer
                                             //gösteriyor


burda bir yanlış yaptığımı sanmıyorum ama düşündüğüm gibi olmuyor. Bu eeproma bilgi kaydı nasıl gerçekleşiyor ki yani şifre değişkenin içeriği
0.adrese 12
1.adrese 34
diyemi yazıyor ?
                                               
Ne kadar bilirsin bil söylediklerin karşındakinin anlıyabildiği kadardır.....&&Hz. Mevlana&&

yazici67

24 Ekim 2012, 14:55:27 #8 Son düzenlenme: 24 Ekim 2012, 15:01:46 yazici67
10 tabanında 1234 sayısı, 16 tabanında 04D2\'ye karşılık gelir. Üstteki mesajımda da belirttiğim gibi incelersek
bu sayı, bellekte örneğin bir \'a\' adresinde saklansın. 8-bitlik belleğe sahip PIC çekirdeğinde bu sayı:

a         >  0xD2
a + 1     >  0x04

şeklinde tutulur.
Kodunuzda da hatalar var ve sorun çıkaran esas sebep bu. Kodda işaretçiyi Int16 tipinde tanımlamışsınız. Yani açık bir şekilde derleyici pointer\'ın int16 olduğunu biliyor. Bu nedenle pointer + 1 dediğinizde işaretci sadece 1 artsa bile, işaret edilen değer 16 bit oluyor. Dolayısıyla yanlış değer okuyorsunuz. Üstteki mesajımda verdiğim kodlarda dikkat ederseniz sayı 16-bit türünden ama işaretçiler 8-bitlik. Yani doğrudan 16-bitlik sayıyı iki byte\'a bölebiliyoruz.
Eklemek istediğim birşey daha var: Bu yaptıklarımız güvenli olmayan yöntemler. Karmaşık yazılımlarda bellek sızıntılarına yol açabilir. Yani bu programı bir Linux, Windows veya herhangi bir RTOS üzerinde denersenin hata almanız muhtemel. Ama PIC\'te OS olmadığı sürece sorun oluşturmaz.  Bu işin daha güvenli yoluda vardır. Aşağıdakiler bellek sızıntısı yaratmayacak güvenli metodlar:
void write_int16_eeprom(int8 address, int16 data) {
   write_eeprom(address, data & 0xFF);
   write_eeprom(address + 1, (data >> 8) & 0xFF);
}


// CCS yerlesik make16 metodu ile
int16 read_int16_eeprom(int8 address) {
    int8 a, b;
    a = read_eeprom(address);
    b = read_eeprom(address + 1);
    return make16(a, b);
}

// Bit kaydirma ile
int16 read_int16_eeprom(int8 address) {
    int8 a, b;
    a = read_eeprom(address);
    b = read_eeprom(address + 1);
    return ((a << 8) | (b));
}


eehsyn

Çok teşekkür ederim yazici67  bilgilerin çok faydalı oldu. Kolay gelsin... :)
Ne kadar bilirsin bil söylediklerin karşındakinin anlıyabildiği kadardır.....&&Hz. Mevlana&&