kuru bir döngü içerisinde DS18B20'den sıcaklık okuduğumuzu varsayalım. Normalde mcu DS18B20'ye sıcaklık dönüşümü için start emrini verir ve dönüşümün bitmesini bekler. Bu süre 750ms civarı biliyoruz.
Aşağıdaki okuma rutininde bekleme yapılıyor.
float ds1820_read()
{
int8 busy=0, temp1, temp2;
signed int16 temp3;
float result;
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
while (busy == 0)
busy = onewire_read();
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
temp1 = onewire_read();
temp2 = onewire_read();
temp3 = make16(temp2, temp1);
result = (float) temp3 / 16.0; //Calculation for DS18S20 with 0.1 deg C resolution
return(result);
}
Ben bekemeden sistemin çalışması için yukarıdaki kodları aşağıdaki şekilde düzenledim.
float ds1820_read()
{
static int1 ds_flag=0;
int8 busy=0, temp1, temp2;
signed int16 temp3;
static float result;
if(ds_flag==0)
{
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
ds_flag=1;
}
else
{
busy = onewire_read();
if(busy==0)return result;
}
ds_flag=0;
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
temp1 = onewire_read();
temp2 = onewire_read();
temp3 = make16(temp2, temp1);
result = (float) temp3 / 16.0; //Calculation for DS18B20 with 0.1 deg C resolution
return(result);
}
Tam istediğim gibi oldu aslında. Sıcaklık dönüşümü yapılmamışsa eğer Bir önceki sıcaklık değeriyle program geri dönüyor. Eğer dönüşüm işlemi tamamlanmışsa sıcaklık değişkeni güncellenip fonksiyon güncel değer ile geri dönüyor.
Fakat sıcaklık değeri stabil olmuyor. Normalde okunan değer 27-28 lerdeyken bir bakıyorsun 70-80'lara çıkıp hemen düzeliyor. Bunun için başka nasıl önlem alabilirim?
Ds18b20ye sıcaklığı oku de,
timer ile 750 ms den fazla bekleyip 800-900
sonra artık kesinlikle hazır olan sıcaklık bilgisii oku.
Veya
temp1, temp2, temp3 ve result değişkenlerini global olarak tanımla
ve programın hiçbiryerinde bu değişkenlerin değerini değiştirme,
aslında sadece result değişkenini global olarak tanımlaman yetecektir bence.
Böyle düşünmemin sebebi şu
result değişkeni 1wire için kullanılan fonksiyon içi bir değişken,
1 wire a fonksiyonu yazanın istediği gibi girip çıkılınca doğru değeri alır
ama fonksiyonun yarısındayken çıkar gidersen
o sıradaki result içinde anlamlı birşey olmak zorunda değildir,
result 1wire başka biryerde bozup kullanabilir,
veya sıfırlayabilir bence.
Yine aynı mantıkla işlemi yukarıda şekilde değilde şöylede yapabilirsin,
static float son_okuma; diye global bir değişken tanımla,
1wire fonksiyonunda
static float result; satırının altına
result=son_okuma; de.
Olcumlerinizin dogrulugu hakkinda problem yasiyormusunuz?
@Ramu Timer ile felan uğraşmayalım şimdi. Çünkü iki adet timerim var ikiside kullanılıyor.
Bence kullandığım mantık iyi. Belki dediğin gibi değişkenlerin fonksiyon içerisinde tanımlanmış olmasından kaynaklanıyordur. Aslında statik olarak tanımlanması fonksiyon içeriisndeki değişkenin değerinin silinmemesi anlamına gelmiyormu? Değişkenleri global yapsam ne gibi artıları olacak?
@serdararikan hocam ben hiç güvenmiyorum bu sensörlere. Doğruluğun hep şüphe duydum. Oda termometreleri ile yan yana koyduğumda hep arada 1-2 derece fark görüyorum.
Gerçi çinden aldığım su geçirmez ds18b20 probları var. Onları kullanıp buzlu su testi yapayım ozaman belli olur.
Bence sonuçta ds1820_read() fonksiyonunu her çağırdığında
fonksiyon static float result; ile değişkeni tekrar tanımlayabilir
static olması buna engel olurmu bilemiyorum,
program yakınlarındaysa dediğim son iki yöntemi denemen 2 dk sürmez
deneyip sonucu yaz, bende merak ettim.
Tamam deneyelim.
çözünürlügü degiştirerek bekleme zamanını azaltabilirsiniz
bende artık hiç güvenmiyorum bu sensörlere.hem hatalı ölçüyor hemde lineer değil.
state machine iş görür bence.
S.A.
Sn. Ferhat ntc kullansanız olmazmı?
okuduğun değeri bir öncekiyle karşılaştır +-5 dereceden fazla değer varsa ciddiye alma
Selam,
Sorun şu; Ds18B20'nin alt fonksiyonları var. Örnegin read bit gibi, ör. pini 1 yapip 30us sonra 0 yapması gerekiyor siz orada beklemeyip başka işlemler yaptığınızda bu 30us sureyi belki 500us'ye çıkarmış oluyorsunuz. Fakat datasheet min 25us max 40us olsun diyor örnek verdim sadece. Umarım sorunu anlatabilmişimdir.
Bir nokta daha, farz edelim siz 750ms bekleme yapıp öyle okudunuz hala başka sıkıntılar var. Örneğin, siz readBit ile ds18b20 den bir bit okuyacaksınız pini low yaptınız ve 30us bekleyip pini high yapacaksınız eğer siz pini low yaptıgınız anda bir interrupt gelirse ve bu interrupt içinde geçen süre 100us ise yine hatalı bilgi alma durumu var. Burada interruptları kapatıp orayı işleyip sonra tekrar açmak gerekiyor.
Bunu bekleme olmadan yapmanın bir yolu olabilir belki , düşünmek lazım.
Esen kalın.
@mucit23 sensör ölçümünü critical section yap. Fonksiyona girerken interruptların durumlarını sakla ve disable et. Çıkarken tekrar interrupt durumunu iade et. Böylece ISR olarak engellemeye maruz kalmazsın. Ayrıca beklemek istemiyorsan bir tick timer kurmalısın bu RTC de olabilir. Bir okuma işlemin bittikten sonra tick değerini al ve bu değer 750ms aşmışmı diye kontrol et. Eğer aşmamışsa sensör okuma fonksiyonuna girme ve boş zamanı diğer fonksiyonlarına harca. Aslında bu işin mantığı için round-robin v.s. bakabilirsin. Yada FSM ile de olabilir.
Mucit23 sorunu çözdünmü bilmiyorum ama
ben meraktan denedim,
fonksiyonu şu şekilde değiştirince istediğin gibi çalışıyor,
ds18b20yi asm ile çalıştırmıştım,
F493 ün belirttiği gibi durumlar var,
notlarıma bakmadan hatırladığım kadarıyla fonksiyonu değiştirdim
yinede sıkıntı çıkacağını sanmıyorum,
ds18b20deki esas bekleme yapan yer
çözünürlüğe bağlı olarak
ds18b20ye sıcaklığı söyle dediğimizde
bu işlemi içinde yapıp bize sonucu söylemesi 750ms kadar sürüyor
bu 750ms boyunca ccsc fonksiyonu cevabın gelmesini boş boş bekliyor,
ben bu kısmı baypas ettim fonksiyonda;
değiştirilmiş hali şöyle;
zaten değişiklik hemen görülüyor ama gerekirse anlatırım,
float ds1820_read()
{
int8 busy=0, temp1, temp2;
signed int16 temp3;
float result;
static int one_read,busy_2;
if(one_read==0) //b
{
onewire_reset();
onewire_write(0xCC);
onewire_write(0x44);
one_read=1; //b
}
// while (busy == 0)
// busy = onewire_read();
while (busy_2 == 0)
{
busy_2 = onewire_read();
return(result); //b
}
one_read=0; //b
onewire_reset();
onewire_write(0xCC);
onewire_write(0xBE);
temp1 = onewire_read();
temp2 = onewire_read();
temp3 = make16(temp2, temp1);
// result = (float) temp3 / 2.0; //Calculation for DS18S20 with 0.5 deg C resolution
result = (float) temp3 / 16.0; //Calculation for DS18B20 with 0.1 deg C resolution
delay_ms(200);
return(result);
}
Bu şekilde kullanan örnek,
2*16 lcd ve rs232 üzerinde sıcaklığı gösteriyor,
isis simulasyonu ve proje dosyası
(expkits in hazırladığı örnekten devşirdim)
https://www.dropbox.com/s/lnwzohlnpbb0zch/Ramu_CCSC_DS18B20_beklemesiz.rar (https://www.dropbox.com/s/lnwzohlnpbb0zch/Ramu_CCSC_DS18B20_beklemesiz.rar)
Hocam benim yaptığımda aynı zaten. Şuanda böyle iyi gibi. Galiba hizla ilgili bir sıkıntı var. One_wire.c dosyasına bakmam lazım.
hocam ben konu disinda birsey merak ediyorum. fonksiyonu neden void deilde float olarak tanimladiniz? ( float ds1820_read() )
Aynı değil busy değişkeni herseferinde 0 yükleniyor sende
ben onu static int busy_2 olarak değiştirdim,
aslında int8 busy tanımlamasını kaldırsam daha net görülürmüş.
Tekrardan bi inceleyeyim
Alıntı yapılan: Karamel - 25 Temmuz 2014, 00:55:09
hocam ben konu disinda birsey merak ediyorum. fonksiyonu neden void deilde float olarak tanimladiniz? ( float ds1820_read() )
c de fonksiyonlar konusuna bakmalısın
geriye değer döndüren fonksiyonlar kısmında yazar,
bu fonksiyon çağrıldıktan sonra
result değişkeni içinde geriye float bir değer döndürüyor,
bu yüzden float olarak tanımlı,
misal integer bir değer döndürseydi
int olarak tanımlayabilirdik.
yanit icin tesekkur ederim ramu hocam. boyle olabilecegini tahmin etmistim ama emin deyildim.
Sensör bayağı hassasmış.
Büyükçe bir bardak içerisine buzları doldurdum. Boşluk kalmayacak şekilde birazda içerisine su koydum. 10 Dakika kadar bekledim ve Su geçirmez ds18b20'yi daldırdım buzların içerisine.
Buzların tam arasındayken 0,8C hatta 0,6C felan görüyorum. Tam sıfır olması zaten beklemiyordum. Bu durumda hata yok gibi.
Şimdi buzların bir kısmı eridi. Buzlar bardağın üstünde yüzüyor. Sensörü bardağın dibine yani buz olmayan kısıma götürünce sıcaklık 1,5-2C oluyor. Sensörü yukarı buzların arasına alınca hemen yine 0,6 lara iniyor.
Buz testinin sonuçları böyle.
Buz içerisine bir miktar tuz koyup deneyiniz...