DS18B20 Negatif Sıcaklık Hesabı

Başlatan Mucit23, 13 Ağustos 2022, 12:20:47

Mucit23

Bayadır bu sensörü kullanmıyorum. Şimdi ufak bir uygulama yaptım ama Negatif sıcaklıkları hesaplamada sorun yaşıyorum.

12 Bit Okuma yapıyorum. 32 derecenin Altında sıcaklık doğrudan Eksiye Düşüyor. Casting işlemi sırasında mı hata yapıyorum acaba

/*******************************************************************************
*   Ds18B20_Read                                                               *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
float Ds18B20_Read(void)
{
    BitAction busy=Bit_RESET;
    int8_t data1;
    int8_t data2;
    float result;
	
    OneWire_Reset();
    OneWire_WriteByte(0xCC);
    OneWire_WriteByte(0x44);
	
    while(busy==Bit_RESET)
		{
       busy=OneWire_ReadBit();
		}
		
    OneWire_Reset();
    OneWire_WriteByte(0xCC);
    OneWire_WriteByte(0xBE);
		
    data1 = OneWire_ReadByte();
    data2 = OneWire_ReadByte();
		
    result=(float)(((int16_t)data2<<8)|data1);
    result=result*0.0625;

    return result;
}

Hesap doğru değil mi? Anlamadım. Eksik veri mi alıyorum acaba? Okurken mi hata yapıyorum. Elimde iki 3 tane sensör var hepsi aynı hatayı veriyor.

Mucit23

Böyle Sorunlar hep beni bulur herhalde. Casting sorunu değil sıcaklık gerçekten Negatife Düşüyor. Ama 32 derece ile 24 Derece arası için geçerli. Okuduğum Binary değerlere bakıyorum.

32 Derecenin Altına düştüğü anda Okuduğum 16 bitlik sayının son 4 biti 0xFXXX oluyor. Sıcakık 24 derecenin altına düşerse düzeliyor. Aynı şekilde 4 derece ve üzerine çıktığında son 4 bit 0xFXXX oluyor.

Gerçekten sıfırın altına düşemedim henüz o yüzden test edemedim.

Bu ne anlama geliyor anlayamadım. Birde Arduino ile deneyeyim bakalım

ete

Sorunun iki 8 bitlik sayıyı 16 biştlik sayıya çevirmede olduğunu düşünüyorum.
    result=(float)(((int16_t)data2<<8)|data1);
Bu formülü çok iyi yorumlayamadım (c dili bilgi eksikliğimden kaynaklı).
Okuduğun Data1 ve Data2 değişkenlerinden Data1 önce okunduğu için LOW byte oluyor. Ardından okunan Data2 ise HIGH byte olmalı. Bu durumde yaratacağın 16 bitlik değişken (Result) =Data2+Data1 şeklinde yerleşmeli. Bunu sağlamak için Result=(Data2<<8)+Data1 şeklinde bir ifade kullanman gerekir. Yani önce Highbyte kısmı değişkene verilip 8 bit sola kaydırılmalı ardıda bu sayıya LowByte eklenmeli.
Elde ediline bu 16 bitlik sayı (yada float olan sayı) 0,0625 çarpılarak sıcaklık hesaplanmalıdır ki bu seninhesaplamada doğru yapılıyor zaten..

Ete
Bilgi hazinedir paylaştıkça büyür.            http://etepic.com

Cemre.

#3
Datasheet'te verilen listenin tamamını denedim, aşağıdaki yapı uygun gözüküyor. Bir bakın isterseniz.
Ben debug amaçlı uzun uzun yazdım ama gereksiz kısımları çıkartıp denersiniz.

http://tpcg.io/_O9UMWP



Mucit23

Yaptığım hesaplamalarda sorun yok. Sorun gerçekten saçma değerler okumamda. Çıkamadım işin içinden. OneWire Kütüphanesinde hata olabilir olamıyorum.

Kütüphane bu şekilde
/******************************************************************************
*  @file    onewire.c
*  @author  
*  @version V1.0.0
*  @date    19-07-2017
*  @brief   OneWire Haberlesme kütüphanesi
******************************************************************************/     
#include <onewire.h> 
#include <systick.h>
	 
	 
void DelayUs(uint32_t us)	
{
	  TIM_SetCounter(TIM3,0);
    while ((TIM_GetCounter(TIM3))<us);

}
/*******************************************************************************
*   OneWire_Init                                                               *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_Init(void)
{
	 GPIO_InitTypeDef GPIO_InitStruct;
   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	
	 RCC_APB2PeriphClockCmd(OneWireRCC, ENABLE);
	 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

   TIM_TimeBaseStructure.TIM_Period = 1000-1;	
   TIM_TimeBaseStructure.TIM_Prescaler = 72-1;
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
   GPIO_InitStruct.GPIO_Pin = OneWirePin;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
   GPIO_Init(OneWireGpio, &GPIO_InitStruct);	
	
	 TIM_Cmd(TIM3,ENABLE);
}

void OneWire_BusInputDirection()
{
	 GPIO_InitTypeDef	GPIO_InitStruct;
   GPIO_InitStruct.GPIO_Pin = OneWirePin;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(OneWireGpio, &GPIO_InitStruct);	
}	

void OneWire_BusOutputDirection()
{
	 GPIO_InitTypeDef	GPIO_InitStruct;
   GPIO_InitStruct.GPIO_Pin = OneWirePin;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
   GPIO_Init(OneWireGpio, &GPIO_InitStruct);	
}


/*******************************************************************************
*   OneWire_Reset                                                              *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_Reset(void)
{
	OneWire_BusOutputDirection();  
	GPIO_ResetBits(OneWireGpio,OneWirePin);
  DelayUs(480);
  OneWire_BusInputDirection();
  DelayUs(480);	
}


//
//	Writing/Reading operations
//
void OneWire_WriteBit(uint8_t bit)
{
	if (bit) // Send '1',
	{
		OneWire_BusOutputDirection(); 
		GPIO_ResetBits(OneWireGpio,OneWirePin);
		DelayUs(6);
		
		OneWire_BusInputDirection(); 
		DelayUs(64);
	} 
	else // Send '0'
	{
		OneWire_BusOutputDirection();
		GPIO_ResetBits(OneWireGpio, OneWirePin);
		DelayUs(60);
		
		OneWire_BusInputDirection();
		DelayUs(10);
	}
}

BitAction OneWire_ReadBit(void)
{
	BitAction readbit;
	
	OneWire_BusOutputDirection(); 
	GPIO_ResetBits(OneWireGpio, OneWirePin);
	DelayUs(2);
	
	OneWire_BusInputDirection();
	DelayUs(10);
	
	readbit =(BitAction) GPIO_ReadInputDataBit(OneWireGpio, OneWirePin);
	
	DelayUs(50);//veya 50
	
  return readbit;
}

/*******************************************************************************
*   OneWire_Write                                                              *
*   Parametreler: data                                                             *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_WriteByte(uint8_t data)
{
	uint8_t i = 8;

	do
	{
		OneWire_WriteBit(data & 1); // LSB first
		data >>= 1;
	} while(--i);
}

/*******************************************************************************
*   OneWire_Read                                                               *
*   Parametreler:                                                              *
*   Return: data                                                               *
*******************************************************************************/
uint8_t OneWire_ReadByte(void)
{
	uint8_t i = 8, byte = 0;

	do{
		byte >>= 1;
		byte |= (OneWire_ReadBit() << 7); // LSB first
	} while(--i);
	
	return byte;
}

Okuma ve yazmadaki süreler hassas diye 1us çözünürlüklü Timer kullanıp O şekilde delay yapıyorum. Şimdi test ettim onları orda da sorun yok.

Arduino da deniyorum sorun yok. Elimde iki tane sensör var ikiside düzgün çalışıyor. Bu sorun tamamen yazılımsal bir sorun olmalı.

Cemre.

one wire için, UART half duplex modda kullanılamaz mı? ille böyle I/O HIGH/LOW yapılacak falan, zor işler bunlar.

Mucit23

Denemek isteyenler için Kütüphanenin tamamını verebilirim. Anlayamadım.

@Cemre. Bununla ilgili bir örnek var mı? UART ile nasıl çalışıyor?

Cemre.

UART half duplex modunda kurulabilir, bu durumda tek pin üzerinden Open-Drain tipte (Pull-up direnci gerekir) Transmit yapılırken aynı zamanda Receive işlemi de gerçekleştirilebilir. Bu şekilde tek pinden seri data çıkışı ve girişi donanımsal olarak gerçekleştirilebilir. Kendim denemedim ancak internette bazı denemeler yapılmış, bir bakın isterseniz.

yas

@Mucit23 hocam, Link'teki dördüncü mesajın içeriği tam sizin aradığınız şey. Fakat yazım positron(proton) basic. Gerekli uyarlamayı/dönüşümü yaparsınız diye düşünüyorum.

Epsilon

#9
@yas hocam konuyla ilgili olmasa da bu tür proton için geliştime bordu olarak  Türkiyede satılan hangi bordları tavsiye edersiniz?
Aliexpress yada bangood da bu tür yazılımı ilede ,kaliteli ürünler varmı acaba?


 

yas

#10
Alıntı yapılan: Epsilon - 13 Ağustos 2022, 17:25:55@yas hocam konuyla ilgili olmasa da bu tür proton için geliştime bordu olarak  Türkiyede satılan hangi bordları tavsiye edersiniz?
Aliexpress yada bangood da bu tür yazılımı ilede ,kaliteli ürünler varmı acaba?


 

Muhakkak vardır. Daha önce başka bir başlıkta belirtiğim gibi mazlum  :D  ile hallediyorum şimdilik.
Arduino türü bir şey işinize yararsa protonun geliştiricisinin kendi tasarladığı amicus18 boardu var. Onu temin edebilirsin. Yada kendin yapabilirsin.

https://www.myamicus.co.uk/Files/Amicus_18/Amicus18%20Documentation/Amicus18%20PIC%20BASIC%20PRO%20-%20DOCUMENTATION/PBP_Amicus18_Hardware_Manual.pdf