Песочница

Тема в разделе "Флудилка", создана пользователем CYITEP_BAC9I, 31 янв 2019.

  1. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Вечер добрый всем.
    Подскажите пожалуйста как расово правильно делать переходы между блоками программы?
    На данном этапе делаю примерно так
    Код (C++):
    #include <stdio.h>
    int var = 1;
    int var_2 = 1;
    void setup()
    {}
    void loop()
    {
    while (var ==1)
       {
    //режим расчета пузырьков воздуха
       }
    clrscr();
    while (var ==2)
       {
      //режим расчета пузырьков водки
       }
    clrscr();
    while (var ==3)
       {
    //режим расчета пузырьков пива
       }
       //при выходе из while основной цикл проходит до конца где и очищает экран  перед следущим режимом
    clrscr();
      }
    блоки программы засовываю в циклы while.
    Плюсы,- программа работает стабильно, нет никаких взбрыкиваний и вмешательства других блоков кода.
    удобно делать очистку экрана при переходах между циклами.
    Минусы, - в каждом блоке, происходит своя собственная проверка нажатий на кнопки, получение данных с датчиков. неудобный переход между блоками.

    хочу попробовать такой вариант на enum перечислениях и switch case. примерно так.
    Код (C++):
    Вариант switch case
    void loop()
    { //здесь делаются все  проверки нажатий на кнопки
    // прием данных с датчиков
    // в switch case делатся обработка по нужным алгоритмам
    //и вывод на экран

      switch (var)
      {
             case 1:
              //режим расчета пузырьков воздуха
              clrscr();
              break;
              case 2:
              //режим расчета пузырьков водки
              clrscr();
              break;
              case 3:
              //режим расчета пузырьков пива
               switch (var_2)
                 {
                  case 1:
                     //пиво светлое один вариант расчета
                  break;
                  default:
                    // пиво темное другой вариант
                  break;
                 }
                 clrscr();
              break;
        default:
        break;
      }
    }
     
    так еще не писал, но вижу очевидные плюсы. обработка данных будет одна в начале цикла, потом переход в нужный раздел. Однако боюсь непредсказуемых ошибок и сложности ветвлений.

    Как вообще принято объединять блоки программ? если вопрос сложен, то подскажите что можно покурить? учебник по С++ вроде весь скурил, а на этот вопрос так и не нашел ответа.

    П.С. может тема приживется, чтоб в ней задавать простенькие вопросы, не создавая новых тем. единственно не знаю в каком разделе разместить. если админ такую тему сочтет полезной, создайте подобную тему в разделе который считаете нужным. а пока пусть во флудилке повесит.
     
    Последнее редактирование: 31 янв 2019
  2. NikitOS

    NikitOS Король шутов Администратор

    Вряд ли приживется...
    Всем надо свою тему создать...
    В чужих писать не хотят
     
    CYITEP_BAC9I нравится это.
  3. Asper Daffy

    Asper Daffy Иксперд

    Если в пол в профиле указан верно, то расово-правильно - через вычисляемый goto (cм. здесь). Но это точно не для девочек! :)
     
    CYITEP_BAC9I и DetSimen нравится это.
  4. DetSimen

    DetSimen Guest

    А чо, так можно было? О_О
     
  5. parovoZZ

    parovoZZ Гуру

    блоки - в алгоритмах. В программе - функции.

    без volatile и с включенной оптимизацией это работать не будет.
     
    CYITEP_BAC9I нравится это.
  6. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    а что там сложного то? описания мало только, если правильно вкурил, применяться должно так?
    Код (C++):

    int i;
    int foo;
    int bar;
    int hack;
    void setup() {
      // put your setup code here, to run once:
    }

    void loop() {
      // put your main code here, to run repeatedly:
    static void *array[] = { &&foo, &&bar, &&hack };
    goto *array[i];

    foo:
    {

    };
    bar:
    {

    };
    hack:
    {

    };
    }
    а так да интересный способ, не знал что так можно
     
  7. Asper Daffy

    Asper Daffy Иксперд

    А кто говорил, что там сложно? Вот у того и спрашивайте :)
     
  8. Daniil

    Daniil Гуру

    Сложно начнется тогда когда не будет контроля за использованием goto, ведь, так соблазнительно его использовать. Потом начинается использование goto по пустякам. Потом через год надо отредактировать прошивку, а проще окажется написать новую.
     
    parovoZZ нравится это.
  9. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    таки работает все же. на данном этапе такой подход к моим записюлькам кода, дает самые стабильные результаты. ничего не глючит, никакаких нежданчиков. однако расплата за это в каждом while? по сути самостоятельный цикл. ну и volatile местами присутствует. Запугали вы меня с goto. попробую на enum and switch case поваять.
     
  10. SergeiL

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

    Когда в 1987г. начал изучать Си под Unix, начальник сказал, увижу goto - будешь все переписывать.
     
    Daniil и NikitOS нравится это.
  11. Asper Daffy

    Asper Daffy Иксперд

    Ваш начальник, наверное, никогда в ядро Unix не заглядывал, а то заставил бы авторов и его переписать
     
    Tomasina и parovoZZ нравится это.
  12. SergeiL

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

    Заглядывал, начальник был правильный, тот с которым вместе не раз собирали систему.
    Наверное по этому и говорил.
     
  13. AlexU

    AlexU Гуру

    Как вариант, можно сделать с помощью функций -- каждую функциональность реализовать в отдельной функции.
    Код (C++):
    // Функции, отвечающие за выполнение работы в определённом режиме,
    // должны иметь одинаковый набор параметров.
    // Функции initFunction, countAirBubles, countBeerBubles, countAlcoholBubles
    // имеют только один аргумент типа int8_t.
    // Количество параметров может быть любым, главное одинаковым.

    void countAirBubles(int8_t pressedKey);
    void countBeerBubles(int8_t pressedKey);
    void countAlcoholBubles(int8_t pressedKey);

    // указатель на текущую функцию
    void (*currentFunction)(int8_t) = NULL;

    // Ниже реализации функций:

    void initFunction(int8_t pressedKey)
    {
        // Что-то делаем для инициализации.
        // Если pressedKey положительное число,
        // то реагируем на нажатие кнопки.
        // Если pressedKey отрицаетльное число,
        // то просто делаем свою работу.
        // Ни каких delay и циклов любого вида.
        // Функция должна завершить работу как можо быстрее.

        // Например, если нажата кнопка,
        // то меняем активную функцию в соответствии с кодом
        switch (pressedKey) {
        case 1:
            currentFunction = countAirBubles;
        case 2:
            currentFunction = countBeerBubles;
        case 3:
            currentFunction = countAlcoholBubles;
        }
    }

    void countAirBubles(int8_t pressedKey)
    {
        // Аналогично initFunction

        // Например, если нажата любая кнопка,
        // то меняем активную функцию на начальную
     
        if (pressedKey > 0)
        {
            currentFunction = initFunction;
        }
    }

    void countBeerBubles(int8_t pressedKey)
    {
        // Аналогично initFunction
    }

    void countAlcoholBubles(int8_t pressedKey)
    {
        // Аналогично initFunction
    }

    // Любимые setup() и loop() :

    void setup()
    {
        // Ещё что-то.....

        // Текущей функцией назначаем функцию initFunction.
        currentFunction = initFunction;

        // Ещё что-то.....
    }

    void loop()
    {

        // фейковая функция
        // реально что-то должно опрашивать клавиатуру
        // и возвращать код нажатой кнопки
        // либо отрицаетльное число,
        // если не нажато ни одной кнопки
        int8_t pressedKey = scanKeyboard();

        currentFunction(pressedKey);

        // Больше в loop ни чего не надо.
        // Вся функциональность по смене режимов и состояний
        // будет реализована в конкретных функциях
        // countAirBubles, countBeerBubles и т.п.

    }
    Фишка такого подхода в том, что, при написании реализации конкретной функции, концентрируешься именно на этой функции, не растекаясь мыслями по всему коду. Но есть некоторые ограничения, связанные с организацией кода внутри функций: по сути код должен быть аналогичен коду в обработчиках прерываний и все функции должны поддерживать один интерфейс.
     
    Tomasina, Сусемьбек, SergeiL и ещё 1-му нравится это.
  14. SergeiL

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

    А я обычно делаю что-то типа callback.
    Код (C++):
    #define MQTT_NUM_SUB_TOP 9

    typedef struct _mqtt_subscribe_struct
    {
      const char  *Mqtt_Sub_String;
      void        (*function)(byte index, byte param);
    } MQTT_Subscibe_Struct;


    MQTT_Subscibe_Struct  MQTT_Subsc_Data[] = {
      {"/mh/ds/bs/leo/count_res",    &reset_counters },
      {"/mh/ds/bs/leo/rel_00",       &rel_switch},
      {"/mh/ds/bs/leo/rel_01",       &rel_switch},
      {"/mh/ds/bs/leo/rel_02",       &rel_switch},
      {"/mh/ds/bs/leo/rel_03",       &rel_switch},
      {"/mh/ds/bs/leo/rel_10",       &rel_switch},
      {"/mh/ds/bs/leo/rel_11",       &rel_switch},
      {"/mh/ds/bs/leo/rel_12",       &rel_switch},
      {"/mh/ds/bs/leo/rel_13",       &rel_switch},
    };


    void reset_counters(byte index, byte param)
    {
      byte i;
      if (param == 1)
      {
        for (i = 0; i < 3; i++)
        {
          Main_Data_byte[i] = 0;
          EEPROM.write(i, Main_Data_byte[i]);
        }
        Mqtt_Update_flag = 0xFF;
        client.publish(MQTT_Subsc_Data[0].Mqtt_Sub_String, "OFF", true);
      }
    }

    void rel_switch(byte index, byte param)
    {

      digitalWrite (DIG_Pins[index - 1], param);

      if( param == 0)
        Main_Data_byte[RELEY_STATE] &= ~(1 << index-1);
      else
        Main_Data_byte[RELEY_STATE] |= (1 << index-1);
      EEPROM.write(RELEY_STATE, Main_Data_byte[RELEY_STATE]);
    }

    void callback(char* topic, byte* payload, unsigned int length)
    {
      char    message[15];
      char    i;

      if(length>14)
      return;

      for (i = 0; i < length; i++)
        message[i] = (char) payload[i];
      message[i] = 0;

      for (i = 0; i < MQTT_NUM_SUB_TOP; i++)
      {
        if ( strcmp(topic, MQTT_Subsc_Data[i].Mqtt_Sub_String) == 0 )
        {
          if (strcmp(message, "ON") == 0 )
            (*(MQTT_Subsc_Data[i].function))(i, 1);
          else
            (*(MQTT_Subsc_Data[i].function))(i, 0);
        }
      }
    }

    void mqtt_subscribe(void)
    {
      byte i;
      for (i = 0; i < MQTT_NUM_SUB_TOP; i++)
      {
        client.subscribe(MQTT_Subsc_Data[i].Mqtt_Sub_String);
        client.loop(); //mqtt loop
      }
    }
     
    Сусемьбек и CYITEP_BAC9I нравится это.
  15. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    спасибо всем большое. Хоть какое то понимание начало приходить, как это делается. Пытаюсь с уровня быдлокодера самоучки, повзрослеть до уровня китайско-индийского программиста.
     
    Daniil нравится это.
  16. Доброй ночи всем кто ещё здесь на форуме. Подскажите пожалуйста, хотябы на вскидку почему виснет дуня? Хотел вывести обработку нажатий кнопок в фон. По прерыванию значение порта С скидывается в переменную. Которая затем расшифровывается в основном цикле и возводятся флаги надатий в свитч кейсе, флаги потом сбрасываются после выполнения действий. Вроде явных ошибок нет а она зараза зависает. То несколько десятков нажатий отработает , то после 2 висит. В чем дело не пойму.
    Код (C++):
    volatile int buttons =0;
    bool  A = false;
    volatile unsigned long  buttons_Time =0;// volatile

    void setup()
    {DDRC = 0b00000000;
    PCMSK1 = 0b00001111;  // разрешаем прерывания на пинах А0, А1, А2, А3
    PCICR |= (1 << PCIE1);
    Serial.begin(9600);
    }
    void loop()
    {

    if( buttons >0  )

    {
        switch (buttons)
        {
                case 0b00000001:    //была нажата кнопка А0
    Serial.println("knopka111");
                break;

                case 0b00000010:    //была нажата кнопка А1
    Serial.println("knopka222");
                break;

                case 0b00000100:     //была нажата кнопка А2
    Serial.println("knopka333");
                break;

                case 0b00001000:     //была нажата кнопка А3
    Serial.println("knopka444");
                break;  
         
        }

    if( millis() - buttons_Time > 50 )  // своеобразный антидребезг

        {
            //разрешаем прерывания на линии с
            PCICR |= (1 << PCIE1);
            //обнуляем переменную
        buttons =0;
          Serial.println("Anti Drebaezgg");

        }
     
    }

    }
    ISR(PCINT1_vect) {
      buttons = PINC; //передаем данные о портах в переменную buttons
      PCICR &= ~(1 << PCIE1); //запрещаем прерывания на линии C

    buttons_Time = millis();
      Serial.println("PRERYVANIE");
    }
     
  17. AlexU

    AlexU Гуру

    Вот это вот:
    Код (C++):
    Serial.println("PRERYVANIE");
    в обработчике прерываний делать нельзя.
     
    Сусемьбек нравится это.
  18. Блин):oops:.
    Спасибо большое.
    Баиньки всем.
     
  19. parovoZZ

    parovoZZ Гуру

    Хм. А я вывожу. И SPI вывожу. И нет проблем.
     
  20. Asper Daffy

    Asper Daffy Иксперд

    Не стоит, но таки можно.