Урок 20. Подключение семисегментного светодиодного (LED) индикатора к Ардуино. Библиотека управления индикатором.

LED индикаторы

Подключим семисегментный светодиодный индикатор к плате Ардуино и научимся управлять им с помощью библиотеки Led4Digits.h.

Предыдущий урок     Список уроков     Следующий урок

В предыдущем уроке подробно описаны схемы подключения семисегментных LED индикаторов к микроконтроллерам. Подключим такой индикатор к плате Ардуино.

 

Мне попался типичный семисегментный светодиодный индикатор GNQ-3641BUE-21. Это четырех разрядный индикатор, очень яркий, светится при малых токах. Технические характеристики можно посмотреть в формате PDF - GNQ-3641Ax-Bx.pdf.

Схема подключения индикатора к плате Ардуино выглядит так.

Схема подключения LED к плате Ардуино

Я собрал ее на монтажной плате.

Подключение LED к плате Ардуино

Для управления индикаторами я написал библиотеку Led4Digits.h. Библиотека позволяет управлять семисегментными индикаторами:

  • размерностью до четырех разрядов ;
  • с любыми вариантами полярностей управляющих импульсов (все схемы подключения);
  • работает в параллельном процессе;
  • позволяет выводить на индикатор:
    • сегменты каждого разряда;
    • цифру каждого разряда;
    • целое число 0 … 9999;
  • для вывода целого числа может быть задано число разрядов;
  • есть режим гашения незначащих разрядов.

Загрузить библиотеку Led4Digits.h можете по этой ссылке. Как устанавливать написано в уроке 9.

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

 

Библиотека управления LED индикаторами для Ардуино Led4Digits.

Вот описание класса. Я привел только public методы и свойства.

class Led4Digits {
  public:
    byte digit[4];  // коды управления сегментами разрядов
    void regen(); // регенерация, метод должен вызываться регулярно
    void tetradToSegCod(byte dig, byte tetrad);  // преобразования тетрады в коды сегментов
    boolean print(unsigned int value, byte digitNum, byte blank); // вывод целого числа
    Led4Digits (byte typeLed, byte digitPin0,  byte digitPin1, byte digitPin2, byte digitPin3,
                byte segPinA, byte segPinB, byte segPinC, byte segPinD,
                byte segPinE, byte segPinF, byte segPinG, byte segPinH );    
} ;

Конструктор.

    Led4Digits (byte typeLed, byte digitPin0,  byte digitPin1, byte digitPin2, byte digitPin3,
                byte segPinA, byte segPinB, byte segPinC, byte segPinD,
                byte segPinE, byte segPinF, byte segPinG, byte segPinH );    

typeLed  Задает полярности управляющих импульсов для сигналов выбора разрядов и сегментов. Поддерживает любые схемы подключения (Урок 19).

typeLed Выбор разряда Выбор сегмента Тип схемы
0 -_- -_- Общий анод с ключами выбора разряда
1 _-_ -_- Общий анод
2 -_- _-_ Общий катод
3 _-_ _-_ Общий катод с ключами выбора разряда

digitPin0 … digitPin3 – выводы выбора разрядов. Если digitPin = 255, то разряд отключен. Это позволяет подключать индикаторы с меньшим количеством разрядов. digitPin0 – младший (правый) разряд.

segPinA … segPinH – выводы управления сегментами.

Например,

Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

означает:  тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13.

Метод  void regen()

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

Например,

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

Массив    byte digit[4]

Содержит состояние сегментов. digit[0] это младший разряд, младший бит digit[0] это сегмент ”A” младшего разряда. Состояние бита равное 1, означает, что сегмент светится.

Например,

digit[1] = B0000101;

означает, что во втором разряде светятся сегменты ”A” и ”C”.

Пример программы, которая последовательно зажигает все сегменты каждого разряда.

// бегущие сегменты
#include <MsTimer2.h>
#include <Led4Digits.h>

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
  MsTimer2::start();               // разрешение прерывания 
}

void loop() {
  for (int i = 0; i < 32; i++) {
    if ( i == 0) disp.digit[0]= 1;
    else if ( i == 8)  disp.digit[1]= 1;
    else if ( i == 16) disp.digit[2]= 1;
    else if ( i == 24) disp.digit[3]= 1;
    else {
      disp.digit[0] = disp.digit[0] << 1;
      disp.digit[1] = disp.digit[1] << 1;
      disp.digit[2] = disp.digit[2] << 1;
      disp.digit[3] = disp.digit[3] << 1;     
    }
    delay(250);   
  } 
}

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

В массиве digit[] сдвигается 1 и индикаторы отображают это.

Метод  void tetradToSegCod(byte dig, byte tetrad)

Метод позволяет выводить на отдельные разряды цифры и буквы шестнадцатеричного кода. Имеет аргументы:

  • dig – номер разряда 0 … 3;
  • tetrad – десятичный код символа. Код 0 отобразит цифру ”0”, код 1 - цифру ”1”, код 14 - букву ”E”.

Например,

tetrad(2, 7);

выведет цифру “7” в третьем разряде.

Пример программы меняющей символы в каждом разряде по очереди.

// цифры по очереди
#include <MsTimer2.h>
#include <Led4Digits.h>

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
  MsTimer2::start();               // разрешение прерывания 
}

void loop() {
  for (int i = 0; i < 64; i++) {
    disp.tetradToSegCod(i>>4, i);       
    delay(250);   
  }
}

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

Метод  boolean print(unsigned int value, byte digitNum, byte blank)

Метод выводит на индикаторы целое число. В нем двоичное число преобразуется в двоично-десятичный код для каждого разряда. Имеет аргументы:

  • value – число, которое выводится на индикатор.
  • digitNum – количество разрядов для числа. Не надо путать с количеством разрядов индикатора. Вы можете захотеть вывести число на 2х разрядах, а на остальных двух отобразить символы, используя digit[].
  • blank – признак гашения незначащих разрядов. blank=0 означает, что число должно отображаться со всеми нулями. Число ”7” будет выглядеть “0007”. При blank, отличном от 0 незначащие нули будут гаситься.

Если число value превышает допустимое для выбранного количества разрядов (digitNum), то функция отобразит на индикаторе ”---” и вернет false.

Пример программы вывода чисел.

// вывод числа
#include <MsTimer2.h>
#include <Led4Digits.h>

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
  MsTimer2::start();               // разрешение прерывания
}

void loop() {
  for (int i = 0; i < 12000; i++) {
    disp.print(i, 4, 1);       
    delay(50);   
  } 
}

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

Последние два метода не меняют состояния сегмента ”H” – децимальной точки. Чтобы изменить состояние точки можно использовать команды:

digit[0] |= 0x80;  // зажечь децимальную точку
digit[0] &= 0x7f;  // погасить децимальную точку

 

Вывод на индикаторы отрицательных чисел (int).

Вывод отрицательных чисел можно производить следующим образом:

  • Проверить знак числа.
  • Если число отрицательное, то напечатать на старшем разряде знак минус и в функции print() изменить знак числа на положительный.
  • Если число положительное, то погасить разряд знака и вывести число функцией print().

Вот программа, которая демонстрирует такой способ. Она выводит числа от -999 до 999.

// вывод отрицательных чисел
#include <MsTimer2.h>
#include <Led4Digits.h>

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
  MsTimer2::start();               // разрешение прерывания 
}

void loop() {
 
  for (int i = -999; i < 1000; i++) {

    if ( i < 0 ) {
    // число отрицательно
    disp.digit[3]= B01000000; // знак -
    disp.print(i * -1, 3, 1);             
    }
    else {
      disp.digit[3]= B00000000; // гашение знака
      disp.print(i, 3, 1);   
    }
           
    delay(50);   
  } 
}

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

 

Вывод на индикаторы дробных чисел, формат float.

Для вывода на индикаторы чисел с плавающей запятой (float) существует много способов с использованием стандартных функций языка C. Это, прежде всего, функция sprint(). Работает очень медленно, требует дополнительных преобразований кодов символов в двоично-десятичные коды, надо из строки выделять точку. С другими функциями те же проблемы.

Я использую другой способ вывода на индикаторы значений переменных float. Способ простой, надежный, быстрый. Сводится к следующим операциям:

  • Число с плавающей запятой умножается на 10 в степени соответствующей требуемому числу знаков после запятой. Если вам необходимо на индикаторы выводить 1 знак после запятой, умножаете на 10, если 2, то умножаете на 100, 3 знака – на 1000.
  • Далее число с плавающей запятой явно преобразуется в целое (int) и выводится на индикаторы функцией print().
  • В нужном разряде ставится точка.

Например, следующие строки выведут на семисегментные светодиодные индикаторы переменную типа float с двумя знаками после запятой.

float x = 2.12345;
disp.print((int)(x * 100.), 4, 1);  
disp.digit[2] |= 0x80;  // зажечь точку третьего разряда

Мы умножаем число на 100, а поставив точку в третьем разряде, делим результат на 100.

Вот программа, выводящая на индикаторы числа с плавающей запятой от 0.00 до 99.99.

// вывод чисел с плавающей запятой
#include <MsTimer2.h>
#include <Led4Digits.h>

// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

void setup() {
  MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
  MsTimer2::start();               // разрешение прерывания 
}

void loop() { 
  float x = 0;
 
  for (int i = 0; i < 10000; i++) {
    x += 0.01;

    disp.print((int)(x * 100.), 4, 1);   
    disp.digit[2] |= 0x80;  // зажечь точку третьего разряда
               
    delay(50);   
  } 
}

// обработчик прерывания 2 мс
void  timerInterrupt() {
  disp.regen(); // регенерация индикатора
}

Как видите, библиотека Led4Digits.h значительно упрощает работу с семисегментыми светодиодными (LED) индикатороми, подключенными к плате Ардуино. Аналога такой библиотеки я не нашел.

 

В следующем уроке подключим к плате Ардуино одновременно светодиодный индикатор и матрицу кнопок. Напишем библиотеку для такой конструкции.

Предыдущий урок     Список уроков     Следующий урок

76 комментариев на «Урок 20. Подключение семисегментного светодиодного (LED) индикатора к Ардуино. Библиотека управления индикатором.»

  1. Замечательная библиотека! Ардуинка по количеству выводов позволяет подключить два четырёхразрядных индикатора (8+8+4=20 или 7+7+4=18). Хотелось бы использовать с двумя- есть ли такая возможность? Самый простой вариант применения- измерение тока и напряжения одновременно.

  2. Я думаю, что при количестве разрядов более 4 удобнее использовать LCD индикатор с контроллером. Сейчас пишу урок на эту тему.
    Что касается LED индикаторов. Может, попробуете сами библиотеку на большее число разрядов переписать? Я старался все объяснить подробно.

    • LCD индикатор с контроллером подключал, семисегментные LED индикаторы 3шт по 4 разряда через регистры тоже подключал. Но интересно было бы именно на голую Arduino PRO mini, то есть чтоб ничего лишнего. И кстати, не больше разрядов, а именно два индикатора, они могут отдельно стоять, и выходы общих анодов (катодов) общие для двух индикаторов, то есть скважность не увеличивается. До написания библиотек я вряд ли дорасту. Вообще странно, что для такой вроде востребованной функции есть только ваша библиотека. Спасибо!

    • Таки нашёл ещё одну библиотеку, тоже 4 разряда:
      https://github.com/fabiantheblind/Seven-Segment-LED-Arduino-Libraries/tree/master/Pineapple

  3. Спасибо, отличная библиотека и пояснения! Но у меня почему-то на цифрах 9, 5, 3 перестаёт работать нижний сегмент, хотя на всех остальных он есть, в чём может быть дело? Проверил все цепи, соединения нормальные.

    • Спасибо. Скорее всего у вас замкнут сегмент d с каким-то другим сегментом. Прозвоните все сегменты между собой.

      • Да действительно был косяк в разводке платы индикатора и сегменты D и E замыкались, один получается гасил другой.

  4. Здравствуйте! Огромное спасибо за ваши уроки!
    Отличная библиотека!
    Скажите, знак «минус» при выводе отрицательных чисел мерцает, — это так должно быть, или я что-то неправильно делаю?

    • Спасибо!
      Нет знак минус мерцать не должен. Посмотрите внимательно, что вы делаете с 3 разрядом. Для вывода отрицательных чисел в функции print должно быть указано 3 разряда.
      disp.print((int)(temperature * -1 * 10.), 3, 1);
      disp.digit[3]= 0x40; // отображается минус
      Посмотрите в уроках 24-27.

  5. Доброго времени суток. Большое спасибо за уроки.
    Возможно ли в качестве ног для разрядов индикатора использовать аналоговые пины
    вместо Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);
    например
    Led4Digits disp(1, A5,A4,A3,A2, 6,7,8,9,10,11,12,13);

  6. Спасибо большое за подробную статью!
    У меня почему то все, что выведено на индикатор, примерно, раз в 2-3 секунды загорается немного ярче, как бы мигает. С чем это может быть связано?
    Еще раз спасибо))

    • Мигает на статичных данных? Т.е. Вы вывели на индикатор один раз число и все разряды равномерно мигают? Или мигают отдельные разряды? Мигают на программах этого урока?
      Я вижу варианты:
      не регулярный вызов функции regen():
      программа все время меняет данные на индикаторах;
      аппаратное замыкание или провалы питания.
      Ни у меня все работает без малейших изменений яркости.

      • Мигают все разряды, при выводе данных с датчика температуры. На обычных числах не мигает.
        Да, похоже провалы питания при опросе датчика.
        Спасибо)

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

    Вот что я переделал:

    #include «Arduino.h»
    #include «Led4Digits2.h»

    //—————————- конструктор ————————————
    Led4Digits2::Led4Digits2 (byte typeLed, byte digitPin0, byte digitPin1,
    byte segPinA, byte segPinB, byte segPinC, byte segPinD,
    byte segPinE, byte segPinF, byte segPinG, byte segPinH ) {

    // загрузка массивов выводов
    _digitPin[0]=digitPin0; _digitPin[1]=digitPin1;
    _segPin[0]=segPinA; _segPin[1]=segPinB; _segPin[2]=segPinC; _segPin[3]=segPinD;
    _segPin[4]=segPinE; _segPin[5]=segPinF; _segPin[6]=segPinG; _segPin[7]=segPinH;

    _typeLed=typeLed; // тип управления

    // инициализация выводов выбора разрядов
    for (int i = 0; i < 2; i++) {
    if ( _digitPin[i] != 255 ) { // если вывод не отключен
    pinMode(_digitPin[i], OUTPUT);
    // устанавливаем вывод в неактивное состояние
    if ( (_typeLed & 1) == 0 ) digitalWrite(_digitPin[i], HIGH);
    else digitalWrite(_digitPin[i], LOW);
    }
    }

    // инициализация выводов выбора сегментов
    for (int i = 0; i 3) _digitNumber= 0;
    if ( _digitPin[_digitNumber] != 255 ) break;
    _digitNumber++; if (_digitNumber > 3) _digitNumber= 0;
    if ( _digitPin[_digitNumber] != 255 ) break;
    }

    // состояние сегментов для нового разряда
    byte d;
    // учет активного состояния сегментов
    if ( (_typeLed & 2) == 0 ) d= (digit[_digitNumber]) ^ 0xff;
    else d= digit[_digitNumber];

    // перегрузка состояния сегментов
    for (byte i = 0; i > 1;
    }

    // включение нового разряда
    if ( (_typeLed & 1) == 0 ) digitalWrite(_digitPin[_digitNumber], LOW);
    else digitalWrite(_digitPin[_digitNumber], HIGH);
    }

    //————————— преобразование тетрады в коды сегментов ————————-
    // аргументы: dig — номер разряда (0 … 3)
    // tetrad — число для отображения
    // в результате коды сегментов оказываются в элементе массива digit[]
    void Led4Digits2::tetradToSegCod(byte dig, byte tetrad) {
    digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
    }

    //————————— вывод целого числа —————————————
    // value — число
    // digitNum — число разрядов
    // blank != 0 — гашение незначащих разрядов
    // возвращает false — ошибка переполнения
    boolean Led4Digits2::print(unsigned int value, byte digitNum, byte blank) {

    // проверка ошибки переполнения

    if ( (value > 99) && (digitNum == 2) ) {
    digit[1] = (digit[1] & 0x80) | 0x40;
    digit[0] = (digit[0] & 0x80) | 0x40;
    return(false);
    }

    // перевод числа в двоично-десятичный код
    byte d1=0;

    // десятки
    while(true) {
    if ( value 1 ) {
    if ( (d3 == 0) && (d2 == 0) && (d1 == 0) && (blank != 0) ) digit[1] &= 0x80; // гашение
    else tetradToSegCod(1, d1);
    }
    tetradToSegCod(0, value);

    return(true);
    }

    • Здравствуйте! Можно отключить ненужные разряды в конструкторе. Они не будут регенерироваться.

      digitPin0 … digitPin3 – выводы выбора разрядов. Если digitPin = 255, то разряд отключен. Это позволяет подключать индикаторы с меньшим количеством разрядов. digitPin0 – младший (правый) разряд.

  8. Подскажите, пожалуйста, скачал установил библитеку, но выдает ошибку
    даже когда скетч содержит:
    #include

    Пишет вот это:
    In file included from sketch_feb12a.ino:1:
    D:\ProEkti\libraries\Led4Digits/Led4Digits.h:40: error: a brace-enclosed initializer is not allowed here before ‘{‘ token
    D:\ProEkti\libraries\Led4Digits/Led4Digits.h:57: error: ISO C++ forbids initialization of member ‘_segCod’
    D:\ProEkti\libraries\Led4Digits/Led4Digits.h:57: error: making ‘_segCod’ static
    D:\ProEkti\libraries\Led4Digits/Led4Digits.h:57: error: invalid in-class initialization of static data member of non-integral type ‘const byte [16]’

    В чем тут ошибка??

  9. Здравствуйте Эдуард! Большое спасибо за уроки, очень много полезного узнал для себя, но опыта всё таки не хватает.
    Прошу вашей помощи: Собрал на Arduino Pro mini Домашнюю метеостанцию использовал часовой модуль DS1307 датчик температуры и влажности si7021
    датчик давления (барометр) BMP180
    Вот вопрос: есть рабочий скетч установки времени с помощью кнопок, пытаюсь совместить с моим скетчем метеостанции и ни чего не выходит выдаёт ошибки на любые действия, не могли бы Вы помочь разобраться что делаю не так?

  10. // вывод числа
    #include
    #include

    // тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
    Led4Digits disp(1, 5,4,3,2, 6,7,8,9,10,11,12,13);

    void setup() {
    MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
    MsTimer2::start(); // разрешение прерывания
    }

    void loop() {
    for (int i = 0; i < 12000; i++) {
    disp.print(i, 4, 1);
    delay(50);
    }
    }

    // обработчик прерывания 2 мс
    void timerInterrupt() {
    disp.regen(); // регенерация индикатора
    }
    Этот скетч не выводит заданную цифру а считает.

  11. Здравствуйте Эдуард. Большое спасибо за уроки. Библиотека из урока 20 мне очень понравилась.Вот только не могу заставить работать шим-(цикл for) строки 32-36.
    Если отключаю библиотеку то шим работает а
    LED индикатор нет.
    Проект «вкл.-выкл. ДХО автомобиля по напряжению+ вольтметр» (это мой первый проект на МК)(на ардуино)

    #include
    #include

    //Led4Digits disp(1, 5,4,3,2, 6, 7, 8, 9, 10, 11, 12, 13); в уроке
    // a, b, c, d, e, f, g, dp(h)
    // (3, 2,4,5,255, 13,11, 9, 7, 6, 12, 10, 8); //у меня

    Led4Digits disp(3, 2,4,5,255, 13,11, 9, 7, 6, 12, 10, 8); //у меня

    int value = 0; // переменная для хранения значения ШИМ
    int flag_chim = 0;
    float u1; //вольтметр//
    void setup() {
    MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
    MsTimer2::start(); // разрешение прерывания
    analogReference(EXTERNAL); //внешнее опорное 3.3в через R- 5k на AREF — 2.84в
    Serial.begin(9600);
    pinMode(A1, INPUT);//вход контроля напряжения
    pinMode(3, OUTPUT); // выход шим на ближний свет (1 сек.- розжиг ,80% мощности)
    pinMode(A2, INPUT); //вход контроля вкл ближнего-дальнего
    }
    void loop() {
    u1= (((float)analogRead(A1)) *0.0307);
    disp.print((int)(u1 * 10.), 4, 1);
    disp.digit[1] |= 0x80; // зажечь точку второго разряда [1]/ зажечь . третьего разряда [2]

    if(flag_chim==0)
    {
    if((analogRead(A1))>440) //порог включения шим 13.5В
    {
    flag_chim = 1;
    32 for(value = 0 ; value <= 180; value+=10) // (0 — 255)напряжение постепенно увеличивается (от 0V to 5V)
    33 {
    34 analogWrite(3, value);
    35 delay(50); // ждём 30 миллисекунд, чтобы был виден эффект (светодиод постепенно загорается)
    36 }
    }
    }
    if((analogRead(A1))<375) //порог выключения шим 12В ( 11,5 * 32,5727 = 375 )
    {
    digitalWrite(3, LOW);
    flag_chim=0;
    }

    }

    // обработчик прерывания 2 мс
    void timerInterrupt() {
    disp.regen(); // регенерация индикатора
    }

    • Здравствуйте!
      Библиотека MsTimer2 использует таймер 2, который формирует ШИМ на выводе 3. Посмотрите в уроке 37 есть таблица соответствия таймеров и выводов ШИМ. Вам надо изменить вывод ШИМ или использовать для прерывания таймер 1. В уроке 29 есть описание библиотеки TimerOne для таймера 1.

      • Спасибо, с шимом разобрался. Теперь другая проблема-не могу сбросить выход шима в ноль при подаче сигнала на А2(вкл ближний штатным рычагом) и восстановить работу шим при выкл рычагом.

        if(analogRead(A2)==LOW)//если ближний свет выключен
        и
        if(analogRead(A2)==HIGH) //если ближний свет включен
        {
        analogWrite(6, LOW);
        flag_chim=0;
        }
        не работают. может как то по другому можно? (свободные пины А2-А5,PD0,PD1)(уже мозг кипит)

        void loop() {
        u1= (((float)analogRead(A1)) *0.0307);
        disp.print((int)(u1 * 10.), 4, 1);
        disp.digit[1] |= 0x80; // зажечь точку второго разряда [1]/ зажечь . третьего разряда [2]
        // delay(100);
        if(analogRead(A2)==LOW)//если ближний свет выключен
        {

        if(flag_chim==0)
        {
        if((analogRead(A1))>440) //порог включения шим 13.5В
        {
        flag_chim = 1;
        for(value = 0 ; value <= 180; value+=5) // (0 — 255)напряжение постепенно увеличивается (от 0V to 5V)
        {
        analogWrite(6, value);
        delay(20); // ждём 30 миллисекунд, чтобы был виден эффект (светодиод постепенно загорается)
        }
        }
        }
        if((analogRead(A1))<375) //порог выключения шим 12В ( 11,5 * 32,5727 = 375 )
        {
        digitalWrite(6, LOW);
        flag_chim=0;
        }
        }
        if(analogRead(A2)==HIGH) //если ближний свет включен
        {
        analogWrite(6, LOW);
        flag_chim=0;
        }
        }

        // обработчик прерывания 2 мс
        void timerInterrupt() {
        disp.regen(); // регенерация индикатора
        }

        • Я что значит if(analogRead(A2)==LOW)?
          analogRead возвращает int, а LOW это константа типа boolean. Непонятно, что вы сравниваете.
          То же analogWrite(6, LOW);. У analogWrite второй аргумент ждет int или byte.

          • Огромное спасибо за столь быстрые ответы.
            Исправил 3 ошибки-
            if(analogRead(A2)500) //если ближний свет включен
            digitalWrite(6, LOW);
            всё заработало.

          • исправленные ошибки
            if(analogRead(A2)500)//если свет выкл
            digitalWrite(6, LOW)

          • Здравствуйте. Как убавить яркость индикатора в тёмное время суток (чтоб не светил в глаза)

          • Здравствуйте! Такой функции в библиотеке нет. Надо реализовывать ШИМ управление сигналами выбора разрядов. Можно попробовать сделать это программно, можно использовать аппаратные ШИМ микроконтроллера.

  12. Здравствуйте, Эдуард!

    А как можно использовать Вашу библиотеку со сдвиговыми регистрами? Если не затруднит, пример кода, пожалуйста.

    Спасибо огромное за Ваши уроки.

    • Здравствуйте! Нет. Эта библиотека предназначена для управления LED индикаторами в мультиплексном режиме, подключенными непосредственно к плате Ардуино. Этим она и хороша.
      Индикаторы со сдвиговым регистром обычно подключают к интерфейсу SPI и используют библиотеку SPI.h. Может быть когда-нибудь напишу свою библиотеку, но мне кажется, что LED индикаторы до 4х разрядов можно подключать непосредственно, а при большем числе разрядов лучше использовать LCD индикаторы.

      • Благодарю за ответ.
        А будут ли уроки, посвящённые SPI и работе со сдвиговыми регистрами?

        • Мне кажется это простая тема. Со временем напишу. Можете написать пожелания на форуме сайта в теме «Какие нужны уроки?»

          • Для Вас, несомненно, простая.
            Я же вторую неделю тыковку чешу, как числа на два разряда через одну 74hc595 вывести.
            Примеров кода в инете навалом, но все, как сговорились, используют либо четыре разряда либо два регистра 🙁
            Пытаюсь код под себя модифицировать — ерунда получается.

          • Посмотрите как сделано в библиотеке Led4Digits.

            //————————— вывод целого числа —————————————
            // value — число
            // digitNum — число разрядов
            // blank != 0 — гашение незначащих разрядов
            // возвращает false — ошибка переполнения
            boolean Led4Digits::print(unsigned int value, byte digitNum, byte blank) {

            // проверка ошибки переполнения
            if ( (value > 9999) && (digitNum == 4) ) {
            digit[3] = (digit[3] & 0x80) | 0x40;
            digit[2] = (digit[2] & 0x80) | 0x40;
            digit[1] = (digit[1] & 0x80) | 0x40;
            digit[0] = (digit[0] & 0x80) | 0x40;
            return(false);
            }
            if ( (value > 999) && (digitNum == 3) ) {
            digit[2] = (digit[2] & 0x80) | 0x40;
            digit[1] = (digit[1] & 0x80) | 0x40;
            digit[0] = (digit[0] & 0x80) | 0x40;
            return(false);
            }
            if ( (value > 99) && (digitNum == 2) ) {
            digit[1] = (digit[1] & 0x80) | 0x40;
            digit[0] = (digit[0] & 0x80) | 0x40;
            return(false);
            }

            // перевод числа в двоично-десятичный код
            byte d1=0;
            byte d2=0;
            byte d3=0;

            // тысячи
            while(true) {
            if ( value < 1000 ) break; value -= 1000; d3++; } // сотни while(true) { if ( value < 100 ) break; value -= 100; d2++; } // десятки while(true) { if ( value < 10 ) break; value -= 10; d1++; } // перегрузка и гашение незначащих разрядов if ( digitNum > 3 ) {
            if ( (d3 == 0) && (blank != 0) ) digit[3] &= 0x80; // гашение
            else tetradToSegCod(3, d3);
            }
            if ( digitNum > 2 ) {
            if ( (d3 == 0) && (d2 == 0) && (blank != 0) ) digit[2] &= 0x80; // гашение
            else tetradToSegCod(2, d2);
            }
            if ( digitNum > 1 ) {
            if ( (d3 == 0) && (d2 == 0) && (d1 == 0) && (blank != 0) ) digit[1] &= 0x80; // гашение
            else tetradToSegCod(1, d1);
            }
            tetradToSegCod(0, value);

            return(true);
            }

  13. Здравствуйте. Хорошие уроки. Разобрался с подключением, принципом работы в данных примерах. Собрал: cемисегментный индикатор на четыре разряда, UNO, HX711 и тензодатчик. Пожалуйста, нужна подсказка по коду. Возможно пример метода работы с датчиками или какие операторы и функции мне стоит разобрать? Ранее испытал запись в монитор порта и вывод на LCD 1602 дисплей. Теперь интересен семисегментный индикатор.

    • Здравствуйте!
      Я с этим датчиком никогда не работал. Может со временем сделаю урок о нем, но сейчас в планах обмен данными между платами.

  14. Здравствуйте Эдуард!
    Спасибо Вам за то что Вы делаете.
    Подскажите пожалуйста: где можно почерпнуть внятную информацию об работе побитовых операций в С++ например таких
    disp.tetradToSegCod(i>>4, i);

    • Здравствуйте!
      Спасибо за добрые слова. На счет битовых операций информации полно в книгах, интернете. Я даже не знаю, что там объяснять. Операции И, ИЛИ, исключающее ИЛИ, сдвиг.

      • Посоветуйте автора. Для C ++ есть разные авторы на сколько я понял Б.Строуступ не для новичков. Посоветуйте автора по микроконтроллерам на уровне протекающих в нем процессов для «чайников» )) не могу разобраться если не понятно как все устроено с низу.

        • Процессы в микроконтроллере и язык C это разные темы. Языки высокого уровня и придуманы, чтобы не разбираться во внутренностях микроконтроллеров.
          Я не знаю, что посоветовать. язык C я очень давно изучал. Сейчас, если что-то подзабыл смотрю в справочной информации в интернете. У меня на полке старая книжка «Язык C» М.Уэйт, С.Прата. Иногда в ней что-то посмотрю.
          Может откроете тему на форуме сайта. Кто-то посоветует. Посмотрите и выберете то, что вам подходит.

  15. Спасибо.
    Тема на Форум с целью поиска инф. слишком костно на мой взгляд. Может когда информацией разживусь тему открою уже с ответами.

  16. Небольшая неточность в тексте:
    Метод void tetradToSegCod(byte dig, byte tetrad)

    Например,

    tetrad(2, 7);

    выведет цифру “7” в третьем разряде.

    компилятор не поймёт

    • Нет, все правильно. Может не совсем корректно написано. 7 это не символ, а десятичное число, разряд в двоично-десятичном исчислении.

      • Извините, не уточнил, по моему,
        не корректно указана имя функции:

        tetrad(2, 7); // tetrad в данном случае не имя функции а принимаемый ею аргумент — та самая 7

        корректно будет

        tetradToSegCod(2, 7);

  17. (2, 16,15,12,255, 13,17,4,6,7,14,3,5); вот мой 3 разрядный дисплей почему то не чего не выводит на 12 пин — левый сигмент причем все прозванивал все работает пробывал все примеры показывает тока 16 и 15 если вывести число 123 товыводит тока 23

    • блин извиняюсь не припаял 12 пин звоню его -видно прижимаю к плати он работает )) а мультиметр убираю нет) библиотека отличная

    • Может все-таки аппаратная ошибка. Попробуйте поменяйте местами в программе выводы выбора разрядов. Например: (2, 12,15,16,255, 13,17,4,6,7,14,3,5); Будет показывать разряд, подключенный к 12 выводу?

  18. Подскажите какую библиотеку использовать вместо MsTimer2, т.к. у меня не совсем ардуино, а клон с контроллером STM32, и при компиляции скетча примера вылетает ошибка библиотеки MsTimer2 с сообщением о не подходящей платформе.

    • Я смог найти таймер среди стандартных библиотек, но после загрузки скетча в STM’ку все индикаторы начали светится постоянно и лишь немного заметно, что идет какой-то перебор светодиодов. В чем может быть проблема? Вот мой скетч — https://codeshare.io/5QZ9mQ А вот содержимое файла библиотеки стандартного таймера который я использовал — https://codeshare.io/adOWkD

      • Здравствуйте!
        Я не работал с такой платой.
        Я бы начал с того, что проверил работу прерывания по таймеру. В прерывании увеличивал переменную на 1 и сравнивал, например, с числом 1000. При равенстве обнулял переменную и посылал символ в последовательный порт. Таким образом, каждые 2 секунды в мониторе последовательного порта должен появляться символ.

  19. здравствуйте. подключил как тут: lesson.iarduino.ru/page/termometr-na-baze-ds18b20-i-oled-displeya-128×64/
    указывает не верную температуру. не могу понять почему и есть ли возможность от калибровать и каким способом. буду признателен.

    • Здравствуйте!
      Я не знаю библиотеки DallasTemperature. Сделайте чтение датчика DS18B20 как у меня в уроке. Выведите сначала температуру в последовательный порт, убедитесь, что измеряет правильно.

  20. Здравствуйте. Поясните, что здесь происходит. Спс
    //————————— преобразование тетрады в коды сегментов ————————-
    // аргументы: dig — номер разряда (0 … 3)
    // tetrad — число для отображения
    // в результате коды сегментов оказываются в элементе массива digit[]
    void Led4Digits::tetradToSegCod(byte dig, byte tetrad) {
    digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
    }
    и почему нельзя просто взять соответствующий код в массиве _segCod

    • Здравствуйте!
      Функция tetradToSegCod не должна изменять состояние старшего сегмента, т.е. децимальной точки.

  21. здравствуйте. убедительно прошу разъяснить мне 2 части вашей библиотеки. я новичок и обучаюсь на базе ваших уроков. однако застрял, т.к. не понимаю смысла.

    1. // состояние сегментов для нового разряда
    byte d;
    // учет активного состояния сегментов
    if ( (_typeLed & 2) == 0 ) d= (digit[_digitNumber]) ^ 0xff;
    else d= digit[_digitNumber];

    массив digit[] только объявлен, данных нет. d присваивается значение данных массива. откуда данные и в чем смысл ^0xff?
    2. void Led4Digits::tetradToSegCod(byte dig, byte tetrad) {
    digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
    }
    здесь я вообще ничего не понимаю, если честно. Объясните мне, пожалуйста, смысл каждой функции. Ответ, если можно, на почту. Огромное спасибо

    • Здравствуйте!
      1. digit[_digitNumber] ^ 0xff; это инверсия байта digit[_digitNumber]. В этом программном блоке анализируется 1й разряд переменной _typeLed и, если он равен 0, то в переменную d загружается инверсное состояние digit[_digitNumber]. Если он равен 1, то загружается не инверсное состояние. Таким образом меняется полярность управляющих сигналов в зависимости от типа индикатора.
      Массив didgit имеет модификатор доступа public. Он может быть загружен из основной программы.
      2. digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ; означает, что в байт digit[dig] загружается байт _segCod[tetrad & 0x0f], но при этом старший бит digit[dig] остается без изменений. Выполните последовательно операции.
      digit[dig] | _segCod[tetrad & 0x0f] мы в digit[dig] взвели все биты, равные 1 из _segCod[tetrad & 0x0f].
      & ((_segCod[tetrad & 0x0f]) | 0x80) мы в digit[dig] сбросили все биты, которые в _segCod[tetrad & 0x0f] равны 0.
      | 0x80 для того, чтобы не сбросить старший бит.
      И еще. Андрей, если у вас объемные вопросы, задавайте их на форуме сайта. Просто там удобнее писать ответ.

  22. Здравствуйте!
    Подскажите пож-ста, что я не так делаю. Пытаюсь вывести показания датчика si7021 на индикатор с тремя разрядами. С одним знаком после запятой, но не получается.

    #include
    #include
    #include
    #include
    HTU21D myHTU21D;

    // тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
    Led4Digits disp(1, 5,4,3,255, 9,7,11,6,10,8,12,13);

    void setup() {
    MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
    MsTimer2::start(); // разрешение прерывания
    }

    void loop() {
    float hum = (myHTU21D.readTemperature());

    // for (int i = 0; i < 10000; i++)
    {
    hum += 0.01;

    disp.print((int)(hum * 100.), 4, 1);
    disp.digit[3] |= 0x80; // зажечь точку третьего разряда

    delay(50);
    }
    }

    // обработчик прерывания 2 мс
    void timerInterrupt() {
    disp.regen(); // регенерация индикатора
    }

    Я пока мало понимая в этом. Мне не понятна вот эта стока в коде:
    disp.print((int)(hum * 100.), 4, 1);

    последние два аргумента.

    При этом коде на индикатор выводится только цифра 6 в последнем разряде и не светится ни одна точка.

    • Здравствуйте!
      Мне кажется, должно быть так:
      hum += 0.05;
      disp.print((int)(hum * 10.), 3, 1);
      disp.digit[1] |= 0x80;

      Для проверки задайте hum= фиксированному числу и посмотрите, как оно отображается.

      disp.print((int)(hum * 10.), 3, 1); означает:
      умножаем на 10, чтобы получить в целой части разряд после запятой;
      3 – используем 3 разряда;
      1 – гасим незначащие нули.

        • Здравствуйте! У меня еще вопрос возник.
          Я вывел на индикатор показания влажности и мне хотелось бы при нажатии кнопки выводить данные температуры с этого же датчика на 5 секунд,

          [code]
          #include
          #include
          #include
          #include

          boolean flagPress=false;
          boolean flagClick=false;
          byte buttonCount=0;
          #define TIME_BUTTON 12
          #define BUTTON_PIN 2

          float current = 0.0;
          float SiHum = 0.0; //переменная для влажности
          float SiTemp = 0.0; //переменная для температуры

          HTU21D myHTU21D;

          Led4Digits disp(1, 5,4,3,255, 9,7,11,6,10,8,12,13);

          void setup()
          {
          pinMode(BUTTON_PIN, INPUT_PULLUP);
          myHTU21D.begin();
          MsTimer2::set(2, timerInterrupt);
          MsTimer2::start();
          }

          void loop() {

          if (flagPress == (!digitalRead(BUTTON_PIN)) ) {
          buttonCount=0;
          }
          else {
          buttonCount++;
          }

          if (buttonCount >= TIME_BUTTON) {
          flagPress = ! flagPress;
          buttonCount = 0;
          if(flagPress == true) flagClick = true;
          }
          SiHum = (myHTU21D.readHumidity());
          SiTemp = (myHTU21D.readTemperature());

          if (flagClick == true) {
          current = SiHum; // считываем в переменную значения влажности
          }

          else {
          current = SiTemp; // считываем в переменную значение температуры
          }

          disp.print((int)(current * 10.), 3, 1);
          disp.digit[1]|= 0x80;
          delay(1000);
          }

          void timerInterrupt()
          {
          disp.regen();
          }

          [/code]

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

          • Здравствуйте!
            Не понятно, почему вы не используете библиотеку Button.h, а только взяли код из уроков по созданию этой библиотеки.

            Я в программу не вникал, но сходу видна ошибка. В блоке
            if (flagClick == true) {
            current = SiHum; // считываем в переменную значения влажности
            }
            Вы не сбрасываете признак flagClick. Одно нажатие кнопки и признак навсегда установлен. Надо
            if (flagClick == true) {
            flagClick=false;
            current = SiHum; // считываем в переменную значения влажности
            }

  23. Спасибо, очень полезные уроки, читаю все и с удовольствием. После них помаленьку пропадает отвращение к С и его клонам. Раньше писал на ASM для 8080, сейчас для Атмел. А теперь буду пробовать и С, благодаря Вашему изложению материала.
    На мой взгляд, не стоит тратить время Ваше на электрические схемы, тем более с указанием параметров элементов, к ним есть вопросы, уж извините. Разместив на их месте ваши уроки программирования Вы его просто украсите.

  24. Добрый вечер,
    Для самолетного высотомера мне был нужен LED драйвер на 5 знаков.
    Мой работал, мягко говоря, неважно. Потратил минут 15 на доработку Вашего (Led4Digits.h & Led4Digits.cpp) и, конечно, не пожалел затраченного времени. Как и ожидал, Ваш работает несравненно лучше. Весьма признателен за все Ваши публикации.
    p.s.Для анода 5 разряда пришлось подключить цифровой выход 0. Доработка для подключения к А0…A7 требует чуть больше времени, поленился…

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *