Универсальный блок управления шаговым двигателем. Нужна помощь в написании программы для мотора.

Тема в разделе "Arduino & Shields", создана пользователем Visor5, 25 сен 2014.

  1. Visor5

    Visor5 Нуб

    Всем привет. Потихоньку пилю дальше свой блок управления шаговым мотором. Механическая часть оказалась самой простой и уже закончена на 90%. На 1-й фото видно как все подключено. В блоке 2 Ардуинки (Nano и Mini Pro), Nano показывает меню и график силы тока на дисплее, а Mini Pro должна управлять мотор шилдом (EasyDriver) и караулить 2 конечных выключателя. В зависимости от программы, при нажатии одного такого конечника должно происходить либо остановка мотора либо смена направления вращения на противоположную. Но на этом этапе осознал что написать программу намного сложнее чем я раньше думал.

    Если с первой Ардуинкой (Nano) все более менее ясно, меню показывает, кнопки считывает нормально, параметры мотора можно менять, показ графика силы тока прикручен. То 2-я Ардуинка не готова совершенно не могу придумать как синхронизировать параметры мотора на обоих платах. Как сделать чтобы ардуинка (номер 2, Mini Pro) и мотор крутила без остановки и следила за кнопками, при увеличении значений крутим быстрее, при уменьшении медленнее. 2 концевика хочу повесить на прерывания на Mini как раз 2 пина для этого есть. Уважаемы гуру программирования подскажите в какую сторону искать. Или существуют более простые пути реализации такого функционала?




    [​IMG] [​IMG] [​IMG]





    Скетч для первой Ардуинки ниже.
     
  2. Visor5

    Visor5 Нуб

    Что-то форум ругается "Пожалуйста, введите сообщение, размером не более чем 10000 символов.". Попробую код на 2-3 части разбить...

    Код (Text):
    #include <SPI.h>
    #include <AccelStepper.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_ST7735.h>

    /* Rotes Display 1,8" Fast Speed SPI:
    CS          -> 10
    A0    (DC) -> 9
    RESET (RST) -> 8
    SDA        -> 11
    SCK  (CLK) -> 13  */

    #define cs  10
    #define dc  9
    #define rst 8

    AccelStepper stepper (1, 5, 4); // Defaults to AccelStepper::FULL4WIRE (5 pins) on 4, 5, 6, 7, 12

    int MS_1 = 6;
    int MS_2 = 7;


    //#define Neutral 0
    #define Mode 1
    #define Up 2
    #define Down 3

    int stepsMotor = 200;                // Steps pro Umdrehung
    int divider = 8;                    //  Teiler für Mikrosteps
    int acceleration = 1000;
    int motorSpeed = 100;                //  steps pro sek
    int motorSpeedRPM = ((stepsMotor*motorSpeed*divider)/60);  // Umdrehungen pro Minute
    int motorRevolution = 10;            //  Umdrehungen
    int moveDirection = 1;              //  Richtung
    int stepsMode = 1;                  //  Microsteps Mode
    boolean motorGo = false;

    int pos = 36000;


    int buttonValue = 0;
    int selected = 0;
    int lastButtonState = 0;
    long lastDebounceTime = 0; long debounceDelay = 110;


    int menuState = 0;
    int xPos = 10;

    Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);


    void setup()
    {
      attachInterrupt(0, endSwitch1Arrive, RISING);
      attachInterrupt(1, endSwitch2Arrive, RISING);
      tft.initR(INITR_BLACKTAB);
      tft.setRotation(3);
      menuStart();
      Serial.begin(9600);
      delay(20);
    }



    void loop()
    {
      menuSelect();
      checkButton();
      tftUpDate();
      delay(20);
    }



    //////////////////////////////////////////////////////////////////////////////////////////////////////////
     
  3. Visor5

    Visor5 Нуб

    Код (Text):
    //////////////////////////////////////////////////////////

    void menuStart(){
      tft.fillScreen(ST7735_BLACK);
      tft.setTextColor(ST7735_GREEN);
      tft.setTextSize(1);
      tft.setCursor(0, 4);
      tft.println(" Display mode");
      tft.setCursor(0, 15);
      tft.println(" Steps per rev");
      tft.setCursor(0, 26);
      tft.println(" Speed rpm");
      tft.setCursor(0, 37);
      tft.println(" Revolutions");
      tft.setCursor(0, 48);
      tft.println(" Steps mode");  
      tft.fillRoundRect(15, 60, 76, 14, 4, ST7735_RED);
      tft.setCursor(23, 63);
      tft.setTextSize(1);
      tft.setTextColor(ST7735_WHITE);
      tft.println("START/STOP");
      tft.fillRoundRect(85, 3, 30, 10, 3, ST7735_GREEN);
      tft.fillRoundRect(85, 14, 30, 10, 3, ST7735_GREEN);
      tft.fillRoundRect(85, 25, 30, 10, 3, ST7735_GREEN);
      tft.fillRoundRect(85, 36, 30, 10, 3, ST7735_GREEN);
      tft.fillRoundRect(85, 47, 30, 10, 3, ST7735_GREEN);
      tft.setCursor(89, 48);
      tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
      tft.print("full");
     
      tft.fillRoundRect(122, 5, 35, 70, 4, ST7735_WHITE);
      tft.fillRoundRect(123, 7, 33, 66, 3, ST7735_RED);
      tft.drawRoundRect(124, 10, 31, 60, 3, ST7735_WHITE);
      tft.drawTriangle(139, 12 , 135, 20, 143, 20, ST7735_WHITE);
      tft.drawTriangle(139, 67 , 135, 59, 143, 59, ST7735_WHITE);
      tft.setCursor(130, 34);
      tft.setTextSize(1);
      tft.setTextColor(ST7735_WHITE);
      tft.println("to");
      tft.setCursor(128, 40);
      tft.print("move");
     
      axis_xy(14, 117, 60);
    // switchLeft();
    // switchRight();
    }



    void axis_xy(uint16_t x0, uint16_t y0, uint16_t lenght) {
      tft.drawFastHLine(x0, y0, lenght, ST7735_GREEN);
      tft.fillTriangle(x0+lenght+7, y0, x0+lenght, y0+2, x0+lenght, y0-2, ST7735_GREEN);
      tft.drawFastVLine(x0+20, y0-2, 5, ST7735_GREEN);
      tft.drawFastVLine(x0+40, y0-2, 5, ST7735_GREEN);
      tft.drawFastVLine(x0+60, y0-2, 5, ST7735_GREEN);

      tft.drawFastVLine(x0, y0-40, 40, ST7735_GREEN);
      tft.drawFastHLine(x0-2, y0+25, 5, ST7735_GREEN);
      tft.drawFastHLine(x0-2, y0-20, 5, ST7735_GREEN);
     
      tft.fillCircle(x0, y0, 2, ST7735_GREEN);
      tft.fillTriangle(x0, y0-45, x0+2, y0-40, x0-2, y0-40, ST7735_GREEN);
     
      tft.setCursor(x0-12, y0-42);
      tft.setTextColor(ST7735_GREEN);
      tft.setTextSize(1);
      tft.println("10 dA");
      tft.setCursor(x0-10, y0-22);
      tft.println("5");
      tft.setCursor(x0-8, y0+4);
      tft.println("0  5  10  15 min");  }



    void tftUpDate(){
      tft.setCursor(91, 4);
      tft.setTextSize(1);
      tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
      tft.print("S.M.");
      tft.setCursor(91, 15);
      tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
      tft.print(stepsMotor);
      tft.setCursor(91, 26);
      tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
      tft.print(motorSpeed);
      tft.setCursor(91, 37);
      tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
      tft.print(motorRevolution);
     
      if( (millis() % 20) == 0){
      int drawGraph = (motorSpeed/2);
      Serial.println(drawGraph);
      if(xPos >= 160 ){
        xPos = 10;
        tft.fillRect(10, 55, 150, 55, ST7735_BLACK);
      } else {
      xPos++;
      //tft.drawFastVLine(xPos, 125-drawGraph, drawGraph, ST7735_YELLOW);
      tft.drawPixel(xPos, 125-drawGraph, ST7735_RED);
     
      // oneDirection();
      }
    }
    }






    int checkButton(){
      int buttonState = analogRead(0);
      if(500<buttonState && buttonState <701) {
          menuState ++;
          Serial.print("menuState Änderung");
          Serial.println(menuState);
          return Mode;}
      if(350<buttonState && buttonState <501) {
          Serial.print("Up");
          return Up;}
      if(120<buttonState && buttonState <351) {
          Serial.print("Down");
          return Down;}
                                        // Logik für's Debouncen (=Entprellen):
      if(selected != lastButtonState) {
        lastDebounceTime = millis();
        lastButtonState = selected;
      }
      if ((millis() - lastDebounceTime) > debounceDelay) {
        if(selected == lastButtonState) {
          lastDebounceTime = millis();
          return selected;
        }
      }
    }

     
     
  4. Visor5

    Visor5 Нуб

    Код (Text):
    void menuSelect(){
      switch (menuState){
     
        case 0:
          delay(20);
          tft.drawRoundRect(121, 4, 37, 72, 4, ST7735_BLACK);
          tft.drawRoundRect(120, 3, 39, 74, 5, ST7735_BLACK);
          tft.drawRoundRect(0, 2, 121, 12, 4, ST7735_CYAN);
          tft.drawRoundRect(1, 3, 119, 10, 3, ST7735_CYAN);
          Serial.println( "Case 0 ");
            switch (checkButton()){
              case Up:
             
                break;
           
              case Down:
             
                break;
             
              case Mode:
                menuState--; }
          break;
       
        case 1:
          delay(20);
          tft.drawRoundRect(0, 2, 121, 12, 4, ST7735_BLACK);
          tft.drawRoundRect(1, 3, 119, 10, 3, ST7735_BLACK);  
          tft.drawRoundRect(0, 13, 121, 12, 4, ST7735_CYAN);
          tft.drawRoundRect(1, 14, 119, 10, 3, ST7735_CYAN);
          Serial.println( "Case 1 ");
            switch (checkButton()){
              case Up:
                stepsMotor++;
                break;
           
              case Down:
                stepsMotor--;
                break;
             
              case Mode:
                menuState--; }
            break;
         
        case 2:
          delay(20);
          tft.drawRoundRect(0, 13, 121, 12, 4, ST7735_BLACK);
          tft.drawRoundRect(1, 14, 119, 10, 3, ST7735_BLACK);
          tft.drawRoundRect(0, 24, 121, 12, 4, ST7735_CYAN);
          tft.drawRoundRect(1, 25, 119, 10, 3, ST7735_CYAN);
          Serial.println( "Case 2 ");
            switch (checkButton()){
              case Up:
                motorSpeed++;
                break;
           
              case Down:
                motorSpeed--;
                break;
             
              case Mode:
                menuState--; }
          break;
        case 3:
          delay(20);
          tft.drawRoundRect(0, 24, 121, 12, 4, ST7735_BLACK);
          tft.drawRoundRect(1, 25, 119, 10, 3, ST7735_BLACK);
          tft.drawRoundRect(0, 35, 121, 12, 4, ST7735_CYAN);
          tft.drawRoundRect(1, 36, 119, 10, 3, ST7735_CYAN);
          Serial.println( "Case 3 ");
            switch (checkButton()){
              case Up:
                motorRevolution++;
                break;
           
              case Down:
                motorRevolution--;
                break;
             
              case Mode:
                menuState--; }
          break;
     
     
        case 4:
          delay(20);
          tft.drawRoundRect(0, 35, 121, 12, 4, ST7735_BLACK);
          tft.drawRoundRect(1, 36, 119, 10, 3, ST7735_BLACK);
          tft.drawRoundRect(0, 46, 121, 12, 4, ST7735_CYAN);
          tft.drawRoundRect(1, 47, 119, 10, 3, ST7735_CYAN);
          Serial.println( "Case 4 ");
            switch (checkButton()){
              case Up:
                delay(50);
                stepsMode++;
                if(stepsMode > 4) stepsMode = 1;          
                break;
           
              case Down:
                delay(50);
                stepsMode--;
                if(stepsMode < 1) stepsMode = 4;
                break;
             
              case Mode:
                menuState--; }
             
             
            switch(stepsMode){
              case 1:
                Serial.println( "StepsMode 1");        // Aktivieren Voll-Schritt  (MS1=0, MS2=0)
                  for (int i=0; i <=1; i++){
                    tft.fillRoundRect(85, 47, 30, 10, 3, ST7735_GREEN);
                tft.setTextSize(1);
                tft.setCursor(89, 48);
                tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
                tft.print("full"); }
                digitalWrite(MS_1, LOW);
                digitalWrite(MS_2, LOW);
                break;
             
              case 2:
                Serial.println( "StepsMode 2");      // Aktivieren Halb-Schritt  (MS1=1, MS2=0)
                  for (int i=0; i <=1; i++){
                    tft.fillRoundRect(85, 47, 30, 10, 3, ST7735_GREEN);
                tft.setTextSize(1);
                tft.setCursor(89, 48);
                tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
                tft.print("1/2 "); }
                digitalWrite(MS_1, HIGH);
                digitalWrite(MS_2, LOW);
                break;    
             
              case 3:
                Serial.println( "StepsMode 3");      // Aktivieren Viertel-Schritte (MS1=0, MS2=1)
                  for (int i=0; i <=1; i++){
                    tft.fillRoundRect(85, 47, 30, 10, 3, ST7735_GREEN);
                tft.setTextSize(1);
                tft.setCursor(89, 48);
                tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
                tft.print("1/4 "); }
                digitalWrite(MS_1, LOW);
                digitalWrite(MS_2, HIGH);        
                break;
             
              case 4:
                Serial.println( "StepsMode 4");      // Aktivieren 1/8-Schritte (MS1=1, MS2=1)
                  for (int i=0; i <=1; i++){
                    tft.fillRoundRect(85, 47, 30, 10, 3, ST7735_GREEN);
                tft.setTextSize(1);
                tft.setCursor(89, 48);
                tft.setTextColor(ST7735_BLACK, ST7735_GREEN);
                tft.print("1/8 "); }
                digitalWrite(MS_1, HIGH);
                digitalWrite(MS_2, HIGH);        
                break;        }
            break;
               
        case 5:
          delay(20);
          tft.drawRoundRect(0, 46, 121, 12, 4, ST7735_BLACK);
          tft.drawRoundRect(1, 47, 119, 10, 3, ST7735_BLACK);
     
          if ((millis() / 500) % 2){
          tft.drawRoundRect(14, 59, 78, 16, 5, ST7735_CYAN);
          tft.drawRoundRect(15, 60, 76, 14, 4, ST7735_CYAN);}
          else{
            tft.drawRoundRect(14, 59, 78, 16, 5, ST7735_BLACK);
            tft.drawRoundRect(15, 60, 76, 14, 4, ST7735_BLACK); }
       
          Serial.println( "Case 5 ");
       
            switch (checkButton()){
              case Up:          // Start /motorStart()
                motorGo = !motorGo;
                break;
              case Down:
                motorGo = !motorGo;
                break;
             
              case Mode:
                menuState--; }
             
            motorDrive();

          break;
       
        case 6:
          delay(20);
            tft.drawRoundRect(14, 59, 78, 16, 5, ST7735_BLACK);
            tft.drawRoundRect(15, 60, 76, 14, 4, ST7735_BLACK);
            tft.drawRoundRect(78, 90, 80, 22, 7, ST7735_CYAN);
          Serial.println( "Case 6 ");
            switch (checkButton()){
              case Up:
                //motorForwardDirect();
                break;
           
              case Down:
                //motorBackDirect();
                break;
             
              case Mode:
                menuState--; }
          break;
        case 7:
          delay(20);
          tft.drawRoundRect(78, 90, 80, 22, 7, ST7735_BLACK);
          tft.drawRoundRect(121, 4, 37, 72, 4, ST7735_CYAN);
          tft.drawRoundRect(120, 3, 39, 74, 5, ST7735_CYAN);
          Serial.println( "Case 7 ");
       
          stepper.setMaxSpeed(10000);
          stepper.setSpeed(8000);
            switch (checkButton()){
              case Up:
                digitalWrite(4, HIGH);
                stepper.runSpeed();
           
                break;
           
              case Down:
                digitalWrite(4, LOW);
                stepper.runSpeed();
             
                break;
             
              case Mode:
                menuState=-1; }
            break;
          }
    }




    void endSwitch1Arrive (){}


    void endSwitch2Arrive (){}

    void motorDrive()
    {
      if(motorGo){
                      stepper.moveTo(pos);
                      stepper.setMaxSpeed(3000);
                      stepper.setAcceleration(10000);          
                      Serial.print("Distance To Go = ");
                      Serial.println(stepper.distanceToGo());
                        if(stepper.distanceToGo() != 0){
                            stepper.run(); }
      }
    }
     
  5. vvr

    vvr Инженерище

    Возьмите мегу, чего вас потянула на два мк
     
  6. Visor5

    Visor5 Нуб

    Места больше нет.
    А чем Мега принципиально отличается от Нано?
    2 платы не потому что пинов не хватает, а для реализации многопоточности процессов. Если на одну плату повесить отрисовку меню, графиков, статус конечников и т.д. + управленме мотором, то мотор будет крутится с большими задержками.
     
  7. geher

    geher Гуру

    У меги не только больше пинов, но шустрость повышенная (за счет более серьезного МК), и внешних прерываний намного больше.
    Но она сама больше, чем нано и мини про вместе взятые.
    А EasyDriver - это который сдвигается на шаг (долю шага) импульсом на пине?
    Тогда мотор можно крутить таймерным прерыванием. А управлять вращением через переменные, определяющие количество "холостых" вызовов функции обработки прерывания между изменениями уровня на управляющем входе драйвера.
     
  8. Visor5

    Visor5 Нуб

    Не слишком долго будет получаться? Нужны 3 кнопки (больше; меньше; переключение меню). Плюс надо определить в каком меню находимся сейчас (чтобы понять какой параметр мотора менять). Кнопки висят на аналоговом входе (на приложенном фото должно быть понятней). Чтобы избежать дребезга у меня сделана задержка в 20 мс при определении. И в то время когда мы поворачиваем мотор мы не можем следить за нажатиями... Может вы могли бы в сам код заглянуть? Мои возможности программирования немногим отличаются от нуля. Не начал бы сам никогда такой проект, если бы не тонны библиотек, примеров для работы с экраном. А вот с мотором не так просто оказалось как думал.

    [​IMG]
     
    Последнее редактирование: 25 сен 2014
  9. Unixon

    Unixon Оракул Модератор

    Прерываний и ввода-вывода то больше, а шустрость ровно та же, вся серьезность ушла в размер памяти.
     
  10. geher

    geher Гуру

    Да, напутал немного. Тактовая у них одинаковая. Не у той платы характеристики смотрел.
    Хотя, может быть, мне показалось, но при перехода с Micro на Mega 2560 железка с большим количеством подключенных модулей стала поворачиваться немного быстрее.