avatar_fatih88

ccs c degişken sorunu

Başlatan fatih88, 06 Eylül 2014, 21:11:16

fatih88

   İyi akşamlar arkadaşlar ccs c de bir problemim var inşallah yardım edecek veya daha önçe bu sorunu çözen varsa yardımcı olursa sevinirim.
   kuracagımız devrede bir adet float değişkenimiz var bu değişkeni dahili eproma kaydetmem gerekiyor. değişkenimizin adı hocamızın ismi olsun tabi bunun yanındada eproma yazabilmek icine diger değişkenler olsun,
float ete=25.6,ete_e;
unsigned int16 a,k;unsigned int8 b,c,d,e;
d=read_eeprom(0);e=read_eeprom(1);
void main()
{
    a=ete*10;c=a%10;b=(a-c)/10;//eproma yazdırmak için float değişkenini tam sayıya dönüştürüyoruz(256)oluyor
    lcd_gotoxy(1,1);
    printf(lcd_putc,"\f f:%f e.t:%u e.o:%u"ete,b,c);//lcdde yazması gereken [f:25.6 e.t:25 e.o:6] yazıyorda :D
    write_eeprom(0,b);write_eeprom(1,0);
    //sorun burdan baslıyor :(
    ete_e=(d*10+e)/10;
    lcd_gotoxy(1,2);
    printf(lcd_putc,"e_okunan:%f",ete_e);//bana göre lcd yazması gereken [e_okunan:25.6] lcd yazdığı  ;D[e_okunan:0]degişkeni unsigned olarakta tanımlıyorum ama signed olarak çeviriyor yani +128 ile -128 otomatikman 0 yapıyor 16 bit olarakta tanımlasam olmuyor bi türlü yapamadım  :(
yardım ederseniz sevinirim.
}
bilgi paylaştıkça çoğalır!!

www.fayelektronik.com

Mucit23

#1
Tür olarak unsigned int16  yapmayı denedinmi?

Aşağıdaki kodu şöyle dene
ete_e=(d*10+e)/10;
yerine
ete_e=(unsigned int16)(d*10+e)/10;
Bu şekilde tür belirtmiş olursun.

Ayrıca gözüme ilişen bazı hatalar var.

float ete=25.6; adında değişkenin olsun. Bunu eproma yazmak için ilk önce tam sayıya çeviriyoruz.

unsigned int16 tam_sayi;
tam sayi=(unsigned int16)ete*10; //Sayıyı tam sayıya çevirmiş olduk. Burada sıkıntın yok.

Şimdi bu tam sayıyı eeproma iki parça halinde yazacağız. Sen buradada ufak bir hata yapmışsın
write_eeprom(0,b);write_eeprom(1,0);
0. adrese b değişkenini yazarken 1. adrese 0 yazmışsın

Her neyse aşağıdaki gibi bir yapı kullanırsan daha efektif bir kodun olur.

write_eeprom(0,(tam_sayi&0xFF));     //0. Adrese düşük 8biti yazmış olduk.
write_eeprom(1,(tam_sayi>>8 )&0xFF);     //1. Adrese yüksek 8 biti yazdık.

Yazma işlemi bu kadar.

Okumayıda aşağıdaki gibi yaparsın.

tam_sayi=(unsigned int16)(read_eeprom(1)<<8 ) | read_eeprom(0);

Fazla kasmaya gerek yok ;)
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

fatih88

write_eeprom(0,b);write_eeprom(1,c); olacaktı yanlış yazmışım kusura bakma
mucit23 kardesim ben epromdan okudugum degerleri tekrar float degere cevirmem gerekliyermiş oldugun bu tatır
tam_sayi=(unsigned int16)(read_eeprom(1)<<8 ) | read_eeprom(0); anladıgım kadarıyla 1. adresten ve 0. adresten alınan bir bytelik veriyi 16bitlik veriye topluyor yani alınan deger 256 olur benim yapamadigim 25.6 olarak float'a cevirmek ilgin icin tesekkurler
bilgi paylaştıkça çoğalır!!

www.fayelektronik.com

Mucit23

tamam işte birşey kalmamış.

tam sayıya çevirdik. Sayımız 256

float ete adında değişkenimiz vardı zaten.

tam_sayi=256
ete=(float)tam_sayi/10;

Bu kadar basit.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

fatih88

kardeşim gerçekten sağol ama olmuyor bunuda denemiştim senin daha önceden yaptıgın kukuçka makinasını glcd ve bir çok fonksiyon ekliyerek ccs c de yadım cihaz sıkıntısız çalışıyor orda ben bu durumu formülize edip yaptım ama proton basıcta bu işlemi yapmam daha kolay oluyordu ben işin bantık kısmındayım beni mantıgıma göre olmuyor çanımı o sıkıyor
diyelimki float degerimiz 43.6 olsun degişkenlerin hangisi 8 hangisi 16 bit belli

tam_sayı=43.6*10=436
t1=436%10=6
t2=436-6=430/10=43
t1=6 oldu t2=43 oldumu
bunları eproma yazdık okuduk
degerleri t3=43 t4=6 olarak aldık bunu floata çevirelim
t_say1=(t3*10+t4)=436
float_deg=(float)t_say1/10=43.6 olması gerekiyor ama deger 18.0 oluyor :(
bilgi paylaştıkça çoğalır!!

www.fayelektronik.com

Mucit23

İlk önce aşağıdaki işlemi yapmana gerek yok.

t2=436-6=430/10=43

Yani 10'a bölmeden önce birler hanesini sıfırlamaya gerek yok.
Değişken türleri tam sayı ise bölümde tam sayı olur.
yani 436/10=43 olur.

yaptığımız işlemlerde hata yok. içimden bir ses eeprom yazma ve okuma rutinlerinde problem yaşıyorsun diyor. Bak bakalım yukarıda anlattıklarına göre t1=6, t2=43 oldu bunları eeproma yazdıktan sonra eepromdan değerleri oku ve t3 ün 43, t4 ün 6 olduğunu doğrula.

buraya kadar yapılan işlemleri doğrulayıp geldikten sonra t_say1=436 mı bunu doğrula.

Eğer bu işlemde doğruysa sonra neden 436/10=18.0 oluyor ona bakalım.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

fatih88

dostum epromdan bilgileri alıyorum adress.0=43 adress.1=6 olarak alıyorum sorun şurda
t_say1=(t3*10+t4)=436olması gerekirken t_say1=180 cıkıyor float a çevirmeden önce benim t_say1ccs c tarafından signed yapıyor onuda nasıl anlıyorum
256-436=-180 oluyor bunun mantıklı bir açıklaması varmı  ben okudugum degere t_say1=(t3*10+t4+256) yaptıgımda sonuc float olarak
43.6 olarak alıyorum mevzu unsigned tanımlanmış bir deger nasıl olurda signed değişkenine döner
saygılarımla
bilgi paylaştıkça çoğalır!!

www.fayelektronik.com

Mucit23

Bu sorunun tek bir sebebi olabilir oda tanımadığın değişken yani t_say1 8 bitlik olarak tanımlanmış. Max 255 alır.

Değişkenin degerinin unsigned int16 türünde olduğuna emin ol. int16 olmasıda yeterli olur. Eğer değişkenin türünde de problem yok ise simülasyon dosyası ile yazılımını bir yere yükle. Akşam bakayım.  Basit bir hata yapıyorsun diye düşünüyorum.
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

Mucit23

ne yaptın sorunu çözdünmü ?
Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

fatih88

kardeşim hakkını hellal et şehir dışında oldugum için yazamadım sorun aynı ben çözemedin
k=(j*10+r)+256;normalde 256 olmaması gerek ama 256 yı eklemeden sorunu gideremedim 256 ekleyince düzgün oluyor mantıken 256 eklemek saçma geliyor daha önceki devremde bu şekilde yapmıştım içime sinmemişti ilgilenirsen sevinirimn
bilgi paylaştıkça çoğalır!!

www.fayelektronik.com

Mucit23

Programını inceledim ve gerçekten anlamakta çok zorlandım. Bu yüzden senin yaptıklarını başka bir programda yazdım. Hatanı buldum. Ama ona gelmeden önce birkaç yanlışın var onlara değineyim.

İlk önce  program yazarken kullandığın değişken isimlerini olabildiğince anlamlı bir şekilde koy. rastgele harfler yerleştirmek güzel bir alışkanlık değildir. Program uzadıkça anlaşılması zor bir hale geliyor.

Diğer bir hatan ise main döngüsü içerisinde eeproma sürekli veri yazman. Pic Mikrodenetleyicileri içerisindeki eeprom hafıza bölgelerinin yazma ömrü sınırldır. Yaklaşık 1000000 gibi bir yazma ömrü vardır. Okumanın ise sınırı yoktur. Bu yüzden programda eeprom kullanılıyorsa olabildiğince gereksiz yazmalardan kaçınılmalıdır. 1000000 çok yüksek bir sayı değil. Çok kısa bir sürede bitebilir.

Aşağıdaki verdiğim programı derleyip isiste çalıştır.
#include <16F877.h>

#device adc=10

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES NOPUT                    //No Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#FUSES RESERVED                 //Used to set the reserved FUSE bits

#use delay(clock=20000000)

#include "EXLCD.C"

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

unsigned int8 w_tam=0,w_onda=0;
unsigned int8 r_tam=0,r_onda=0;

float w_sayi=43.6;
float r_sayi=0;


void main()
{

   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   //setup_comparator(NC_NC_NC_NC);
  // setup_vref(FALSE);
 
   set_tris_a(0x00);
   set_tris_b(0x00);
   set_tris_c(0x00);
   set_tris_d(0x00);
   set_tris_e(0x00);
   output_a(0x00);
   output_b(0x00);
   output_c(0x00);
   output_d(0x00);
   output_e(0x00);
   
   delay_ms(100);
   lcd_init();
   printf(lcd_putc,"\f");
   lcd_gotoxy(1,1);
   printf(lcd_putc,"Eeprom Test");
   delay_ms(1000);
   printf(lcd_putc,"\f");
   
   w_tam=(unsigned int16)(w_sayi*10)/10;//w_tam=436/10=43 sonuç tam sayı olur
   w_onda=(unsigned int16)(w_sayi*10)%10;//436'nın Modu alınır sonuç 6 dır.
   //Bu değerleri ilk önce ekrana sonra eeproma yazalım
   
   lcd_gotoxy(1,1);
   printf(lcd_putc,"w_sayi=%2.1f",w_sayi);
   lcd_gotoxy(1,2);
   printf(lcd_putc,"w_tam=%u w_ond=%u",w_tam,w_onda);
   
   write_eeprom(0,w_tam); //Tam sayı 0. adrese yazılıyor
   write_eeprom(1,w_onda); //Diğer düşük sayı 1. adrese yazılıyor.
   //eeproma yazdık.Şimdide okuyalım.
   
   delay_ms(2000);
   
   r_tam=read_eeprom(0);  //0. Adresten tam sayı okunuyor
   r_onda=read_eeprom(1); //1. Adreseten birler hanesi okunuyor.
   
   r_sayi=(float)((unsigned int16)r_tam*10+r_onda)/10;
   
   printf(lcd_putc,"\f");
   lcd_gotoxy(1,1);
   printf(lcd_putc,"r_tam=%u r_ond=%u",r_tam,r_onda);
   lcd_gotoxy(1,2);
   printf(lcd_putc,"r_sayi=%2.1f",r_sayi);
   WHILE(TRUE)
   {
   } 
}

Asıl hatana gelirsek,
Aslında sen 43.6 sayısını doğru bir şekilde 436 yapıp 43 ve 6 olmak üzere iki değişkene yazıp eeproma yazıyordun.
eepromdan okumadada problem yok. Sorun eepromdan okuduğun 43 ve 6 sayılarını tekrar 436 yapmada.

Senin kullandığın kod aşağıdaki gibiydi.
k=(j*10+r);

Normalde sıkıntı olmaması gerekir j nin değeri 43, r ise 6 j*10=430 olması gerekir ama olmuyor bunun yerine 170 küsür bir değer alıyor.
Sebebi ise j değişkeninin unsigned int8 olarak tanımlanmış olması.

CCS nin huyudur. Yapılan işlemin sonucunun kaç bitlik bir sayı olacağını bilemez bu yüzden değişkenin türlerine bakarak işlem yapar.

senin j değişkeninin 8 bitlik olarak tanımlandığı için sayısal olarak max 255 alır. Ama senin yaptığın j*10 işleminin sonucu 430 dolayısıyla  8 bitlik sınırı aşıyor. Sende 430-255=175 yani 170 küsür bir değer görüyorsun. Tüm mesele bu.

Çözümü ise yukarıdaki kodda verdiğim gibi işlemin türünü kendin belirlemen

k=((unsigned int16)j*10+r); Bu şekilde yaparsan sorun çözülür.

Bende aşağıdaki gibi yapmışım.

r_sayi=(float)((unsigned int16)r_tam*10+r_onda)/10;  //Sayi tekrardan 43.6

Aşağıda çok karıştırmışsın. Bukadar işleme gerçekten gerek yok. ;)
   lcd_gotoxy(1,1);
   printf(lcd_putc,"T:%u O:%u f:%f",B,i,f);
   d=c*10;
   i=d%10;
   b=(d-i)/10;
   lcd_gotoxy(1,2);
   printf(lcd_putc,"E.T:%u E.O:%u",j,r);
   k=(j*10+r)+256;
   f=(float)k/10;
   write_eeprom(0,b);write_eeprom(1,i);
   delay_ms(300);


Mesela görmüşken aşağıdaki kodu ele alalım.

b=(d-i)/10;

Burada yaptığın işlem 436 sayısından 6 sayısını çıkartıp 10'a tam bölünmesini sağlamak. Ama buna zaten gerek yok. Eğer B değişkenin unsigned int16 türünde ise yapılan işlemin sonucu reelde virgüllü olsa bile b değişkenine sadece tam sayı değeri yüklenir. yani b değişkeninin değeri 436/10=43 olur.

Aşağıdaki gibi yapsanda işlem gerçekleşir
b=(unsigned int16)d/10;

Herneyse bu kodlar çalışır ama ilk başta söylediğim gibi sayıyı normal bir sayı gibi düşünüp parçalamaktansa (436 = 43 - 6)8 bitlik parçalar halinde ayırmak herzaman daha iyi olur. Yukarıda yapılan yöntem herzaman düzgün çalışmaz. 16 bit bir sayıyı (mesela 436 olsun) eeproma iki parça halinde yazarken aşağıdaki yapıyı

write_eeprom(0,(tam_sayi&0xFF));     
write_eeprom(1,(tam_sayi>>8 )&0xFF);   

okuyup tekrar 16 bitlik bir sayı olarak kullanmak içinsede aşağıdaki yapıyı kullansan çok daha iyi olur. ;)

tam_sayi=(unsigned int16)(read_eeprom(1)<<8 ) | read_eeprom(0);

Zira senin sayın 436 yerine 4367 olsa senin kodlar çalışmayacak ve aynı mantıkla yapmak isetersen ekstran 1-2 byte daha kullanmış olacaksın.

Umarım konu anlaşılmıştır.  :)

Bir ulusu yok etmenin En iyi yolu o ulusun dilini yok etmektir.

www.arectron.com/

aoe

#11
neden kimse pointer kullanımına yanaşmıyor bu tarz işlemlerde acaba.

float readfloat_eeprom(unsigned char addr)
{
float f_okunan = 0.0;
long addrokunan = 0;
addrokunan = (long)&f_okunan;
for(int i=0;i<8;i++)
{
*(char*) (addrokunan+i) = read_eeprom((addr+i));
}
return  f_okunan;
}
void writefloat_eeprom(unsigned char addr, float deger)
{
float f_yaz = deger;
for(int i= 0;i <8;i++)
{
write_eeprom(addr+i, *(char*) ( ((long)&f_yaz) +i));
}
}


hem bu şekilde float değişkenini tam sayıya çevirerek 4 bytelık kayıpdanda kurtulmuş oluruz. eğer direk float değişken kullanılıcaksa.

Powered by EzPortal