В прошлой статье мы разбирали устройство семисегментного светодиодного индикатора и собрали из четырех таких приборов устройство:

led dyn5

 

Сегодня мы будем его оживлять, т.е. выводить на индикаторы какую-то осмысленную информацию.

Вкратце еще раз напомню принцип работы таких индикаторов. Они состоят из светодиодов, которые мы зажигаем в определенной комбинации, чтобы получить нужный нам символ или цифру. Каждый индикатор имеет один общий провод (в нашем случае - анод) и восемь выводов, по числу сегментов. Соответствующие друг другу сегментные выводы индикаторов соединяем между собой. Анодные выводы используются для включения и выключения индикаторов. 

Используется принцип динамической индикации. То есть, если последовательно переключать индикаторы с определенной скоростью (около 50 раз в секунду), то человеческому глазу будет казаться, что они горят одновременно.

Ну, поехали программировать. Под спойлером я сразу расположу полный рабочий скетч получившейся программы, а потом разберу ее по кусочкам.

Полный код скетча:

#define DIG1 9
#define DIG2 10
#define DIG3 11
#define DIG4 12
#define A 2
#define B 3
#define C 4
#define D 5
#define E 6
#define FF 7
#define G 8
#define TAKT 5
#define BRIGHT 5

int dig1 = 0;
int dig2 = 0;
int dig3 = 0;
int dig4 = 0;


void setup() {                
  pinMode(A, OUTPUT); pinMode(B, OUTPUT);
  pinMode(C, OUTPUT); pinMode(D, OUTPUT);
  pinMode(E, OUTPUT); pinMode(FF, OUTPUT);
  pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT); pinMode(DIG3, OUTPUT);
  pinMode(DIG4, OUTPUT);
  digitalWrite(A,HIGH); digitalWrite(B,HIGH);
  digitalWrite(C,HIGH); digitalWrite(D,HIGH);
  digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
  digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH);
  digitalWrite(DIG2,HIGH); digitalWrite(DIG3,HIGH);
  digitalWrite(DIG4,HIGH);
}

void loop() {
  DisplayMath((millis() / 1000));
  DisplayShow();
}

void DisplayMath(int data) {
  int DataTemp;
  dig1 = dig2 = dig3 = dig4 = 0;
  if (data < 100) {
    while (data >= 10) {
      data -= 10;
      dig2++;
    }
    dig1 = data;
 
  }
   
      if ((data >= 100)&& (data < 1000)){
        
         while (data >= 100)     {
         data -= 100;
         dig3++;    
         }
         while (data >= 10)     {
         data -= 10;
         dig2++;    
         }
         dig1 = data;
      }  
      
      if ((data >= 1000)&& (data < 10000)){
        
        while (data >= 1000)     {
         data -= 1000;
         dig4++;    
         }
        
         while (data >= 100)     {
         data -= 100;
         dig3++;    
         }
         while (data >= 10)     {
         data -= 10;
         dig2++;    
         }
         dig1 = data;
      }  
     
}


void DisplayShow() {
  digitalWrite(DIG1,HIGH);
  Show(dig1);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG1,LOW);
  delay(TAKT-BRIGHT);
  digitalWrite(DIG2,HIGH);
  Show(dig2);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG2,LOW);
  delay(TAKT-BRIGHT);
//===============================

 digitalWrite(DIG3,HIGH);
  Show(dig3);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG3,LOW);
  delay(TAKT-BRIGHT);

  digitalWrite(DIG4,HIGH);
  Show(dig4);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG4,LOW);
  delay(TAKT-BRIGHT);  
}

void Show(int digit) {
  switch(digit) {
    case 0: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
    }
    break;
    case 1: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
    }
    break;
    case 2: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 3: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 4: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 5: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 6: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 7: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW);
    }
    break;
    case 8: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 9: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
  }
}

void Clean() {
    digitalWrite(A,HIGH); digitalWrite(B,HIGH);
    digitalWrite(C,HIGH); digitalWrite(D,HIGH);
    digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
    digitalWrite(G,HIGH);
}

Приступаем разбирать важные куски скетча:

Сначала задаем выводы Ардуины, к которым будут подключены наши индикаторы, а также - другие параметры и переменные:

#define DIG1 9                // выводы Ардуины
#define DIG2 10             // для подключения анодов
#define DIG3 11             // индикаторов
#define DIG4 12
#define A 2                     // выводы Ардуины
#define B 3                     // для подключения сегментов
#define C 4                    // индикаторов
#define D 5
#define E 6
#define FF 7
#define G 8
#define TAKT 5              // параметры, определяющие
#define BRIGHT 5          // время свечения индикатора (яркость)

int dig1 = 0;                     // четыре целочисленных переменных
int dig2 = 0;                    // для каждого разряда (индикатора)
int dig3 = 0;
int dig4 = 0;


void setup() {                
  pinMode(A, OUTPUT); pinMode(B, OUTPUT);      // первичная настройка всех выводов для 
  pinMode(C, OUTPUT); pinMode(D, OUTPUT);     // работы на выход
  pinMode(E, OUTPUT); pinMode(FF, OUTPUT);
  pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT);
  pinMode(DIG2, OUTPUT); pinMode(DIG3, OUTPUT);
  pinMode(DIG4, OUTPUT);
  digitalWrite(A,HIGH); digitalWrite(B,HIGH);           // гашение всех сегментов
  digitalWrite(C,HIGH); digitalWrite(D,HIGH);
  digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
  digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH);
  digitalWrite(DIG2,HIGH); digitalWrite(DIG3,HIGH);
  digitalWrite(DIG4,HIGH);

//++++++++++++++++++++++++++++++++++++++++

Вроде бы, с установками все просто и вопросов быть не должно. Поэтому перейдем сразу к функциям.

Функция Clean() - это то же самое гашение индикаторов, что и в первоначальной установке, только вызывается в процессе работы. При установке на сегментах высокого уровня - индикаторы гаснут, независимо от того, какой уровень присутствует на анодах.

 void Clean() {
    digitalWrite(A,HIGH); digitalWrite(B,HIGH);
    digitalWrite(C,HIGH); digitalWrite(D,HIGH);
    digitalWrite(E,HIGH); digitalWrite(FF,HIGH);
    digitalWrite(G,HIGH);
}

//++++++++++++++++++++++++++++++++++++++++

Функция Show(int digit) - предназначена непосредственно для зажигания определенных сегментов, соответствующих переданному в нее целому числу digit. Работает она так - в функцию передается целое число. При помощи оператора switch() - case, она сравнивает его с предопределенными значениями, и , если натыкается на совпадение этих значений, то зажигает определенные сегменты индикатора, соответствующие переданному в функцию числу

void Show(int digit) {
  switch(digit) {                             
    case 0: {                                                                    //если переданное в функцию число - 0
      digitalWrite(A,LOW); digitalWrite(B,LOW);        // то зажигаются сегменты индикатора,
      digitalWrite(C,LOW); digitalWrite(D,LOW);        // образующие рисунок цифры 0
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
    }
    break;
    case 1: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
    }
    break;
    case 2: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 3: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 4: {
      digitalWrite(B,LOW); digitalWrite(C,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 5: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 6: {
      digitalWrite(A,LOW); digitalWrite(C,LOW);
      digitalWrite(D,LOW); digitalWrite(E,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
    case 7: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW);
    }
    break;
    case 8: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(E,LOW); digitalWrite(FF,LOW);
      digitalWrite(G,LOW);
    }
    break;
    case 9: {
      digitalWrite(A,LOW); digitalWrite(B,LOW);
      digitalWrite(C,LOW); digitalWrite(D,LOW);
      digitalWrite(FF,LOW); digitalWrite(G,LOW);
    }
    break;
  }
}

 //++++++++++++++++++++++++++++++++++++++

Функция DisplayShow() - обеспечивает поочередную индикацию всех четырех разрядов нашего устройства. Причем, как говорилось выше - с такой скоростью, чтобы для человеческого глаза казалось, что они горят одновременно. Глобальные переменные dig1 - dig4 должны содержать поразрядно цифры, которые нам необходимо индицировать.

void DisplayShow() {
  digitalWrite(DIG1,HIGH);          // зажигаем первый индикатор подачей на анод высокого уровня (1).
  Show(dig1);                                // вызываем функцию Show(dig1) и устанавливаем на сегментах уровни для индикации соответствующей цифры.
  delay(BRIGHT);                          // делаем короткую паузу, чем она больше, тем больше яркость горения индикатора.
  Clean();                                        // гасим индикатор
  digitalWrite(DIG1,LOW);           // подаем на анод низкий уровень (0)
  delay(TAKT-BRIGHT);              // чисто для экспериментов - поиграться со значениями времени горения индикатора:-) 

//_----------------------
  digitalWrite(DIG2,HIGH);
  Show(dig2);
  delay(BRIGHT);
  Clean();
  digitalWrite(DIG2,LOW);
  delay(TAKT-BRIGHT);

//+++++++++++++++++++++++++++++++++++++++++

Самая важная функция DisplayMath(int data). В нее передается целое число (data), которое для нашего 4-х разрядного устройства может быть в интервале от 0 до 9999. Эта функция разбивает это число по разрядам для индикации соответствующих цифр в каждом разряде нашего устройства. 

Общий принцип такой: от заданного для индикации числа, в цикле отнимают тысячи, сотни или десятки, одновременно инкрементируя старший разряд. Но лучше всего это понять на примерах:

void DisplayMath(int data) {
  dig1 = dig2 = dig3 = dig4 = 0;      // в переменные, соответстующие разрядам индикатора записывается 0
  if (data < 100) {                               // если число, переданное для индикации меньше 100,
    while (data >= 10) {                     // пока число больше 10, в цикле отнимаем от него
      data -= 10;                                  //десятки, одновременно
      dig2++;                                       // инкрементируя на каждом проходе переменную dig2, соответствующую цифре второго разряда.
    }
    dig1 = data;                                 // остаток, когда число станет меньше 10, записываем в переменную первого разряда.
 
  }
   
      if ((data >= 100)&& (data < 1000)){              // если переданное число в интервале от 100 до 1000
        
         while (data >= 100)     {                               // аналогично вышеизложенному, вычитаем из него
         data -= 100;                                                 // сотни, одновременно накапливая третий разряд (сотни)
         dig3++;    
         }
         while (data >= 10)     {                                 // когда в результате вычитаний сотен, число станет <100
         data -= 10;                                                   // но >=10, начинаем вычитать десятки,
         dig2++;                                                         // накапливая второй разряд (десятки)
         }
         dig1 = data;                                                 // остаток записываем в первый разряд
      }  
      
      if ((data >= 1000)&& (data < 10000)){       // аналогично поступаем, если переданное число находится
                                                                              // в интервале от 1000 до 9999.
        while (data >= 1000)     {
         data -= 1000;
         dig4++;    
         }
        
         while (data >= 100)     {
         data -= 100;
         dig3++;    
         }
         while (data >= 10)     {
         data -= 10;
         dig2++;    
         }
         dig1 = data;
      }  
     
}

//++++++++++++++++++++++++++++++++++++++++

Для проверки работоспособности также использована уже знакомая функция millis(), которая отсчитывает миллисекунды, прошедшие с момента включения устройства. В данном случае, она передает для индикации количество секунд с момента включения, которые мы и можем наблюдать на индикаторах:

led dyn7

 

Используя описанные функции, на основе таких индикаторов, совсем нетрудно собрать какие-нибудь часы с термометром, как в предыдущих статьях. Единственное, за чем нужно следить, чтобы в процессе работы всех частей скетча не было временных задержек, бОльших, чем используются в функциях, осуществляющих саму динамическую индикацию.

Добавить комментарий