Sonsuz Döngü

Şöyle yaptım yine çalışmadı yav. :kizgin3:

C++:
void loop() {
  ts = millis();
  if (ts != prev_ts)
  {
    u8g2.setFont(u8g2_font_6x10_tr);
    u8g2.drawStr(90, 32, "Tem");
    u8g2.setFont(u8g2_font_6x10_tr);
    u8g2.drawStr(108, 31, "p");
    if ((ts % 1000) == 0)
    {
      if (temp >= 21) {
        flag = !flag;
        if (flag)
        {
          u8g2.drawLine(116, 25, 116, 40);
          u8g2.drawLine(123, 25, 123, 40);
          u8g2.setFont(u8g2_font_u8glib_4_tr);
          u8g2.setCursor(118, 30);
          u8g2.print("F");
          u8g2.setCursor(118, 35);
          u8g2.print("A");
          u8g2.setCursor(118, 40);
          u8g2.print("N");
        }
        else
        {
          // turn off LED
          u8g2.drawLine(116, 25, 116, 40);
          u8g2.drawLine(123, 25, 123, 40);
        }
        digitalWrite(fan_led, HIGH);
      }
    }
    u8g2.setFont(u8g2_font_unifont_t_weather);
    u8g2.drawStr(113, 39, "\u0031");
    digitalWrite(fan_led, LOW);
    u8g2.setFont(u8g2_font_chikita_tr);
    u8g2.setCursor(94, 40);
    u8g2.print(temp);
    u8g2.setFont(u8g2_font_chikita_tr);
    u8g2.drawStr(107, 40, "C");

    prev_ts = ts;
  }
}
Bende ubuntu kullanırken böyle oluyorum.
3 gün upraşıp discord kurabildim.
 
O zaman sen en iyisi bu blink işini timer'a bağla ve bir kesme halletsin. Ondan sonra artık loop fonksiyonunda ne yaparsan yap muntazam bir şekilde blink gerçekleşir. Bundan baya önce ben bir örnek projede timer kesmesi yapılandırmasını yapmıştım.


C++:
/* tanimladigimiz kesme fonksiyonunun saniyede kac defa
   cagirilacagini belirleyen degisken */
int isr_rate = 10;

int blink = 1;

#define BLINK_PERIOD 10
int counter;
int flag;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  /* Atmel 328 in birinci timer'ini kesme kaynagi
     olarak yapilandiriyoruz */
  TCCR1A = 0;
  TCNT1 = 0;
  OCR1A = 16000000 / (isr_rate * 64) - 1;
  TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
}

ISR(TIMER1_COMPA_vect)
{
  if (counter == 0)
  {
    counter = BLINK_PERIOD;

    if (blink)
    {
      flag = !flag;
      if (flag)
      {
        digitalWrite(LED_BUILTIN, HIGH);
      }
      else
      {
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
  }
  else
  {
    --counter;
  }
}

void loop()
{
}
 
O zaman sen en iyisi bu blink işini timer'a bağla ve bir kesme halletsin. Ondan sonra artık loop fonksiyonunda ne yaparsan yap muntazam bir şekilde blink gerçekleşir. Bundan baya önce ben bir örnek projede timer kesmesi yapılandırmasını yapmıştım.


C++:
/* tanimladigimiz kesme fonksiyonunun saniyede kac defa
   cagirilacagini belirleyen degisken */
int isr_rate = 10;

int blink = 1;

#define BLINK_PERIOD 10
int counter;
int flag;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  /* Atmel 328 in birinci timer'ini kesme kaynagi
     olarak yapilandiriyoruz */
  TCCR1A = 0;
  TCNT1 = 0;
  OCR1A = 16000000 / (isr_rate * 64) - 1;
  TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
}

ISR(TIMER1_COMPA_vect)
{
  if (counter == 0)
  {
    counter = BLINK_PERIOD;

    if (blink)
    {
      flag = !flag;
      if (flag)
      {
        digitalWrite(LED_BUILTIN, HIGH);
      }
      else
      {
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
  }
  else
  {
    --counter;
  }
}

void loop()
{
}
Gerek kalmadı abi hallettim.
Ezbere kopyala yapıştır yapmadan kodları anlamaya çalışarak yapmak lazımmış. Mantık yoluyla gidince kodlar yerli yerine oturuyor. :)
 
Şöyle yaptım yine çalışmadı yav. :kizgin3:

Bir dakka, burada 5, 6, 7, 8 satır her milisaniyede çağrılıyor. Öldürmüşsün işlemciyi :) Onları gerektiği zaman çağır, ne o öyle her milisaniye. Şunu dene:

C++:
int flag = 0;
unsigned long prev_ts, ts;

void loop()
{
  ts = millis();
  if (ts != prev_ts)
  {
    if (labs(ts - prev_ts) >= 1000)
    {
      flag = !flag;
 
      if (flag)
      {
          // blink ON durumu, gerekeni ekrana yaz
      }
      else
      {
          // blink OFF durumu, gerekeni ekrana yaz
      }

      prev_ts = ts;
    }
  }
}
 
Bir dakka, burada 5, 6, 7, 8 satır her milisaniyede çağrılıyor. Öldürmüşsün işlemciyi :) Onları gerektiği zaman çağır, ne o öyle her milisaniye. Şunu dene:

C++:
int flag = 0;
unsigned long prev_ts, ts;

void loop()
{
  ts = millis();
  if (ts != prev_ts)
  {
    if (labs(ts - prev_ts) >= 1000)
    {
      flag = !flag;
 
      if (flag)
      {
          // blink ON durumu, gerekeni ekrana yaz
      }
      else
      {
          // blink OFF durumu, gerekeni ekrana yaz
      }

      prev_ts = ts;
    }
  }
}
Tamam abi bu şekilde düzelttim, çalışıyor. :saril:
 
O zaman sen en iyisi bu blink işini timer'a bağla ve bir kesme halletsin. Ondan sonra artık loop fonksiyonunda ne yaparsan yap muntazam bir şekilde blink gerçekleşir. Bundan baya önce ben bir örnek projede timer kesmesi yapılandırmasını yapmıştım.


C++:
/* tanimladigimiz kesme fonksiyonunun saniyede kac defa
   cagirilacagini belirleyen degisken */
int isr_rate = 10;

int blink = 1;

#define BLINK_PERIOD 10
int counter;
int flag;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);

  /* Atmel 328 in birinci timer'ini kesme kaynagi
     olarak yapilandiriyoruz */
  TCCR1A = 0;
  TCNT1 = 0;
  OCR1A = 16000000 / (isr_rate * 64) - 1;
  TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10);
  TIMSK1 |= (1 << OCIE1A);
}

ISR(TIMER1_COMPA_vect)
{
  if (counter == 0)
  {
    counter = BLINK_PERIOD;

    if (blink)
    {
      flag = !flag;
      if (flag)
      {
        digitalWrite(LED_BUILTIN, HIGH);
      }
      else
      {
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
  }
  else
  {
    --counter;
  }
}

void loop()
{
}
Abi millis ile yapıp void loop içine koyduğumuz zamanlama her şeyi etkiliyor galiba.
Reset barını doldururken belli bir hızın altına düşüremiyorum bir türlü.
Şimdi bu senin timer'ı kullanayım dedim ama kodlara baktım atmel 328'in çipine göre yazmışsın kodları.
Benim öyle bir zamanlama fonksiyonuna ihtiyacım var ki nerede kaç saniye ile çağırırsam orada çalışacak bir şey.
Misal timer(1000); yapınca istediğim yerde 1sn sayacak başka hiç bir yere etki etmeyecek. Böyle bir şey mümkün mü acaba?
 
Abi millis ile yapıp void loop içine koyduğumuz zamanlama her şeyi etkiliyor galiba.
Reset barını doldururken belli bir hızın altına düşüremiyorum bir türlü.
Şimdi bu senin timer'ı kullanayım dedim ama kodlara baktım atmel 328'in çipine göre yazmışsın kodları.
Benim öyle bir zamanlama fonksiyonuna ihtiyacım var ki nerede kaç saniye ile çağırırsam orada çalışacak bir şey.
Misal timer(1000); yapınca istediğim yerde 1sn sayacak başka hiç bir yere etki etmeyecek. Böyle bir şey mümkün mü acaba?
Bunu mutlaka yapabiliyoruz.

Delta markalı en ucuz plc'lerde dahi 1 saniyelik hazır sayaçlar var.
Ama bilmiyoruz c++'da nası yapabiliriz bunu :(
 
millis fonksiyonu senin yazdığın kodu etkilememesi lazım. Tam olarak zamanı nasıl alıyor bilmiyorum ama arka planda çalışan bir timer registerini okuyordur. Debugger ile bir bakalım. Bunun için ayrı bir konu açacağım.
 
İçinde millis fonksiyonu çağrılan arduino programının ELF dosyasını yükledim ve millis fonksiyonuna baktım. Fonksiyonun tek yaptığı şey, interruptları kapatıyor, sonra timer0 ın sayaç registerini okuyor ve interrupt'ları eski haline getiriyor. İnterrupt'ların kapalı olduğu süre mikrosaniye bile değil.

1650317712072.png
 
İçinde millis fonksiyonu çağrılan arduino programının ELF dosyasını yükledim ve millis fonksiyonuna baktım. Fonksiyonun tek yaptığı şey, interruptları kapatıyor, sonra timer0 ın sayaç registerini okuyor ve interrupt'ları eski haline getiriyor. İnterrupt'ların kapalı olduğu süre mikrosaniye bile değil.

16736 eklentisine bak
Ben anlamadım. :oops:
 
İçinde millis fonksiyonu çağrılan arduino programının ELF dosyasını yükledim ve millis fonksiyonuna baktım. Fonksiyonun tek yaptığı şey, interruptları kapatıyor, sonra timer0 ın sayaç registerini okuyor ve interrupt'ları eski haline getiriyor. İnterrupt'ların kapalı olduğu süre mikrosaniye bile değil.

16736 eklentisine bak
Migrenim yüzünden tam takip edemedim. Şimdi biraz baktım.
Anladığım kadarıyla millis() "timer" dan her an anlık değer alıyor. Yani aslında "timer" yazmakla "millis()" yazmak aynı şey. millis() sadece bu timer'a ulaşmanın bir yolu gibi. Bizim asıl sayacımız "if" içerisinde yazdığımız sayısal değer. millis() fonksiyonunu "void loop()" başında çağırdıktan sonra istediğimiz yerde "if" koşulu ile sayaç oluşturabiliriz. Buraya kadar doğru anladığımı düşünüyorum. Yanlışsam beni düzeltin.

Şimdi başka bir konu var.
Herşeye rağmen zamana istediğim gibi hükmedemeyince kodun tamamında ne kadar delay, delayMicroseconds, millis vs. varsa kapattım.
Sonra ekrandaki reset barı takip etmek üzere çalıştırdım. Tüm sayaçları bu adımda kapattığım için reset barının anlık olarak dolup cihazı resetlemesini umuyordum ama olmadı. Her zamanki gibi belli bir hızda doluyor ve altına inmiyor.
Kısacası nedenini anlayamadığım bir şekilde yaptığım testlere göre yaklaşık olarak 400ms nin altına atanmış hiç bir sayaç çalışmıyor.
Yani delay(10); da yapsak delay(400); gibi çalışıyor. Ancak 400ms nin üstünde bir değer atandığında gözle görülür bir yavaşlama olmaya başlıyor.

İlk aklıma gelen ekranın yenileme hızı oldu ama bunun bir etken olmadığını hemen anladım. Çünkü voltajı ölçmesi gereken ADC pini boşta olduğu için ekranda çok hızlı değişebilen oynak bir voltaj görebiliyorum zaten.

Başka bir deneme yapmaya karar verdim.
Bildiğiniz üzere ekrana bir şey yazdırabilmemiz için kodlarımızı u8g2.clearBuffer ve u8g2.sendBuffer arasına yazmamız şart.
Benim kodlarım şu şekilde:
Bu kod bloğunda bekleme süresini microsaniye cinsinden vermeme rağmen yaklaşık olarak 400 milisaniye de bir döngü oluyor.
C++:
if (butonDurum == 0 && menuOk == 1) { // Reset butonuna basıldıysa
        for (int i = 0; i < 63; i++) {
          u8g2.clearBuffer();
          drawF(0, 0, 128, 64, 1, 1, 126, 62);
          u8g2.setFont(u8g2_font_nokiafc22_tu);
          u8g2.drawStr(27, 30, "RESETLENIYOR...");
          u8g2.drawFrame(29, 40, 63, 7);
          u8g2.drawBox(30, 40, i, 6);
          delayMicroseconds(10000);
          u8g2.sendBuffer();
        }
        resets();
      }

Daha sonra bu sorunun ekran kütüphanesinden kaynaklı olup olmadığını anlamak için for döngüsünü u8g2.clearBuffer ve u8g2.sendBuffer dışında bir yere yazıp Serial Monitörden takip etmeye karar verdim.
Buradaki kodlar ise şöyle:
Kodları dışarı yazıp serial monitörden takip ettiğim de gördümki 400ms süre altına inebiliyorum.
Bu durumda ekrana yazdıracağımız değerler 400ms'nin altında olamayacak malesef.
C++:
if (butonDurum == 0 && menuOk == 1) { // Reset butonuna basıldıysa
         for(int x=0;x<=62;x++){
            Serial.print("Sayaç: ");
            Serial.println(x);
            delay(100);
          }
        resets();
      }
 
Son düzenleme:
Abi çok uğraştım ama 2.0'daki debug sadece MKR isimli arduino kartlarında Nano ioT kartında ve zero modelinde olduğunu yazmışlar. Bunu uno nano için nasıl çalıştırırız bulamadım
 
Abi çok uğraştım ama 2.0'daki debug sadece MKR isimli arduino kartlarında Nano ioT kartında ve zero modelinde olduğunu yazmışlar. Bunu uno nano için nasıl çalıştırırız bulamadım
Salla ben zaten buldum sorunu.
 
Son düzenleme:
Eğer bir kod bloğunun ne kadar sürede işlediğini net bir şekilde ölçmek istiyorsan, girişinde bir GPIO'yu high yap, çıkışında da low yap. sonra da osiloskop ile palsın uzunluğunu ölç. Bu sana tam olarak hangi fonksiyon çok uzun sürer söyler.

Senin yukarıda koyduğun grafik kodunun 400 ms sürmesi çok tuhaf. Bu kadar sürmemesi lazım, gene başka bir problem var. Şöyle minimal bir kod yaz. Programda başka hiçbirşey olmasın. Sonra da osiloskop ile tanımladığın GPIO ya bak. Bir karedalga göreceksin ve onun yükselen ve düşen kenarı arasındaki süre, aşağıdaki kodun çalışma süresi olacak. Eğer daha önce dediğin gibi display PICO'ya paralel arabirim ile bağlı ise bunun milisaniyeler mertebesinde bitiyor olması lazım.

C++:
void loop()
{
    digitalWrite(BOS_BIR_GPIO, HIGH);
    u8g2.clearBuffer();
    drawF(0, 0, 128, 64, 1, 1, 126, 62);
    u8g2.setFont(u8g2_font_nokiafc22_tu);
    u8g2.drawStr(27, 30, "RESETLENIYOR...");
    u8g2.drawFrame(29, 40, 63, 7);
    u8g2.drawBox(30, 40, i, 6);
    u8g2.sendBuffer();   
    digitalWrite(BOS_BIR_GPIO, LOW);
}
 
Eğer bir kod bloğunun ne kadar sürede işlediğini net bir şekilde ölçmek istiyorsan, girişinde bir GPIO'yu high yap, çıkışında da low yap. sonra da osiloskop ile palsın uzunluğunu ölç. Bu sana tam olarak hangi fonksiyon çok uzun sürer söyler.

Senin yukarıda koyduğun grafik kodunun 400 ms sürmesi çok tuhaf. Bu kadar sürmemesi lazım, gene başka bir problem var. Şöyle minimal bir kod yaz. Programda başka hiçbirşey olmasın. Sonra da osiloskop ile tanımladığın GPIO ya bak. Bir karedalga göreceksin ve onun yükselen ve düşen kenarı arasındaki süre, aşağıdaki kodun çalışma süresi olacak. Eğer daha önce dediğin gibi display PICO'ya paralel arabirim ile bağlı ise bunun milisaniyeler mertebesinde bitiyor olması lazım.

C++:
void loop()
{
    digitalWrite(BOS_BIR_GPIO, HIGH);
    u8g2.clearBuffer();
    drawF(0, 0, 128, 64, 1, 1, 126, 62);
    u8g2.setFont(u8g2_font_nokiafc22_tu);
    u8g2.drawStr(27, 30, "RESETLENIYOR...");
    u8g2.drawFrame(29, 40, 63, 7);
    u8g2.drawBox(30, 40, i, 6);
    u8g2.sendBuffer();
    digitalWrite(BOS_BIR_GPIO, LOW);
}
Abi sorun sanırım for döngüsünde.
Aşağıdaki görsel for döngüsü olmadanki çalışma şekli. Tam kare dalgayı görecek kadar yakınlaştıramadım ama görebildiğim kadarıyla en uzun aralık 8,93ms.
write_1.png




Bu da for döngüsünün içinde u8g2.sendBuffer'ın 63 defa gönderilmesi sonucu çıkan ekran. 338.78ms sürüyor.
trigger.png
 
Son düzenleme:
Yukarıdaki kod bloğu 63 defa gönderiliyorsa 400 ms sürebilir. Peki neden 63 defa gönderilmesi gerekiyor? Ekrana ne yazılacaksa bir kere yazdırmak yetmiyor mu?
 
Yukarıdaki kod bloğu 63 defa gönderiliyorsa 400 ms sürebilir. Peki neden 63 defa gönderilmesi gerekiyor? Ekrana ne yazılacaksa bir kere yazdırmak yetmiyor mu?
Abi o reset barı dolduran kod. Tek tek gönderilmesi gerek. Ona yapabileceğim tek şey i değişkeninin değerini 2 artırıp 63 yerine 32 döngüye düşürmek olur. Bu sayede istediğim hızda ulaşabileceğimi umuyorum.

Beni düşündüren başka bir yerde daha bu kısıtlayama takılıyor olmam.
Mesela şurada for döngüsü ile alakası olmayan bir kod bloğu var.
Burada senin millis() ile oluşturduğun kodu kullanarak "FAN" ibaresinin 100ms aralıkla yanıp sönmesini istiyorum ama yine yaklaşık 400ms de bir dönüyor. 500-600ms yaptım mı değeri ancak görebiliyorum yavaşladığını.

For döngüsü şarta bağlı olduğu için sadece şart sağlandığında çalışması gerekir ama sanki sürekli çalışıyor gibi bir durum var.
Yada yine başka bir yerde bir şeyler oluyor.
C++:
  if (temp >= 23) {
    flag = !flag;
    if (flag)
    {
      u8g2.drawLine(116, 25, 116, 40);
      u8g2.drawLine(123, 25, 123, 40);
      u8g2.setFont(u8g2_font_u8glib_4_tr);
      if (labs(ts - prev_ts) >= 100)
      {
        u8g2.drawStr(118, 30, "F");
        u8g2.drawStr(118, 35, "A");
        u8g2.drawStr(118, 40, "N");
        prev_ts = ts;
      }
    }
 
Yukarıdaki kod bloğu 63 defa gönderiliyorsa 400 ms sürebilir. Peki neden 63 defa gönderilmesi gerekiyor? Ekrana ne yazılacaksa bir kere yazdırmak yetmiyor mu?

Yav aslında gene de sürmemesi lazım :cheeky2: Paralel bus'tan 1 KByte veri gönderiyorsun sonuçta. Belki ekran belleğine yazılırken biraz formatlanıyordur ama gene de bu süre çok abzürt. Bir şekilde paralel bus'a veri yazarken çok büyük bir blokaj oluyor.

Sana şöyle örnek vereyim. Ben şu anda üzerinde çalıştığım projede 32 bit Renesas işlemcisi kullanıyorum. Bu ARM bazlı bir işlemci ve 120 MHz saat hızında çalışıyor. Benim kullandığım ekrana TFT veri gönderirken saniyede 120 MİLYON adet 16 bit veri gönderebiliyorum! Ama ben kullandığım ekrana uygun olsun diye şu anda 30 MByte/s şeklinde sınırlandırdım.

Senin kullandığın işlemci de 32 bit ARM bazlı işlemci ve 133 MHz saat hızında çalışıyor, yani Renesas'tan daha performanslı. Paralel bus'tan çok hızlı veri transferi yapabiliyor olman lazım. Buradaki tek kısıtlama, ekran ne kadar hızla veri kabul edebiliyor.
 

Çevrimiçi personel

Forum istatistikleri

Konular
5,788
Mesajlar
99,008
Üyeler
2,464
Son üye
s4met

Son kaynaklar

Son profil mesajları

cemalettin keçeci wrote on HaydarBaris's profile.
barış kardeşim bende bu sene akıllı denizaltı projesine girdim ve sensörleri arastırıyorum tam olarak hangi sensör ve markaları kullandınız yardımcı olabilir misin?
m.white wrote on Altair's profile.
İyi akşamlar.Arabanız ne marka ve sorunu nedir.Ben araba tamircisi değilim ama tamirden anlarım.
* En mühim ve feyizli vazifelerimiz millî eğitim işleridir. Millî eğitim işlerinde mutlaka muzaffer olmak lâzımdır. Bir milletin hakikî kurtuluşu ancak bu suretle olur. (1922)
Kesici/Spindle hızı hesaplamak için SpreadSheet UDF'leri kullanın, hesap makinesi çok eski kalan bir yöntem :)
Dr. Bülent Başaran,
Elektrik ve Elektronik Mühendisi
Yonga Tasarım Özdevinimcisi
Üç güzel "çocuk" babası
Ortahisar/Ürgüp/Konya/Ankara/Pittsburgh/San Francisco/Atlanta/Alaçatı/Taşucu...

Back
Top