STM32F103 DS18B20 Kütüphanesi

Başlatan Mucit23, 19 Temmuz 2017, 14:31:18

Mucit23

Selamlar

STM32F103 ile DS18b20 Sıcaklık sensörünü çalıştırmak için uğraşıyorum. Adam akıllı bir onewire kütüphanesi bulamadım. Bende oturdum CCS'de kullandığım one wire protokollerini STM32F103'de çalışacak şekilde yeniden yazdım.

/******************************************************************************
*  @file    onewire.c
*  @author  Ferhat YOL
*  @version V1.0.0
*  @date    19-07-2017
*  @brief   OneWire Haberlesme kütüphanesi
******************************************************************************/     
#include <onewire.h> 
#include <systick.h>
	 
	 GPIO_InitTypeDef GPIO_InitStruct;

/*******************************************************************************
*   OneWire_Init                                                               *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_Init(void)
{
	 RCC_APB2PeriphClockCmd(OneWireRCC, ENABLE);
	
   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_DIR                                                                *
*   Parametreler: dir                                                          *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_DIR(uint8_t dir)
{
   GPIO_InitStruct.GPIO_Pin = OneWirePin;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	 if(dir)
	 {
	   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	 }
	 else
	 {
	   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD; 
	 }

   GPIO_Init(OneWireGpio, &GPIO_InitStruct);	    
}

/*******************************************************************************
*   OneWire_Reset                                                              *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_Reset(void)
{
	OneWire_DIR(OUT);  
	GPIO_ResetBits(OneWireGpio,OneWirePin);
  delay_us(500);	
	OneWire_DIR(IN);
	delay_us(500);
	OneWire_DIR(OUT);

}

/*******************************************************************************
*   OneWire_Write                                                              *
*   Parametreler: data                                                             *
*   Return:                                                                    *
*******************************************************************************/
void OneWire_Write(uint8_t data)
{
    unsigned char i;
    for (i=0; i<8; i++)
    {
			  OneWire_DIR(OUT);
        GPIO_ResetBits(OneWireGpio,OneWirePin);
			  delay_us(2);
			  if((data>>i) & 0x01)
				{
				   GPIO_SetBits(OneWireGpio,OneWirePin);
				}
				else
				{
				   GPIO_ResetBits(OneWireGpio,OneWirePin);				   
				}
				delay_us(60);
				OneWire_DIR(IN);
				delay_us(2);
    }
}

/*******************************************************************************
*   OneWire_Read                                                               *
*   Parametreler:                                                              *
*   Return: data                                                               *
*******************************************************************************/
unsigned char OneWire_Read(void)
{
    unsigned char i;
    unsigned char data, bitshifter;
    data = 0;
    bitshifter = 1;
    for (i=0; i<8; i++)
    {
        OneWire_DIR(OUT);
        GPIO_ResetBits(OneWireGpio,OneWirePin);
        delay_us(6);
        OneWire_DIR(IN);
        delay_us(4);
        if (GPIO_ReadInputDataBit(OneWireGpio,OneWirePin))
				{
            data |= bitshifter;
				}
        delay_us(50);
        bitshifter = bitshifter<<1;
    }
    return data;
}


Haberleşmeyi bir türlü düzgün yapamadım. Sürekli yanlış veri alıyorum(0xFF) Arada sırada düzgün bir şekilde Sıcaklık bilgisini okuduğumda oluyor. Ama genellikle hatalı çalışıyor.

Sıcaklık okumak için Aşağıdaki rutinleri kullanıyorum
/*******************************************************************************
*   Ds18B20_Read                                                               *
*   Parametreler:                                                              *
*   Return:                                                                    *
*******************************************************************************/
float Ds18B20_Read(void)
{
    int busy;
    int sayi1;
    int sayi2;
    float result;
	
    OneWire_Reset();
    OneWire_Write(0xCC);
    OneWire_Write(0x44);
	
    while(busy==0)
    busy=OneWire_Read();
		
    OneWire_Reset();
    OneWire_Write(0xCC);
    OneWire_Write(0xBE);
    sayi1 = OneWire_Read();
    sayi2 = OneWire_Read();
		
    result=sayi2*256+sayi1;
		
    result=result/16.0;
		
    delay_ms(250);
    return result;
}


Ben ya süreleri tutturamıyorum yada başka bir hata yapıyorum anlamış değilim. Elinde düzgün çalışan bir kütüphane olan varmı?

Erol YILMAZ

ONE WIRE'ı  bi donanım ile okumak pek mümkün görünmüyor, Bu açıdan biraz problemli...
UART ile birşeyler yapıyorlar ama iyi incelemek lazım.




Mucit23

Hocam donanım ile yapmaya çalışmıyorum, Gerek yok buna. Bana Software OneWire Kütüphanesi gerekiyor. Kullanan varmı daha önce?

M_B

@Mucit23 hocam bir ara STM32F407 de test etmiş ve calıştırmıstım.
Umarım işinize yarar.

ds18b20.h
#ifndef	__DS18B20_H_
#define	__DS18B20_H_
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/

#define DQ_PIN	                       GPIO_Pin_11		  
#define DQ_GPIO_PORT                   GPIOC
#define DQ_GPIO_CLK                    RCC_AHB1Periph_GPIOC  



#define DQ_PIN_WRITE(x) ((x) ? (GPIO_SetBits(DQ_GPIO_PORT,DQ_PIN))  : (GPIO_ResetBits(DQ_GPIO_PORT,DQ_PIN)) );
#define DQ_PIN_READ 	((GPIO_ReadInputDataBit(DQ_GPIO_PORT,DQ_PIN))&0x01)

extern void onewire_reset(void);
extern void onewire_write(char data);
extern unsigned char onewire_read( void );
extern float ds18b20_read(void);

#endif


ds18b20.c
#ifndef	__DS18B20_C_
#define	__DS18B20_C_

#include "stm32f4xx.h"
#include "ds18b20.h"
#include "stdio.h"
#include <string.h>



#define	in  1
#define out 0

GPIO_InitTypeDef GPIO_InitStructure;



void DelayUs(u32 t)	
{
	t*=6;			 // 32 Mhz DelayUs
	while(t--);
}



/******************************************************************************
*******************************************************************************/

/*
void init_port (void)
{	

 
  GPIO_InitStructure.GPIO_Pin = RES_PIN | SCE_PIN | DC_PIN |SDIN_PIN |SCLK_PIN ; Ok
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}
*/

/***********************************************************************************
***********************************************************************************/

void TRIS_PIN(char x)
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	
    GPIO_InitStructure.GPIO_Pin = DQ_PIN;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;	
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	
if(!x)
  	{
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
		GPIO_Init(DQ_GPIO, &GPIO_InitStructure);
	}
else 
  	{GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_IN ;}
  	GPIO_Init(DQ_GPIO, &GPIO_InitStructure);
}



void onewire_reset(void)
{
    TRIS_PIN(out);
    DQ_PIN_WRITE(0)
    DelayUs(480);
    TRIS_PIN(in);
    DelayUs(400);
    TRIS_PIN(out);
}

void onewire_write(char data)
{
    unsigned char i, bitshifter;
    bitshifter = 1;
    for (i=0; i<8; i++)
    {
        if (data & bitshifter)
        {
            TRIS_PIN(out);
            DQ_PIN_WRITE(0)
            DelayUs(3);
            TRIS_PIN(in);
            DelayUs(60);
        }
        else
        {
            TRIS_PIN(out);
            DQ_PIN_WRITE(0)
            DelayUs(60);
            TRIS_PIN(in);
        }
	bitshifter = bitshifter<<1;
    }
}

unsigned char onewire_read( void )
{
    unsigned char i;
    unsigned char data, bitshifter;
    data = 0; bitshifter = 1;
    for (i=0; i<8; i++)
    {
        TRIS_PIN(out);
        DQ_PIN_WRITE(0)
        DelayUs(6);
        TRIS_PIN(in);
        DelayUs(4);
        if (DQ_PIN_READ)
            data |= bitshifter;
        DelayUs(50);
        bitshifter = bitshifter<<1;
    }
    return data;
}

float ds18b20_read(void)
{
    int busy,sayi1,sayi2;
    float result;
    onewire_reset();
    onewire_write(0xCC);
    onewire_write(0x44);

    while(busy==0)
        busy=onewire_read();

    onewire_reset();
    onewire_write(0xCC);
    onewire_write(0xBE);
    sayi1 = onewire_read();
    sayi2 = onewire_read();

    result=sayi2*256+sayi1;
    result=result/16.0;   

    DelayMs(250);
    return result;
}

//----------------------------------------------------------------------------//
#endif
İmkanın sınırlarını görmek için imkansızı denemek lazım.                                                             Fatih Sultan Mehmet

Okan AKÇA

Ccs nin yada micro c ninkinler gayet guzel çalışıyor

MrDarK

CCS'de çalıştırdığım kodu STM'ye almak için Logic Analyser ile sürelere ve gidip gelen datalara göre bir delay çevrimi yapmıştım. O şekilde çalıştırdım. Mucit hocam bence ccs'deki koddan bu şekilde yürüyün derim :)

Hatta sürelere proteus'un osilaskobunu kullanarak bakmıştım.
Picproje Eğitim Gönüllüleri ~ MrDarK

RaMu

Şöyle dener misin:


void OneWire_Write(uint8_t data)
{
    unsigned char i;
    for (i=0; i<8; i++)
    {
			  OneWire_DIR(OUT);
        GPIO_ResetBits(OneWireGpio,OneWirePin);
			  delay_us(2);
			  if((data>>i) & 0x01)
				{
			           delay_us(60);
				OneWire_DIR(IN);
				}
				else
				{


				   delay_us(2);	
				OneWire_DIR(IN);			   
				}
	
    }
}


Sorularınıza hızlı cevap alın: http://www.picproje.org/index.php/topic,57135.0.html

Mucit23

@RaMu yok o şekilde sürekli 4095 verisi geliyor. Benim ilk yaptığım kodlarda 500 msn aralıklarla okuma yapıyorum. 1 kere düzgün sonuç geliyorsa diğerinde 4095 okuyorum. Sonrasında yine düzgün sıcaklık değeri geliyor.

@M_B F4 için verdiğin kütüphanenin GPIO komutlarını F1 de çalışacak şekilde düzenledim fakat sorun aynı.

Ben F1 de gecikme işlemleri için SysTick kullanıyorum. 50uS gecikme verdiğim yerlerde yaklaşık 52US lik bir gecikme yapıyor. Değerler hemen hemen doğru.

Aşağıda data hattına ait lojik analyser çıktısını ekledim

1 Kere düzgün okuma yapılıyorsa diğerinde uzunca boş bir veri geliyor.
Buda düzgün okumanın yapıldığı kısım.


Sorun nedir anlamıyorum.

kantirici

OneWire protokolü süreye karşı oldukça hassas. Muhtemelen bundan kaynaklı bir sıkıntı mevcut. us gecikme için systick yerine for ile dummy sayaç yapıp osilaskoptan hassasiyetini ayarlamak daha iyi sonuç verecektir.

void delay_us(uint32_t us)
{
  IO1 = 1;
   for(uint32_t i = 0; i < us*CARPAN;i++);
  IO1 = 0;
}

skara1214

 one shot timeri da delay olarak kullanabilirsin
Herkes ölür ama herkes gerçekten yaşamaz

Mucit23

Biraz sanayi işi oldu ama deneme yanılma ile doğru gecikmeleri buldum. Aslında okuma fonksiyonu hatalıymış. Dumy Gecikme fonksiyonu ile doğru değerleri bulmak daha zor.  Okuma ve yazma ile ilgili ince bir ayar çeksem daha stabil olacak. Logic analyser ile bakmam lazım.

Şuan çalışıyor fakat sprintf ile ilgili bir sorun var anlamadım.

     sicaklik=Ds18B20_Read();
     sprintf(text,"%f",sicaklik); Bu şekilde text'e atınca sorun yok örneğin 30.22345453 şeklinde yazıyor
Fakat
     sprintf(text,"%2.1f",sicaklik); Bu şekilde yazınca ekranda 4095.9 gibi sabit bir değer görüyorum. Sıcaklık okuma fonksiyonlarım aynı. Bu neden olur? 

Mucit23

Şuan Oldukça saçma çalışıyor. Anlamıyorum. Gecikmeleri birebir logic analyser ile ölçüyorum. Doğru olduğunu söyleyebilirim. Fakat problem yaşanıyor.

Özellikle şu sprintf kullanımında niye sorun yaşanıyor bunu hiç anlamıyorum. Sprintf ile ne alakası var yahu!!

vitruvius

"sicaklik" ve "text" değerlerin ne iki durumda da?

MC_Skywalker

#13
sprintf(lcd_buff,"Volt:%.2f", OrtalamaX )
şeklinde denermsin. I2C OLED ile ADC den gelen float veriyi gösteriken benim başıma benzeri gelmişti.

baran123

#14
Embitz de sprintf ile float basmaya çalışırsan problem yaşıyorsunç Şu ayarı yapman gerekli

"sprintf ve float ı aynı anda kullanamıyoruz. sebebini araştırıyorum.
Ekleme
1. proje başlangıcında heap ve stack alanını belirle (default olarak heap 0x00 geliyor)
2.projede builtoption-compiler setting-other option a -u _printf_float ı ekle."

Yani şöyle


@muhittin_kaplan  hocadan alıntıdır. :)