- Katılım
- 17 Eyl 2013
- Mesajlar
- 9,084
- Tepkime puanı
- 23,743
- Yaş
- 62
- Konum
- İstanbul
- Web sitesi
- www.sumeryamaner.com
- İlgi Alanı
- Uçak
Servo senkronizasyon modülü
Bu konuyu 6 Mart günü açmışım. Bugün 19 Mart ve planlanan modülün "Pro" ve "Lite" versiyonları kullanıma hazır. Tüm testler ve debug işlemlerinden geçtiler.
Arşivde bulunması açısından kodları buraya koyuyorum. Bana göre gerçekten de ilginç programlama teknikleri içeriyorlar.
Önce "Pro" versiyonu. Üç servoya kadar hem merkez hem de iki uç ayrı ayrı ayarlanabiliyor. Çok gerekli mi bilemiyorum ama Futaba'nın modülü de böyle.
Bu konuyu 6 Mart günü açmışım. Bugün 19 Mart ve planlanan modülün "Pro" ve "Lite" versiyonları kullanıma hazır. Tüm testler ve debug işlemlerinden geçtiler.
Arşivde bulunması açısından kodları buraya koyuyorum. Bana göre gerçekten de ilginç programlama teknikleri içeriyorlar.
Önce "Pro" versiyonu. Üç servoya kadar hem merkez hem de iki uç ayrı ayrı ayarlanabiliyor. Çok gerekli mi bilemiyorum ama Futaba'nın modülü de böyle.
Kod:
#include <EEPROM.h>
const byte servoin = 3;
const byte servo1 = 6;
const byte servo2 = 5;
const byte servo3 = 4;
const byte mode1 = 14;
const byte mode2 = 15;
const byte decrease = 16;
const byte increase = 17;
const byte centerLED = 12;
const byte epa1LED = 11;
const byte epa2LED = 10;
const byte servo1LED = 9;
const byte servo2LED = 8;
const byte servo3LED = 7;
volatile int servoinPWM = 1500;
volatile int servo1PWM = 1500;
volatile int servo2PWM = 1500;
volatile int servo3PWM = 1500;
volatile int intcounter = 0;
volatile byte sregvalue; // ISR sırasında status registerini saklıyor
long x;
volatile byte progflag = 0;
volatile byte keyflag = 0;
byte eepromerror = 0;
byte hibyte;
byte lobyte;
unsigned long timer;
unsigned long fark;
// CNT değerleri - 700 ile + 700 arası, EPA değerleri 0 - 700 arası
int servo1cnt;
unsigned int servo1epa1;
unsigned int servo1epa2;
int servo2cnt;
unsigned int servo2epa1;
unsigned int servo2epa2;
int servo3cnt;
unsigned int servo3epa1;
unsigned int servo3epa2;
volatile byte LED = 0;
byte keypress = B00111111;
int key = 0;
int key1 = 0;
int key2 = 0;
int b = 0;
const int debounce = 200;
const int bounce = 160;
void timerinit()
{
noInterrupts(); // disable global interrupts
TCCR2A = 0; // prescaler 256
TCCR2B = 0;
TCCR2B |= (0 << CS20);
TCCR2B |= (1 << CS21);
TCCR2B |= (1 << CS22);
TCNT2 = 0;
TIMSK2 |= (1 << TOIE2); // enable global interrupts
interrupts();
}
ISR(TIMER2_OVF_vect)
{
sregvalue = SREG;
intcounter++;
if (intcounter > 4)
{
intcounter = 0;
if (progflag == 0)
{
x = servoinPWM - 1500; // x -700 ile + 700 arasında bir değer alıyor
if (x < 0)
{
servo1PWM = 1500 + ((x * servo1epa1) / 700) + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
servo2PWM = 1500 + ((x * servo2epa1) / 700) + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
servo3PWM = 1500 + ((x * servo3epa1) / 700) + servo3cnt; //Servo3 için çıkış değeri oluşturuluyor
}
else
{
servo1PWM = ((x * servo1epa2) / 700) + 1500 + servo1cnt; //Servo1 için çıkış değeri oluşturuluyor
servo2PWM = ((x * servo2epa2) / 700) + 1500 + servo2cnt; //Servo2 için çıkış değeri oluşturuluyor
servo3PWM = ((x * servo3epa2) / 700) + 1500 + servo3cnt; //Servo3 için çıkış değeri oluşturuluyor
}
}
if (servoinPWM > 800)
{
digitalWrite(servo1, HIGH);
delayMicroseconds(servo1PWM);
digitalWrite(servo1, LOW);
digitalWrite(servo2, HIGH);
delayMicroseconds(servo2PWM);
digitalWrite(servo2, LOW);
digitalWrite(servo3, HIGH);
delayMicroseconds(servo3PWM);
digitalWrite(servo3, LOW);
}
}
SREG = sregvalue;
}
void setup()
{
pinMode(mode1, INPUT_PULLUP);
pinMode(mode2, INPUT_PULLUP);
pinMode(decrease, INPUT_PULLUP);
pinMode(increase, INPUT_PULLUP);
pinMode(centerLED, OUTPUT);
pinMode(epa1LED, OUTPUT);
pinMode(epa2LED, OUTPUT);
pinMode(servo1LED, OUTPUT);
pinMode(servo2LED, OUTPUT);
pinMode(servo3LED, OUTPUT);
pinMode(servo1, OUTPUT);
pinMode(servo2, OUTPUT);
pinMode(servo3, OUTPUT);
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
if ((digitalRead(mode1) == 0) && (digitalRead(mode2) == 0))
{
keyflag = 1;
}
delay(1000);
if ((digitalRead(mode1) == 0) && (digitalRead(mode2) == 0) && keyflag == 1)
{
progflag = 1;
flashleds2(); //Programlama moduna girildiğini göstermek için tüm LED'ler birlikte beş kez hızlıca yakılıp söndürülüyor.
}
else
{
flashleds(); //Normal modu göstermek için tüm LED'ler sıra ile bir kez yakılıp söndürülüyor
}
EEPROMtest();
if (eepromerror > 0) // EEPROM hatasında servo LED'lerini yakıp söndürerek beklemede kalıyoruz. Programa girmiyoruz. Güç kesilene kadar böyle devam.
{
while (eepromerror > 0)
{
digitalWrite(servo1, HIGH);
digitalWrite(servo2, HIGH);
digitalWrite(servo3, HIGH);
delay(300);
digitalWrite(servo1, LOW);
digitalWrite(servo2, LOW);
digitalWrite(servo3, LOW);
delay(300);
}
}
EEPROMoku();
delay(100);
timerinit();
}
void loop()
{
if (progflag == 0)
{
normal();
}
else
{
progmode();
}
}
void normal() // Programlama modunda değilsek loop()'tan sürekli bu işlev çağrılıyor
{
digitalWrite(servo1LED, LED);
if (LED == 0)
{
LED = 1;
}
else
{
LED = 0;
}
noInterrupts();
servoinPWM = pulseIn(servoin, HIGH, 21000); //Alıcıdan sinyali mikrosaniye olarak okuyoruz
x = servoinPWM;
interrupts();
}
void progmode() // Programlama modunda isek loop()'tan sürekli bu çağrılıyor
{
int servosira = 1; // 1 No'lu servo ile başlıyoruz
int islevsira = 1; // Center modu ile başlıyoruz. 1: Center, 2: Alt EPA, 3: Üst EPA
int pressedkey = 0; // 0: Key yok, 1: Mode1(servo), 2: Mode2(işlev), 3: Decrease, 4: Increase, 5: Exit
while (pressedkey < 5)
{
noInterrupts();
switch (islevsira)
{
case 1:
servo1PWM = 1500 + servo1cnt;
servo2PWM = 1500 + servo2cnt;
servo3PWM = 1500 + servo3cnt;
break;
case 2:
servo1PWM = 1500 + servo1cnt - servo1epa1;
servo2PWM = 1500 + servo2cnt - servo2epa1;
servo3PWM = 1500 + servo3cnt - servo3epa1;
break;
case 3:
servo1PWM = 1500 + servo1cnt + servo1epa2;
servo2PWM = 1500 + servo2cnt + servo2epa2;
servo3PWM = 1500 + servo3cnt + servo3epa2;
break;
}
servoinPWM = 1500;
interrupts();
pressedkey = button();
switch (pressedkey)
{
case 0:
break;
case 1:
servosira++;
if (servosira > 3) servosira = 1;
break;
case 2:
islevsira++;
if (islevsira > 3) islevsira = 1;
break;
case 3: // Burada o an seçili olan parametreyi bir azaltacağız. Range check yapıp düzelteceğiz.
if (servosira == 1)
{
switch (islevsira)
{
case 1:
servo1cnt = servo1cnt - 4;
if (servo1cnt < (-200)) servo1cnt = -200;
break;
case 2:
servo1epa1 = servo1epa1 - 4;
if (servo1epa1 < 1) servo1epa1 = 1;
break;
case 3:
servo1epa2 = servo1epa2 - 4;
if (servo1epa2 < 1) servo1epa2 = 1;
break;
}
}
if (servosira == 2)
{
switch (islevsira)
{
case 1:
servo2cnt = servo2cnt - 4;
if (servo2cnt < (-200)) servo2cnt = -200;
break;
case 2:
servo2epa1 = servo2epa1 - 4;
if (servo2epa1 < 1) servo2epa1 = 1;
break;
case 3:
servo2epa2 = servo2epa2 - 4;
if (servo2epa2 < 1) servo2epa2 = 1;
break;
}
}
if (servosira == 3)
{
switch (islevsira)
{
case 1:
servo3cnt = servo3cnt - 4;
if (servo3cnt < (-200)) servo3cnt = -200;
break;
case 2:
servo3epa1 = servo3epa1 - 4;
if (servo3epa1 < 1) servo3epa1 = 1;
break;
case 3:
servo3epa2 = servo3epa2 - 4;
if (servo3epa2 < 1) servo3epa2 = 1;
break;
}
}
break;
case 4: // Burada o an seçili olan parametreyi bir artıracağız. Range check yapıp düzelteceğiz.
if (servosira == 1)
{
switch (islevsira)
{
case 1:
servo1cnt = servo1cnt + 4;
if (servo1cnt > 200) servo1cnt = 200;
break;
case 2:
servo1epa1 = servo1epa1 + 4;
if (servo1epa1 > 700) servo1epa1 = 700;
break;
case 3:
servo1epa2 = servo1epa2 + 4;
if (servo1epa2 > 700) servo1epa2 = 700;
break;
}
}
if (servosira == 2)
{
switch (islevsira)
{
case 1:
servo2cnt = servo2cnt + 4;
if (servo2cnt > 200) servo2cnt = 200;
break;
case 2:
servo2epa1 = servo2epa1 + 4;
if (servo2epa1 > 700) servo2epa1 = 700;
break;
case 3:
servo2epa2 = servo2epa2 + 4;
if (servo2epa2 > 700) servo2epa2 = 700;
break;
}
}
if (servosira == 3)
{
switch (islevsira)
{
case 1:
servo3cnt = servo3cnt + 4;
if (servo3cnt > 200) servo3cnt = 200;
break;
case 2:
servo3epa1 = servo3epa1 + 4;
if (servo3epa1 > 700) servo3epa1 = 700;
break;
case 3:
servo3epa2 = servo3epa2 + 4;
if (servo3epa2 > 700) servo3epa2 = 700;
break;
}
}
break;
}
if (pressedkey > 0);
{
digitalWrite(centerLED, LOW);
digitalWrite(epa1LED, LOW);
digitalWrite(epa2LED, LOW);
digitalWrite(servo1LED, LOW);
digitalWrite(servo2LED, LOW);
digitalWrite(servo3LED, LOW);
switch (servosira)
{
case 1:
digitalWrite(servo1LED, HIGH);
break;
case 2:
digitalWrite(servo2LED, HIGH);
break;
case 3:
digitalWrite(servo3LED, HIGH);
break;
}
switch (islevsira)
{
case 1:
digitalWrite(centerLED, HIGH);
break;
case 2:
digitalWrite(epa1LED, HIGH);
break;
case 3:
digitalWrite(epa2LED, HIGH);
break;
}
}
}
EEPROMyaz();
while (1 == 1) // Burada artık programı kilitliyoruz. Servo LED'leri hızlı yanıp sönüyorlar. Artık programlama bitti. Sistemin resetlenmesi gerekiyor.
{
digitalWrite(servo1LED, HIGH);
digitalWrite(servo2LED, HIGH);
digitalWrite(servo3LED, HIGH);
delay(100);
digitalWrite(servo1LED, LOW);
digitalWrite(servo2LED, LOW);
digitalWrite(servo3LED, LOW);
delay(100);
}
}
void EEPROMoku()
{
noInterrupts();
servo1cnt = EEPROM.read(1) + 256 * EEPROM.read(0) - 2000;
servo1epa1 = EEPROM.read(3) + 256 * EEPROM.read(2);
servo1epa2 = EEPROM.read(5) + 256 * EEPROM.read(4);
servo2cnt = EEPROM.read(7) + 256 * EEPROM.read(6) - 2000;
servo2epa1 = EEPROM.read(9) + 256 * EEPROM.read(:coolxf:;
servo2epa2 = EEPROM.read(11) + 256 * EEPROM.read(10);
servo3cnt = EEPROM.read(13) + 256 * EEPROM.read(12) - 2000;
servo3epa1 = EEPROM.read(15) + 256 * EEPROM.read(14);
servo3epa2 = EEPROM.read(17) + 256 * EEPROM.read(16);
interrupts();
}
void EEPROMyaz()
{
noInterrupts();
hibyte = (servo1cnt + 2000) / 256;
lobyte = (servo1cnt + 2000) - 256 * hibyte;
EEPROM.write(0, hibyte);
EEPROM.write(1, lobyte);
hibyte = servo1epa1 / 256;
lobyte = servo1epa1 - 256 * hibyte;
EEPROM.write(2, hibyte);
EEPROM.write(3, lobyte);
hibyte = servo1epa2 / 256;
lobyte = servo1epa2 - 256 * hibyte;
EEPROM.write(4, hibyte);
EEPROM.write(5, lobyte);
hibyte = (servo2cnt + 2000) / 256;
lobyte = (servo2cnt + 2000) - 256 * hibyte;
EEPROM.write(6, hibyte);
EEPROM.write(7, lobyte);
hibyte = servo2epa1 / 256;
lobyte = servo2epa1 - 256 * hibyte;
EEPROM.write(8, hibyte);
EEPROM.write(9, lobyte);
hibyte = servo2epa2 / 256;
lobyte = servo2epa2 - 256 * hibyte;
EEPROM.write(10, hibyte);
EEPROM.write(11, lobyte);
hibyte = (servo3cnt + 2000) / 256;
lobyte = (servo3cnt + 2000) - 256 * hibyte;
EEPROM.write(12, hibyte);
EEPROM.write(13, lobyte);
hibyte = servo3epa1 / 256;
lobyte = servo3epa1 - 256 * hibyte;
EEPROM.write(14, hibyte);
EEPROM.write(15, lobyte);
hibyte = servo3epa2 / 256;
lobyte = servo3epa2 - 256 * hibyte;
EEPROM.write(16, hibyte);
EEPROM.write(17, lobyte);
interrupts();
}
void EEPROMtest() // EEPROM testi yapılıp flag ile sonuç bildiriliyor
{
eepromerror = 0;
unsigned long b = 0;
unsigned int temp;
for (int i = 0; i < 18; i++)
{
b = b + EEPROM.read(i);
}
if (b == 4590)
{
temp = EEPROM.read(0);
EEPROM.write(0, 0);
if (EEPROM.read(0) != 0)
{
eepromerror = 1;
}
EEPROM.write(0, temp);
}
}
int button() // 0: Geçerli tuş yok. 1: Mode1. 2: Mode2. 3: Decrease. 4: Increase. 5: Done.
{
key1 = buttonbas();
key2 = debouncebutton();
if ((key1 == key2) && ((key1 * key2) != 0))
{
return key1;
}
return 0;
}
int buttonbas()
{
keypress = PINC & B00001111;
for (int n = 0; n < 10; n++)
{
keypress &= PINC;
}
if (keypress == B00001100) return 5;
if (keypress == B00001110) return 1;
if (keypress == B00001101) return 2;
if (keypress == B00001011) return 3;
if (keypress == B00000111) return 4;
return 0;
}
int debouncebutton() //Buraya gelirken key1 değişkeni basıldığı belirlenen butonu içeriyor. Yani 0 - 5 arası bir değer.
{
if (key1 == 0) return key1; //Tuşa basılmamış ise hiçbir şey yapmadan geri dön
b = 0; //Sayaç sıfırlanıyor
for (int n = 0; n < debounce; n++)
{
key = buttonbas(); //Butonlar "debounce" kez okunuyor
if (key == key1) b++; //Eğer okunan değer ilk okunan değer ile aynı ise b sayacı bir artırılıyor
else if (key != 0) return 0; //Farklı bir değer okunduysa ve bu değer 0 değil ise bu durum bounce nedeniyle değil başka butona basma nedeniyle olmuştur. 0 döndürüyoruz.
}
if (b < bounce) return 0; //Okunan değerlerin en az % 80'i key1 ile aynı olmalı. Yoksa 0 döndürüyoruz
while (buttonbas() != 0) //Buraya geldiğimize göre "debounce" test okumasındaki değerlerin en az "bounce"'ı orijinal key1 değeri ile aynı demektir. Artık butonun bırakılmasını bekliyor ve key1 değerini döndürüyoruz
{
}
return key1;
}
void flashleds()
{
digitalWrite(centerLED, HIGH);
delay(200);
digitalWrite(centerLED, LOW);
digitalWrite(epa1LED, HIGH);
delay(200);
digitalWrite(epa1LED, LOW);
digitalWrite(epa2LED, HIGH);
delay(200);
digitalWrite(epa2LED, LOW);
digitalWrite(servo1LED, HIGH);
delay(200);
digitalWrite(servo1LED, LOW);
digitalWrite(servo2LED, HIGH);
delay(200);
digitalWrite(servo2LED, LOW);
digitalWrite(servo3LED, HIGH);
delay(200);
digitalWrite(servo3LED, LOW);
}
void flashleds2() //Tüm LED'leri birlikte beş kez hızlıca yakıp söndüren işlev
{
for (int n = 0; n < 5; n++)
{
digitalWrite(centerLED, HIGH);
digitalWrite(epa1LED, HIGH);
digitalWrite(epa2LED, HIGH);
digitalWrite(servo1LED, HIGH);
digitalWrite(servo2LED, HIGH);
digitalWrite(servo3LED, HIGH);
delay(200);
digitalWrite(centerLED, LOW);
digitalWrite(epa1LED, LOW);
digitalWrite(epa2LED, LOW);
digitalWrite(servo1LED, LOW);
digitalWrite(servo2LED, LOW);
digitalWrite(servo3LED, LOW);
delay(200);
}
}