ds18b20 one wire protokolünde zamanlama hatası

Başlatan gogge, 11 Mayıs 2010, 00:29:55

gogge

Arkadaşlar selamlar;

ds18b20 kullanarak one wire protokolünü öğrenmeye çalışıyorum. Üzerinde fazlaca uğraştım. 16f877 (4MHz) için aşağıdaki kodları yazdım.

4MHz osilatör ile normal zamanlama aralıklarını kullandığımda cihaz reset olmuyor. Ancak osilatörü 8MHz olarak ayarladığımda ya da reset fonksiyonunda zaman aralıklarını yarıya düşürdüğümde cihaz reset oluyor ve doğru ölçüm değerini lcdde görebiliyorum. (ISIS'de)

Uygulamada; 8MHz osilatör ile sıcaklık yanlış olarak ölçülüyor. (3 C civarında)

Kullandığım kütüphaneler ve kodlar aşaığıdadır. Sorunun nereden kaynaklandığını söyleyebilirseniz sevinirim. (delay ve lcd kütüphaneleri standart hi-tech kütüphaneleridir.)

Not: Kodlar Fırat Deveci'nin kitabından faydalanılarak yazılmıştır.
one_wire.h
#define TRIS_W TRISC7 //Bağlantılar 
#define WIRE RC7  
extern unsigned char onewire_reset(void); 
extern unsigned char onewire_read_bit(void); 
extern void onewire_write_bit(unsigned char veri); 
extern unsigned int onewire_read_byte(void); 
extern void onewire_write_byte(unsigned char data);


one_wire.c
#include <pic.h>  
#include "one_wire.h" 
#include "delay.h"  

unsigned char onewire_reset(void)  
{     
	unsigned char sonuc; 
	WIRE=0;     	// Hat sıfıra çekiliyor    
	TRIS_W=0;    	// Hat çıkış yapılıyor    
	DelayUs(250);
//	DelayUs(230); 	// 640us>x>480us arasında bekleniyor     
	TRIS_W=1;    	// Pull-up yükseltmesi bekleniyor    
	DelayUs(35);   	// 70us bekleniyor     
	sonuc=WIRE;    	// 0 Hazır, 1 Hazır değil     
//	DelayUs(220);
	DelayUs(200); 	// x>420us'den büyük olmalı        
	return sonuc;   
}      
 
unsigned char onewire_read_bit(void) 
{  
	unsigned char veri;    
	WIRE=0;  		// Hat sıfıra çekiliyor  
	TRISC=0x00;  
	DelayUs(5);  	// 5 mikrosaniye bekleniyor  
	TRISC=0x80;  		// Pull-Up'ın hattı yükseltmesi bekleniyor  
	DelayUs(10); 	// 10 mikrosaniye bekleniyor    
	if(WIRE)  		// Hat okunuyor   
		veri=1; 	// Okunan veri 1  
	else   
		veri=0; 	// Okunan veri 0  
	DelayUs(60);    
	return veri; 
}  

void onewire_write_bit(unsigned char veri) 
{  
	if(veri)   			// 1 gönderiliyor  
	{   
		TRIS_W=0;   	// Hat sıfırlanıyor   
		WIRE=0;   
		DelayUs(5); 	// 5 mikrosaniye bekleniyor    
		TRIS_W=1;  		// Pull-Up'ın hattı yükseltmesi bekleniyor   
		DelayUs(60); 	// 60 mikrosaniye bekleniyor  
	}  
	else    			// 0 gönderiliyor  
	{   
		TRIS_W=0;   	// Hat sıfırlanıyor   
		WIRE= 0;   
		DelayUs(60);  	// 60 mikrosaniye bekleniyor   
		TRIS_W=1;  		// Pull-Up'ın hattı yükseltmesi bekleniyor  
	} 
}

unsigned int onewire_read_byte(void) 
{    
	unsigned char i,veri=0, bitler=1;     
	for(i=0;i<=7;i++)     
	{        
		if ( onewire_read_bit() == 1 )         
			veri |= bitler;         
		bitler=bitler<<=1;     
	}     
	return veri;  
} 

void onewire_write_byte(unsigned char veri)  
{     
	unsigned char bitler=1, i;      
	for (i=0;i<=7;i++)     
	{        
		if (veri&bitler)        
		{         
			onewire_write_bit(1);        
		}        
		else        
		{         
			onewire_write_bit(0);        
		}        
		bitler=bitler<<=1;     
	}  
}


main.c
#include <htc.h>
#include <stdio.h>
#include "delay.h"
#include "lcd.h"
#include "one_wire.h"

void ds18b20 (unsigned int *sicak, unsigned int *onda)
{
	unsigned char sayi1,sayi2;
	
	while(onewire_reset());
	onewire_write_byte(0xCC);
	onewire_write_byte(0x44);
	DelayMs(250); 
	DelayMs(250);
	DelayMs(250);
	while(onewire_reset());
	onewire_write_byte(0xCC);  
	onewire_write_byte(0xBE);
	
	sayi2=onewire_read_byte();
	sayi1=onewire_read_byte();
	 
	onewire_reset();
	 
	*onda=0;
	*sicak=(sayi1*16)+(sayi2>>4);
	if(sayi2 & 0x08)
		*onda=500;
	if(sayi2 & 0x04)
		*onda+=250;
	if(sayi2 & 0x02)
		*onda+=125;
	if(sayi2 & 0x01)
		*onda+=62; 
} 


void
main(void)
{
	unsigned int sicaklik,onda;
	unsigned char ekran[16]="";
	PORTB=0x00;
	PORTC=0x00;
	TRISB=0x00;
	TRISC=0x00;
	
	lcd_init();
	lcd_clear();
	for(;;)
	{
		ds18b20(&sicaklik, &onda);
		lcd_goto(0x04);
		lcd_puts("Sicaklik");
		lcd_goto(0x45);
		sprintf(ekran,"%d.%d'C",sicaklik,onda);
		lcd_puts(ekran);
		DelayMs(250);
		//lcd_clear();
	}

}



gogge

unsigned char onewire_reset(void)  
{     
	unsigned char sonuc; 
	WIRE=0;     	// Hat sıfıra çekiliyor    
	TRIS_W=0;    	// Hat çıkış yapılıyor    
	DelayUs(250);
//İptal	DelayUs(230); 	// 640us>x>480us arasında bekleniyor     
	TRIS_W=1;    	// Pull-up yükseltmesi bekleniyor    
	DelayUs(35);   	// *******35us bekleniyor ve 8Mhz osilatör*****************   
	sonuc=WIRE;    	// 0 Hazır, 1 Hazır değil     
//iptal	DelayUs(220);
	DelayUs(200); 	// x>420us'den büyük olmalı        
	return sonuc;   
}     

Aynı kodu kullanarak 8MHz ile bord üzerinde devre çalıştı. Ancak isis'de 8 Mhz ile çalışmıyor.

Bir yerlerde ilginçlik var ama çözemedim.

JKramer

Hi-Tech kullanmıyorum ama delay.h'da bir sorun var sanırım. Sonuçta o beklemelerle (480us yerine 250 us gibi) iletişimde sorun çıkması gerekiyor.

Isis'de farklı hızlarda (4-8 Mhz) adım adım çalıştırarak beklemelerin ne kadar olduğuna baktınız mı?

gogge

Cevabınız için teşekkür ederim. İsis de zamanlamaları kontrol etmedim. Etmekte fayda var. Sonucu yazarım.

gogge

Zamanlamalarda sorun var. Olayı çözemedim. Kodlar dallas one wire protokolüne uygun olmasına rağmen çalışmadı.

Hi-tide kullanıyorum. Bir ara sicaklik ölçümü yapabilmiştim. Kodlar aynı olmasına rağmen daha sonra yeniden derlediğimde devre çalışmadı. (Uygulamada ve simülasyonda)

Benzer durumlarla karşılaşan başka arkadaşlar var mı bilmiyorum. Ama ilginç bir sorun yaşıyorum vesselam.

gogge

Cevabınız için teşekkür ederim. ds18b20 gerçekten problemli. Zamanlamayla ilgili çok şey denedim ama bir türlü çalıştıramadım.

Bir kaç defasında 8mhz ile sistem çalıştı. Aynı kodu tekrar derlediğimde ise çalışmadı. Yuh dedirtti kendine.

ds18b20 için elbetteki bir zorunluluk yok. Amaç protokolü öğrenmekti. I2C sensörlerle hiç çalışmadım. Artık o tarafa yönelelim.

M_B

Merhaba gogge;
Delay.c icinde hiç kristal ayarı yaptın mı.
Yukardaki programında Kristal ayarını ve configlerini goremedim.
Hi-Tech C nin içindeki Delay.c default olarak 4 Mhz kristal olarak ayarlıdır.
Kristal ayarı nasıl yapılır gormek istersen altaki linki inceleyin

https://www.picproje.org/index.php/topic,26345.msg178374.html#msg178374
İmkanın sınırlarını görmek için imkansızı denemek lazım.                                                             Fatih Sultan Mehmet

gogge

Alıntı yapılan: M_B - 14 Mayıs 2010, 14:35:42
Merhaba gogge;
Delay.c icinde hiç kristal ayarı yaptın mı.
Yukardaki programında Kristal ayarını ve configlerini goremedim.
Hi-Tech C nin içindeki Delay.c default olarak 4 Mhz kristal olarak ayarlıdır.
Kristal ayarı nasıl yapılır gormek istersen altaki linki inceleyin

https://www.picproje.org/index.php/topic,26345.msg178374.html#msg178374


Ana program içinde ayar yapmıştım. Ama delay.c içerisinde yapmamıştım. Bahsettiğiniz konuyu da incelemiştim. Sorun devam ediyor malesef. Teşekkürler.

gogge

#8
Alıntı yapılan: FxDev - 16 Mayıs 2010, 00:35:16
Kodlarının tamamını foruma koyabilir misin?
Sorunu merak ettim...

İncelerseniz sevinirim.

http://www.4shared.com/file/yicOqA1F/ds18b20_onewire.html

papylon

Arkadaşlarında dediği gibi HI-TECH'in delay rutini pek de verimli değil.
Aşağıdaki Microchip'in sitesinden PIC16 ve 18 serisi için yazılmış çok daha verimli Delay kütüphaneleri var, onları kullanmanızı tavsiye ederim.
Ayrıca incelemek isterseniz faydalı birçok uygulama örnekleri de var.

http://www.microchipc.com/sourcecode/

gogge

Arkadaşlar ilginiz için çok teşekkür ederim. Bu sorunu yardımlarınız sayesinde çözeceğim inş.

Aslında one wire özellikli cihaz kullanmam şart değil. Kodlarda sorun olmadığına göre sıkıntının kaynağını belirlemek istediğimden üzerinde bu denli duruyorum. 

Sonucu yazarım.


gogge

Arkadaşlar sorun halloldu. FxDev ve papylon ilginiz için teşekkürler...

***http://www.microchipc.com/sourcecode/ linkindeki delay kütüphaneleri ile sorunsuz çalıştı. (sadece 8MHz'de)

***Zamanlamaları DelayMs(100); yazdığım yere _delay(50000);_delay(50000); şeklinde yaptığımda da çalıştı. (4mhz ve 8mhz denendi sorun yok)

gogge

Alıntı yapılan: FxDev - 17 Mayıs 2010, 18:08:49
Zamanlamaları kötü Hi-Tech'in yanında verilen delay kütüphanesinin...
Ben artık kristal hızı değişmeyecekse _delay() fonksiyonunu kullanmaya başladım açıkçası.

Hassas zamanlamalarda kesinlikle dikkat etmek gerekiyor. Çeken bilir :)

Microchip'in sitesindeki gelişmiş delay kütüphaneleri de doğru sonuç veriyor.

gogge

Fxdev'in önerileri doğrultusunda hazırlanmış one_wire protokol kütüphanesi.
Zamanlamalar 4 MHz için.

one_wire.c
#include <pic.h>  
#include "one_wire.h" 
#include "delay.h"  

unsigned char onewire_reset(void)  
{     
	unsigned char sonuc; 
	WIRE=0;     	// Hat sıfıra çekiliyor    
	TRIS_W=0;    	// Hat çıkış yapılıyor    
//	DelayUs(250); 
//	DelayUs(230); 	// 640us>x>480us arasında bekleniyor     
	 _delay(500);
	TRIS_W=1;    	// Pull-up yükseltmesi bekleniyor    
//	DelayUs(70);   	// 70us bekleniyor    
	 _delay(70);
	sonuc=WIRE;    	// 0 Hazır, 1 Hazır değil     
//	DelayUs(220);
//	DelayUs(200); 	// x>420us'den büyük olmalı    
	 _delay(500);
	return sonuc;  
}      
 
unsigned char onewire_read_bit(void) 
{  
	unsigned char veri;    
	WIRE=0;  		// Hat sıfıra çekiliyor  
	TRISC=0x00;  
//	DelayUs(5);  	// 5 mikrosaniye bekleniyor  
	 _delay(5); 
	TRISC=0x80;  		// Pull-Up'ın hattı yükseltmesi bekleniyor  
//	DelayUs(10); 	// 10 mikrosaniye bekleniyor  
	 _delay(10);
	if(WIRE)  		// Hat okunuyor   
		veri=1; 	// Okunan veri 1  
	else   
		veri=0; 	// Okunan veri 0  
//	DelayUs(60);   
	 _delay(60);
	return veri; 
}  

void onewire_write_bit(unsigned char veri) 
{  
	if(veri)   			// 1 gönderiliyor  
	{   
		TRIS_W=0;   	// Hat sıfırlanıyor   
		WIRE=0;   
//		DelayUs(5); 	// 5 mikrosaniye bekleniyor    
		_delay(5);
		TRIS_W=1;  		// Pull-Up'ın hattı yükseltmesi bekleniyor   
//		DelayUs(60); 	// 60 mikrosaniye bekleniyor  
		 _delay(60);
	}  
	else    			// 0 gönderiliyor  
	{   
		TRIS_W=0;   	// Hat sıfırlanıyor   
		WIRE= 0;   
//		DelayUs(60);  	// 60 mikrosaniye bekleniyor  
		 _delay(60);
		TRIS_W=1;  		// Pull-Up'ın hattı yükseltmesi bekleniyor  
	} 
}

unsigned int onewire_read_byte(void) 
{    
	unsigned char i,veri=0, bitler=1;     
	for(i=0;i<=7;i++)     
	{        
		if ( onewire_read_bit() == 1 )         
			veri |= bitler;         
		bitler=bitler<<=1;     
	}     
	return veri;  
} 

void onewire_write_byte(unsigned char veri)  
{     
	unsigned char bitler=1, i;      
	for (i=0;i<=7;i++)     
	{        
		if (veri&bitler)        
		{         
			onewire_write_bit(1);        
		}        
		else        
		{         
			onewire_write_bit(0);        
		}        
		bitler=bitler<<=1;     
	}  
}

one_wire.h
#define TRIS_W TRISC7 //Bağlantılar 
#define WIRE RC7  
extern unsigned char onewire_reset(void); 
extern unsigned char onewire_read_bit(void); 
extern void onewire_write_bit(unsigned char veri); 
extern unsigned int onewire_read_byte(void); 
extern void onewire_write_byte(unsigned char data);

XX_CİHAN_XX

Sorununu çözmüşsün ama ek olarak bir tavsiyede bulunayım.
Ben delay fonksiyonları ile ilgili bir sıkıntı yada tedirginlik yaşadığımda, hassas bir zamanlamaya da ihtiyaç duyuyorsam genelde
#asm

#endasm
satırları arasında pikomatik tarzı istediğin gecikme için assembly kodu veren hazır programlardan aldığım kodu kullanıyorum.
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.