void debounce() konusunda:
fonksiyon ve yapı hatalı çünkü
1- Bu fonksiyon PinSw'nin FALLING hâlinde yani *0'a çekildiğinde çağrılıyor. Dolayısıyla PinSw durumu zaten 0 demek ve siz if kontrolünde buton durumu 0 ise işlem yaptırmıyorsunuz. Yani fonksiyonu bypass ediyorsunuz. Bunun yerine fonksiyonu kullanmayacaksanız kesme hiç aktive etmeyin.
2- Kesmeler içerisinde değişken tanımlaması yapmamak gerekiyor,
3- boolean yerine bool değişkeninin daha kararlı çalıştığı Arduino referanslarında bahsediliyor.
4- Kesmeyi bu fonksiyondan çıkarken değil, bu fonksiyon yoluyla ürettiğiniz veriyi işledikten sonra yeniden aktive ediniz.
Kod:
void debounce() {
bool butonDurum = digitalRead(PinSw); // 2.Madde, Değişken kesme dışına alındı. 3.Madde "boolean" "bool" ile değiştirildi.
detachInterrupt(PinSw); // 1.Madde, Kesme Kapatıldı
if (butonDurum == 0) {
}
delayMicroseconds(5000);
}
1.Madde, Kesme Kapatıldı
2.Madde, Değişken kesme dışına alındı.
3.Madde "boolean" "bool" ile değiştirildi.
4.Madde bu kod buton kullanıldığı yerde, işlem bittikten sonra eklenecek.
Kod:
attachInterrupt(digitalPinToInterrupt(PinSw) , debounce , FALLING );
void encoder() konusunda:
1- delayMicroseconds() ile zaman kontrolü sağlıyorsunuz. Bu nedenle millis() fonksiyonu üzerinden ikinci bir kontrole gerek yok. Kesme içerisinde fazladan meşguliyet oluşturuyor.
2- Sayac değişkenini bu fonksiyon içerisinde işliyorsunuz, ancak bu değeri bu fonksiyondan çıktıktan sonra loop() fonksiyonu içerisinde sırası geldiğinde yazdırınız, çünkü kesmenin işleme hızı bu sebeple Serial.print kodunun çalışma hızına düşmekte bu nedenle sizin encoder hareketinizle oluşturulan senkronizasyon bozulmaktadır.
3- Kesmeyi bu fonksiyondan çıkarken değil, bu fonksiyon yoluyla ürettiğiniz veriyi işledikten sonra yeniden aktive ediniz.
Kod:
void encoder() {
PinDT = digitalRead(PinDt);
detachInterrupt(PinCLK);
if (PinDT == HIGH) {
sayac++;
Serial.print(sayac);
Serial.println(" : sag");
} else {
sayac--;
Serial.print(sayac);
Serial.println(" : sol");
}
delayMicroseconds(10000); //Burası Debounce süresi için 10 milisaniye gecikme vererek encoder pals okuma sıklığını saniyede en falza 100'e ayaralar.
oncekiZaman = millis();
}
1.Madde millis() fonksiyonu kaldırıldı.
2.Maddeyi tam anlayamadım. sayac değişkeni burada tanımlanıyor, daha sonra canım nerede isterse orada çağırıyorum zaten. Burada demek istediğiniz "fonksiyon içinde
serial.print
kullanma" mı? Eğer öyleyse işim bittiğinde bütün serial.print kodlarını temizleyeceğim zaten. Şimdilik bilgi almak amaçlı tutuyorum.
3.Madde debounce daki ile aynı mantık. sayac değişkenini kullan, işin bitince bu kod ile kesmeyi aktif et.
Kod:
attachInterrupt(digitalPinToInterrupt(PinCLK), encoder, FALLING);
void loop() konusunda:
1- İlk satırda rigth_btn ve left_btn pinlerinden okuduğunuz değerleri birer değişkene atayınız. digitalRead() fonksiyonu pinin bu fonksiyon ile kontrol edildiği andaki değerini size verir. Her okuduğunuzda yeni bir değer döndürebilir. Özellikle birbiriyle karşılaştıracağınız pinleri aynı anda kaydediniz ki if-else bloğu içerisinde mantık hatasına yol açacak durumlara mahal kalmasın. Sonra bu değişken üzerinden if-else blokları içerisinde bu değişkenler üzerinden kontrol gerçekleştiriniz. Böylece bu butonların ilk okunduğu andaki değerlerine göre doğru ve öngörülebilir kesin işlemler yapabilirsiniz, diğer türlü her okumada yeni durumları üzerinden kararsız okumalar meydana gelecektir. Yukarılarda
@semih_s pin durumlarını ilk satırdaki gibi aynı anda bir değişkene aktarmıştı, bu if-else içerisinde birbiriyle karşılaştırılacak pinleri bir değişkene kaydetmek için güzel bir yöntem.
2- Bir de right_btn basılı ise sayac değişkenini sıfırlıyorsunuz, ancak left_btn basılmış ise bunu yapmıyorsunuz neden?
Bu durumda bu kısımdaki kodlar şöyle olacaktır:
Kod:
byte butonlar = digitalRead(right_btn) + digitalRead(left_btn) << 1;
if (butonlar == 0b01) {//right_btn basılı durumu
sayac = 0;
kursor_konum++;
if (kursor_konum > 3) {kursor_konum = 0;}
} else if (butonlar == 0b10) { //left_btn basılı durumu
kursor_konum--;
if (kursor_konum < 1) {kursor_konum = 3;}
}
1.Maddeyi gayet iyi anladım. Sizin tanımladığınız şekilde kullanacağım.
2.Madde: Projede Maksimum akım değeimiz 5A olacak. Kürsor basamağımız 4 konumdan oluştuğu için ilk basamağı atlamak durumundaydım. Yani 00.00 da ilk basamağı atlayınca 05.00 A olacak şekilde yazdırmam gerekiyordu. O yüzeden sayacı ilk basamakta sıfırlayıp bu değeri, ilk basamağa yazdırıp direk ikinci basamağa geçirmek için o olay.
En son hatırladığım böyleydi. Ama başka bir şey içinde yapmış olabilirim. Şuan emin olamadım.
Bu durumda kodların en son düzenlenmiş hali şöyledir;
Kod:
#include <Arduino.h>
#include <U8g2lib.h>
#include "Wire.h"
#include "I2CKeyPad.h"
#include "hardware/watchdog.h"
/// 128x64 Ekran Tanımlaması ///////////////
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 18 /* A4 */ , /* data=*/ 17 /* A3 */, /* CS=*/ 16 /* A2 */, /* reset=*/ U8X8_PIN_NONE);
//U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /* clock=*/ 0, /* data=*/ 1, /* CS=*/ 10, /* reset=*/ 21);
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R0, /*PICO SPI CLOCK PİN clock=*/ 10 /* A4 */ , /*PICO SPI TX data=*/ 11 /* A3 */, /*PICO CHIP SELECT CS=*/ 13 /* A2 */, /* reset=*/ U8X8_PIN_NONE);
//Timur abinin kodları
#define MAX_VOLTAJ 30.0
#define MIN_VOLTAJ 0.0
unsigned int kursor_konum; // 0 .. 3 arasinda degisiyor. 0 en soldaki hane
float katsayilar[] = {10, 1, 0.1, 0.01};
float voltaj = 0;
volatile int sayac = 0;
// Encoder Pinleri /////////////////////
#define PinCLK 7
#define PinDt 8
#define PinSw 6
/// 4x Yön Tuşları ////////////////////////
#define up_btn 2 //19
#define right_btn 3 //18
#define down_btn 4 //17
#define left_btn 5 //16
volatile bool PinDT = LOW;
long oncekiZaman;
int ival;
static char buffer[50];
void setup(void) {
Serial.begin(115200);
Wire.setSDA(0);
Wire.setSCL(1);
Wire.begin();
u8g2.begin();
pinMode(PinCLK, INPUT);
pinMode(PinDt, INPUT);
pinMode(PinSw, INPUT_PULLUP);
pinMode(up_btn, INPUT);
pinMode(right_btn, INPUT);
pinMode(down_btn, INPUT);
pinMode(left_btn, INPUT);
attachInterrupt(digitalPinToInterrupt(PinCLK) , encoder , FALLING );//BAĞLI PIN LOW OLURSA KES
attachInterrupt(digitalPinToInterrupt(PinSw) , debounce , FALLING );//BAĞLI PIN LOW OLURSA KES
}
//// ÇERÇEVE OLUŞTURMA FONKSİYONU/////////////
void drawF(int x, int y, int width, int height, int x2, int y2, int width2, int height2) {
u8g2.drawFrame(x, y, width, height);
u8g2.drawFrame(x2, y2, width2, height2);
}
/// Rotary Encoder Buton Fonksiyonu ///////
void debounce() {
bool butonDurum = digitalRead(PinSw);
detachInterrupt(PinSw);
detachInterrupt(PinCLK);
if (butonDurum == 0) {
}
delayMicroseconds(5000);
}
void encoder() {
PinDT = digitalRead(PinDt);
detachInterrupt(PinCLK);
detachInterrupt(PinSw);
if (PinDT == HIGH) {
sayac++;
Serial.print(sayac);
Serial.println(" : sag");
} else {
sayac--;
Serial.print(sayac);
Serial.println(" : sol");
}
delayMicroseconds(10000); //Burası Debounce süresi için 10 milisaniye gecikme vererek encoder pals okuma sıklığını saniyede en falza 100'e ayaralar.
oncekiZaman = millis();
}
void loop(void) {
u8g2.clearBuffer();
byte butonlar = digitalRead(right_btn) + digitalRead(left_btn) << 1;
if (butonlar == 0b01) {//right_btn basılı durumu
sayac = 0;
kursor_konum++;
if (kursor_konum > 3) {
kursor_konum = 0;
}
} else if (butonlar == 0b10) { //left_btn basılı durumu
kursor_konum--;
if (kursor_konum < 1) {
kursor_konum = 3;
}
}
if (sayac) {
float yeni_voltaj = voltaj + sayac * katsayilar[kursor_konum];
if ((yeni_voltaj <= MAX_VOLTAJ) && (yeni_voltaj >= MIN_VOLTAJ))
{
voltaj = yeni_voltaj;
//ekrani_tazele();
}
sayac = 0;
attachInterrupt(digitalPinToInterrupt(PinCLK), encoder, FALLING);
attachInterrupt(digitalPinToInterrupt(PinSw) , debounce , FALLING );
}