Проблемы с кнопками. Страанные и нелогичные.(закрыто)

Тема в разделе "Arduino & Shields", создана пользователем Поручик, 3 сен 2016.

  1. Поручик

    Поручик Нерд

    Пипл, такой вот вопрос... я высел на тупняки.
    пилю одну штуку, не суть какую.
    на искру нео повесил LCD 16x2 через сдвиговый, 4 кнопки на подтягивающих резисторах, делаю меню многоуровневое.
    теперь проблема.
    работает 2 кнопки из 4. Сначала думал провода померли, нет живы. потом думал пины померли, поменял пины на мёртвые кнопки, всё равно не фурычит, совсем. кнопки живы, в коде все их запиливаю одинаковым обрботчиком.
    я в недоумении.

    Код (C++):

    boolean buttWasUp = true;
    int menuState = 0; //текущая позиция меню
    int time_photo=0;
    int n_framez=1;
    int time_delay_framez=10;
    int time_frame=1;
    bool photo=1;

    #define BUT_PL 6 //кнопка "+"
    #define BUT_MN 7 //кнопка "-"
    #define BUT_SEND 5 //кнопка "отправить"
    #define BUT_ENT 4 //кнопка "ввод"

    void PrintMenu(int state) {
              switch (state){
                case 0:              
                    lcd.clear();
                    lcd.print("Select mode");
                    lcd.setCursor(0, 1);
                break;
             
                case 1:
                    lcd.clear();
                    lcd.print("Long photo");
                    lcd.setCursor(0, 1);    
                break;
                         
                case 11:
                    lcd.clear();
                    lcd.print("Time:");
                    lcd.setCursor(0, 1);
                    lcd.print(time_photo);
                break;
                         
                case 2:
                    lcd.clear();
                    lcd.print("Timelapse Photo");
                    lcd.setCursor(0, 1);
                break;
                         
                case 21:
                    lcd.clear();
                    lcd.print("Frames");
                    lcd.setCursor(0, 1);
                    lcd.print(n_framez);            
                break;
                         
                case 22:
                    lcd.clear();
                    lcd.print("Time frize");
                    lcd.setCursor(0, 1);
                    lcd.print(time_delay_framez);
                break;
                         
                case 23:
                    lcd.clear();
                    lcd.print("Time of frame");
                    lcd.setCursor(0, 1);
                    lcd.print(time_frame);
                break;
                         
                case 3:
                    lcd.clear();
                    lcd.print("Manual Mode");
                    lcd.setCursor(0, 1);            
                break;

            }
    }
     
    void setup() {
     

      Serial.begin(9600);

      pinMode(BUT_PL, INPUT_PULLUP); //подключаем кнопки
      pinMode(BUT_MN, INPUT_PULLUP);
      pinMode(BUT_SEND, INPUT_PULLUP);
      pinMode(BUT_ENT, INPUT_PULLUP);
      lcd.begin(16, 2); //окончательно активируем дисплей
      lcd.setCursor(0, 0);
      lcd.clear();
      lcd.print("Select mode");
      lcd.setCursor(0, 1);
    }

    void loop() {
      // put your main code here, to run repeatedly:
    boolean keyPL;
    boolean keyMN;
    boolean keySND;
    boolean keyENT;

          keyPL = digitalRead(BUT_PL);
          if (buttWasUp && !keyPL) {
            delay(10);
            keyPL = digitalRead(BUT_PL);
            if (keyPL) {
              Serial.println(1);
              switch (menuState){
                case 0:              
                    menuState=1;
                    PrintMenu(menuState);
                break;
             
                case 1:
                    menuState=2;
              PrintMenu(menuState);    
                break;
                         
                case 11:
                   time_photo++;
                   PrintMenu(menuState);
                break;
                         
                case 2:
                   menuState=3;
                   PrintMenu(menuState);
                break;
                         
                case 21:
                   n_framez++;
                   PrintMenu(menuState);
                break;
                         
                case 22:
                   time_delay_framez++;
                   PrintMenu(menuState);
                break;
                         
                case 23:
                   time_frame++;
                   PrintMenu(menuState);
                break;
                         
                case 3:
                   menuState=1;
                   PrintMenu(menuState);            
                break;

            }
            }
          }
         
                keyMN = digitalRead(BUT_MN);
          if (buttWasUp && !keyMN) {
            delay(10);
            keyMN = digitalRead(BUT_MN);
            if (keyMN) {
              Serial.println(2);
              switch (menuState){
                case 0:
                  menuState=3;
                  PrintMenu(menuState);
                break;
             
                case 1:
                   menuState=3;
                   PrintMenu(menuState);
                break;
                         
                case 11:
                   if (time_photo>2) {time_photo--;}
                    else {time_photo=1;}
                    PrintMenu(menuState);
                break;
                         
                case 2:
                   menuState=1;
                   PrintMenu(menuState);
                break;
                         
                case 21:
                   if (time_photo>2) {n_framez--;}
                    else {n_framez=1;}
                    PrintMenu(menuState);
                break;
                         
                case 22:
                   if (time_photo>1) {time_delay_framez--;}
                    else {time_delay_framez=1;}      
                    PrintMenu(menuState);      
                break;
                         
                case 23:
                   time_frame--;
                   if (time_frame>2) {time_frame--;}
                    else {time_frame=1;}
                    PrintMenu(menuState);              
                break;
                         
                case 3:
                   menuState=2;
                   PrintMenu(menuState);
                break;
            }
          }
         
            keySND = digitalRead(BUT_SEND);
          if (buttWasUp && !keySND) {
            delay(10);
            keySND = digitalRead(BUT_SEND);
            if (keySND) {
    Serial.println(4);
            }
          }
         
                keyENT = digitalRead(BUT_ENT);
          if (buttWasUp && !keyENT) {
            delay(10);
            keyENT = digitalRead(BUT_ENT);
            if (keyENT) {
              Serial.println(3);
               switch (menuState){
                case 0:
                  menuState=3; Serial.println(menuState);
                  PrintMenu(menuState);      
                break;
             
                case 1:
                  menuState=11; Serial.println(menuState);
                  PrintMenu(menuState);
                break;
                         
                case 11:
                  menuState=3; Serial.println(menuState);
                  PrintMenu(menuState);
                break;
                         
                case 2:
                  menuState=21; Serial.println(menuState);
                  PrintMenu(menuState);
                break;
                         
                case 21:
                  menuState=22; Serial.println(menuState);
                  PrintMenu(menuState);          
                break;
                         
                case 22:
                  menuState=23; Serial.println(menuState);
                  PrintMenu(menuState);          
                break;
                         
                case 23:
                  menuState=21; Serial.println(menuState);
                  PrintMenu(menuState);          
                break;
                         
                case 3:

                break;
            }
            }
          }
          }
    }
     
  2. qwone

    qwone Гик

    У вас не проблема с кнопками. У вас проблема с архитектурой программы.
    Я лично решаю в 3 вычислительных потока. 1 - экран 2 клавиатура и действия в ней 3 это действия устройства не зависимо от работы кнопок и экрана.
    Код (C++):
    uint8_t non_stop_program1(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t non_stop_program2(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t non_stop_program3(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    void setup() {
      Serial.begin(9600);
    }
    void loop() {
      if (non_stop_program1(500))  {
    // Здесь вы организовываете вывод на экран. Вызывается раз в 0.5 сек
        Serial.println("knok");
    }
      if (non_stop_program2(200))  {
    // Здесь вы организовываете ввод с клавиатуры. Вызывается раз в 0.2 сек
      }
      if (non_stop_program3(100))  {
    // Здесь сама работа устройства не зависимая от вашего ввода и показа на экран. Вызывается раз в 0.1 сек(может быть по желанию другим)
       }
    }
     
     
    Поручик, yul-i-an и ostrov нравится это.
  3. yul-i-an

    yul-i-an Гик

    Во первых для переменной хранящей позицию меню размерность int великовата (растрата памяти).
    Во вторых необходимо определится с размерностью других переменных.
    Не увидел в коде проверку на достижение переменными верхних и нижних границ, может смотрел не внимательно, можно функцию написать например
    Код (C++):
    //Возвращает измененную переменную
    //time_photo = (time_photo, 2, 0, 100);
    //(изменяемая переменная, шаг, минимум, максимум)
    //изменяет значение переменной и проверяет на достижение
    //допустимых границ
    int cngVal(int var, int stp, int mn, int mx){
    var+=stp;
    (var>mx)?var=mx:(var<mn)?var=mn:var=var;
    return var;
    }
    Постоянно вызываете вывод на экран, можно вместо вызова PrintMenu(menuState) завести флажок (например fl_PS), и если флажок стоит то перерисовывать экран
    Код (C++):
    //вместо вызова PrintMenu(menuState) ставим флаг fl_PS=1;
    if (fl_PS){//если надо перерисовать экран
    PrintMenu(menuState);//перерисовываем
    fl_PS=0;//сбрасываем флаг
    }
    Вместо того чтобы в каждом case стирать экран
    Код (C++):
    void PrintMenu(int state) {
              switch (state){
                case 0:        
                    lcd.clear();
                    lcd.print("Select mode");
                    lcd.setCursor(0, 1);
                break;
       
                case 1:
                    lcd.clear();
                    lcd.print("Long photo");
                    lcd.setCursor(0, 1);
                break;
    ...
    Вынести lcd.clear() в начало функции
    Код (C++):
    void PrintMenu(int state) {
           lcd.clear();//сюда
              switch (state){
                case 0:        
                    lcd.print("Select mode");
                    lcd.setCursor(0, 1);
                break;
       
                case 1:
                    lcd.print("Long photo");
                    lcd.setCursor(0, 1);
                break;
    ...
    Вместо
    Код (C++):
                    lcd.print("Select mode");
                    lcd.setCursor(0, 1);
    Написать функцию вывода текста в указанном месте - PrintTXT(x,y,"text") можно память высвободить.
    В общем весь повторяющийся код заносить в функции.
    И по кнопкам
    Непонятно для чего Вам этот флажок buttWasUp
    Можно тоже функцию написать
    Код (C++):
    boolean keyState(byte BUT){
      key = digitalRead(BUT);    
      if (buttWasUp && !key) {
        delay(10);
        return digitalRead(BUT);
      }
    }
    Код изменяется до следующего вида
    Код (C++):
    //гдето в loop опрашиваем кнопки
    keyPL = keyState(BUT_PL);
    keyMN = keyState(BUT_MN);
    keySND = keyState(BUT_SND);
    keyENT = keyState(BUT_ENT);
    И упрощаем код (более читаемый)
    Код (C++):
    //дальше по коду вместо
    keySND = digitalRead(BUT_SEND);
    if (buttWasUp && !keySND) {
      delay(10);
      keySND = digitalRead(BUT_SEND);
      if (keySND) {
        Serial.println(4);
      }
    ...

    //Оставляем только
      if (keySND) {
        Serial.println(4);
      }
     
    Последнее редактирование: 3 сен 2016
  4. yul-i-an

    yul-i-an Гик

    Адекватное решение, но я бы в loop один раз получал-бы millis (currentMillis()=millis()), а потом передавал это значение в функцию.
    Код (C++):
    void loop() {
      currentMillis=millis();
      if (non_stop_program1(currentMillis,500))  {
    // Здесь вы организовываете вывод на экран. Вызывается раз в 0.5 сек
        Serial.println("knok");
    }
    ...
    Чтобы не дергать её каждый раз.
     
  5. qwone

    qwone Гик

    Цитата:Чтобы не дергать её каждый раз.
    А вот здесь вы не правы. millis()будут разными. Конечно чаще совпадают, но вот в нужном не совпадут.
    Если вы решили. clear вынести за скобки. Так надо еще панель в viev добавить. Ну там номер окна высветить. Зажечь нужные пиктограммы, и Е помигать. Если переменые надо изменить. Да и еще пищалку надо повесть. Вдруг аварию надо изобразить.
     
  6. Поручик

    Поручик Нерд

    а можно чууть подробнее пояснить, что происходит в первых функциях?
     
  7. qwone

    qwone Гик

    Подробнее. Вот человек умеет делать кхе шалаш, ладно сруб. Отлично умеет. Но если ему надо делать 2-х этажное здание, то навыков делать сруб ему маловато будет. А если еще подвод комуникаций, свет, вода, слив, то это полная жопа. Это я к тому, что бы городить большие программы надо создания архитектуры. Вот у вас кнопки перестали работать. И это только начало. Вы изделие еще туда не повесили.
     
  8. Поручик

    Поручик Нерд

    ммм.... я кажется задал вполне конкретный вопрос, с просьбой пояснить приведённый Вами пример, а не просил рассказать про то, почему у меня кривой код.
     
  9. qwone

    qwone Гик

    Ну вот мой вариант. Тоже кривоват.
    Код (C++):
    /*  Схема подключения
    I2C LCD1602          GND -> GND
                          +5V -> +5V
                          SDA -> A4(SDA)
                          SCL -> A5(SCL)

    *  Ардуино энкодер   CLK -> A2   CLK_Pin   0 нажата 1 нет
                          DT  -> A1   DT_Pin    0 нажата 1 нет
                          SW  -> A0   SW_Pin    0 нажата 1 нет
                          GND -> GND
                          +5V -> +5V                    
    */

    // ============= Переменные  ====================================
    // системные переменные - переменные и константы предназначеные для подержания системы
    uint8_t mode_viev                 ; // 0 режим показа экранов / 1 режим редактирования переменной на экране
    uint8_t stat_blink_mode_viev      ; // мигалка mode_viev
    uint8_t screen_number             ; // номер текущего демонстрируемого окна
    const int number_of_screen = 3    ; // количество окон в системе
    // технологические переменные - переменные и константы предназначеные для выполнения функций устройства


    // ============= Подключение LCD1602 по I2C =====================
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей

    void LCD_ini(){            //  инициализация дисплея
      mode_viev = 0          ; // установить режим редактирования
      stat_blink_mode_viev=0 ;
      screen_number  = 1     ; // показать экран 1
      lcd.init()             ;                  
      lcd.backlight()        ; // Включаем подсветку дисплея
    }

    // --- Экран 1 ---
    void Screen1_viev()   {    // показать  экран  1
      lcd.print("***") ;
    }
    // --- Экран 2 ---
    void Screen2_viev()   {    // показать  экран  2
      lcd.print("***") ;
    }
    // --- Экран 3 ---
    void Screen3_viev()   {    // показать  экран  3
      lcd.print("***") ;
    }
    // -- Панель --
    void  Panel_Viev()     {     // показать на экране режим и номер окна
      lcd.setCursor(13, 1) ;
      if (stat_blink_mode_viev&&mode_viev) lcd.print("E");   // показ значка обычный режим
                                      else lcd.print(" ");   // показ значка  режим редактирования
      lcd.print(" ")  ;
      lcd.print(screen_number)  ;
    }
    // -- Общий вывод на дисплей--
    void Viev(){
      lcd.clear();
      switch (screen_number) {
          case 1:Screen1_viev();break;  // показать экран устройствa 1
          case 2:Screen2_viev();break;  // показать экран устройствa 2
          case 3:Screen3_viev();break;  // показать экран устройствa 3
      }
      stat_blink_mode_viev = !stat_blink_mode_viev ;
      Panel_Viev();
    }
    // ========== обработчик энкодера ===========================
    const int CLK_Pin=A2  ;            // нога CLK кнопки 0 нажата 1 нет
    const int DT_Pin=A1   ;            // нога DT  кнопки 0 нажата 1 нет
    const int SW_Pin=A0   ;            // нога кнопки 0 нажата 1 нет

    uint8_t statCLK,statCLK_old ;      // переменные: состояние ноги CLK сейчас и раньше
    uint8_t SW ,SW_old  ;      // переменные: состояние ноги SW сейчас и раньше

    void Encoder_ini()         {       //  инициализация энкодера и кпопки в нем
      pinMode(SW_Pin, INPUT_PULLUP)  ; // вывод на ввод с подтягивающим резистром
      pinMode(CLK_Pin, INPUT);
      pinMode(DT_Pin, INPUT);
      statCLK_old = digitalRead(CLK_Pin);
      SW = digitalRead(SW_Pin);
    }
    uint8_t Encoder(){
      statCLK = digitalRead(CLK_Pin);
      if ((statCLK == 0)&&(statCLK_old ==1 )){ //  счет по фронту
         statCLK_old=statCLK;
         return (digitalRead(DT_Pin)+1); // 1 по часовой 2 против часовой
        };
      statCLK_old=statCLK;
      return 0; // изменений не произошло
    }
    uint8_t SW_botton() {
      SW_old = SW;
      SW = digitalRead(SW_Pin);
      if (!SW &&SW_old) return 1;  // срабатывание по нажатию кнопки
      else return 0;
      }
    // ==== ядро системы ======
    uint8_t non_stop_program1(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t non_stop_program2(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t non_stop_program3(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    // ==== главная часть =====
    void setup() {
       LCD_ini();          //  инициализация дисплея
       Encoder_ini();      //  инициализация энкодера и кпопки в нем
    }
    void loop() {
      if (non_stop_program1(500))  { // обновление раз в 0.5 сек информации на дисплее
        Viev();
    }
      if (non_stop_program2(200))  { //  Ввод с клавиатуры,анализ и выработка действия. Вызывается раз в 0.2 сек
          if (SW_botton()) {              // если произошло нажатие клавиши    
            // вот сюда и ставьте свою отправку в интернет
          }
      }
      if (non_stop_program3(100))  {
    // Здесь сама работа устройства не зависимая от вашего ввода и показа на экран. Вызывается раз в 0.1 сек(может быть по желанию другим)
       }
    }
     
    Собери запусти посмотри.
    Разумется обработка кнопок есть. А вот дальше нет.
     
    Alex_KAN и Поручик нравится это.
  10. yul-i-an

    yul-i-an Гик

    Всё зависит от времени выполнения кода, в критичных ко времени местах можно и перепроверить millis, от конкретной задачи зависит.
     
  11. qwone

    qwone Гик

    Посмотрите применение. 3 и4 поток на экран и кнопки. 1 и 2 на устройство

    Код (C++):
    //программа управления дворниками http://arduino.ru/forum/programmirovanie/upravlenie-dvornikami-na-avtomobile-pobeda-1957-g-v
    /*
    I2C LCD1602          GND -> GND
                          +5V -> +5V
                          SDA -> A4(SDA)
                          SCL -> A5(SCL)

    *  Ардуино энкодер   CLK -> A2   CLK_Pin   0 нажата 1 нет
                          DT  -> A1   DT_Pin    0 нажата 1 нет
                          SW  -> A0   SW_Pin    0 нажата 1 нет
                          GND -> GND
                          +5V -> +5V        

    галетник  общий -> GND ардуино   режим
               1 выв -> 2            дворник не работает         0 вкл 1 откл
               2 выв -> 3            дворник работает все время  0 вкл 1 откл
               3 выв -> 4            дворник раз в 2 мин         0 вкл 1 откл
               4 выв -> 5            дворник раз в 6 мин         0 вкл 1 откл
    мотор база транзистора -> 5                                  1 вкл 0 откл
                     земля -> GND
    конечник парковки
    дворника            -> 6                                     0 вкл 1 откл  
                  земля -> GND
    */

    // ====  конструкция дворника  ===============================
    // pin's
    const int mode_0_pin =  2 ; // дворник не работает         0 вкл 1 откл
    const int mode_1_pin =  3 ; // дворник работает все время  0 вкл 1 откл
    const int mode_2_pin =  4 ; // дворник раз в 2 мин         0 вкл 1 откл
    const int mode_3_pin =  5 ; // дворник раз в 6 мин         0 вкл 1 откл
    const int motop_pin  =  13 ; // подключение мотора          1 вкл 0 откл
    const int dvornic_pin = 7 ; // конечник парковки дворника  0 вкл 1 откл
    // переменные
    uint8_t movement_step     ; /* 0 опрос (state movement)разрешения двигаться
                                   1 выход дворника из зоны парковки (time_1,Future)
                                   2 движение дворника до срабатывания концевика в зоне парковки
                                   3 вход дворника в зону парковки (time_2,Future)
                                   4 отработать паузу между махами дворника
    */

    uint8_t state_movement    ; // состояние движения 1 двигать дворник 0 нет
    const int time_1  = 20    ; // время гарнтированого выхода дворника из зоны парковки
    uint32_t Future           ; // время перехода на следущее состояние
    const int time_2  = 20    ; // время гарнтированого входа дворника в зону парковки
    uint32_t pause_between_movements ; // пауза между движениями дворника
    uint32_t past             ; // время miillis перед паузой между движениями дворника

    void dvornic_ini(){
       pinMode(mode_0_pin,INPUT_PULLUP  ) ;
       pinMode(mode_1_pin,INPUT_PULLUP  ) ;
       pinMode(mode_2_pin,INPUT_PULLUP ) ;
       pinMode(mode_3_pin,INPUT_PULLUP  ) ;
       pinMode(motop_pin , OUTPUT ) ;
       pinMode(dvornic_pin, INPUT_PULLUP ) ;
    }
    // ============= Переменные  ====================================
    // системные переменные - переменные и константы предназначеные для подержания системы
    uint8_t mode_viev                 ; // 0 режим показа экранов / 1 режим редактирования переменной на экране
    uint8_t stat_blink_mode_viev      ; // мигалка mode_viev
    uint8_t screen_number             ; // номер текущего демонстрируемого окна
    const int number_of_screen = 3    ; // количество окон в системе
    uint8_t Encoder_data              ; // данные с энкодера
    uint8_t SW_data                   ; // данные с кнопки
    // технологические переменные - переменные и константы предназначеные для выполнения функций устройства

    uint16_t Input(){
      if (! digitalRead(mode_0_pin)) return 0;
      if (! digitalRead(mode_1_pin)) return 1;
      if (! digitalRead(mode_2_pin)) return 2;
      if (! digitalRead(mode_3_pin)) return 3;
    return 10;
    }
    // ============= Подключение LCD1602 по I2C =====================
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей

    void LCD_ini(){            //  инициализация дисплея
      mode_viev = 0          ; // установить режим редактирования
      stat_blink_mode_viev=0 ;
      screen_number  = 1     ; // показать экран 1
      lcd.init()             ;                  
      lcd.backlight()        ; // Включаем подсветку дисплея
    }
    void inc_screen_number(){
      if (screen_number < number_of_screen) screen_number++;
    }
    void dec_screen_number(){
      if (screen_number > 1) screen_number--;
    }
    // --- Экран 1 ---
    void Screen1_viev()   {    // показать  экран  1
      lcd.print(state_movement) ;
      lcd.print("  ");
      lcd.print(pause_between_movements) ;
    }
    // --- Экран 2 ---
    void Screen2_viev()   {    // показать  экран  2
      lcd.print(movement_step) ;
    }
    // --- Экран 3 ---
    void Screen3_viev()   {    // показать  экран  3
      lcd.print("***") ;
    }
    // -- Панель --
    void  Panel_Viev()     {     // показать на экране режим и номер окна
      lcd.setCursor(13, 1) ;
      if (stat_blink_mode_viev&&mode_viev) lcd.print("E");   // показ значка обычный режим
                                      else lcd.print(" ");   // показ значка  режим редактирования
      lcd.print(" ")  ;
      lcd.print(screen_number)  ;
    }
    // -- Общий вывод на дисплей--
    void Viev(){
      lcd.clear();
      switch (screen_number) {
          case 1:Screen1_viev();break;  // показать экран устройствa 1
          case 2:Screen2_viev();break;  // показать экран устройствa 2
          case 3:Screen3_viev();break;  // показать экран устройствa 3
      }
      stat_blink_mode_viev = !stat_blink_mode_viev ;
      Panel_Viev();
    }
    // ========== обработчик энкодера ===========================
    const int CLK_Pin=A2  ;            // нога CLK кнопки 0 нажата 1 нет
    const int DT_Pin=A1   ;            // нога DT  кнопки 0 нажата 1 нет
    const int SW_Pin=A0   ;            // нога кнопки 0 нажата 1 нет

    uint8_t statCLK,statCLK_old ;      // переменные: состояние ноги CLK сейчас и раньше
    uint8_t SW ,SW_old  ;      // переменные: состояние ноги SW сейчас и раньше

    void Encoder_ini()         {       //  инициализация энкодера и кпопки в нем
      pinMode(SW_Pin, INPUT_PULLUP)  ; // вывод на ввод с подтягивающим резистром
      pinMode(CLK_Pin, INPUT);
      pinMode(DT_Pin, INPUT);
      statCLK_old = digitalRead(CLK_Pin);
      SW = digitalRead(SW_Pin);
    }
    uint8_t Encoder(){
      statCLK = digitalRead(CLK_Pin);
      if ((statCLK == 0)&&(statCLK_old ==1 )){ //  счет по фронту
         statCLK_old=statCLK;
         return (digitalRead(DT_Pin)+1); // 1 по часовой 2 против часовой
        };
      statCLK_old=statCLK;
      return 0; // изменений не произошло
    }
    uint8_t SW_botton() {
      SW_old = SW;
      SW = digitalRead(SW_Pin);
      if (!SW &&SW_old) return 1;  // срабатывание по нажатию кнопки
      else return 0;
      }
      // -- Общий вывод на дисплей--
    void Controls() {  // система управления
       SW_data      = SW_botton() ;
       Encoder_data = Encoder() ;
       if  ((mode_viev == 0)&&(Encoder_data == 1))  inc_screen_number() ;
       if  ((mode_viev == 0)&&(Encoder_data == 2))  dec_screen_number();
       if  ((mode_viev == 1)&&(Encoder_data == 1)); // Edit_Encoder_inc() ;
       if  ((mode_viev == 1)&&(Encoder_data == 2)); // Edit_Encoder_dec();                                        
       if  (SW_data == 1)    mode_viev = ! mode_viev;
    }
    // == ядро системы ==
    uint8_t process1_non_stop_program(uint16_t span){
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t process2_non_stop_program(uint16_t span){
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t process3_non_stop_program(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    uint8_t process4_non_stop_program(uint16_t span) {
      static uint32_t future = 0;
      if (millis()<future) return 0;
      future += span;
      return 1;
    }
    // ================= главная часть программы =======

    void setup() {

      dvornic_ini();
      LCD_ini();          //  инициализация дисплея
      Encoder_ini();      //  инициализация энкодера и кпопки в нем
    }

    void loop() {
       if (process1_non_stop_program(200))  {
       switch ( Input() ) {                     // считы
         case 0: state_movement = 0 ; // не двигать дворником
                 break;
         case 1: state_movement = 1 ; // двигать дворником без пауз
                 pause_between_movements = 0;
                 break;
         case 2: state_movement = 1 ; // двигать дворником с паузой 2 сек
                 pause_between_movements = 2000;
                 break;
         case 3: state_movement = 1 ;// двигать дворником с паузой 5 сек
                 pause_between_movements = 5000;
                 break;          
                 }
      }
       if (process2_non_stop_program(5))  {
            switch (movement_step) {
        case 0: if (state_movement) { movement_step = 1;            // 0 опрос (state movement)разрешения двигаться
                              Future = millis()+time_1;
                              digitalWrite(motop_pin, 1); }
                              break;
        case 1: if (millis() > Future) movement_step =2 ;           // 1 выход дворника из зоны парковки (time_1,future)
                               break;
        case 2: if (! digitalRead(dvornic_pin)){ movement_step =3 ; // 2 движение дворника до срабатывания концевика в зоне парковки
                               Future = millis()+time_2;}
                               break;
        case 3: if (millis() > Future){ movement_step = 0 ;          // 3 вход дворника в зону парковки (time_2,future)
                               digitalWrite(motop_pin, 0);
                               past = millis(); }
                               break;
        case 4: if  (millis() > past+pause_between_movements) movement_step = 0 ; //4 отработать паузу между махами дворника                      
                               break;
                               }
        }
      if (process3_non_stop_program(200))  { // обновление раз в 0.5 сек информации на дисплее
        Viev();
        }
      if (process4_non_stop_program(5))  { //  Ввод с клавиатуры,анализ и выработка действия. Вызывается раз в 0.1 сек
        Controls();
        }
    }
     
     
  12. Поручик

    Поручик Нерд

    ага, спасибо, утром поковыряю.
     
  13. Поручик

    Поручик Нерд

    хотя по итогу, я так и не сообразил, в чём конкретно проблема и почему две из четырёх кнопок работают, а две нет.
    архитектура и разбитие на три отдельные "потока" это понятно, оно просто в каждый момент времени делает что-то одно из нужного. выводит на экран, читает кнопки или выполняет основной код. А вот почему на непоточной архитектуре оно не отлавливает две кнопки я понять не могу. совсем.
     
  14. qwone

    qwone Гик

    Здесь еще веселее. Код надо писать так, что бы легко отлавливать ошибки. Вот ввод с кнопок надо офомить одной, в крайнем случает 2 функциями. А вы размазали по программе и спрашиваете, почему часть работает, а часть нет. Вот по этой причине и не работает. Что там что-то у вас не так, а это не так долго искать.
     
  15. Поручик

    Поручик Нерд

    со всем разобрался, тема закрыта.
     
  16. yul-i-an

    yul-i-an Гик

    Итоговый код вкладывать будите?
     
  17. Поручик

    Поручик Нерд

    на самом деле нет, по крайней мере сейчас, просто напишу в чём косяк и как я его отловил.
    Отловил я его начав убирать "не работающие" кнопки из кода, и выяснил, что число begin end нечётное. Собственно в этом и была проблема. Две последние кнопки попадали в один обработчик.
     
  18. Поручик

    Поручик Нерд

    продолжаем развлекуху.

    Код (C++):
      if(HandContr==false){//если не ручное управление
    uint8_t buf1[VW_MAX_MESSAGE_LEN];
    uint8_t buflen=VW_MAX_MESSAGE_LEN;
    int i=1;
    if (vw_get_message(buf1, &buflen)){//если что-то пришло
    if (buf1[0] != FIRST_BYTE || buf1[buflen-1] != LAST_BYTE){ // но оно не соответствует байтам первый и последний то дропаем
        return;
    }
    while (buf1[i] != LAST_BYTE) {//если байты правильные, то перекачиваем буфер в код
      key1[i-1]= buf1[i];//  КОСЯК СУДЯ ПО ВСЕМУ ГДЕ-ТО ТУТ, ТАК КАК, ЕСЛИ key1 ПРОГНАН МАКСИМАЛЬНО ДЛИННЫМ КОДОМ, ТО ВСЁ РАБОТАЕТ ОК. ЕСЛИ СНАЧАЛА ПРОГНАТЬ КОРОТКИЙ КОД, ТО В КЕЙ ПИШЕТСЯ КАКАЯ-ТО ЕРУНДА
    i++;
    }
    key1[i-1]=0;
    Serial.println(key1);
    modeChois(key1);//отправляем в обработку
    }    
    }
    собственно проблема в комментариях к коду... отловить его я не могу никак. я пробовал инициализировать массивы отдельно, пробовал фиксированные длины пакетов, ничего не помогает....
     
  19. Поручик

    Поручик Нерд

    ваааа ><
    я уже себе мозг выломал! что со мной не так. и с кодом.
     
  20. fogary

    fogary Гик

    Что такое key1, нуль-терминированная строка?
    Можно пример правильного ввода и неправильного?