LCD de Ondalıklı sayıyı basamaklarla olusturup Eproma kaydetmek Hk.

Başlatan axionvb, 27 Mart 2011, 02:33:18

axionvb

Değerli Grup üyeleri,
Bu güne kadar yaptığım devreleri sizlerin verdiği değerli bilgiler ile yaptım ve pic konusunu öğrenme ile ilgili olarak epey bir konu öğrendim. Şimdi hazırlamakta olduğum bir devre için değerli yardımlarınıza ve çözüm önerilerinize ihtiyacım var.
16F452 ile 16x2 LCD ekran ve RB4...RB7 ye pull-up dirençlerle bağlı 4 adet buton ile LCD ekranında 20452.75 şeklinde bir sayı oluşturmak ve bu sayıyı olutururken her basamak değerini RB5 ve RB6 ya bağlı Yukarı ve Aşağı buton olarak isimlendirdiğim butonlar aracılığı ile yapmak istiyorum. Program ilk çalıştırıldığında Epromun sıfırıncı adresine yukarıda verdiğim sayı örneğine uygun olarak başlangıçta 00000.00 değerini yüklemek ve daha sonra epromdan bu değeri okumak ve bir diziye almak istiyorum. ilk basamak değerini LCD komutuyla yanıp sönmesini sağladıktan sonra. Yukarı aşağı butonlarla 0-9 arası sayının basamak değerini değiştirmek ve OK butonuna basınca bir sonraki basamağa geçmek ve bu basamak değerini diziye aktarmak.  OK butonu ile basamaklarda ilerlerken ondalık sembolünü geçip ondalıktaki ilk değere konumlanmak ve bu şekilde ondalık kısmınıda girip değerleri diziye aldıktan sonra son basamakta OK butonuna basınca diziye kaydedilmiş son halini ondalıklı sayı olarak epromda saklamak istiyorum. Bunun için ben aşağıdaki örnek satırları yazdım fakat değeri ekrana düzgün yazdıramadım bu nedenle eproma da doğru yazılımadı. Bu konuda yardım edermisiniz.
#include <Deneme.h>
#include "Flexible_LCD.c"

#use fast_io(b)
#use fast_io(c)

char m3HF[8];

void Eprom_Ondalik_Yaz(int8 Adres, float Veri)
{
   int8 i;
   for(i=0;i<16;++i)
   {
      write_eeprom(Adres+i,*((int8 *)(&Veri)+i)); 
   }
}
float Eprom_Ondalik_Oku(int8 Adres)
{
   int8 i;
   float Veri;
   for(i=0;i<16;++i)
   {
      *((int8 *)(&Veri)+i)=read_eeprom(Adres+i);      
   }
   return Veri;
}

void main()
{
   setup_psp(PSP_DISABLED);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_adc_ports(NO_ANALOGS);
   setup_adc(ADC_OFF);
   setup_CCP1(CCP_OFF);
   setup_CCP2(CCP_OFF);
   
   set_tris_b(0xF0);
   set_tris_c(0x00);
   output_b(0x00);
   output_c(0x00);
    
   enable_interrupts(INT_RB);
   enable_interrupts(GLOBAL);
   while(1)
   {
         if(read_eeprom(30)!=1)
         {
              float k;
              k=00000.00;              
              Eprom_Ondalik_Yaz(0,k);
          }
          if(BasamakAktif==0)
         {            
            sprintf(m3HF,"%05.2f",Eprom_Ondalik_Oku(0));
            lcd_imlec(2,1);
            printf(lcd_Yaz,"%c%c%c%c%c.%c%c",m3HF[0],m3HF[1],m3HF[2],m3HF[3],m3HF[4],m3HF[6],m3HF[7]);
         }
          if(Basamak==9)
            {
               Eprom_Ondalik_Yaz(0,m3Hf);
               Delay_Ms(500);
            }
   }
}


Yukarıdaki kodu İsis de çalıştırdığımda LCD ekranına 00.00. şeklinde yazıyor. Mesaj fazla uzun olmasın diye Yukarı,Aşağı ve OK butonlarına basılma durumunda yapılan işlemleri ve değer artırma bölümlerini eklemedim.

subram

yazdığın programa bakamadım ama şöyle bişey yapabilirsin; kullanacağın sayının ondalık işaretini kaldırırsan elinde 7 basamaklı bir sayı oluşur.
programda BASAMAK adında bir değişken oluştur. bu değikende kaçıncı basamakta olduğunu tutacaksın ( 0 ile 6 arası- 7 basamak olduğu için)
sonra her  Ok butonuna basınca bu değeri arttır.herhangi bir sayı girip OK butona bastığımız zaman BASAMAK değikenin değerine göre bu sayı;
1 000 000,
100 000,
10 000,
1 000,
100,
10,
1   

sayıları ile çarpılarak SAYI'oluşturmuş olursun. ekrana yazdırmak için sayıyı önce normal bölme ile tam kısmını sonra modlu bölme ile ondalık kısmını elde edebilirsin..

İkinci alternatif ondalık ve tam sayı kısımlarını ayrı ayrı iki sayı olarak düşünüp. iondalık kısmını
10 000
1 000
100
10
1

ile çarpıp  tam sayıyı elde etmek sonra ondalık kısmı içinde girilen sayıları;

10

çarpıp ondalık kısmı elde edebilirsin.

anlatabildim mi bimiyorum acele ile yazdım.
http://www.elektronark.org  Türkiyede Elektronik Kültürünü Değiştirmeye Geliyoruz

Klein

Float tip değişken 4 byte uzunluğunddır. oysa siz 16byte okuma yapmışsınız.
şu şekilde float sayı okuyup yazabilirsini.
void ee_write_float(unsigned int addr , float *floatptr){
unsigned char edata;
unsigned char 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 char I;
	for(I=0;I<4;I++){
		edata=ee_read_byte(I+addr);	
  		*((unsigned char *)floatptr+I) = edata;
	}
}

axionvb


Klein

kendi yazdığım fonksiyonlar.
siz  write_eeprom(......) , ...read_eeprom(...)  fonksiyonlarını kullanabilirsiniz bunun yerine. 

axionvb

Son mesajınızı görmeden önce bende read_eeprom olarak değiştirmiştim ee_read_Byte fonksiyonunu fakat aşağıdaki fonksiyonla eproma yazılan veriyi okuyup m3HF dizisine atmak istedim fakat ee_read_float fonksiyonunda parentez içindeki değeri kabul etmiyor ve Expect Comma hatası veriyor. Bu arada kullandığım derleyici CCS C 4.114

sprintf(m3HF,"%05.2f",ee_read_float(0));

Klein

ee_read_float(...) fonksiyonunda  dönüş değeri  parametre olarak verdiğiniz değişkene gönderiliyor.
Dikkatinizden kaçmış olmalı. Fonksiyonun bir dönüş değeri yok.

fonksiyonu şu şekilde kullanabilirsiniz.
float  temp;
ee_read_float(adres, &temp);
sprintf(......,"%..f",temp);


axionvb

Expect Comma yı google çeviri ile çevirdiğimde virgül bekleniyor şeklinde çevirdi. bende ne virgülü diye şaşırmış ve fonksiyonu birdaha inceledim ve sizin de bahsettiğiniz gibi geri dönüş için parametre vermediğimi gördüm.
Aşağıdaki gibi okutma yaptım.
float x,y;
y=ee_read_float(0,x);
sprintf(m3HF,"%05.2f",y);

sizin yazdığınız şekil daha doğru gibi geldi. Ben fazladan değişken kullanmıştım. Hanıma perde asmak için yardım ettiğimden hemen cevap yazamamıştım.

şimdi de ekrana 00.50 şeklinde yazıyor.
ben programın başında eproma aşağıdaki komutlarla 00000.00 değerini göndermiştim.

float k;
k=0;
ee_write_float(0,k);


sonra aşağıdaki komutlarla ekrana yazdırdığımda 00.50 şeklinde yazıyor. oysa başlangıçta 00000.00 şeklinde yazsın istiyorum.

float Temp;
char m3HF[8];

Eprom_Ondalik_Oku(0,&Temp);
sprintf(m3HF,"%05.2f",Temp);
lcd_imlec(2,1);         
printf(lcd_Yaz,"%05.2f",Temp);

Klein

yazarken de  k nın kendisinideğil adresini parametre olarak gemen gerek.

float k;
ee_write_float(0,&k);

axionvb

Dediğiniz şekilde yaptım. Fakat ekrana 00000.00 şeklinde yazdıramadım.
float k;
k=11111.11;
ee_write_float(0,&k);

şeklinde girersem LCD ekrana 11111.11 şeklinde yazıyor. Fakat k=00000.00; şeklinde girersem hatalı kabul ediyor. k=0; olarak verirsem LCD ekrana 00.00 şeklinde yazıyor. Sanırım başlangıçta 00.00 ı kabul edip her basamakta değerleri arttırarak sayıları oluşturmayı ve 6. basamaktada . sembolünü ekleyerek yapmayı deneyeceğim.

axionvb

Sanırım stres yaptım. İstediğim şeyi bir türlü yapamıyorum. Şu anda kilitlenmiş durumdayım.

Klein

Şu an  sorunun eeprom'a  yazma ve okuma ile ilgili değil.
Sorunun sprintf ile ilgili.

sprintf(....,"%05.2f",....)   yazdığında okta dahil 5 karakter bas diyorsun.  bu yüzden 2 tamsayı , 1 nokta iki tane de desimal yazıyor toplam 5 hane oluyor.
sprintf(....,"%07.2f",....) şeklinde yazarsan  noktadan önce 4 sıfır basar.

axionvb

Ben bu komut içindeki %05.2f i noktadan önce 5 hane, noktadan sonra 2 hane diye biliyordum. Dediğiniz düzeltmeyi yapacağım.

axionvb

Sevgili Klein,

Verdiğiniz bilgiler ışıgında gerekli düzeltmeleri yaptım. Böylece eproma float değer kaydetme ve okuma ile ilgili sorunları senin yardımınla çözdüm. Fakat ekranda değiştirdiğim sayıyı float yapamadım.

Program ilk başlarken 00000.00 olarak ekrana geliyor ve ilk karekter yanıp sönme efekti ile o hane üzerinde işlem yapıldığını kullanıcıya bildiriyor. Yukarı Aşağı butonlarına basıldığında ekrandaki sembol Lcd_getc komutu ile okunup m3HF dizinini ilk bölümüne yazılıyor. Bu işlemle ekranda hangi sayı varsa o sayıdan itibaren artma azaltma yapıyor. Neyse sayının tüm haneleri değiştirildikten sonra bu değişikliğin float tipe dönüştürülüp senin verdiğin yöntem ile eproma yazılması gerekiyor. Başlangıçta 00000.00 olan sayı butonlarla 20496.23 şekline getirildi bu esnada m3HF[8] dizesinin içeriği ;
m3HF[0]='2'
m3HF[0]='0'
m3HF[0]='4'
m3HF[0]='9'
m3HF[0]='6'
m3HF[0]='.'
m3HF[0]='2'
m3HF[0]='3'

bu dizi char m3HF[8] şeklinde tanımlandı.

bu aşamadan sonra m3HF dizesi nasıl float yapılacak.
Ben şu işlemi yaptım ama hatalı oldu
Float Sonuc;
Sonuc=(m3HF[0]*10000)+(m3HF[0]*1000)+(m3HF[0]*100)+(m3HF[0]*10)+(m3HF[0]*1)+(m3HF[0]*0.10)+(m3HF[0]*0.01);

Bu problemi de çözersek yazılım tarafında fazla sorun kalmayacak.

Teşekkürler...

Klein

Hesaplama yapmana gerek yok. 

sscanf(buffer,"%07.2f"&temp);

fonksiyonu  bufferde string halinde bulunan float sayıyı float tipindeki temp değişkenine doğrudan float sayı olarak aktarır.

C'de stringler üzerinde çalışırken dikkat etmen gereken bir kural var.  string için ayırdığın  bellek alanı her zaman gireceğin stringden 1 fazla olmalı ve  stringden sonraki bayt muhakkak 0 olmalı. sprintf  sen belirtmesen de dizinin sonuna 0 koyar.  Eğer sprintf çıktısı olarak aldığın metin uzunluğu bellek alanın ile eşitse , sonuna 0 koyduğu için 0 yapılan adres  diziden sonraki ilk değişken olacaktır. Bu sorun derleme zamanı hatası vermeyeceği için bazı durumlarda saç baş yoldurur.

ekleme :
m3HF[0]='2'
m3HF[0]='0'
m3HF[0]='4'
m3HF[0]='9'
m3HF[0]='6'
m3HF[0]='.'
m3HF[0]='2'
m3HF[0]='3'

tüm satırlarda dizinin 0. elemanına yazıyor olduğuna dikkat et.