DS18B20 Błąd przy temperaturze ujmnej.

Wszystko o co chcesz zapytać na temat mikrokontrolerów ARM firmy STMicroelectronics: problemy z pisaniem programu, problemy sprzętowe, niejasności w DS czy AN itp.
StaryAnoda

DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » sobota 31 gru 2016, 21:09

Hej

Jak to jak udało mi się w końcu zbudować, termometr na układzie DS18B20 i STM32F103. Przy temperaturze dodatniej wszystko pięknie działa od 0 - 125 stopnie wynik jest pięknie wyświetlany, natomiast przy ujemnej temperaturze otrzymuję 4095,12 stopni. Taktowanie procesora 8MHz.


Kod: Zaznacz cały

#include "stm32f1xx_it.h"
#include "stm32f10x.h"
#include <stdio.h>

uint8_t Reset, Temperature_MSB, Temperature_LSB;
char String_Temperature[10];
float Temperature;

#define D4_SET (GPIOB -> ODR |= GPIO_ODR_ODR15);
#define D5_SET (GPIOB -> ODR |= GPIO_ODR_ODR14);
#define D6_SET (GPIOB -> ODR |= GPIO_ODR_ODR13);
#define D7_SET (GPIOB -> ODR |= GPIO_ODR_ODR12);
#define E_SET (GPIOA -> ODR |= GPIO_ODR_ODR9);
#define RS_SET (GPIOA -> ODR |= GPIO_ODR_ODR8);

#define D4_RESET (GPIOB -> ODR &= ~GPIO_ODR_ODR15);
#define D5_RESET (GPIOB -> ODR &= ~GPIO_ODR_ODR14);
#define D6_RESET (GPIOB -> ODR &= ~GPIO_ODR_ODR13);
#define D7_RESET (GPIOB -> ODR &= ~GPIO_ODR_ODR12);
#define E_RESET (GPIOA -> ODR &= ~GPIO_ODR_ODR9);
#define RS_RESET (GPIOA ->ODR &= ~GPIO_ODR_ODR8);

#define SIO_SET (GPIOA -> ODR |= GPIO_ODR_ODR10);

#define SIO_RESET (GPIOA -> ODR &= ~GPIO_ODR_ODR10);

void Lcd_Send_Half_Byte(uint8_t Data)
{
   if (Data & 0x01) D4_SET else D4_RESET;
   if (Data & 0x02) D5_SET else D5_RESET;
   if (Data & 0x04) D6_SET else D6_RESET;
   if (Data & 0x08) D7_SET else D7_RESET;
}

void Lcd_Write_Byte(uint8_t Data)
{
   E_SET;
   Lcd_Send_Half_Byte(Data >> 4);
   E_RESET;

   E_SET;
   Lcd_Send_Half_Byte(Data);
   E_RESET;

   Delay_ms(5);
}

void Lcd_Write_Command(uint8_t Command)
{
   RS_RESET;
   Lcd_Write_Byte(Command);
}

void Lcd_Write_Data(uint8_t Data)
{
   RS_SET;
   Lcd_Write_Byte(Data);
}

void Lcd_Init(void)
{
   RS_SET;
   E_SET;
   Delay_ms(45);
   E_RESET;
   RS_RESET;


   E_SET;
   Lcd_Send_Half_Byte(0x03);
   E_RESET;
   Delay_ms(5);

   E_SET;
   Lcd_Send_Half_Byte(0x03);
   E_RESET;
   Delay_ms(5);

   E_SET;
   Lcd_Send_Half_Byte(0x03);
   E_RESET;
   Delay_ms(5);

   E_SET;
   Lcd_Send_Half_Byte(0x02);
   E_RESET;
   Delay_ms(5);

   Lcd_Write_Command(0x28); // Function SET // OFF DISPLAY // DISPLAY TWO-LINE // MATRIX CHARACTER 5 * 7 POINTS
   Lcd_Write_Command(0x01); // CLEAR DISPLAY /
   Lcd_Write_Command(0x06); // ENTRY MODE SET //
   Lcd_Write_Command(0x0C); // DISPLAY ON //

   Delay_ms(5);
}


void Lcd_Char(char c)
{
   Lcd_Write_Data(c);
}

void Lcd_Send_String (char * String)
{
   while(*String)   Lcd_Char(*String++);
}

void Lcd_Int(int val)
{
   char bufor[17];
   sprintf(bufor,"%d",val);
   Lcd_Send_String(bufor);
}

void Lcd_XY(uint8_t Y, uint16_t X)
{
   switch (Y)
   {
   case 0: Y = 0x00; break;
   case 1: Y = 0x40; break;
   }
   Lcd_Write_Command((0x80 + Y + X));
   Delay_ms(5);
}

inline __attribute__((always_inline)) inline void SET_SIO_OUTPUT(void)
{
   GPIOA -> CRH &= ~GPIO_CRH_CNF10_1;
   GPIOA -> CRH |= GPIO_CRH_MODE10_1;
   GPIOA -> CRH &= ~GPIO_CRH_CNF10_0;
}

inline __attribute__((always_inline)) inline void SET_SIO_INPUT(void)
{
   GPIOA -> CRH &= ~GPIO_CRH_MODE10_1;
   GPIOA -> CRH &= ~GPIO_CRH_CNF10_0;
   GPIOA -> CRH |= GPIO_CRH_CNF10_1;
   GPIOA -> ODR &= ~GPIO_ODR_ODR10;
}

inline __attribute__((always_inline)) inline void Delay_us(uint16_t Time)
{
   TIM1 -> CNT = 0;
   while((TIM1 -> CNT) <= Time);
}

uint8_t One_Wire_Reset_Pulse(void)
{
   uint8_t Presence_Impulse = 0;

   SET_SIO_OUTPUT();
   SIO_RESET;
   Delay_us(480);
   SET_SIO_INPUT();
   Delay_us(37);

   if(!(GPIOA ->IDR & GPIO_IDR_IDR10))
   {
      Presence_Impulse ++;
   }

   Delay_us(443);
   if(GPIOA ->IDR & GPIO_IDR_IDR10)
   {
      Presence_Impulse ++;
   }

   if(Presence_Impulse == 2)
   {
      return Presence_Impulse = 1;
   }
   else
   {
      return Presence_Impulse = 0;
   }
}

void One_Wire_Send_Bit(uint8_t Bit)
{
   SET_SIO_OUTPUT();
   if(Bit == 0)
   {
      SIO_RESET;
      Delay_us(60);
      SIO_SET;
      Delay_us(1);
   }
   else
   {
      SIO_RESET;
      Delay_us(1);
      SIO_SET;
      Delay_us(60);
   }
}

void One_Wire_Send_Byte (uint8_t Byte)
{
   uint8_t Cnt = 0x01;

   while(1)
   {
      if(Byte & Cnt)
      {
         One_Wire_Send_Bit(1);
      }
      else
      {
         One_Wire_Send_Bit(0);
      }
      Cnt <<= 1;
      if(!Cnt) break;
   }
}

uint8_t One_Wire_Read_Bit(void)
{
   uint8_t Bit = 0;

   SET_SIO_OUTPUT();
   SIO_RESET;
   Delay_us(5);
   SET_SIO_INPUT();
   Delay_us(5);

   if(GPIOA ->IDR & GPIO_IDR_IDR10)
   {
      Bit = 1;
   }
   else
   {
      Bit = 0;
   }
   Delay_us(45);

   return Bit;
}

uint8_t One_Wire_Read_Byte(void)
{
   uint8_t Read_Byte = 0;
   uint8_t Cnt = 0;

   while(1)
   {
      if(One_Wire_Read_Bit())
      {
         Read_Byte |= 0x01 << Cnt;
      }
      Cnt ++;
      if(Cnt > 7) break;
   }
   return Read_Byte;
}


int main (void)
{
   RCC -> APB2ENR = RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_TIM1EN;

   GPIOB -> CRH |= GPIO_CRH_MODE15_1;
   GPIOB -> CRH &= ~GPIO_CRH_CNF15_0;

   GPIOB -> CRH |= GPIO_CRH_MODE14_1;
   GPIOB -> CRH &= ~GPIO_CRH_CNF14_0;

   GPIOB -> CRH |= GPIO_CRH_MODE13_1;
   GPIOB -> CRH &= ~GPIO_CRH_CNF13_0;

   GPIOB -> CRH |= GPIO_CRH_MODE12_1;
   GPIOB -> CRH &= ~GPIO_CRH_CNF12_0;

   GPIOA -> CRH |= GPIO_CRH_MODE9_1;
   GPIOA -> CRH &= ~GPIO_CRH_CNF9_0;

   GPIOA -> CRH |= GPIO_CRH_MODE8_1;
   GPIOA -> CRH &= ~GPIO_CRH_CNF8_0;

   TIM1 -> PSC = 8;
   TIM1 -> ARR = 65535;
   TIM1 -> CR1 = TIM_CR1_CEN;

   SysTick_Config(8000000/1000);

   Lcd_Init();
   Lcd_XY(0,0);
   Lcd_Send_String("TERMOMETR MY LIB");
   Lcd_XY(1,5);
   Lcd_Send_String("DS18B20");
   Delay_ms(2000);
   Lcd_Write_Command(0x01);

   Lcd_XY(0,5);
   Lcd_Send_String("DS18B20");

   while(1)
   {
      Reset = One_Wire_Reset_Pulse();

      if(Reset == 1)
      {
         One_Wire_Send_Byte(0xCC);
         One_Wire_Send_Byte(0x44);
         Delay_ms(750);
         Reset = One_Wire_Reset_Pulse();
         One_Wire_Send_Byte(0xCC);
         One_Wire_Send_Byte(0xBE);
         Temperature_LSB = One_Wire_Read_Byte();
         Temperature_MSB = One_Wire_Read_Byte();
         Reset = One_Wire_Reset_Pulse();

         Temperature = (float)(Temperature_LSB + (Temperature_MSB << 8)) * 0.0625;
         sprintf(String_Temperature, "%.2f", Temperature);
         Lcd_XY(1, 0);
         Lcd_Send_String("                ");
         Lcd_XY(1, 0);
         Lcd_Send_String("TEMP: ");
         Lcd_Send_String(String_Temperature);
         Lcd_Send_String(" *C");
      }
      else
      {
         Lcd_XY(1, 0);
         Lcd_Send_String(" BRAK CZUJNIKA");
      }
   }
}


StaryAnoda

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » niedziela 01 sty 2017, 17:27

Hej znowu

Podłączyłem analizator stanów logicznych. Do układu który działa na AVR ten sam kod i na STM kod który jest zaprezentowany wyżej ? Na AVR wskazuję temperaturę ujmeną. Czy na podstawie tych dwóch screenów może ktoś potwierdzić, że sposób konwersji dwóch bajtów na liczbę float jest błędny ?

AVR
Screenshot (62).png

STM
Screenshot (63).png
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Awatar użytkownika
acid3
User
User
Posty: 466
Rejestracja: czwartek 03 wrz 2015, 22:42
Lokalizacja: Kłopoty-Stanisławy
Kontaktowanie:

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: acid3 » niedziela 01 sty 2017, 19:10

A czy mógłbyś wrzucić SAVE CAPTURE z Logica (surówkę), czyli wszystkie dane do zaimportowania u siebie.

StaryAnoda

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » poniedziałek 02 sty 2017, 15:49

To tak

Nie rozwiązałem tego problemu. Zmieniłem ten kod na poniższy który działa poprawnie:

Kod: Zaznacz cały

if((Temperature_MSB & 0xF8) != 0)
         {
            Temperatura_int = (Temperature_LSB + (Temperature_MSB << 8));
            Temperatura_int = (~Temperatura_int) & 0xFFFF;
            Temperatura_int ++;
            Temperature_Float = Temperatura_int * -0.0625;
         }
         else
         {
            Temperatura_int = (Temperature_LSB + (Temperature_MSB << 8));
            Temperature_Float = Temperatura_int * 0.0625;
         }

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: Antystatyczny » poniedziałek 02 sty 2017, 15:53

Mógłbyś wrzucić całą funkcję konwertującą, bo widzę, że chyba doszła jakaś zmienna. A co do pierwszego kodu, nie musisz pisać tak:

Kod: Zaznacz cały

inline __attribute__((always_inline)) inline void SET_SIO_INPUT(void)


Wystarczy tak:

Kod: Zaznacz cały

inline __attribute__((always_inline))  void SET_SIO_INPUT(void)
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

StaryAnoda

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » poniedziałek 02 sty 2017, 16:15

Zmienne globalne:

Kod: Zaznacz cały

uint8_t Reset, Temperature_MSB, Temperature_LSB;
char String_Temperature[10];
uint16_t Temperatura_int;
float Temperature_Float;


Kod: Zaznacz cały

   while(1)
   {
      Reset = One_Wire_Reset_Pulse();

      if(Reset == 1)
      {
         One_Wire_Send_Byte(0xCC);
         One_Wire_Send_Byte(0x44);
         Delay_ms(750);
         Reset = One_Wire_Reset_Pulse();
         One_Wire_Send_Byte(0xCC);
         One_Wire_Send_Byte(0xBE);
         Temperature_LSB = One_Wire_Read_Byte();
         Temperature_MSB = One_Wire_Read_Byte();
         Reset = One_Wire_Reset_Pulse();

         if((Temperature_MSB & 0xF8) != 0)
         {
            Temperatura_int = (Temperature_LSB + (Temperature_MSB << 8));
            Temperatura_int = (~Temperatura_int) & 0xFFFF;
            Temperatura_int ++;
            Temperature_Float = Temperatura_int * -0.0625;
         }
         else
         {
            Temperatura_int = (Temperature_LSB + (Temperature_MSB << 8));
            Temperature_Float = Temperatura_int * 0.0625;
         }

         sprintf(String_Temperature, "%.2f", Temperature_Float);
         Lcd_XY(1, 0);
         Lcd_Send_String("                ");
         Lcd_XY(1, 0);
         Lcd_Send_String("TEMP: ");
         Lcd_Send_String(String_Temperature);
         Lcd_Send_String(" *C");
      }
      else
      {
         Lcd_XY(1, 0);
         Lcd_Send_String(" BRAK CZUJNIKA");
      }
   }

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: Antystatyczny » poniedziałek 02 sty 2017, 16:24

Prawdę mówiąc nie rozumiem, w jakim celu wrzucasz tutaj maskowanie:

Kod: Zaznacz cały

Temperatura_int = (~Temperatura_int) & 0xFFFF;
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

StaryAnoda

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » poniedziałek 02 sty 2017, 17:16

Faktycznie ten zapis jest zbędny, wystarczy zapis:

Kod: Zaznacz cały

Temperatura_int = ~Temperatura_int;

Awatar użytkownika
Antystatyczny
Geek
Geek
Posty: 1168
Rejestracja: czwartek 03 wrz 2015, 22:02

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: Antystatyczny » poniedziałek 02 sty 2017, 21:22

No właśnie, tak mi się wydawało, ale wolałem zapytać. Jeszcze pytanie dotyczące obsługi wyświetlacza: Nie masz w funkcjach wyświetlania liczb stałoprzecinkowych? Widzę, że posiłkujesz się sprintf'em.
"The true sign of intelligence is not knowledge but imagination" Albert Einstein.

StaryAnoda

Re: DS18B20 Błąd przy temperaturze ujmnej.

Postautor: StaryAnoda » wtorek 03 sty 2017, 19:50

Hej

Tak posiłkowałem się sprintfem, ale naumiałem się już używać liczb stałoprzecinkowych :P


Wróć do „ARM STMicroelectronics”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 2 gości