Atmega88 hesap hatam nerede?

Başlatan zakbay, 29 Şubat 2012, 15:33:05

zakbay

Arkadaşlar merhaba

atmega88 dahili 1v1 dahili referans ile adc sini kullanmaya başladım. lm35 okuyorum

hesaplarım 1 volt üzerinden olduğu için
okuma yaptıktan sonra değeri 1.1 le çarpmak istiyorum. Ama bir yerde hata yapıyorum galiba sonuçlar alakasız çıkıyor.

uint16_t gecici;

	gecici = ADCL + (ADCH<<8);
        sicaklik = (gecici * 110 ) /100;       bu olmuyor
        sicaklik = (unsigned int)((gecici * 110 ) /100);       bu da olmuyor


float değişken kullanmadan bunu nasıl halledebilirim

ecilipse ve winavr kullanıyorum
Tek dostum çalışmak...

Kabil ATICI

Bu tür işlerde hesap işlerini işlemcide yapmak yerine ben doğrudan tablolama yöntemini kullanıyorum. Program biraz büyüyor ama, daha hızlı işlem yapıyor. Hatta ekrana yazdıracağım değeri tablodan alıp kullanıyorum. Tabloyu da exel programını kullanarak gerekli hesaplamaları yaparak oluşturuyorum.
ambar7

zakbay

Picte sorun olmuyor her türlü kabul ediyordu.
Atmel de yeni şeylerle karşılaşınca bocalıyorum  ;D
Bakalım bulacağız çözümü bir şekilde
Tek dostum çalışmak...

Kabil ATICI

Anlattığım çözümü Atmel serisi işlemcilerde kullanıyorum. asm'de bazı işleri yapmak  zor olduğu için kestirmeden gitmek iyi oluyor...
ambar7

tmcone

"gecici" değişkenin 16 bitlik bir değer tutabilir. ADC sonucun 1023 ise 110 ile çarptığında sonuç 20 bitlik bir sonuç olur; bu da taşmaya neden olacaktır. Değişkenini 32 bit tanımlarsan sorun çözülür. ADC sonucunu ölçeklerken 2 nin katları şeklinde bir bölen seçmen optimizasyon açısından çok daha iyi olur. Örneğin 1.1 katsayısı için basitçe sonucu aşağıdaki gibi 1.1 * 32 = 35.2 nin tam sayı kısmı ile çarpıp 5 sağa kaydırma yaparsan 32 bitlik bir değişkene ihtiyacın olmaz ve işlem süresi oldukça kısalır. Bu durumda azami hatan 1023 için 1023 * (1.1 - (35 / 32)) = 7 olur. Çarpanı büyüterek bu hatayı azaltabilirsin.

sicaklik = (gecici *35)  >>  5;

tmcone

Alıntı yapılan: ambar7 - 29 Şubat 2012, 16:15:15
Bu tür işlerde hesap işlerini işlemcide yapmak yerine ben doğrudan tablolama yöntemini kullanıyorum. Program biraz büyüyor ama, daha hızlı işlem yapıyor. Hatta ekrana yazdıracağım değeri tablodan alıp kullanıyorum. Tabloyu da exel programını kullanarak gerekli hesaplamaları yaparak oluşturuyorum.

Bir önceki mesajımda belirttiğim yöntemi kullarsanız (ek olarak * 1000)  32 bitlik bir çarpan ile virgülden sonra 3 basamak doğrulukta bile sonucu hesaplayabilirsiniz. Ayrıca ekrana yazdırmanız için de float sayılar gerekmez.

zakbay

#6
ilginç ama yine olmadı
Garip şimdilik ondalık kısma ihtiyacım olmadığı için ilkini kullanacağım daha sonra tekrar bakacağım
selamlar

program ilk hali
sicaklik = (unsigned int)((Temp * 11)/100);    ondalık kısmı kaybetmeyi göze alırsak bu oluyor
-----------------------------------------
sicaklik = (unsigned int)((Temp * 110)/100.0); olmadı
-----------------------------------------
sicaklik = (unsigned int) (Temp *35)>>5;	olmadı
Tek dostum çalışmak...

zakbay

sorun çözüldü  type casting olayını diğerleri içinde yapmak gerekiyormuş.

Sicaklik = (unsigned int)((unsigned long)Temptemp * (unsigned long)110 / 100);


Çözüm adresi
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=36708
Tek dostum çalışmak...

tmcone

Alıntı yapılan: zakbay - 01 Mart 2012, 16:14:18
sorun çözüldü  type casting olayını diğerleri içinde yapmak gerekiyormuş.

Sicaklik = (unsigned int)((unsigned long)Temptemp * (unsigned long)110 / 100);


Çözüm adresi
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=36708

Sorununa çözüm bulmuşsun ama sorunun nedenini  anlayamamışsın...

zakbay

Alıntı yapılan: tmcone - 01 Mart 2012, 17:15:41
Sorununa çözüm bulmuşsun ama sorunun nedenini  anlayamamışsın...

Cevabınızı Yeni gördüm
Siz daha detaylı anlatırsanız hep birlikte öğreniriz iyi olur ilerlememiz adına :)

Bugüne kadar ağırlıklı olarak basic ve pic kullandım.

Bu işin üstadları kadar c bilgim yok hala öğreniyorum.
Ben anladığımı yazayım eksikleri siz tamamlayın o zaman 

Sicaklik = (unsigned int)  burada sağ tarafta yapılan işlemlerin sonucunun unsigned int tipinde olacağı belirtiliyor

((unsigned long)Temptemp * (unsigned long)110 / 100);

buradaki unsigned long lar temptemp ve 110 un unsigned long tipinde işleme alınacağını belirtir. çıkan sonuçta 100 e bölünerek ilk kullanılan unsigned int sınırları içine inmesini sağlıyor.


Biraz karışık oldu galiba ama siz toparlarsınız anlatmak istediklerimi

Selamlar
Tek dostum çalışmak...