Ekranlı Servo Tester

Yahu kulaklarım o kadar çok çınladı ki ancak yeni kendime gelebildim. Sümer abi,

hani hazır yazılmış kodu kütüphane haline getireceğimden değil ama :evil: gene de kodunu görebilsek ne güzel olurdu diyorum :D ... Ne bileyim, koda yorum olarak eklenmiş "şuraya deadband ekledim", "şurada titreşimi kaldırdım", "burada interruptlara şöyle yaptım" gibi satırlarda olsa, hani olmazda, kodu hızlı bir şekilde kütüphane haline getireceklere kolaylık olurdu ...

Bu arada eline sağlık Sümer abi :D ...

Hemen geliyor. En son modelimizin (7 segment LED göstergeli) kodu: (Yorumlar yetersiz olabilir)

Kod:
/*
   Atmega 328 @ 16MHz external
   Çıkış PD0
   Buton PB0
   Rotary Encoder A PB2 PCINT2
   Rotary Encoder B PD5 PCINT21
   mode0 Center
   mode1 Kaba adımlı Coarse
   mode2 Normal (hassas adımlı) Fine
   mode3 Sweep
   Shift registerli 4 haneli 7 segment display kullanılıyor
   SCLK PC3
   RCLK PC4
   DIO PC5
   Power On sırasında butona basılı ise 760 - 1520 seçimi yapılıyor
*/


#define buttonpin 8
#define rotaryA 10
#define rotaryB 5
#define pwmpin 0
#define SCLK 17
#define RCLK 18
#define DIO 19

volatile unsigned int pwm = 1520;
volatile unsigned int dolgu;
unsigned int prevpwm = 1520;
unsigned int oldpwm = 1520;
boolean button;
byte mode;
byte stp = 5;
boolean dir = 1;
volatile boolean pwmon;
volatile boolean slow = 1; // 1: 1520 uS, 0: 760 uS
volatile boolean rA;
volatile boolean rB;

volatile byte pointer;
byte bitmap[10]; // 7 segment digit datasını tutuyor
byte buf[4]; // Devir değerini alfanümerik olarak tutuyor
volatile byte prtbuf[4]; // Devir değerinin digit datasına çevrilmiş halini tutuyor
byte rowbyte;

byte sweeppointer;
byte sweeppointercounter;
byte sweepfactor;

boolean working;


ISR(TIMER1_COMPA_vect)
{
  digitalWrite(pwmpin, LOW);
  if (pwmon)
  {
    pwmon = 0;
    TCNT1 = 0;
    OCR1A = dolgu * (slow + 1);
  }
  else
  {
    pwmon = 1;
    digitalWrite(pwmpin, HIGH);
    TCNT1 = 0;
    OCR1A = pwm * (slow + 1);
  }
}

ISR(TIMER2_OVF_vect)
{
  sei(); // İşte meşhur titreşim önleyici satır! Interrupt içinde interrupt açılıyor.
  TCNT2 = 17;
  LED_OUT(prtbuf[pointer]);
  switch (pointer)
  {
    case 0:
      LED_OUT(8);
      break;
    case 1:
      LED_OUT(4);
      break;
    case 2:
      LED_OUT(2);
      break;
    case 3:
      LED_OUT(1);
      break;
  }
  digitalWrite(RCLK, LOW);
  digitalWrite(RCLK, HIGH);
  pointer++;
  if (pointer > 3) pointer = 0;
}


ISR(PCINT0_vect)
{
  rA = digitalRead(rotaryA);
  rB = digitalRead(rotaryB);
  if (rA)
  {
    if ((mode == 1) || (mode == 2)) //  coarse / fine
    {
      if (rA == rB)
      {
        if (mode == 2) pwm--;
        if (mode == 1) pwm = pwm - 8;
      }
      else
      {
        if (mode == 2) pwm++;
        if (mode == 1) pwm = pwm + 8;
      }
    }
    if (mode == 3) // sweep
    {
      if (rA == rB)
      {
        stp--;
        if (stp < 1) stp = 1;
      }
      else
      {
        stp++;
        if (stp > 20) stp = 20;
      }
    }
  }
}

void setup()
{
  pinMode(buttonpin, INPUT_PULLUP);
  pinMode(rotaryA, INPUT_PULLUP);
  pinMode(rotaryB, INPUT_PULLUP);
  pinMode(pwmpin, OUTPUT);
  pinMode(RCLK, OUTPUT);
  pinMode(SCLK, OUTPUT);
  pinMode(DIO, OUTPUT);
  bitmap[0] = B11000000;
  bitmap[1] = B11111001;
  bitmap[2] = B10100100;
  bitmap[3] = B10110000;
  bitmap[4] = B10011001;
  bitmap[5] = B10010010;
  bitmap[6] = B10000010;
  bitmap[7] = B11111000;
  bitmap[8] = B10000000;
  bitmap[9] = B10010000;
  oldpwm = pwm;
  cli();
  TCCR1A = 0;
  TCCR1B = B00000010; // Timer1 prescaler 8
  TCCR1C = 0;
  TCCR2A = 0;
  TCCR2B = B00000100; // Timer2 prescaler 256
  TIMSK1 = 2; // OCR1A interrupt enabled
  TIMSK2 = 1; // Timer2 overflow interrupt enabled
  PCICR = 1; // PCINT0 Enabled
  PCMSK0 = B00000100; // PCI2 enabled (PB2, Arduino 10)
  sei();
  if (!digitalRead(buttonpin))
  {
    delay(10);
    if (!digitalRead(buttonpin)) changespeed();
    while (!digitalRead(buttonpin));
  }
}

void loop()
{
  working = 1;
  if (pwm < 800) pwm = 800;
  if (pwm > 2200) pwm = 2200;
  button = digitalRead(buttonpin);
  if (!button)
  {
    delay(10);
    button = digitalRead(buttonpin);
    if (!button) changemode();
  }
  if (mode == 3)
  {
    printout(stp);
  }
  else
  {
    if(slow)
    {
      printout(pwm);
    }
    else
    {
      printout(pwm / 2);
    }
  }
  switch (mode)
  {
    case 0:
      midoutput();
      break;
    case 1:
      normaloutput();
      break;
    case 2:
      normaloutput();
      break;
    case 3:
      sweep();
      break;
  }
}

void normaloutput()
{
  dolgu = 20000 - pwm;
}

void midoutput()
{
  pwm = 1520;
  dolgu = 18480;
}

void sweep()
{
  if (dir)
  {
    pwm = prevpwm + stp;
    if (pwm > 2200)
    {
      pwm = 2200;
      dir = 0;
    }
  }
  else
  {
    pwm = prevpwm - stp;
    if (pwm < 800)
    {
      pwm = 800;
      dir = 1;
    }
  }
  prevpwm = pwm;
  dolgu = 20000 - pwm;
  delay(10);
}

void changemode()
{
  mode++;
  if (mode > 3) mode = 0;
  if (mode == 3) oldpwm = pwm;
  if (mode == 1) pwm = oldpwm;
  delay(10);
  while (!digitalRead(buttonpin));
}

void changespeed()
{
  while (!digitalRead(buttonpin)); // Buton bırakılana kadar bekliyoruz
  delay(10); // Debounce
  while (!digitalRead(buttonpin)); // Buton bırakılana kadar bekliyoruz
  while (digitalRead(buttonpin))
  {
    if (slow)
    {
      printout(1520);
    }
    else
    {
      printout(760);
    }
    if (digitalRead(rotaryB))
    {
      delay(10);
      if (digitalRead(rotaryB))
      {
        slow = !slow;
        while (digitalRead(rotaryB))
        {
          if (!digitalRead(buttonpin))
          {
            slow = !slow;
            return;
          }
        }
      }
    }
  }
}


void printout(unsigned int x)
{
  buf[0] = x / 1000;
  buf[1] = (x - 1000 * buf[0]) / 100;
  buf[2] = (x - 1000 * buf[0] - 100 * buf[1]) / 10;
  buf[3] = x % 10;
  if (buf[0] == 0)
  {
    buf[0] = 255;
    if (buf[1] == 0)
    {
      buf[1] = 255;
      if (buf[2] == 0) buf[2] = 255;
    }
  }
  for (int n = 0; n < 4; n++)
  {
    if (buf[n] < 10)
    {
      prtbuf[n] = bitmap[buf[n]];
    }
    else
    {
      prtbuf[n] = 255;
    }
  }
  dp_OFF();
  if (working)
  {
    if (mode < 3)
    {
      dp_SET(mode);
    }
    else // Sweep modunda Decimal Point hareketli
    {
      sweeppointercounter++;
      sweepfactor = map(stp, 1, 20, 75, 30); // Decimal Point hareket hızını belirliyor
      if (sweeppointercounter > sweepfactor)
      {
        sweeppointercounter = 0;
        sweeppointer++;
        if (sweeppointer > 3) sweeppointer = 0;
      }
      dp_SET(sweeppointer);
    }
  }
}

void LED_OUT(unsigned char X)
{
  unsigned char i;
  for (i = 8; i >= 1; i--)
  {
    if (X & 0x80)
    {
      digitalWrite(DIO, HIGH);
    }
    else
    {
      digitalWrite(DIO, LOW);
    }
    X <<= 1;
    digitalWrite(SCLK, LOW);
    digitalWrite(SCLK, HIGH);
  }
}

void dp_OFF()
{
  for (int m = 0; m < 4; m++)
    prtbuf[m] |= B10000000; // All Decimal Points OFF
}

void dp_SET(byte z)
{
  prtbuf[z] &= B01111111; // Selected Decimal Point ON
}
 
Al işte, işin yoksa kütüphaneyi tık tık yerine koymak yerine ISR içinde niye sei() kullanılır diye oku...
 
Al işte, işin yoksa kütüphaneyi tık tık yerine koymak yerine ISR içinde niye sei() kullanılır diye oku...
Yahu elalemin yazdığı ne idüğü belirsiz kütüphaneyi niye koyayım oraya ki?! :p
Zavallı Atmega'ya üç interrupt birden yüklemişim zaten. Var mı bunu yapacak library!? :D
 
Yahu elalemin yazdığı ne idüğü belirsiz kütüphaneyi niye koyayım oraya ki?! :p
Zavallı Atmega'ya üç interrupt birden yüklemişim zaten. Var mı bunu yapacak library!? :D
Abi zaten ben bunu sana değil kendime söylüyorum. Bunu yapacak bir libray yok, gıcıklığına oturmuş bunu Sümer abi yapmış, bu kodu kütüphaneye çevirebilmem için ISR içinde niye tekrar interrupt açılması gerektiğini, ya da ne zaman açılması gerektiğini okuyup anlamam gerekiyor.
 
Abi zaten ben bunu sana değil kendime söylüyorum. Bunu yapacak bir libray yok, gıcıklığına oturmuş bunu Sümer abi yapmış, bu kodu kütüphaneye çevirebilmem için ISR içinde niye tekrar interrupt açılması gerektiğini, ya da ne zaman açılması gerektiğini okuyup anlamam gerekiyor.
Üç interrupttan biri time critical, (PWM darbesini oluşturan) diğer ikisi (rotary encoderi okuyan ve 7 segment göstergeyi süren) çok az time ciritical. O nedenle daha az time critical olanların ISR'lerinde interruptları açmak lazım ki üretilen PWM darbesinin süresinde oynama olmasın. Yani aslında diğer ISR'nin başına da sei(); komutunu yazmam lazımdı. Ancak butonu çevirirken oluşacak titreşim pek farkedilmediği için bu hali ile de çalışıyor.
Ama display sürülmesi sürekli yapıldığı için sık sık çakışma olabiliyordu ve gerçekten de servo titriyordu. Tek satır işi bitirdi. :)
 
  • Beğen
Tepkiler: Ali Emre KAYGIN
Bugün Sümer abimin servo tester' ı denedim.Harika çalışıyor :thumbup:
Hakan’ım elle bazı servoların zor hareket etmesi normal. Bazen benim de başıma geliyor. Bu durumda üniteyi değiştirip denemek ya da mevcut üniteyi resetleyip yeniden ayarlamak bir seçenek olabilir.
 
Ben üniteyi de bir değiştireyim diyorum , elimde bir tane tarot zyxS var, onu kullanacağım , sorun yine olursa artık ne zaman 3 tane birden servo alırım , o zamana kadar makine yatar.
 
  • Beğen
Tepkiler: Türker Akgün