Arduino Donma/Kitlenme Sorunu

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
Herkese merhaba,
Bir proje üzerinde çalışıyorum. Normalde projede bulanık mantık kullanarak fan hız ayarı yapıyorum fakat Arduino donma sorunu yaşıyorum. Hafıza sorunu olabileceğini düşünüp projeyi temel haline getirdim. Değişken ve fonksiyonları kaldırdım. Fakat halen donma sorunu yaşıyorum. Hafızayı çok yoğun olarak kullandığımı düşünmüyorum. Kodları aşağıya bıraktım. Donma problemi belli bir süre çalıştıktan sonra oluyor. Bu süre 1.5 saat de oldu 7 saat de. Arduino'yu 12V adaptör ile besliyorum. Herhangi bir elektrik kesintisi sorunu olmuyor. Program loop'tan çıkmış gibi kalıyor. Bu konuda yardımınızı bekliyorum. Şimdiden teşekkürler.

C:
#include <Servo.h>
#include "DHT.h"
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>

#define SU A0
#define DHTPIN A1 //DHT Sensörünün bağlı olduğu pin
#define DHTTYPE DHT11 //DHT sensörünün tipi
#define IN1 13
#define IN2 12
#define IN3 11
#define IN4 10
#define ENA 6
#define ENB 5
#define AMPUL 7

int milisaniye = 0;
int saniye = 0;
float sicaklik; //DHT11 gelen değer
float nem; //DHT11 gelen değer
byte fanHiz;
byte servoKonum = 45;
bool servoFlag = false;
byte i;


DHT dht(DHTPIN, DHTTYPE);
Servo servoMotor; //45-Orta / 80-yukari / 10-asagi
LiquidCrystal_I2C lcd(0x27, 16, 2);

void setup() {

  servoKonum = EEPROM.read(100);
  dht.begin(); //DHT11 sensörü  tanımlandı
  servoMotor.attach(9);  /* Servo motor 9 numarali pine baglandi */
  servoMotor.write(servoKonum);
  pinMode(AMPUL,OUTPUT);
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);
  digitalWrite(7,HIGH);
  digitalWrite(IN1,LOW);
  digitalWrite(IN4,LOW);

  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  analogWrite(ENA,0);
  analogWrite(ENB,0);
 
  lcd.begin();

  cli();
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
  sei();
}

ISR(TIMER2_COMPA_vect){
  milisaniye++;
  if(milisaniye >= 8000)
  {
    milisaniye=0;
    saniye++;
    
    }
  if (saniye >= 43200)
    saniye = 0;

  if (saniye == 0)
    servoFlag = true;
}
 
void loop() {

  sicaklik = dht.readTemperature();//DHT11 sıcaklık sensöründen veri alınıyor
  nem = dht.readHumidity();//DHT11 sıcaklık sensöründen veri alınıyor

  if (!isnan(sicaklik) && !isnan(nem))
  {
    
    if (sicaklik <= 37.5)
      digitalWrite(7,LOW);
    else if (sicaklik >= 38.3)
      digitalWrite(7,HIGH);

    if (sicaklik < 30 || nem < 40)
      fanHiz = 150;
    else if (sicaklik < 36 || nem < 50)
      fanHiz = 75;
    else if (sicaklik < 39 || nem < 60)
      fanHiz = 0;
    else if (sicaklik >= 39 || nem >= 60)
      fanHiz = 255;

    analogWrite(ENA, fanHiz);
    
    if(servoFlag)
    {
      servoKonum = EEPROM.read(100);
      if(servoKonum == 10)
      {
        for (i = 10; i <= 80; i++)
        {
          servoMotor.write(i);
          delay(15);
        }
        EEPROM.write(100, 80);
        }
      else
      {
        for (i = 80; i >= 10; i--)
        {
          servoMotor.write(i);
          delay(15);
        }
        EEPROM.write(100, 10);
        }
      servoFlag = false;
      }
    }

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("S: ");
    lcd.print(sicaklik);
    lcd.print(" / N: ");
    lcd.print(nem);
    lcd.setCursor(0,1);
    lcd.print("Fan:");
    lcd.print(fanHiz);

  delay(1000);
 
}
 

Gokrtl

Gökhan Kartal
Staff member
Katılım
27 Şubat 2019
Mesajlar
7,561
Ben de acemi sayılırım. Kendimce kafama takılan bazı konuları dile getireyim.

Hangi arduino modelini kullanıyorsunuz? Klonların da çeşitleri var.
Elektrik kesintisi sorunu yoksa servo konumu için eeprom yerine değişken kullanabilirsin.
Ekstra bir buton koy, cihazı kapatman gerektiğinde butona basarak servonun o anki konumunu eeproma yaz. böylece eeprom'u daha az kullanmış olursun.
EEPROM'un belli bir okuma yazma sayısı vardır. Loop içinde bunu ms'ler için de onlarca-yüzlerce kez oku-yaz yaptırıyorsan ilerde sıkıntı çıkar.
EEPROM ömrünü bitirdiğinde nasıl bir sıkıntı çıkarır bilmiyorum. Daha önce hiç EEPROM ömrü doldurmadım. Belki de sorunun kaynağı budur.
Dediğim gibi EEPROM'u minimum kullanacak şekilde yapılandırıp, arduinoyu da başka bir kart kullanarak tekrar deneyin.
Ayrıca kullandığınız arduino pro mini, nano gibi küçük kartlardansa servo için harici besleme de kullanmanız gerekecektir.
Burada servonun ne iş yaptığı da önemli. Eğer koluna ağır bir yük biniyorsa daha fazla akım ihtiyacı doğacaktır. Bu durum da büyük arduino modelleri bile yetmeyip harici beslemeye ihtiyaç duyabilir.
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
Öncelikle ilgilendiğin için teşekkürler.

Arduino UNO kullanıyorum fakat klon modelini bilmiyorum.
EEPROM'a kaydetme sebebim her ihtimale karşı elektrik kesintisinde konumu kaybetmemek. Burada elektrik kesintisi yok dememin sebebi donma sonrası elektriksel bir problem olmaması.
Loop içerisinde EEPROM'u fazla kullanmıyorum. Timer aracılığı ile 12 saatte bir çalışacak şekilde ayarladım. Yani if içerisine her 12 saatte bir girecek.
Şimdiye kadar servoyu çalıştıracak zamanı bulamadı. O aşamaya gelmeden kitleniyor. Yani akımın sebep olduğunu düşünmüyorum.

Dediğin gibi kartı değiştirip tekrar deneyeceğim. Tekrar teşekkürler.
 

Gokrtl

Gökhan Kartal
Staff member
Katılım
27 Şubat 2019
Mesajlar
7,561
Öncelikle ilgilendiğin için teşekkürler.

Arduino UNO kullanıyorum fakat klon modelini bilmiyorum.
EEPROM'a kaydetme sebebim her ihtimale karşı elektrik kesintisinde konumu kaybetmemek. Burada elektrik kesintisi yok dememin sebebi donma sonrası elektriksel bir problem olmaması.
Loop içerisinde EEPROM'u fazla kullanmıyorum. Timer aracılığı ile 12 saatte bir çalışacak şekilde ayarladım. Yani if içerisine her 12 saatte bir girecek.
Şimdiye kadar servoyu çalıştıracak zamanı bulamadı. O aşamaya gelmeden kitleniyor. Yani akımın sebep olduğunu düşünmüyorum.

Dediğin gibi kartı değiştirip tekrar deneyeceğim. Tekrar teşekkürler.
Kartın resmini ekleyebilir misin?
Bir tane model var herkes en ucuz o diye gidip onu alıyor ama o kartta ciddi sıkıntılar var.
Eğer sendeki de o karttansa daha iyi bir model önerebilirim.
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
IMG_20210522_113050.jpg
 

Gokrtl

Gökhan Kartal
Staff member
Katılım
27 Şubat 2019
Mesajlar
7,561
Tam tahmin ettiğim gibi. Piyasadaki en kötü kart. Bu kart sahipleri ile çok karşılaştım. Kimisi mp3 çalar modülü kullanamadı, kimi sd kart modülü. Büyük ihtimalle sendeki donma sorunu da bu karttan dır. Aşağıya ekleyeceğim resimdekinden almanı tavsiye ederim.
Üzerinde özellikle kırmızı ile yuvarlak içine aldığım kare çipten olmalı. Unoların kaliteli olanı bu kart.
Daha önce mp3,sd kart okuyucu gibi şikayetler ile gelen arkadaşların sonrunlarını bu kart ile denedim ve sorun yaşamadım.

kaliteli arduino uno.PNG
 

Sercan

Kıdemli Üye
Katılım
17 Mart 2019
Mesajlar
3,391
Kullandığın güç kaynağı nedir?
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
Arduino klonumu değiştirdim. Hatta problemin memory'den olması ihtimaline karşı Arduino Mega aldım. Fakat sorun yine aynı. Yaklaşık 20 saat bir problem olmadan çalıştı. Her şey gayet normaldi. Fakat baktığımda tekrar donmuş olarak buldum. Sanırım memory leak sorunu var. Kodumda bir problem olabilir. İncelemek isteyen olursa diye kodumu bırakıyorum. Herhangi bir fikri olan varsa görüşlerinize ve önerilerinize açığım.
İyi çalışmalar.

C:
#include <Servo.h>
#include "DHT.h"
#include <virtuabotixRTC.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>


#define CLK_PIN 4
#define DAT_PIN 3
#define RST_PIN 2
#define SU A0
#define DHTPIN A1
#define DHTTYPE DHT11
#define IN1 13
#define IN2 12
#define IN3 11
#define IN4 10
#define ENA 6
#define ENB 5
#define AMPUL 7

int milisaniye = 0;
byte saniye = 0;
float sicaklik; //DHT11 gelen değer
float nem; //DHT11 gelen değer
int suSeviyesi;//0-Boş / 200-az / 330-orta / >350-dolu
byte servoKonum = 45;
bool servoFlag = false;


DHT dht(DHTPIN, DHTTYPE);
Servo servoMotor;
LiquidCrystal_I2C lcd(0x27, 16, 2);
virtuabotixRTC RTCsaat(CLK_PIN, DAT_PIN, RST_PIN);

void setup() {
  res = false;
  servoKonum = EEPROM.read(100);
  dht.begin(); //DHT11 sensörü  tanımlandı
  servoMotor.attach(9);  /* Servo motor 9 numarali pine baglandi */
  //RTCsaat.setDS1302Time(50,35,12,4,12,11,2020);
  servoMotor.write(servoKonum);
  pinMode(AMPUL,OUTPUT);
  pinMode(IN1,OUTPUT);
  pinMode(IN2,OUTPUT);
  pinMode(IN3,OUTPUT);
  pinMode(IN4,OUTPUT);
  pinMode(22, OUTPUT);
  digitalWrite(22, HIGH);
  digitalWrite(7,HIGH);
  digitalWrite(IN1,LOW);
  digitalWrite(IN2,LOW);
  digitalWrite(IN3,LOW);
  digitalWrite(IN4,LOW);
  lcd.begin();
 
  RTCsaat.updateTime();

  cli();
  TCCR2A = 0;// set entire TCCR2A register to 0
  TCCR2B = 0;// same for TCCR2B
  TCNT2  = 0;//initialize counter value to 0
  // set compare match register for 8khz increments
  OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
  // turn on CTC mode
  TCCR2A |= (1 << WGM21);
  // Set CS21 bit for 8 prescaler
  TCCR2B |= (1 << CS21);   
  // enable timer compare interrupt
  TIMSK2 |= (1 << OCIE2A);
  sei();
}

ISR(TIMER2_COMPA_vect){
  milisaniye++;
  if(milisaniye >= 8000)
  {
    milisaniye=0;
    RTCsaat.updateTime();
    if((RTCsaat.hours == 00 && RTCsaat.minutes == 00 && RTCsaat.seconds == 00)||(RTCsaat.hours == 12 && RTCsaat.minutes == 00 && RTCsaat.seconds == 00))
      servoFlag = true;
    saniye++;
    
    }
}

void servoCalistir()
{
  servoKonum = EEPROM.read(100);
  if(servoKonum == 10)
  {
    byte i;
    for (i = 10; i <= 80; i++)
    {
      servoMotor.write(i);
      delay(15);
    }
    EEPROM.write(100, 80);
    }
  else
  {
    byte i;
    for (i = 80; i >= 10; i--)
    {
      servoMotor.write(i);
      delay(15);
    }
    EEPROM.write(100, 10);
    }
  servoFlag = false;
  }

float bulanikFan(float t, float h)
{
  float fanHiz = 0;
  if(!isnan(t) || !isnan(h)){
      float sabit[2] = {0};
      float yavas[3] = {0};
      float orta[3] = {0};
      float hizli[4] = {0}; //Kural tablosuna göre cikis sayilari

      float sDusuk = 0;
      float sOrta = 0;
      float sIdeal = 0;
      float sYuksek = 0; //Sıcaklık dilsel degerleri

      float nKuru = 0;
      float nNormal = 0;
      float nNemli = 0; //nem dilsel degerleri

      float fSabitMax = 0;
      float fYavasMax = 0;
      float fOrtaMax = 0;
      float fHizliMax = 0; //fan dilsel degerleri

      sDusuk = trimf(t, 0, 10, 28);
      sOrta = trimf(t, 22, 30, 36);
      sIdeal = trimf(t, 34, 37, 40);
      sYuksek = trimf(t, 39, 50, 57);//Sicaklik girisi icin ucgen uyelik fonksiyonlari tanimlandi

      nKuru = trimf(h, 0, 20, 43);
      nNormal = trimf(h, 27, 50, 73);
      nNemli = trimf(h, 57, 80, 100);//Nem girisi icin ucgen uyelik fonksiyonlari tanimlandi

      // Kural tablosu yazılmaya başlanır
      
      yavas[0] = andFonk(sDusuk, nKuru);
      orta[0] = andFonk(sDusuk, nNormal);
      hizli[0] = andFonk(sDusuk, nNemli); //Dusuk sicaklik icin tüm nem olasılıkları

      yavas[1] = andFonk(sOrta, nKuru);
      yavas[2] = andFonk(sOrta, nNormal);
      orta[1] = andFonk(sOrta, nNemli); //Orta sicaklik icin tüm nem olasılıkları

      sabit[0] = andFonk(sIdeal, nKuru);
      sabit[1] = andFonk(sIdeal, nNormal);
      hizli[1] = andFonk(sIdeal, nNemli);//Ideal sicaklik icin tüm nem olasılıkları

      orta[2] = andFonk(sYuksek, nKuru);
      hizli[2] = andFonk(sYuksek, nNormal);
      hizli[3] = andFonk(sYuksek, nNemli); //Yuksek sicaklik icin tüm nem olasılıkları

      fSabitMax = DiziMax(sabit, 2);
      fYavasMax = DiziMax(yavas, 3);
      fOrtaMax = DiziMax(orta, 3);
      fHizliMax = DiziMax(hizli, 4);

      fanHiz = (fSabitMax * 0) + (fYavasMax * 33) + (fOrtaMax * 67) + (fHizliMax * 100);
      fanHiz = fanHiz / (fSabitMax + fYavasMax + fOrtaMax + fHizliMax);

      return fanHiz;
    }
  }
float DiziMax(float a[], int b) {
    float buyuk = a[0];
    for (int i = 1; i < b; i++) { if (a[i] > buyuk)
            buyuk = a[i];
    }
    return buyuk;
}
float andFonk(float a, float b) {
    if (a < b) {
        return a;
    } else {
        return b;
    }
}

float trimf(float x,float a, float b, float c){
    float f;
    if(x<=a)
       f=0;
    else if((a<=x)&&(x<=b))
       f=(x-a)/(b-a);
    else if((b<=x)&&(x<=c))
       f=(c-x)/(c-b);
    else if(c<=x)
       f=0;
    return f;
  }

void loop() {
  float fanh = 0;
  RTCsaat.updateTime();
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  analogWrite(ENA,0);
  analogWrite(ENB,0);
  sicaklik = dht.readTemperature();//DHT11 sıcaklık sensöründen veri alınıyor
  nem = dht.readHumidity();//DHT11 sıcaklık sensöründen veri alınıyor


  if (!isnan(sicaklik) && !isnan(nem))
  {
    fanh = bulanikFan(sicaklik, nem) * 2.55;
    analogWrite(ENA, fanh);
    if (sicaklik <= 37.5)
    {
      digitalWrite(7,LOW);
      EEPROM.write(101,1);
      }
    else if (sicaklik >= 38.3)
    {
      digitalWrite(7,HIGH);
      EEPROM.write(101,0);
      }
      
    suSeviyesi = analogRead(SU);
    if(suSeviyesi < 200 && nem < 40)
      analogWrite(ENB, 255);
    else
      analogWrite(ENB, 0);
 
    if(servoFlag)
      servoCalistir();
    
    }

    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("S: ");
    lcd.print(sicaklik);
    lcd.print(" / N: ");
    lcd.print(nem);
    lcd.setCursor(0,1);
    lcd.print("Fan:");
    lcd.print(fanh);
    lcd.print("/Su:");
    lcd.print(suSeviyesi);

 
  delay(1000);
 
}
 

taydin

Timur Aydın
Staff member
Katılım
24 Şubat 2018
Mesajlar
13,133
Saniyede 8000 defa kesme üretecek şekilde yapılandırmışsın. 4 GHz de çalışan Core i7 lerde bile linux scheduler kesme sıklığı saniyede 1000 defa, bu çok fazla ve bu uygulama için gerekli değil. Saniyede BİR kesme üretsen bile senin işini görmesi lazım.

İkincisi, kesme rutininin içinden RTC kütüphanesi fonksiyonu çağırıyorsun. Bu fonksiyon belki de bir ISR içinden çağrılmaya uygun değil ve bu da takılmaya sebep olabilir. updateTime fonksiyonunu kesme içinden çağıracağına, kesme içinde bir flag set et, sonra da ana döngüde updateTime çağır ve o flag'ı sıfırla.
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
Dediklerinizi uygulayıp tekrar deneyeceğim. Fakat bu dedikleriniz 20 saat çalışma süresince neden sorun olmuyor onu anlamadım. Çünkü o 20 saat içerisinde kesme işlemi gerçekleşti. RTC kodu istediğim şekilde çalıştı yani.
 

taydin

Timur Aydın
Staff member
Katılım
24 Şubat 2018
Mesajlar
13,133
Dediklerinizi uygulayıp tekrar deneyeceğim. Fakat bu dedikleriniz 20 saat çalışma süresince neden sorun olmuyor onu anlamadım. Çünkü o 20 saat içerisinde kesme işlemi gerçekleşti. RTC kodu istediğim şekilde çalıştı yani.

Çünkü kesmenin kod akışında meydana geldiği nokta önemli. İstatistik olarak o kritik noktaya denk gelmesinin süresi 20 saat.
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
Timer'ı ayarlayabildiğim en yüksek prescaler olan 64'e ayarladım. Bu şekilde saniyede 1000 kez kesme işlemi gerçekleştirdim. ISR fonksiyonu içerisinde de saat kontrolünü bir flag değişkeni ile yaptım. Sonuç yine aynıydı. Daha sonra Timer kesmesini komple kaldırdım. Şu an düzeldi gibi 2 gündür problemsiz çalışıyor. Fakat Timer'ın neden sorun olduğunu anlayamadım.
 

umk

Aktif Üye
Katılım
22 Haziran 2018
Mesajlar
174
@omerfbuber, Google da "arduino stuck" diye aratınca şuna denk geldim.


Adamın sorunu senin probleminle alakalı olmayabilir ama çözüm kısmında compiler ın warning şeçeneklerini açınca daha önceden görülmeyen kritik sorunların belirgin hale geldiğinden bahsediyor. Bunun için File->Preferences menüsünde "Compiler Warnings" None iken ALL seçilmeli....

Bu şekilde yapılıp ilk verdiğin programı derlediğimizde, int saniye.. tanımlamam program içerisinde saniye >=43200 olarak kullanmışsın ki integer değişken maks 32767 değeri alabilir bu durumda karşılaştırma anlamsız oluyor gibi derleyici bunun için warning veriyor....
İkinci verdiğin programı derlediğimizde, "In function 'float bulanikFan(float, float)': warning: control reaches end of non-void function [-Wreturn-type] veriyor ki return if cümlesinin içinde kalmış. if koşulu sağlanmasza return yok gibi.... Bu hatalar işlemcinin davranışını etkileyebilir. Belki de donma bu yüzden meydana geliyor....
 

omerfbuber

Üye
Katılım
12 Mart 2021
Mesajlar
15
@omerfbuber, Google da "arduino stuck" diye aratınca şuna denk geldim.


Adamın sorunu senin probleminle alakalı olmayabilir ama çözüm kısmında compiler ın warning şeçeneklerini açınca daha önceden görülmeyen kritik sorunların belirgin hale geldiğinden bahsediyor. Bunun için File->Preferences menüsünde "Compiler Warnings" None iken ALL seçilmeli....

Bu şekilde yapılıp ilk verdiğin programı derlediğimizde, int saniye.. tanımlamam program içerisinde saniye >=43200 olarak kullanmışsın ki integer değişken maks 32767 değeri alabilir bu durumda karşılaştırma anlamsız oluyor gibi derleyici bunun için warning veriyor....
İkinci verdiğin programı derlediğimizde, "In function 'float bulanikFan(float, float)': warning: control reaches end of non-void function [-Wreturn-type] veriyor ki return if cümlesinin içinde kalmış. if koşulu sağlanmasza return yok gibi.... Bu hatalar işlemcinin davranışını etkileyebilir. Belki de donma bu yüzden meydana geliyor....

Evet haklısın, sen yazınca fark ettim bu hataları. Bir de bunları düzenleyip deneyeceğim. Teşekkürler.
 
  • Beğen
Reactions: umk
Top