Помогите с кодом что то запутался.

Тема в разделе "Arduino & Shields", создана пользователем Knyaz243, 28 янв 2022.

  1. Knyaz243

    Knyaz243 Нуб

    Если есть у кого ни будь идеи подскажите или как то окультурить все это!! Спасибо!

    Код (C++):
    #include <math.h>

    int digit_pin[] = {9, 8, 7}; // PWM Display digit pins from left to right

    #define dataPin  10             // пин подключен к входу 74HC595 DS
    #define latchPin 11             // пин подключен к входу 74HC595 ST_CP
    #define clockPin 12             // пин подключен к входу 74HC595 SH_CP
    const uint8_t digitFonts[11] = {B00000001, B01001111,
    B00010010, B00000110, B01001100, B00100100,
    B00100000, B00001111, B00000000, B00000100,B01111111};

    #define DIGIT_ON  LOW
    #define DIGIT_OFF  HIGH
    #define tdelay 6500

    int button1=18;    // кнопка старт
    int button2=19;    //кнопка воврата времени к установленному
    int button3=16;    // кнопка - уменьшение таймера
    int button4=17;    // кнопка + увеличение таймера

    int countdown_time = 420;

    struct struct_digits {
        int digit[3];
      };


    void setup() {              
      for (int i=0; i<3; i++) {
        pinMode(digit_pin[i], OUTPUT);
      }

      pinMode(button1,INPUT_PULLUP);
      pinMode(button2,INPUT_PULLUP);
      pinMode(button3,INPUT_PULLUP);
      pinMode(button4,INPUT_PULLUP);
       pinMode(latchPin, OUTPUT);
       pinMode(clockPin, OUTPUT);
       pinMode(dataPin, OUTPUT);
       digitalWrite(latchPin, LOW );    // ставим HIGH на "защёлку", чтобы регистр не принимал сигнал
    }


    void lightNumber(int numberToDisplay)
    {
        if ( numberToDisplay >= 0 && numberToDisplay <=10)
        {
            digitalWrite(latchPin, LOW);  // цифра ноль
            shiftOut(dataPin, clockPin, LSBFIRST, digitFonts[numberToDisplay]);
            digitalWrite(latchPin, HIGH);
        }
    }


    void SwitchDigit(int digit) {
      for (int i=0; i<3; i++) {
        if (i == digit) {
          digitalWrite(digit_pin[i], DIGIT_OFF);
        } else {
          digitalWrite(digit_pin[i], DIGIT_ON);
        }
      }
    }


    struct struct_digits IntToDigits(int n)
    {
      struct struct_digits dig;
      int zeros=0;
      int sec;
      int sec1;          
      int sec2;        
      int d;
        for (int i=2; i>=0;  i--)
      {                    
                d=n/60;          
                sec=n-d*60;
                sec1=sec/10;
                sec2=sec-sec1*10;
                if (d!=0 && i==2 )
                {
                  dig.digit[i]=d;
                }
                else if (sec<60 && i==1)
                {
                  //sec1=sec/10;
                  dig.digit[i]=sec1;
                }
                else if (sec2<10 && i==0)
                {
                  //sec2=sec-sec1*10;
                  dig.digit[i]=sec2;
                }
                 else
                {
                  dig.digit[i]=10;
                }
                                   
      }
      return dig;
    }

    void PrintNumber(int n, int time)
    {
      struct struct_digits dig;

      dig = IntToDigits(n);
     
      for (int i=0; i<= time/20; i++)
      {
        if (digitalRead(button2)==LOW)     // кнопка "Reset"
        {
          return;
        }
        for (int j=0; j<3; j++)
        {
          SwitchDigit(j);
          lightNumber(dig.digit[j]);
          delayMicroseconds(tdelay);
        }
      }
    }



    bool Countdown(int n, int del) // возврат времени к установленному ранее значению кнопка " Reset"
    {
      for (int q=n; q>0; q--)
      {
        PrintNumber(q,del);
        if (digitalRead(button2)==LOW)
        {
          return false;
        }
      }
      PrintNumber(0,0);

      return true;
    }


    void reset()
    {
         int m, zeros, d,  pressed3 = 0,pressed4 = 0;
         m=countdown_time;
     
        struct struct_digits dig;
        dig = IntToDigits(countdown_time);
     
      while (digitalRead(button1)==HIGH) // Кнопка " Start"
          {
        for (int j=0; j<3; j++) {
          SwitchDigit(j);
          lightNumber(dig.digit[j]);
          delayMicroseconds(tdelay);
        }
       
        if (digitalRead(button3)==LOW) // кнопка "-"
        {
          if (pressed3 == 0 || pressed3 > 30) // скорость уменьшения тайменра
          {
            if (countdown_time > 0)
            {
              countdown_time -= 1 ;
            }
            dig = IntToDigits(countdown_time);
          }
          pressed3 += 1;
        }
                else if (digitalRead(button4)==LOW)   // кнопка "+"
                  {
                if (pressed4 == 0 || pressed4 > 30)  //скорость увеличения таймера
                      {
                if (countdown_time <599)
                         {
                    countdown_time += 1 ;
                         }
                   
                   dig = IntToDigits(countdown_time);
                       }
                  pressed4 += 1;
                   }
        if (digitalRead(button3)==HIGH)
        {
          pressed3=0;
        }
         if (digitalRead(button4)==HIGH) {
         pressed4=0;
        }
      }
    }



    void loop(){
      reset();
      while (!Countdown(countdown_time,962))
      {
        reset();
      }
      while (digitalRead(button2)==1){};
    }
     
  2. User248

    User248 Гик

    Точность хода можно регулировать здесь, в функции loop:
    Код (C++):
    while (!Countdown(countdown_time, 962))
    Число 962. Чем больше, тем больше задержка. А delay можно оставить на 5 мс. Он и отвечает за скорость стробирования знаков (то есть, последовательное включение). Хотя, можно попробовать поизменять, и может свечение соседних сегментов станет менее заметно.
     
  3. SergeiL

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

    Чуть окультурил ;),
    Но не проверял:
    Код (C++):
    int digit_pin[] = {9, 8, 7};    // PWM Display digit pins from left to right

    #define dataPin  10             // пин подключен к входу 74HC595 DS
    #define latchPin 11             // пин подключен к входу 74HC595 ST_CP
    #define clockPin 12             // пин подключен к входу 74HC595 SH_CP

    const uint8_t digitFonts[11] = {B00000001, B01001111, B00010010, B00000110, B01001100, B00100100, B00100000, B00001111, B00000000, B00000100, B01111111};

    #define DIGIT_ON    HIGH
    #define DIGIT_OFF   LOW

    const uint8_t button1 = 18;  // кнопка старт
    const uint8_t button2 = 19;  // кнопка воврата времени к установленному
    const uint8_t button3 = 16;  // кнопка - уменьшение таймера
    const uint8_t button4 = 17;  // кнопка + увеличение таймера

    #define STATE_STOP    0
    #define STATE_START   1

    uint8_t countdown_state = STATE_STOP;

    int countdown_value = 420;
    int countdown_time = countdown_value;

    uint8_t disp_buff[3]      = {0, 0, 0};

    void setup()
    {
      for (int i = 0; i < 3; i++) {
        digitalWrite(digit_pin[i], DIGIT_OFF);
        pinMode(digit_pin[i], OUTPUT);
      }
      pinMode(button1, INPUT_PULLUP);
      pinMode(button2, INPUT_PULLUP);
      pinMode(button3, INPUT_PULLUP);
      pinMode(button4, INPUT_PULLUP);
      digitalWrite(latchPin, LOW );    // ставим HIGH на "защёлку", чтобы регистр не принимал сигнал
      pinMode(latchPin, OUTPUT);
      digitalWrite(latchPin, HIGH);
      pinMode(clockPin, OUTPUT);
      digitalWrite(latchPin, HIGH);
      pinMode(dataPin, OUTPUT);
    }

    void Time_End(void)    // вызывается при 000,0
    {
      ;   // !!!!!!!!! BooM !!!!!!!!!!!!!
    }

    void Time_Check(uint32_t cur_millis)
    {
      static uint32_t old_millis = 0;
      static uint8_t  old_state = STATE_STOP;
      static int      old_time = 0;

      uint8_t t_min;
      uint8_t t_sec_10;
      uint8_t t_sec_01;

      if ( (countdown_state == STATE_START) && ( old_state != countdown_state || cur_millis - old_millis >= 1000) ) // 1 sec
      {
        old_millis = cur_millis;
        old_state = STATE_START;
     
        if ( countdown_time)
          countdown_time--;
        else
        {
          countdown_state = STATE_STOP;
          Time_End();
          return;
        }
      }

      if (countdown_state == STATE_STOP)
        old_state = STATE_STOP;

      if (old_time != countdown_time)
      {
        old_time = countdown_time;
        t_min     = (uint8_t) (countdown_time / 60);
        t_sec_10  = (uint8_t) ((countdown_time % 60) / 10);
        t_sec_01  = (uint8_t) ((countdown_time % 60) % 10);

        if ( t_min != 0)
          disp_buff[2] = digitFonts[t_min];
        else
          disp_buff[2] = digitFonts[10];

        disp_buff[1] = digitFonts[t_sec_10];
        disp_buff[0] = digitFonts[t_sec_01];
      }
    }

    void Dysplay_Refresh(uint32_t cur_millis)
    {
      static uint32_t   old_millis = 0;
      static uint8_t    prev_pos = 2;
      static uint8_t    pos = 0;

      if ( cur_millis - old_millis >= 7 )  // обновляем разряд раз в 7мс ( 7*3=21мс )
      {
        old_millis = cur_millis;

        digitalWrite(digit_pin[prev_pos], DIGIT_OFF);

        digitalWrite(latchPin, LOW);  // цифра ноль
        shiftOut(dataPin, clockPin, LSBFIRST, disp_buff[pos]);
        digitalWrite(latchPin, HIGH);

        digitalWrite(digit_pin[pos], DIGIT_ON);
     
        prev_pos = pos;
        if (pos == 2)
          pos = 0;
        else
          pos++;
      }
    }

    void Key_Check(uint32_t cur_millis)
    {
      static uint32_t old_millis = 0;
      static uint8_t pressed3 = 0, pressed4 = 0;

      if ( cur_millis - old_millis >= 50 )  //  заходим сюда каждые 50ms
      {
        old_millis = cur_millis;

        if ( countdown_state == STATE_STOP && digitalRead(button1) == LOW ) // кнопка start
        {
          countdown_state = STATE_START;
          countdown_value = countdown_time;
        }

        if (countdown_state == STATE_START && digitalRead(button2) == LOW) // кнопка reset
        {
          countdown_state = STATE_STOP;
          countdown_time = countdown_value;
        }

        if (countdown_state == STATE_STOP && digitalRead(button3) == LOW) // кнопка "-"
        {
          if (pressed3 == 0 || pressed3 >= 10) // скорость уменьшения тайменра
          {
            if (countdown_time > 0)
            {
              countdown_time--;
            }
          }
          if (pressed3 <= 10)  // если не дошли до 10+
            pressed3++;
        }
        else  // отпустили  кнопку "-"
        {
          pressed3 = 0;
        }

        if (countdown_state == STATE_STOP && digitalRead(button4) == LOW) // кнопка "+"
        {
          if (pressed4 == 0 || pressed4 >= 10)  //скорость увеличения таймера
          {
            if (countdown_time < 599)
            {
              countdown_time++;
            }
          }
          if (pressed4 <= 10)  // если не дошли до 10+
            pressed4++;
        }
        else    // отпустили  кнопку "+"
        {
          pressed4 = 0;
        }
      }
    }

    void loop()
    {
      uint32_t cur_millis = millis();

      Time_Check(cur_millis);
      Dysplay_Refresh(cur_millis);
      Key_Check(cur_millis);
    }
     
     
    User248 нравится это.
  4. User248

    User248 Гик

    Попробовал в эмуляторе. Всё работает.
     
  5. SergeiL

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

    Сегменты могли подсвечиваться, потому, что сначала перекидывалось напряжение на другой общий анод, а потом задвигалась информация в сдвиговый регистр.
    То есть, какое то время на выбранном сегменте присутствовала информация с предыдущего сегмента.
    Я сделал так:
    1) снятие напряжения с предыдущего анода,
    2) передача информации в сдвиговый регистр,
    3) включение сегмента,
    4) пауза 7мс .
    Посмотрим, изменится ли подсвечивание сегментов с моим кодом.
     
  6. User248

    User248 Гик

    Кстати, да. В эмуляторе тоже есть такая проблема в старом коде. А с вашим кодом такой проблемы нет. При смене знака какая-то инерция угасания присутствует, но потом всё чисто.
     
  7. SergeiL

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

    Моментально, да не совсем. Там цикл из digitalWrite(), а digitalWrite() и сам не быстрый.
    Плюс одновременно подавалось питание на два сегмента.

    К примеру нужно вывести данные на 0-ой сегмент:
    1) включаем сегмент 0 (он уже выводит те же данные, что и на 2-ом сегменте)
    2) выключаем сегмент 1, который и так выключен.
    3) выключаем сегмент 2 ( а на нулевом все еще отображаются данные 2-го сегмента)
    3) сдвигаем данные в сегмент 0, не гася его.
    4) только сейчас на сегменте 0 появляются корректные данные!

    А у светодиодов, можно сказать, что инерции нет.
     
  8. User248

    User248 Гик

    А я в старом коде поменял порядок включения, и проблема исчезла.
    Было:
    Код (C++):

        SwitchDigit(j);
        lightNumber(dig.digit[j]);
     
    Стало:
    Код (C++):

        lightNumber(dig.digit[j]);
        SwitchDigit(j);
     
     
  9. SergeiL

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

    С первого взгляда - "те же яйца, только в профиль".
    Но возможно влияет время задвигания байта и время закидывания параметров в функцию (переменной вместо структуры).
    ИМХО правильней как у меня:
    1) снятие напряжения с предыдущего анода,
    2) передача информации в сдвиговый регистр,
    3) включение сегмента,
    4) пауза 7мс .
     
  10. User248

    User248 Гик

    Да, какие-то артефакты проскакивают иногда. Тогда можно так:
    Код (C++):

    void displaySet(struct struct_digits &dig)
    {
      for (int j = 0; j < 3; j++)
      {
        for (int i = 0; i < 3; i++) digitalWrite(digit_pin[i], DIGIT_ON); // off digits
        lightNumber(dig.digit[j]);
        digitalWrite(digit_pin[j], DIGIT_OFF); // on digit
        delay(7);
      }
    }

    void lightNumber(int numberToDisplay)
    {
      if ( numberToDisplay >= 0 && numberToDisplay <= 10)
      {
        digitalWrite(latchPin, LOW);  // цифра ноль
        shiftOut(dataPin, clockPin, LSBFIRST, digitFonts[numberToDisplay]);
        digitalWrite(latchPin, HIGH);
      }
    }
     
     
    Последнее редактирование: 7 фев 2022
  11. SergeiL

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

    Да можно и так.
    А for-ы то зачем, ведь и так понятно, что выключается, и что включается.
    Мы же знаем, где были на предыдущем шаге, знаем какой сегмент включали, его и выключаем, а задвигаем в текущий, его включаем.
     
  12. User248

    User248 Гик

    Это черновик, по быстрому. Хотя, в случае offDigit, если на индексе 0, то предыдущий индекс - 2. Лишние заморочки, так проще.
     
  13. SergeiL

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

    Да все заморочки - две статические переменные. Посмотрите, у меня в коде выше нет циклов.
    Посмотрим, как этот код заработает у ТС.
     
  14. Knyaz243

    Knyaz243 Нуб

    Блин большое спасибо!!! Все попробую на выходных, в командировку отправили! Хорошо когда такие люди есть!!!
     
  15. Knyaz243

    Knyaz243 Нуб

    Такой вопрос еще, какой эмулятор используете?
     
  16. User248

    User248 Гик

    Бесплатный онлайн симулятор Tinkercad. В нём есть только Arduino Uno и индикаторы только одноразрядные. Пришлось соединить их параллельно.

    Tinkercad.png
     
  17. Knyaz243

    Knyaz243 Нуб

    Понятно, спасибо! Пользовался им как то не очень удобно, (иногда зависает, обновляешь страницу половина слетает).А что нибудь офлайн есть нормальное?
     
  18. b707

    b707 Гуру

    оффлайн проще всего живую ардуину подключить и пробовать
     
  19. SergeiL

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

    А эмулятор Протеус, из которого тут некоторые не вылезают. Не пробовали?
    Я его не пробовал, поэтому не знаю, что за зверь, и что позволяет.
    Я обычно на готовой железке отлаживаюсь.
    А если просто алгоритм отладить, без работы с железом - то мне проще на виртуалке в DOS на Си написать, скомпилировать и отладить, а потом на МК перетащить..
     
  20. Рокки1945

    Рокки1945 Гуру

    Можно прямым текстом - :).