Включение двух 3-разрядных индикаторов

Тема в разделе "Arduino & Shields", создана пользователем Glyuk, 6 май 2016.

  1. Glyuk

    Glyuk Нерд

    Требуется выводить информацию на 2 трёхразрядных семисегментных индикатора.
    Собрал схему:
    [​IMG]
    Код:
    Код (C++):
    #include "math.h"
    #define DATA_PIN    13                 // пин данных (англ. data)
    #define LATCH_PIN   12                 // пин строба(защёлки) (англ. latch)
    #define CLOCK_PIN   11                 // пин такта (англ. clock)
    #define DATA_PIN2   10                 // пин данных (англ. data)
    #define LATCH_PIN2   9                 // пин строба(защёлки) (англ. latch)
    #define CLOCK_PIN2   8                 // пин такта (англ. clock)
    byte SegDisplay;                       // переменная для вывода символов на индикаторе
    byte RazrDisplay;                      // переменная для включения разрядов
    byte SegDisplay2;                      // переменная для вывода символов на индикаторе
    byte RazrDisplay2;                     // переменная для включения разрядов
    byte razryad[3]={127,191,223};         // массив цифр, указывающий разряды
    byte segments[12]= {                   // массив цифр, генерирующий из сегментов цифры
      252, 96, 218, 242,                   // 0, 1, 2, 3
      102, 182, 190, 224,                  // 4, 5, 6, 7
      254, 246, 2, 0 };                    // 8, 9, -, .
    int POT_PIN = A0;                      // потенциометр
    int POT_PIN2 = A2;                     // потенциометр

    void setup(){
      pinMode(DATA_PIN, OUTPUT);           // DATA_PIN выход
      pinMode(CLOCK_PIN, OUTPUT);          // CLOCK_PIN выход
      pinMode(LATCH_PIN, OUTPUT);          // LATCH_PIN выход
      pinMode(DATA_PIN2, OUTPUT);          // DATA_PIN выход
      pinMode(CLOCK_PIN2, OUTPUT);         // CLOCK_PIN выход
      pinMode(LATCH_PIN2, OUTPUT);         // LATCH_PIN выход                
    }
    void loop(){
      int POT = analogRead(POT_PIN);
      int POT_NUMBER = map(POT, 0, 1023, 0, 120);
      int number = 0;                     // создаем переменную для вывода на экран
          number = POT_NUMBER;                              
                                          // Разбиваем цифру по разрядам индикатора
      if (number < 10){                   // если наша цифра меньше 10, то
        Indicate(0, 11);                  // пишем в первый разряд пусто
        Indicate(1, 11);                  // пишем во второй разряд пусто
        Indicate(2, number);              // пишем в третий разряд цифру
      }
      else if (number < 100){             // если наша цифра меньше 100, то
        Indicate(0, 11);                  // пишем в первый разряд пусто
        Indicate(1, number / 10);         // пишем во второй разряд - цифру делёную на 10
        Indicate(2, number % 10);         // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      else {                              // если наша цифра меньше 1000, то
        Indicate(0, number / 100);        // пишем в первый разряд - цифру делёную на 100
        Indicate(1, (number % 100) / 10); // пишем во второй разряд - цифру цифру оставшуюся от деления на 100 делённую на 10
        Indicate(2, number % 10);         // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }

      int POT2 = analogRead(POT_PIN2);
      int POT_NUMBER2 = map(POT2, 0, 1023, 0, 120);
      int number2 = 0;                     // создаем переменную для вывода на экран
          number2 = POT_NUMBER2;                  
                                           // Разбиваем цифру по разрядам индикатора
      if (number2 < 10){                   // если наша цифра меньше 10, то
        Indicate2(0, 11);                  // пишем в первый разряд пусто
        Indicate2(1, 11);                  // пишем во второй разряд пусто
        Indicate2(2, number2);             // пишем в третий разряд цифру
      }
      else if (number2 < 100){             // если наша цифра меньше 100, то
        Indicate2(0, 11);                  // пишем в первый разряд пусто
        Indicate2(1, number2 / 10);        // пишем во второй разряд - цифру делёную на 10
        Indicate2(2, number2 % 10);        // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      else {                               // если наша цифра меньше 1000, то
        Indicate2(0, number2 / 100);       // пишем в первый разряд - цифру делёную на 100
        Indicate2(1, (number2 % 100) / 10);// пишем во второй разряд - цифру цифру оставшуюся от деления на 100 делённую на 10
        Indicate2(2, number2 % 10);        // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
    }

    void Indicate(int r,int x){
    SegDisplay=segments[x];                                     // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
    RazrDisplay=razryad[r];                                     // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
      digitalWrite(LATCH_PIN, LOW);                             // устанавливаем синхронизацию "защелки" на LOW
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, RazrDisplay); // Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, SegDisplay);  // Записываем информацию для первого регистра (Номер символа)
      digitalWrite(LATCH_PIN, HIGH);                            // "защелкиваем" регистр, тем самым устанавливая значения на выходах
          delayMicroseconds(2500);                              // пауза, чтобы сегменты "разгорелись"
    }

    void Indicate2(int r2,int x2){
    SegDisplay2=segments[x2];                                     // получаем цифру и выводим символ, из массива цифр, соответствующий этой цифре.
    RazrDisplay2=razryad[r2];                                     // получаем цифру и выводим номер регистра, из массива цифр, соответствующий этой цифре.
      digitalWrite(LATCH_PIN2, LOW);                              // устанавливаем синхронизацию "защелки" на LOW
          shiftOut(DATA_PIN2, CLOCK_PIN2, LSBFIRST, RazrDisplay2);// Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN2, CLOCK_PIN2, LSBFIRST, SegDisplay2); // Записываем информацию для первого регистра (Номер символа)
      digitalWrite(LATCH_PIN2, HIGH);                             // "защелкиваем" регистр, тем самым устанавливая значения на выходах
          delayMicroseconds(2500);                                // пауза, чтобы сегменты "разгорелись"
    }  
    С таким кодом на обоих индикаторах тускло горят 2 и 3 разряды,1 разряд на обоих нормально, мерцание пропало после установки задержки в 2.5 миллисекунды после функций indicate.
    [​IMG]
    Если задержку в одной из функций убрать, то нормально работает идникатор, в функции которого задержка осталась, что можно сделать?
     

    Вложения:

    • t6666.JPG
      t6666.JPG
      Размер файла:
      832,2 КБ
      Просмотров:
      795
    • hJUbCzZi2vk.jpg
      hJUbCzZi2vk.jpg
      Размер файла:
      33,2 КБ
      Просмотров:
      918
    Последнее редактирование: 6 май 2016
  2. AlexU

    AlexU Гуру

    Попробуйте организовать вывод на индикаторы следующим образом:
    1. вывод в первый сегмент обоих индикаторов Indicate1(0, XX) & Indicate2(0, XX);
    2. небольшая задержка;
    3. вывод во второй сегмент обоих индикаторов Indicate1(1, XX) & Indicate2(1, XX);
    4. небольшая задержка;
    5. вывод в третий сегмент обоих индикаторов Indicate1(2, XX) & Indicate2(2, XX);
    6. небольшая задержка.
    И, если есть возможность, функционал опроса датчиков лучше вынести в отдельный поток -- вывод на индикаторы оставить в 'loop()', а опрос организовать через таймер.
     
  3. Glyuk

    Glyuk Нерд

    Включил все регистры последовательно, так наверно проще даже будет:
    [​IMG]
    Изменил функцию:
    Код (C++):

    #include "math.h"
    #define DATA_PIN    13                 // пин данных (англ. data)
    #define LATCH_PIN   12                 // пин строба(защёлки) (англ. latch)
    #define CLOCK_PIN   11                 // пин такта (англ. clock)
    byte SegDisplay;                       // переменная для вывода символов на индикаторе
    byte RazrDisplay;                      // переменная для включения разрядов
    byte razryad[3]={127,191,223};         // массив цифр, указывающий разряды
    byte segments[12]= {                   // массив цифр, генерирующий из сегментов цифры
      252, 96, 218, 242,                   // 0, 1, 2, 3
      102, 182, 190, 224,                  // 4, 5, 6, 7
      254, 246, 2, 0 };                    // 8, 9, -, .
    int POT_PIN = A2;                      // потенциометр
    int POT_PIN2 = A0;                     // потенциометр

    void setup(){
      pinMode(DATA_PIN, OUTPUT);           // DATA_PIN выход
      pinMode(CLOCK_PIN, OUTPUT);          // CLOCK_PIN выход
      pinMode(LATCH_PIN, OUTPUT);          // LATCH_PIN выход            
    }
    void loop(){
      int POT = analogRead(POT_PIN);
      int POT_NUMBER = map(POT, 0, 1023, 0, 120);
      int number = 0;                  
          number = POT_NUMBER;
       
      int POT2 = analogRead(POT_PIN2);
      int POT_NUMBER2 = map(POT2, 0, 1023, 0, 120);
      int number2 = 0;                  
          number2 = POT_NUMBER2;    

      if (number < 10 or number2 <10){           // если наша цифра меньше 10, то
        Indicate(0, 11, 11);                     // пишем в первый разряд пусто
        Indicate(1, 11, 11);                     // пишем во второй разряд пусто
        Indicate(2, number, number2);            // пишем в третий разряд цифру
      }
      else if (number < 100 or number2 < 100){   // если наша цифра меньше 100, то
        Indicate(0, 11, 11);                     // пишем в первый разряд пусто
        Indicate(1, number / 10, number2 / 10);  // пишем во второй разряд - цифру делёную на 10
        Indicate(2, number % 10, number2 % 10);  // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      else {                                                       // если наша цифра меньше 1000, то
        Indicate(0, number / 100, number2 / 100);                  // пишем в первый разряд - цифру делёную на 100
        Indicate(1, (number % 100) / 10, (number2 % 100) / 10);    // пишем во второй разряд - цифру цифру оставшуюся от деления на 100 делённую на 10
        Indicate(2, number % 10, number2 % 10);                    // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      }
      void Indicate(int r, int x, int r2){
        digitalWrite(LATCH_PIN, LOW);                             // устанавливаем синхронизацию "защелки" на LOW
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, razryad[r]);    // Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, segments[x]);   // Записываем информацию для первого регистра (Номер символа)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, razryad[r]);    // Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, segments[r2]);  // Записываем информацию для первого регистра (Номер символа)
        digitalWrite(LATCH_PIN, HIGH);                            // "защелкиваем" регистр, тем самым устанавливая значения на выходах
          delayMicroseconds(5);                                   // пауза, чтобы сегменты "разгорелись"
      }
     
    Теперь, чтобы горели 2 разряда на одном из индикаторов нужно и на втором включать 2 разряда, чтобы 3 разряда горели, нужно чтобы и на втором 3 разряда горело, иначе показывает ерунду. На сколько я понимаю проблема в цикле
    Код (C++):
    if (number < 10 or number2 <10){           // если наша цифра меньше 10, то
        Indicate(0, 11, 11);                     // пишем в первый разряд пусто
        Indicate(1, 11, 11);                     // пишем во второй разряд пусто
        Indicate(2, number, number2);            // пишем в третий разряд цифру
      }
      else if (number < 100 or number2 < 100){   // если наша цифра меньше 100, то
        Indicate(0, 11, 11);                     // пишем в первый разряд пусто
        Indicate(1, number / 10, number2 / 10);  // пишем во второй разряд - цифру делёную на 10
        Indicate(2, number % 10, number2 % 10);  // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      else {                                                       // если наша цифра меньше 1000, то
        Indicate(0, number / 100, number2 / 100);                  // пишем в первый разряд - цифру делёную на 100
        Indicate(1, (number % 100) / 10, (number2 % 100) / 10);    // пишем во второй разряд - цифру цифру оставшуюся от деления на 100 делённую на 10
        Indicate(2, number % 10, number2 % 10);                    // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
    В программировании я не силён, что можно с этим сделать?
     
  4. Unixon

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

    Вы в оба разрядных регистра запихиваете одни и те же данные, естественно зажигаться будут оба индикатора.

    Несколько замечаний:

    1) Электрическое. Обратите внимание на допустимый ток вывода регистра и на допустимый суммарный ток через вывод GND самого регистра, куда у вас подключены GNDn от индикаторов. В этом месте стоит подключать индикаторы не напрямую к регистрам, а через транзисторы (полевик типа 2N7000/2N7002 сойдет).
    2) Количество регистров можно сократить до 3-х, поскольку у вас 6 сегментов, для управления разрядами достаточно одного регистра.
    3) Программное. Поскольку в процессе индикации данные не меняются, вычисляйте содержимое массивов один раз заранее, а потом уже выводите. Ну и ... razryad называется digit :)
     
    Glyuk нравится это.
  5. Glyuk

    Glyuk Нерд

    На сколько я понял нужно сделать так:
    Код (C++):
    #include "math.h"
    #define DATA_PIN    13                 // пин данных (англ. data)
    #define LATCH_PIN   12                 // пин строба(защёлки) (англ. latch)
    #define CLOCK_PIN   11                 // пин такта (англ. clock)
    byte SegDisplay;                       // переменная для вывода символов на индикаторе
    byte RazrDisplay;                      // переменная для включения разрядов
    byte SegDisplay2;                       // переменная для вывода символов на индикаторе
    byte RazrDisplay2;                      // переменная для включения разрядов
    byte razryad[3]={127,191,223};         // массив цифр, указывающий разряды
    byte segments[12]= {                   // массив цифр, генерирующий из сегментов цифры
      252, 96, 218, 242,                   // 0, 1, 2, 3
      102, 182, 190, 224,                  // 4, 5, 6, 7
      254, 246, 2, 0 };                    // 8, 9, -, .
    int POT_PIN = A2;                      // потенциометр
    int POT_PIN2 = A0;                     // потенциометр

    void setup(){
      pinMode(DATA_PIN, OUTPUT);           // DATA_PIN выход
      pinMode(CLOCK_PIN, OUTPUT);          // CLOCK_PIN выход
      pinMode(LATCH_PIN, OUTPUT);          // LATCH_PIN выход            
      Serial.begin(9600);
    }
    void loop(){
      int POT = analogRead(POT_PIN);
      int POT_NUMBER = map(POT, 0, 1023, 0, 121);
      POT_NUMBER = constrain(POT_NUMBER, 1, 120);
      int number = 0;                    
          number = POT_NUMBER;  
         
      int POT2 = analogRead(POT_PIN2);
      int POT_NUMBER2 = map(POT2, 0, 1023, 0, 121);
      POT_NUMBER2 = constrain(POT_NUMBER2, 1, 120);
      int number2 = 0;                  
          number2 = POT_NUMBER2;    

      if (number < 10 or number2 < 10){                  // если наша цифра меньше 10, то
        Indicate(0,  11,      0,  11);                     // пишем в первый разряд пусто
        Indicate(1,  11,      1,  11);                     // пишем во второй разряд пусто
        Indicate(2,  number,  2,  number2);                // пишем в третий разряд цифру
      }
      else if (number < 100 or number2 < 100){           // если наша цифра меньше 100, то
        Indicate(0,  11,            0,  11);               // пишем в первый разряд пусто
        Indicate(1,  number / 10,   1,  number2 / 10);     // пишем во второй разряд - цифру делёную на 10
        Indicate(2,  number % 10,   2,  number2 % 10);     // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      else {                                                       // если наша цифра меньше 1000, то
        Indicate(0,  number / 100,        0,  number2 / 100);        // пишем в первый разряд - цифру делёную на 100
        Indicate(1,  (number % 100) / 10, 1,  (number2 % 100) / 10); // пишем во второй разряд - цифру цифру оставшуюся от деления на 100 делённую на 10
        Indicate(2,  number % 10,         2,  number2 % 10);         // пишем в третий разряд - цифру цифру оставшуюся от деления на 10
      }
      }
      void Indicate(int r, int x, int r2, int x2){
        SegDisplay = segments[x];                    
        RazrDisplay = razryad[r];
        SegDisplay2 = segments[x2];                    
        RazrDisplay2 = razryad[r2];                  
        digitalWrite(LATCH_PIN, LOW);                             // устанавливаем синхронизацию "защелки" на LOW
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, RazrDisplay);    // Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, SegDisplay);   // Записываем информацию для первого регистра (Номер символа)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, RazrDisplay2);    // Записываем информацию для второго регистра (Номер разряда)
          shiftOut(DATA_PIN, CLOCK_PIN, LSBFIRST, SegDisplay2);  // Записываем информацию для первого регистра (Номер символа)
        digitalWrite(LATCH_PIN, HIGH);                            // "защелкиваем" регистр, тем самым устанавливая значения на выходах
          delay(5);                                               // пауза, чтобы сегменты "разгорелись"
        }
    Но ничего не изменилось!
     
  6. Unixon

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

    Вы не там изменили код. Смысл замечания был в том, что не нужно в loop() каждый раз бить число на разряды. Поскольку у вас цикл динамической индикации зачем-то перемешан с главным циклом (измерение-индикация-управление), то данные каждый раз другие. Динамическую индикацию нужно выносить в отдельные функции. Например, RefreshDisplay() должна вызываться по таймеру из обработчика прерывания и тупо выбрасывать буфер дисплея в регистры, а UpdateDisplay(int n) бить число n на разряды и заполнять буфер дисплея новыми данными. UpdateDisplay(n) уже может вызываться из главного цикла или любого другого места асинхронно для обновления данных дисплея.
     
  7. Glyuk

    Glyuk Нерд

    Можете по-подробнее объяснить как это реализовать?
     
  8. Unixon

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

    Если еще подробнее, то это уже только код писать от и до :)