C Programlama diliyle şamatalar

Başlatan z, 23 Ekim 2011, 15:32:04

fatih6761

Hocam sayılar floating point ise iş değişir. Küsürat iki basamaksa floating point sayıları fixed point'e çevirerek kaydedebilirsiniz. Ya da her floating point sayı 32-bit yer tutar. İki tanesi 8-byte eder. String'e çevirip yazma okuma yapmakla doğrudan floating point yazıp okumak arasında dağlar kadar fark var. Stringe çevirmek en kötü olasılık. Yazdığınız yere bakarak C dili kabul ediyorum. Bu konuda derleyicinin dökümanlarını biraz araştırın.Standart 32-bit floating sayı kullanıyorsa bir pointer ile hallolur. Örneğin:
// yazma
float key = 1000.0f; // sondaki f önemli sebebi çok defa anlatıldı.
int * keyptr = &key;
eeproma_yaz(keyptr, 4); // keyptr adresinden itibaren 4-byte yazılacak
// okuma
char keyArray[4];
eepromdan_oku(keyArray, 4); // keyArray dizisine 4-byte eepromdan oku
float key = *((float *)keyArray);

Gökhan BEKEN

Alıntı yapılan: yldzelektronik - 13 Eylül 2013, 18:32:26
sayı maksimum 1100.00 olabiliyor.En az 800.00.Küsüratta da evet .99 en fazla.
Toplam 3 bayt ile kaydedilebilir.
Sayının tam kısmı en fazla 1100 değil 66536 kadar büyük bile olsa 16 bit yani 2 bayt ile kaydedilebilir, ondalıklı kısmı maksimum 99 değil 255 bile olsa 1 baytta halledilebilir.
1100=0x044C yani 16 bit(2bayt)
99=0x69 yani 8 bit(1bayt)
Özel mesaj okumuyorum, lütfen göndermeyin.

yldzelektronik

Ccs helpinde float ile ilgili yer alan bilgiler şöyle:






Ayrıca ex_float.c diye örnek kodu var.O da şöyle:

/////////////////////////////////////////////////////////////////////////
////                          EX_FLOAT.C                             ////
////                                                                 ////
////  This program shows input, output and standard operations with  ////
////  floating piont numbers.  I/O is RS232.                         ////
////                                                                 ////
////  Jumpers:                                                       ////
////     PCM,PCH    pin C7 to RS232 RX, pin C6 to RS232 TX           ////
////                                                                 ////
////  This example will work with the PCM and PCH compilers.  The    ////
////  following conditional compilation lines are used to include a  ////
////  valid device for each compiler.  Change the device, clock and  ////
////  RS232 pins for your hardware if needed.                        ////
/////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2003 Custom Computer Services         ////
//// This source code may only be used by licensed users of the CCS  ////
//// C compiler.  This source code may only be distributed to other  ////
//// licensed users of the CCS C compiler.  No other use,            ////
//// reproduction or distribution is permitted without written       ////
//// permission.  Derivative programs created using this software    ////
//// in object code form are not restricted in any way.              ////
/////////////////////////////////////////////////////////////////////////


#if defined(__PCM__)
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif

#include <stdlib.h>
#include <input.c>

void main() {
   long int l;
   float a, b;

   while(TRUE) {
      printf("\r\nEnter first number: ");
         a=get_float();

      printf("\r\nEnter second number: ");
         b=get_float();

      printf("\r\n\nA= %E\r\n", a);
      printf("B= %E\r\n", b);
      printf("\r\na + b = %E", a + b);
      printf("\r\na - b = %E", a - b);
      printf("\r\na * b = %E", a * b);
      printf("\r\na / b = %E\r\n", a / b);

      if(a <= b)
         printf("a<=b, ");
      else
         printf("a>b, ");
      if(a < b)
         printf("a<b, ");
      else
         printf("a>=b, ");
      if(a == b)
            printf("a==b\r\n");
      else
         printf("a!=b\r\n");

      l = (long int)a;
      printf("\r\n(long)a = %lu ", l);
      a = (float)l;
      printf("\r\n(float)(long)a = %E\r\n", a);
   }
}


Resimlerden birinde benim dikkatimi çeken ifade;

CCS uses the same format Microchip uses in the 14000 calibration constants

Merak ettiğim ccs nin kullandığı float sayılar standartlara uygun olan mı?(ifade ne kadar doğru oldu bilmiyorum ama kastım standart c nin ne tarafında olduğu) Ayrıca double için;

double
Is a reserved word but is not a supported data type.

ifadesine yer vermiş.Ne demektir?Ayrılmış fakat desteklenmiyor ne demektir?
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

yldzelektronik

Çözüm için meftunun bahsettiği üzere

void write_eepromfloat(char position_eeprom,float flt){
   int16 katsayi = flt;
   char kusurat = (flt - katsayi) * 100;
   write_eeprom16bit(position_eeprom,katsayi);
   write_eeprom(position_eeprom + 2,kusurat);
}

float read_eepromfloat(position_eeprom){
   float katsayi = read_eeprom16bit(position_eeprom);
   float kusurat = (float)read_eeprom(position_eeprom + 2) / 100;
   float flt = katsayi + kusurat;
   return flt;
}


şeklinde bir yöntem denedim ve çalışıyor.Ancak bir sıkıntı var.Bazı sayılarda 0.01 eksik değer dönüyor..Sebebini anlayamadım.Öyle lineer de değişmiyor.

Yani 12.12 de aynı değer dönüyor.Ancak 123.12 den dönen değer 123.11 65535.25 den dönen değer 65535.25 .Garipsedim biraz.Sebebi ne ola ki?
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

fatih6761

Hocam bu kadar sıkıştırmaya ihtiyacınız var mı gerçekten? 3-bayt yerine 4-bayt olması çok önemli değilse bir önceki mesajımda verdiğim yöntemi uygulayın. Hatta CCS C içinse doğrudan kodu vereyim:
void write_eepromfloat(int8 addr, float val){
   int8 * ptr = &val;
   write_eeprom(addr, *(ptr));
   write_eeprom(addr+1, *(ptr+1));
   write_eeprom(addr+2, *(ptr+2));
   write_eeprom(addr+3, *(ptr+3));
}

float read_eepromfloat(int8 addr){
   int8 data[4];
   data[0] = read_eeprom(addr);
   data[1] = read_eeprom(addr + 1);
   data[2] = read_eeprom(addr + 2);
   data[3] = read_eeprom(addr + 3);
   return *((float *)data);
}

Bu yöntemle float veri tipinin tüm hassasiyetini kullanabilirsiniz. Hem de hiç bir hatalı değer olmadan.

Klein

Eğer sayın float ise: göstergede tam değeri göremezsin. Kaç hane ggösteriyorsan ona göre yuvarlanmış halini görürsün.

Örneğin:
Sayı  123.1156   bu sayıyı noktadan sonra 2 hane görmek istersen 123.12 görürsün.

kaydederken noktadan sonraki haneleri 100 ile çarptın.  0.1156 * 100 = 11,56 olur. Bunu tamsayıya çevirip yazdığında 11 olarak kaydedersin ve 11 olarak okursun.

Sayılarla bu şekilde oynayarak eeprom'a kaydetmek  benim önereceğim bir yöntem değil. Float sayı 4 byte. o zaman 4 bytaolarak kaydedeceksiniz. Hızlı olsun demişsiniz ama bölme çarpma işlemleri için bir sürü zaman harcamışsınız. Bence verimsiz bir yöntem.
Bence doğru olan @fatih6761 arkadaşın söylediği gibi pointer ile tüm 4 bayt kaydedip geri 4 byte olarak okumak.

önereceğim yöntem bu.
void ee_write_float(unsigned int addr , float *floatptr){
unsigned char edata;
unsigned int I;
 	for(I=0;I<4;I++){
		edata = *((unsigned char *)floatptr+I);
		ee_write_byte(addr+I,edata);
	}
}

void ee_read_float(unsigned int addr , float *floatptr){
unsigned char edata;
unsigned int I;
	for(I=0;I<4;I++){
		edata=ee_read_byte(I+addr);	
  		*((unsigned char *)floatptr+I) = edata;
	}
}


float sayi = 123.567
ee_write_float(adres , &sayi);
ee_read_float(adres , & sayi);


başka bir yol ise
typedef union
{
    float f;
   char c[4];
}FtoC;

void ee_write_float ( int adres, float sayi)
{
FtoC x;

   x.f = sayi;
   for( char i =0 i< 4; i++)
  {
      eeprom_write_byte(i+adres, x.c[i];
 }

}

float ee_read_float(int adres)
{
FtoC x;
    for(char i =0; i< 4; i++)
   {
      x.c[i] = ee_read_byte(adres);
   }  
   return(x.f);
}



yldzelektronik

Alıntı yapılan: fatih6761 - 14 Eylül 2013, 14:50:13
Hocam bu kadar sıkıştırmaya ihtiyacınız var mı gerçekten? 3-bayt yerine 4-bayt olması çok önemli değilse bir önceki mesajımda verdiğim yöntemi uygulayın. Hatta CCS C içinse doğrudan kodu vereyim:
void write_eepromfloat(int8 addr, float val){
   int8 * ptr = &val;
   write_eeprom(addr, *(ptr));
   write_eeprom(addr+1, *(ptr+1));
   write_eeprom(addr+2, *(ptr+2));
   write_eeprom(addr+3, *(ptr+3));
}

float read_eepromfloat(int8 addr){
   int8 data[4];
   data[0] = read_eeprom(addr);
   data[1] = read_eeprom(addr + 1);
   data[2] = read_eeprom(addr + 2);
   data[3] = read_eeprom(addr + 3);
   return *((float *)data);
}

Bu yöntemle float veri tipinin tüm hassasiyetini kullanabilirsiniz. Hem de hiç bir hatalı değer olmadan.

Hocam teşekkür ederim 6 haneye kadar denedim ve tık fark yok.Girdiğim değer aynı şekilde çalışıyor.
Yalnız kodu biraz açıklar mısın?
   write_eeprom(addr, *(ptr));

satırıyla eeproma ptrnin adres değerini mi yazdırıyoruz?
  int8 * ptr = &val;
satırıyla val değişkeninin adresini almıyor muyuz?
Ben her yeni değer girdiğimde farklı adreslere mi atanıyor bu değişken?Anlayamadım?

@Klein
Alıntı yapılan: Klein - 14 Eylül 2013, 14:54:45
...
önereceğim yöntem bu.
...
başka bir yol ise
typedef union
{
    float f;
   char c[4];
}FtoC;

void ee_write_float ( int adres, float sayi)
{
FtoC x;

   x.f = sayi;
   for( char i =0 i< 4; i++)
  {
      eeprom_write_byte(i+adres, x.c[i];
 }

}

float ee_read_float(int adres)
{
FtoC x;
    for(char i =0; i< 4; i++)
   {
      x.c[i] = ee_read_byte(adres);
   }  
   return(x.f);
}

Anlamadığım kısımlar var.

ee_write içinde sadece x.cyi yazdırmışsın.Ancak float sayı x.f içinde doğru mu?Peki x.c ye hiçbir müdahele yapmadan neden onu yazdırdın?


Ekleme: Union olduğunu farkettim.Ki bu da aynı bellek alanına farklı isimlerle erişme imkanı sağlıyor.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

fatih6761

@yldzelektronik hocam siz fonksiyonu çağırdığınızda sayının stack'de bir kopyası oluşturulur ve fonksiyon bu kopyaya ulaşır.
int8 * ptr = &val;

kısmında dediğiniz gibi bir int8 pointer oluşturuyoruz ve bu pointer'da float değişkenimizin adresini veriyoruz. Yani ptr, val'in adresini taşıyor. float 4 bayt ama biz bu ptr ile her baytı birer int8'miş gibi adresleyebiliyoruz.
Eeproma yazarken *ptr (bu*(ptr) ile aynıdır) ptr'nin işaret ettiği adresteki bir baytı ifade eder. Eeproma bellekten sırayla 4-baytı yazıyoruz.
İyi çalışmalar, kolay gelsin...

yldzelektronik

#623
Alıntı yapılan: fatih6761 - 14 Eylül 2013, 15:38:12
@yldzelektronik hocam siz fonksiyonu çağırdığınızda sayının stack'de bir kopyası oluşturulur ve fonksiyon bu kopyaya ulaşır.
int8 * ptr = &val;

kısmında dediğiniz gibi bir int8 pointer oluşturuyoruz ve bu pointer'da float değişkenimizin adresini veriyoruz. Yani ptr, val'in adresini taşıyor. float 4 bayt ama biz bu ptr ile her baytı birer int8'miş gibi adresleyebiliyoruz.
Eeproma yazarken *ptr (bu*(ptr) ile aynıdır) ptr'nin işaret ettiği adresteki bir baytı ifade eder. Eeproma bellekten sırayla 4-baytı yazıyoruz.
İyi çalışmalar, kolay gelsin...

Hocam kusura bakma biraz zor anlıyorum.

Şimdi *ptr ile oluşturduk.

*ptr = &value ile float value nin bellekteki adresini yazdık.Yani daha valuenin değeriyle ilgilenmedik.Doğru mu?

Eğer böyle ise şöyle bir şey oluyor.Benim elimde ptr içinde duran bir adres var ve bu adres sıralı 4 byte ile float bir sayı taşıyor.Peki ben o adresteki değeri ptr ile nasıl görücem?

write_eeprom(adres,*prt); ile ben parametre olarak valuenin adresinin ilk bytenı geçtim?

Şöyle;

float value = 123.123; // Bellekte 0x00 adresinde.
int *ptr = &value; //ptrnin içinde 0x00 oldu.

Ben herhangi bir yere *ptr olarak geçersem 0x00 adresinin ilk byte olarak taşıdığı değere erişiyorum.Yani 123.123 4 bytelık sayısının ilk bytena eriştim.Doğru mu?

Yani o zaman şu oluyor;
*ptr ile
ptr kullanımı fark ediyor. Doğru mu?

Bir yere *ptr olarak geçersem adresin taşıdığı değere, ptr olarak geçersem o adrese yani buradaki 0x00 a erişirim.Doğru mu?

Teşekkürler.
Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

mir_as82

Hocam pointer in adresine ulaşmak icin ne yapmaliyiz? Yine bir pointer mi tanimlamaliyiz? Baska bir soru da, pointer kullaniminda herhangi bir sinirlama var mi?

XX_CİHAN_XX

Alıntı yapılan: mir_as82 - 14 Eylül 2013, 16:16:01
Hocam pointer in adresine ulaşmak icin ne yapmaliyiz? Yine bir pointer mi tanimlamaliyiz? Baska bir soru da, pointer kullaniminda herhangi bir sinirlama var mi?
Pointer türünden bir pointer tanımlamak için iki tane ** operatörü kullanılır.
int **ipp;
int i = 5;
int *ip1 = &i;
ipp = &ip1;

Sınırlama olayı hafıza kapasitesi ile ilgili bir durum.
Yirmi yaşındaki bir insan, dünyayı değiştirmek ister . Yetmiş yaşına gelince , yine dünyayı değiştirmek ister, ama yapamayacağını bilir.

Gökhan BEKEN

Alıntı yapılan: mir_as82 - 14 Eylül 2013, 16:16:01
Baska bir soru da, pointer kullaniminda herhangi bir sinirlama var mi?
visual c++ ta sınırlama var, bellekteki bütün verileri okuyayım derseniz; güvenlik sebebiyle, compile etmenize izin vermiyor. Sadece programınızdaki belli başlı adresleri okuyabiliyorsunuz. Ancak standart c++ ta böyle değil.
Özel mesaj okumuyorum, lütfen göndermeyin.

fatih6761

İşletim sistemi varsa bellek koruma ünitesi engeller. @Meftun hocamın da dediği gibi derleyici de bunu engelleyebilir ancak koda birkaç satır ekleyerek derleyicinin bu özelliği kapatılabilir.

yldzelektronik

Kişinin başına gelen hayır Allah'tandır. Kişinin başına gelen şer nefsindendir. Nefislerimizle kendimize zulüm ediyoruz.

CoşkuN

Bu konu altında oldukça faydalı tartışmalar oluyor ancak tek bir konu başlığı altında olması takibi zorlaştırıyor.
Bu mesajın altına açılan yeni konular farklı adlarla C programlama bölümü adı altında açılsa daha faydalı olacağını düşünüyorum.