Подключим семисегментный светодиодный индикатор к плате Ардуино и научимся управлять им с помощью библиотеки Led4Digits.h.
Предыдущий урок Список уроков Следующий урок
- Описание класса Led4Digits.
- Конструктор библиотеки Led4Digits.h.
- Управление сегментами.
- Управление разрядами.
- Вывод целых чисел (unsigned int), двоично-десятичное преобразование.
- Вывод отрицательных чисел (int).
- Вывод на индикаторы дробных чисел, формат float.
В предыдущем уроке подробно описаны схемы подключения семисегментных LED индикаторов к микроконтроллерам. Подключим такой индикатор к плате Ардуино.
Мне попался типичный семисегментный светодиодный индикатор GNQ-3641BUE-21. Это четырех разрядный индикатор, очень яркий, светится при малых токах. Технические характеристики можно посмотреть в формате PDF - GNQ-3641Ax-Bx.pdf.
Схема подключения индикатора к плате Ардуино выглядит так.
Я собрал ее на монтажной плате.
Для управления индикаторами я написал библиотеку 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(); // регенерация индикатора
}
Содержит состояние сегментов. 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) индикатороми, подключенными к плате Ардуино. Аналога такой библиотеки я не нашел.
Существуют библиотеки работы с LED дисплеями через сдвиговый регистр. Кто-то мне написал, что нашел библиотеку, работающую с LED дисплеем, непосредственно подключенным к плате Ардуино. Но при ее использовании разряды индикатора светятся неравномерно, подмигивают.
В отличие от аналогов библиотека Led4Digits.h:
- Работает параллельным процессом. В основном цикле программа загружает данные в определенные переменные, которые автоматически, отображаются на дисплее. Вывод информации и регенерация индикаторов происходят в прерывании по таймеру, незаметно для основной программы.
- Цифры дисплея светятся равномерно, без миганий. Это свойство обеспечивается тем, что регенерация происходит в цикле, строго заданном прерыванием по таймеру.
- Библиотека имеет компактный код, выполняется быстро, минимально нагружает контроллер.
В следующем уроке подключим к плате Ардуино одновременно светодиодный индикатор и матрицу кнопок. Напишем библиотеку для такой конструкции.
Замечательная библиотека! Ардуинка по количеству выводов позволяет подключить два четырёхразрядных индикатора (8+8+4=20 или 7+7+4=18). Хотелось бы использовать с двумя- есть ли такая возможность? Самый простой вариант применения- измерение тока и напряжения одновременно.
Я думаю, что при количестве разрядов более 4 удобнее использовать LCD индикатор с контроллером. Сейчас пишу урок на эту тему.
Что касается LED индикаторов. Может, попробуете сами библиотеку на большее число разрядов переписать? Я старался все объяснить подробно.
LCD индикатор с контроллером подключал, семисегментные LED индикаторы 3шт по 4 разряда через регистры тоже подключал. Но интересно было бы именно на голую Arduino PRO mini, то есть чтоб ничего лишнего. И кстати, не больше разрядов, а именно два индикатора, они могут отдельно стоять, и выходы общих анодов (катодов) общие для двух индикаторов, то есть скважность не увеличивается. До написания библиотек я вряд ли дорасту. Вообще странно, что для такой вроде востребованной функции есть только ваша библиотека. Спасибо!
Таки нашёл ещё одну библиотеку, тоже 4 разряда:
https://github.com/fabiantheblind/Seven-Segment-LED-Arduino-Libraries/tree/master/Pineapple
Здравствуйте. Можно ли переделать данную библиотеку под посегментную индикацию. Т.к.разрядов 17. Яркость не устраивает при поразрядной индикации
Спасибо, отличная библиотека и пояснения! Но у меня почему-то на цифрах 9, 5, 3 перестаёт работать нижний сегмент, хотя на всех остальных он есть, в чём может быть дело? Проверил все цепи, соединения нормальные.
Спасибо. Скорее всего у вас замкнут сегмент d с каким-то другим сегментом. Прозвоните все сегменты между собой.
Да действительно был косяк в разводке платы индикатора и сегменты D и E замыкались, один получается гасил другой.
Здравствуйте! Огромное спасибо за ваши уроки!
Отличная библиотека!
Скажите, знак «минус» при выводе отрицательных чисел мерцает, — это так должно быть, или я что-то неправильно делаю?
Спасибо!
Нет знак минус мерцать не должен. Посмотрите внимательно, что вы делаете с 3 разрядом. Для вывода отрицательных чисел в функции print должно быть указано 3 разряда.
disp.print((int)(temperature * -1 * 10.), 3, 1);
disp.digit[3]= 0x40; // отображается минус
Посмотрите в уроках 24-27.
Доброго времени суток. Большое спасибо за уроки.
Возможно ли в качестве ног для разрядов индикатора использовать аналоговые пины
вместо 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);
Да, конечно. Возможно, придется задавать аналоговые входы, как номера цифровых выводов. Вместо A0 — 14, A1 — 15 и т.д.
Спасибо, буду пробовать.
Подскажите где нужно задавать цифрами? Вот здесь: Led4Digits disp()? Или где-то еще, до вызова функции?
Здравствуйте!
Не понял вопрос. Если речь идет о выводе цифр но отдельные разряды индикатора, то с помощью функции tetradToSegCod. В уроке есть пример.
Спасибо большое за подробную статью!
У меня почему то все, что выведено на индикатор, примерно, раз в 2-3 секунды загорается немного ярче, как бы мигает. С чем это может быть связано?
Еще раз спасибо))
Мигает на статичных данных? Т.е. Вы вывели на индикатор один раз число и все разряды равномерно мигают? Или мигают отдельные разряды? Мигают на программах этого урока?
Я вижу варианты:
не регулярный вызов функции regen():
программа все время меняет данные на индикаторах;
аппаратное замыкание или провалы питания.
Ни у меня все работает без малейших изменений яркости.
Мигают все разряды, при выводе данных с датчика температуры. На обычных числах не мигает.
Да, похоже провалы питания при опросе датчика.
Спасибо)
Здравствуйте, подскажите, пожалуйста, как мне переписать библиотеку под двухразрядный индикатор? Всю голову сломал, куча бессонных ночей, но результат не добился одни ошибки.
Вот что я переделал:
#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 – младший (правый) разряд.
Спасибо! Разобрался! Оказалось все очень просто. Замечательная библиотека!
а ведь это было в тексте! 😉
невнимательно читаете.
Здравствуйте, Эдуард! Что значит отключить в конструкторе? Надо прописать digitPin = 255 в файле библиотеки или в loop или в setup?
Простите за глупые вопросы.
Кажется я понял. Нужно присвоить в начале скетча старшему разряду значение 255, а не номер пина. Вот здесь: 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 );
Правильно я понял? Спасибо.
Да, правильно.
Подскажите, пожалуйста, скачал установил библитеку, но выдает ошибку
даже когда скетч содержит:
#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]’
В чем тут ошибка??
Александр, посмотрите комментарии к уроку 26. Похоже у вас та же проблема.
Здравствуйте Эдуард! Большое спасибо за уроки, очень много полезного узнал для себя, но опыта всё таки не хватает.
Прошу вашей помощи: Собрал на Arduino Pro mini Домашнюю метеостанцию использовал часовой модуль DS1307 датчик температуры и влажности si7021
датчик давления (барометр) BMP180
Вот вопрос: есть рабочий скетч установки времени с помощью кнопок, пытаюсь совместить с моим скетчем метеостанции и ни чего не выходит выдаёт ошибки на любые действия, не могли бы Вы помочь разобраться что делаю не так?
// вывод числа
#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(); // регенерация индикатора
}
Этот скетч не выводит заданную цифру а считает.
Спасибо разобрался сам.
Здравствуйте Эдуард. Большое спасибо за уроки. Библиотека из урока 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)
Здравствуйте. Как убавить яркость индикатора в тёмное время суток (чтоб не светил в глаза)
Здравствуйте! Такой функции в библиотеке нет. Надо реализовывать ШИМ управление сигналами выбора разрядов. Можно попробовать сделать это программно, можно использовать аппаратные ШИМ микроконтроллера.
Здравствуйте, Эдуард!
А как можно использовать Вашу библиотеку со сдвиговыми регистрами? Если не затруднит, пример кода, пожалуйста.
Спасибо огромное за Ваши уроки.
Здравствуйте! Нет. Эта библиотека предназначена для управления 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);
}
Здравствуйте. Хорошие уроки. Разобрался с подключением, принципом работы в данных примерах. Собрал: cемисегментный индикатор на четыре разряда, UNO, HX711 и тензодатчик. Пожалуйста, нужна подсказка по коду. Возможно пример метода работы с датчиками или какие операторы и функции мне стоит разобрать? Ранее испытал запись в монитор порта и вывод на LCD 1602 дисплей. Теперь интересен семисегментный индикатор.
Здравствуйте!
Я с этим датчиком никогда не работал. Может со временем сделаю урок о нем, но сейчас в планах обмен данными между платами.
Здравствуйте Эдуард!
Спасибо Вам за то что Вы делаете.
Подскажите пожалуйста: где можно почерпнуть внятную информацию об работе побитовых операций в С++ например таких
disp.tetradToSegCod(i>>4, i);
Здравствуйте!
Спасибо за добрые слова. На счет битовых операций информации полно в книгах, интернете. Я даже не знаю, что там объяснять. Операции И, ИЛИ, исключающее ИЛИ, сдвиг.
Посоветуйте автора. Для C ++ есть разные авторы на сколько я понял Б.Строуступ не для новичков. Посоветуйте автора по микроконтроллерам на уровне протекающих в нем процессов для «чайников» )) не могу разобраться если не понятно как все устроено с низу.
Процессы в микроконтроллере и язык C это разные темы. Языки высокого уровня и придуманы, чтобы не разбираться во внутренностях микроконтроллеров.
Я не знаю, что посоветовать. язык C я очень давно изучал. Сейчас, если что-то подзабыл смотрю в справочной информации в интернете. У меня на полке старая книжка «Язык C» М.Уэйт, С.Прата. Иногда в ней что-то посмотрю.
Может откроете тему на форуме сайта. Кто-то посоветует. Посмотрите и выберете то, что вам подходит.
Спасибо.
Тема на Форум с целью поиска инф. слишком костно на мой взгляд. Может когда информацией разживусь тему открою уже с ответами.
Небольшая неточность в тексте:
Метод void tetradToSegCod(byte dig, byte tetrad)
…
Например,
tetrad(2, 7);
выведет цифру “7” в третьем разряде.
компилятор не поймёт
Нет, все правильно. Может не совсем корректно написано. 7 это не символ, а десятичное число, разряд в двоично-десятичном исчислении.
Извините, не уточнил, по моему,
не корректно указана имя функции:
tetrad(2, 7); // tetrad в данном случае не имя функции а принимаемый ею аргумент — та самая 7
корректно будет
tetradToSegCod(2, 7);
(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 выводу?
Спасибо!
Отличные уроки.
Спасибо за библиотеки.
Спасибо. Рад, если помог.
Подскажите какую библиотеку использовать вместо MsTimer2, т.к. у меня не совсем ардуино, а клон с контроллером STM32, и при компиляции скетча примера вылетает ошибка библиотеки MsTimer2 с сообщением о не подходящей платформе.
Я смог найти таймер среди стандартных библиотек, но после загрузки скетча в STM’ку все индикаторы начали светится постоянно и лишь немного заметно, что идет какой-то перебор светодиодов. В чем может быть проблема? Вот мой скетч — https://codeshare.io/5QZ9mQ А вот содержимое файла библиотеки стандартного таймера который я использовал — https://codeshare.io/adOWkD
Здравствуйте!
Я не работал с такой платой.
Я бы начал с того, что проверил работу прерывания по таймеру. В прерывании увеличивал переменную на 1 и сравнивал, например, с числом 1000. При равенстве обнулял переменную и посылал символ в последовательный порт. Таким образом, каждые 2 секунды в мониторе последовательного порта должен появляться символ.
здравствуйте. подключил как тут: lesson.iarduino.ru/page/termometr-na-baze-ds18b20-i-oled-displeya-128×64/
указывает не верную температуру. не могу понять почему и есть ли возможность от калибровать и каким способом. буду признателен.
Здравствуйте!
Я не знаю библиотеки DallasTemperature. Сделайте чтение датчика DS18B20 как у меня в уроке. Выведите сначала температуру в последовательный порт, убедитесь, что измеряет правильно.
не получается
может вы укажите на какой урок нужно обратить внимание
Здравствуйте!
Посмотрите урок 26. Там реализован термометр на DS18B20.
Здравствуйте. Поясните, что здесь происходит. Спс
//————————— преобразование тетрады в коды сегментов ————————-
// аргументы: 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 не должна изменять состояние старшего сегмента, т.е. децимальной точки.
здравствуйте. убедительно прошу разъяснить мне 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 для того, чтобы не сбросить старший бит.
И еще. Андрей, если у вас объемные вопросы, задавайте их на форуме сайта. Просто там удобнее писать ответ.
Здравствуйте!
Подскажите пож-ста, что я не так делаю. Пытаюсь вывести показания датчика 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; // считываем в переменную значения влажности
}
Спасибо, очень полезные уроки, читаю все и с удовольствием. После них помаленьку пропадает отвращение к С и его клонам. Раньше писал на ASM для 8080, сейчас для Атмел. А теперь буду пробовать и С, благодаря Вашему изложению материала.
На мой взгляд, не стоит тратить время Ваше на электрические схемы, тем более с указанием параметров элементов, к ним есть вопросы, уж извините. Разместив на их месте ваши уроки программирования Вы его просто украсите.
Спасибо за добрые слова.
Но по поводу электрических схем не соглашусь. Многие ценят моим уроки за комплексное освещение разработок.
Раз так, приношу извинения, погорячился…
Добрый вечер,
Для самолетного высотомера мне был нужен LED драйвер на 5 знаков.
Мой работал, мягко говоря, неважно. Потратил минут 15 на доработку Вашего (Led4Digits.h & Led4Digits.cpp) и, конечно, не пожалел затраченного времени. Как и ожидал, Ваш работает несравненно лучше. Весьма признателен за все Ваши публикации.
p.s.Для анода 5 разряда пришлось подключить цифровой выход 0. Доработка для подключения к А0…A7 требует чуть больше времени, поленился…
Здравствуйте! Рад, если помог.
Добрый день,
подскажите, запустил стандартный скетч для одного 7-мисегментного индикатора.
Цифры от 0 и до 9 через секунду меняются.
а вот как сделать чтоб , например, при отображении «5» загорался светодиод на 13 выходе?
Здравствуйте!
Например, сравнивать число, которые выводите на индикатор с 5 и зажигать светодиод, если они равны.
if(x == 5) digitalWrite(13, HIGH);
else digitalWrite(13, LOW);
Конечно, еще надо установить режим вывода 13.
Здравствуйте!
Это лучшая библиотека для св/д индикатора, которую мне удалось найти на просторах интернета. Сейчас пытаюсь сделать часы с будильником по вашим урокам и библиотекам. Однако столкнулся с рядом проблем:
1. T.к. длительное нажатие кнопки не обрабатывается, пришлось сделать одну кнопку для переключения режимов индикации времени/будильника, вторую для включения утсановки времени/будильника, а третья изменяет настраиваемый параметр в большую сторону.
2. При настройке времени/будильника не знаю как сделать чтобы мигали часы в первом и втором разрядах и минуты в третьем и четвертом и пока нет мигающей точки, поэтому путаница.
В таком виде функционирует:
//MyAlarmClock
#include
#include
#include
#include
iarduino_RTC time(RTC_DS1307); // подключаем RTC модуль на базе чипа DS1307, используется аппаратная шина I2C
#define SOUND_PIN 17 // звуковой излучатель, вывод 18 (A3)
// тип индикатора 1; выводы разрядов 5,4,3,2; выводы сегментов 6,7,8,9,10,11,12,13
Led4Digits disp(1, 2,3,4,5, 13,11,9,7,6,12,10,8);
Button PIN_button_SET(15, 10); // кнопка 1, вывод 15 (A1)
Button PIN_button_UP(14, 10); // кнопка 2, вывод 14 (A0)
Button PIN_button_SELECT(16, 10); // кнопка 3, вывод 16 (A2)
uint8_t VAR_mode_SHOW = 1; // режим вывода: 1-время 2-будильник
uint8_t VAR_mode_SET = 0; // режим установки времени: 0-нет 1-сек 2-мин 3-час 4-день 5-мес 6-год 7-день_недели 8-часы будильника 9-минуты будильника
uint8_t VAR_alarm_HOUR = 0; // будильник часы
uint8_t VAR_alarm_MIN = 0; // будильник минуты
bool VAR_alarm_FLAG1 = true; // будильник разрешение работы
bool VAR_alarm_FLAG2 = false; // будильник совершение действий (сигнализация)
byte soundCount=0; // счетчик времени звука
void setup() {
MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
MsTimer2::start(); // разрешение прерывания
pinMode(SOUND_PIN, OUTPUT); // вывод звукового излучателя
time.begin(); //инициируем модуль часов
}
void loop() {
if(VAR_mode_SHOW==1){ // если установлен режим вывода времени
time.gettime();
disp.print(time.Hours*100 + time.minutes, 4, 0); // выводим время
}
if(VAR_mode_SHOW==2){ // если установлен режим вывода будильника
disp.print(VAR_alarm_HOUR*100 + VAR_alarm_MIN, 4, 0); // выводим будильник
}
//———————— проверка будильника
if(VAR_alarm_FLAG1){ // если будильник включён
if(time.seconds==00){ // если в текущем времени 0 секунд
if(time.minutes==VAR_alarm_MIN){ // если совпали минуты
if(time.Hours==VAR_alarm_HOUR){ // если совпали часы
VAR_alarm_FLAG2=true; // устанавливаем флаг разрешающий срабатывание будильника
}
}
}
}else{VAR_alarm_FLAG2=false;} // если будильник выключен, то сбрасываем флаг разрешающий совершение действий будильника (сигнализация)
if(VAR_alarm_FLAG2){digitalWrite(SOUND_PIN, ! digitalRead(SOUND_PIN));} // включаем звук будильника
//———————— переключение режима отображения времени/будильника
if ( PIN_button_SELECT.flagClick == true ) {
PIN_button_SELECT.flagClick= false; // сброс признака
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
soundCount = 50; // звук на нажатие кнопки 50*2 мс
VAR_mode_SHOW=VAR_mode_SHOW==1?2:1; // инверсия режима
VAR_mode_SET = 0; //отмена настройки времени/будильника
}
}
//———————— переключение режима установки времени/будильника
if ( PIN_button_SET.flagClick == true && VAR_mode_SHOW==1 ) {
PIN_button_SET.flagClick= false; // сброс признака
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
soundCount = 50; // звук на нажатие кнопки 50*2 мс
switch (VAR_mode_SET){
case 0: VAR_mode_SET = 3; break;
case 3: VAR_mode_SET = 2; break;
case 2: VAR_mode_SET = 0; break;
}
}
}
if ( PIN_button_SET.flagClick == true && VAR_mode_SHOW==2 ) {
PIN_button_SET.flagClick= false; // сброс признака
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
soundCount = 50; // звук на нажатие кнопки 50*2 мс
switch (VAR_mode_SET){
case 0: VAR_mode_SET = 8; break;
case 8: VAR_mode_SET = 9; break;
case 9: VAR_mode_SET = 0; break;
}
}
}
//———————- настройка времени/будильника
if ( PIN_button_UP.flagClick == true ) {
PIN_button_UP.flagClick= false; // сброс признака
soundCount = 50; // звук на нажатие кнопки 50*2 мс
if(VAR_alarm_FLAG2){VAR_alarm_FLAG2=false;}else{ // если будильник сработал, то выключаем его
switch (VAR_mode_SET){ // инкремент (увеличение) устанавливаемого значения
/* мин */ case 2: time.settime(-1, (time.minutes==59?0:time.minutes+1), -1, -1, -1, -1, -1); break;
/* час */ case 3: time.settime(-1, -1, (time.Hours==23?0:time.Hours+1), -1, -1, -1, -1); break;
/* ч.б.*/ case 8: VAR_alarm_HOUR=VAR_alarm_HOUR==23?0:VAR_alarm_HOUR+1; break;
/* м.б.*/ case 9: VAR_alarm_MIN =VAR_alarm_MIN ==59?0:VAR_alarm_MIN +1; break;
}
}
}
//—————————————————————-
}
// обработчик прерывания 2 мс
void timerInterrupt() {
disp.regen(); // регенерация индикатора
PIN_button_SET.filterAvarage(); // сканирование кнопки, метода фильтрации по среднему
PIN_button_UP.filterAvarage(); // сканирование кнопки, метода фильтрации по среднему
PIN_button_SELECT.filterAvarage(); // сканирование кнопки, метода фильтрации по среднему
// звук
if (soundCount != 0) {
digitalWrite(SOUND_PIN, ! digitalRead(SOUND_PIN));
soundCount—;
}
}
Здравствуйте!
Для того, чтобы разряды мигали надо периодически гасить их в массиве digit[].
Лучше такие объемные вопросы выкладывать на форуме сайта.
Здравствуйте Эдуард. Внимательно посмотрел комментарий
к уроку 20 и все равно не могу понять для чего в методе Led4Digits::tetradToSegCod(byte dig, byte tetrad)
стоит строка кода: digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
Дело в том что я вместо него вписал интуитивно мне более
понятный код: digit[dig]= _segCod[tetrad & 0x0f];
и все программы работают.
Здравствуйте!
Цель этой строки — загрузить код, состоящий из 7 битов. При этом не изменить старший бит, т.е. состояние децимальной точки. Для этого производится операция ИЛИ с 0 в старшем разряде, а затем операция И с 1 в старшем разряде. А ваш код изменит старший разряд. И, установленное ранее состояние децимальной точки, может потеряться.
Спасибо, скажите пожалуйста а для чего нам может
понадобиться старое значение старшего бита
digit[dig] когда мы вызываем метод tetradToSegCod.
ведь во всех примерах в уроке 20 мы обходились без него.
И еще скажите а можно этот бит сохранить так:
digit[dig]= digit[dig] & 0x80 | _segCod[tetrad & 0x0f}.
Здравствуйте!
Чтобы децимальная точка не мелькала при установке кодов индикатора.
Код ваш правильно работать не будет. Он загрузит старший бит из _segCod[tetrad & 0x0f]. А надо не изменить бит.
Что-то я уже сомневаюсь в своем коде. Возможно надо так:
digit[dig]= (digit[dig] | (_segCod[tetrad & 0x0f] & 0x7f)) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
Я уже не помню всей логики работы.
Добрый вечер! Гляньте пожалуйста правильно ли я собрал схему для управления семисегментными индикаторами. Индикаторы GNS-30011BD с ОА. Каждый сегмент состоит из 6 последовательно соединенных светодиодов.
Схема: https://s8.hostingkartinok.com/uploads/images/2018/01/541b125893411fc8deb073477dba4ef1.jpg
Здравствуйте!
Мне кажется стоит использовать динамическую индикацию, тем более, что индикаторов сего 3. Схема значительно уменьшится.
Напряжение питания индикаторов (12 В) на пределе. Небольшое изменение падения напряжения на светодиодах индикатора или ключах может привести к тому, что резко уменьшится яркость или ток превысит допустимый. Лучше было бы увеличить напряжение питания, конечно, подкорректировать сопротивление ограничительных резисторов.
Я тоже думал сразу про динамическую индикацию. Но примера в сети с использованием ULN2003A и динамической индикации не нашел. Будет ли корректно работать ваша библиотка при использовании ULN2003A, не будет ли видно мерцания? По поводу питания, к сожалению увеличить напряжение я не могу, могу только увеличить номиналы резисторов.
Да, библиотека работать будет. Она рассчитана на всевозможные полярности управляющих сигналов.
Я подключил 3-значный индикатор BA56-11EWA(GWA). Отредактировал библиотеку. Вы могли бы ее проверить? Я минимальными навыками программиста обладаю, так сказать.
Здравствуйте!
Проверьте на тестовых программах, подобных тем, какие приводятся в уроке. Это будет настоящая проверка.
Доброго дня. Огромное спасибо за уроки и библиотеку динамической индикации.Все работает отлично. Хотелось бы услышать Ваш совет, как организовать регулировку яркости индикатора по уровню освещенности?
Здравствуйте! Спасибо за оценку моих уроков.
Яркость можно регулировать, меняя скважность импульсов тока через сегменты.
Можно изменить библиотеку. Добавить счетчик длительности импульса и программный ШИМ для него. Таким способом практически можно реализовать не более 4 градаций ШИМ.
Идеальный вариант управлять общим ключем питания от аппаратного ШИМ. Но необходимо реализовать прерывания по началу периода ШИМ и в нем запускать управление ключами индикатора.
Отличная библиотека!
Подскажите плиз вот такой короткий код:
void loop()
{ delay(1);
disp.digit[0] = B00000101;
}
Все прекрасно работает. Убираю delay — на индикатор не выводится ничего… То же самое со всеми методами библиотеки: print, tetradToSegCod. Если нет строки delay — на индикаторе пусто, если есть — все прекрасно работает. Почему такое?
Здравствуйте!
Затрудняюсь ответить. Мне кажется должно работать. Но в любом случае непонятно, зачем так часто перезагружать значение массива. Без функции delay() вы перезаписываете массив с периодом несколько микросекунд.
не работает, честно говорю. А вопрос зачем? — для эксперимента… Понятно что в реальной жизни такой код совершенно ни к чему, но хочется понять суть… Подозреваю, что дело, наверное, именно в микросекундах, которые гораздо короче чем 1 мс вызова прерывания… Но дальше этой мысли чё-то я ничего придумать не могу. Ну ладно, не буду писать такие эксперементальные коды
Когда у меня будет собрана и подключена схема с LED индикаторами, обязательно проверю и постараюсь разобраться.
Добрый день! А что означает «Общий анод с ключами выбора разряда»? Общий анод понятно, а что за ключи выбора разряда?
Здравствуйте!
В предыдущем уроке написано. Имеются ввиду анодные ключи для усиления тока. В этом режиме инвертируются управляющие сигналы.
Здравствуйте! Подскажите, как переделать библиотеку Led4Digits для посегментной индикации. Разрядов 17, яркость при поразрядной индикации низкая
Здравствуйте!
Динамическую индикацию такой разрядности редко применяют для светодиодных индикаторов. Будет очень низкая яркость или придется коммутировать большие токи.
А библиотека должна работать по такому же принципу, только больше переменных, циклов и т.п.
Дак вот т в том проблема, всё собрал, библиотеку переделал для 17 разрядов, работает хорошо, но тускло. Как выкрутиться, минимальными переделками?
Здравствуйте Эдуард, в строке 99 библиотеки предлагаю упростить код логического выражения.
void Led4Digits::tetradToSegCod(byte dig, byte tetrad) {
digit[dig]= (digit[dig] | _segCod[tetrad & 0x0f]) & ((_segCod[tetrad & 0x0f]) | 0x80) ;
//если цель сохранить состояние децимальной точки то IMHO результат должен быть тот же
void Led4Digits::tetradToSegCod(byte dig, byte tetrad) {
digit[dig] = digit[dig] & 0x80 | _segCod[tetrad & 0x0f] ;
Здравствуйте!
Я уже не помню что-для чего. Но, думаю, вы не правы.
digit[dig] & 0x80 уничтожит все данные, кроме старшего бита.
Насколько я понимаю Вы эти данные заменяете тетрадой из массива, которая содержит бит карту состояния диодов для отображения шестнадцатеричной цифры, на которую мы хотим поменять текущее значение в разряде с номером dig. Есть ли смысл сохранять какие то «элементы» от старой цифры, кроме десятичной точки, закодированной в старшем разряде?
Хочу поблагодарить автора за объёмную работу и за отличный результат.
Ну и задать вопрос: раз уж в качестве примера используются часы, то нельзя ли в библиотеку добавить опцию регулирования яркости через ШИМ? Как же часам без этого? )
Здравствуйте!
Регулировку яркости программным способом сделать достаточно проблематично. Необходимо повысить частоту прерываний от таймера и реализовать ШИМ для управления общими ключами. Возрастет вычислительная нагрузка на микроконтроллер.
Можно реализовать аппаратно, но увеличится схема.
Помогите пожалуйста! Хочу вывести хоть что-нибудь на двухразрядный индикатор, но совершенно ничего не выходит. Вот код:
#include
#include
Led4Digits disp(2,7,8,255,255,35,39,43,45,47,49,51,53);
void setup() {
MsTimer2::set(2, timerInterrupt);
MsTimer2::start();
// put your setup code here, to run once:
}
void loop() {
for (int i = 0; i<6000; i++)
{
disp.print (i,2,1);
}
}
void timerInterrupt(){
disp.regen();
}
Здравствуйте!
А у вас какая плата? Если мега, то не работает MsTimer2. Надо использовать другую библиотеку для таймера.
Запустите сначала программы из урока.
Да, мега. Получилось выводить значения на индикатор, и MsTimer2 вроде бы работает. Вообще, я хочу попробовать понижать значение на индикаторе с помощью кнопки. Посоветуйте пожалуйста через что лучше осуществить такую задумку. Я все перепробовал: if/else, for, while, но ничего не получается
Здравствуйте!
А что значит понижать значение на индикаторе? Вычитать 1 с определенной скоростью?
Да, например, изначально индикатор отображает число 30, а после нажатия кнопки понижает значение на 1. И так до нуля
Т.е изначально число равно 30, потом происходит нажатие на кнопку, число уменьшается до 29, и сохраняется. Потом еще нажатие, — число понижается до 28 и т.д
Например, с использованием библиотеки Button.
if ( button.flagClick == true ) {
// был клик кнопки
button.flagClick= false; // сброс признака
count—; // -1 из счетчика
}
Спасибо, попробую осуществить это на практике. Правда, пока все равно не понятно, как до этой части скетча, правильно объявить сам счетчик с нужными значениями, выводимыми на индикатор
Что-то не получается. Я относительно недавно начал заниматься программированием, можете подсказать, где я совершил ошибку? Задача по-прежнему та же: с помощью кнопки, уменьшать значение числа на индикаторе на 1
#include
#include
#include
#define BUTTON_1_PIN 24
Button (BUTTON_1_PIN,15);
Led4Digits disp(2, 30,28,255,255, 35,39,53,47,49,43,45,51);
int count[9]={1,2,3,4,5,6,7,8,9};
void setup()
{
MsTimer2::set(2, timerInterrupt);
MsTimer2::start();
}
void loop() {
button1.filterAvarage();
if (button.flagClick==true){
button.flagClick=false;
count-;
disp.print (i,2,1);
}
delay (250);
}
void timerInterrupt(){
disp.regen();
}
Возьмите скетч из урока 20, раздел метод print.
Запустите ее, проверьте, что все работает.
В этой программе надо добавить счетчик и сделать +1 к нему по кнопке.
#include
#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);
Button button(14, 20); // создание объекта кнопка
int count=0;
void setup() {
MsTimer2::set(2, timerInterrupt); // прерывание по таймеру 2 мс
MsTimer2::start(); // разрешение прерывания
disp.print(count, 4, 1);
}
void loop() {
// проверка кнопки
if ( button.flagClick == true ) {
button.flagClick= false;
count++;
disp.print(count, 4, 1);
}
}
// обработчик прерывания 2 мс
void timerInterrupt() {
disp.regen(); // регенерация индикатора
button.scanState();
}
Эдуард, спасибо Вам огромное! У меня все работает как нужно! У меня еще вопрос: вот все это должно работать при наличии магнитного поля (используется датчик Холла). После объявления пинов, и остального, я пытался его прописать примерно так:
if (value = HIGH){
do{
if (button.flagClick==true){
…
Но ничего не получается. Как лучше поступить? Даже в void setup не прописывается. Может я циклы не так использую?
У вас в первом if знак присвоения =, а не проверки равенства ==.
Здравствуйте, Эдуард! Извините, что отвлекаю-не пойму , почему не могу скачать вашу библиотеку из урока №20 Led4Digits.h? Я зарегестрировался, оплатил аккаунт за 1 месяц (номер заказа 1554576992, операция № 169469019, 06.04.2019г, 42,11 р.) , а у меня в тексте всё высвечивается — оплатите 25 р. за доступ ко всем ресурсам сайта…
Здравствуйте!
У вас доступ открыт. Вы под своим логином на сайт входите?
Еще, вы неправильно указали адрес эл. почты (don.uwarow2012@mail.ru). Я не могу вам письмо отправить.
Попробуйте войти под своим логином. Если не получится, напишите.
Эдуард, извините , ещё раз, всё нормально, всё открылось, доступ к ресурсам появился! Всех благ.
Эдуард, можно узнать, как при достижении счетчика значения «count<1" , задать новое условие? Я пытаюсь сделать так, чтобы при достижении значения меньше единицы, воспроизводился новый аудио файл, но скорее всего неправильно задаю условие. Вот код:
File myFile;
TMRpcm tmrpcm;
Led4Digits disp(2, 30,28,255,255, 35,39,46,47,49,43,45,48);
Button button(24,20);
int count = 10;
int led = 8;
void setup()
{
MsTimer2::set(2, timerInterrupt);
MsTimer2::start();
disp.print(count,2,0);
tmrpcm.speakerPin = 11; // Динамик подключен на пин 11
tmrpcm.setVolume (5);
tmrpcm.quality (2);
if (!SD.begin(SDPIN)){
return;
}
pinMode (led,OUTPUT);
}
void loop() {
if (button.flagClick == true){
button.flagClick=false;
count—;
disp.print (count,2,0);
tmrpcm.play("sound/wep_GEN.wav");
digitalWrite (led, HIGH);
delay (200);
digitalWrite (led,LOW);
if ( count < 1){
tmrpcm.play("sound2/wep_GEN_empty.wav");
digitalWrite (led,LOW);
}
}
}
void playSound (char *file){
tmrpcm.play(file);
return;
}
void timerInterrupt(){
disp.regen();
button.scanState();
}
Всё, я разобрался) Решил проблему с помощью while)
всё сразу заработало ! класс ! попробую теперь подключить сразу 3 индикатора на TM1637 включить на разные пины . если получится вывести разные данные напишу . а нет , так включу 2 по вашей схеме (это 24 контакта ) и один на TM1637 ( 2 контакта ). как обещают китайцы хоть это и I2C но адресация идёт по контактам . больше всего доволен что сразу всё заработало без криков без воплей и без предсмертного хрипа . спасибо дорогой Эдуард за классную работу и классную библиотеку .
сейчас подключил 3 индикатора такие же 7 сегментные на микросхеме TM1637 . библиотеку взял отсюда
https://proto-constructor.ru/displei/17-displei-na-baze-drajvera-tm1637-izuchaem-vozmozhnosti.html
Proto Constructor
Программирование плат Arduino, Digispark, микроконтроллеров и не только…
Дисплеи на базе драйвера TM1637 — изучаем возможности
скачал установил . так как плата ардуино не тянет 3 дисплея их запитал от блока питания дивиди (приносили на ремонт). GND у них подключил к земле блока питания и сразу соединил с GND платы ардуино . 5V у них соединил с выводом 5V блока питания ( хотя там на холостом ходу около 8 вольт но это не страшно ) .у ардуино 5 вольт не трогаем ( главное соединить вместе минусы везде (граунды,земли).у первого дисплея CLK соединил на 6 пин ардуино , DIO на 7 пин . второй дисплей сответственно CLK на 8 пин и DIO на9 пин. третий CLK на 10 пин и DIO на 11 пин . взял самый первый скетч из сайта который указал выше . задал все дополнительные новые пины подключения #define CLK1 8
#define DIO1 9
#define CLK2 10
#define DIO2 11
, добавил ещё два объекта tm1637a и tm1637b , для интереса(проверки) задал еще 2 массива StringToDisp1[] StringToDisp2[] с другими числами и в void loop дописал везде добавки и добавил команды tm1637a.display(StringToDisp1);
tm1637b.display(StringToDisp2);
все три дисплея показывают разную информацию . значит можно на одном показывать время , на втором оставшиеся ресурсы , а с третьего заносить нужные нам настройки и так далее . можно подключит ещё дисплеи . три дисплея заняли всего 6 контактов . и можно не тратиться на дорогие ( к тому темнеющии через 5 минут) жидкокристаллические дисплеи . и очень большая экономия контактов .
Подскажите, как вывести температуру. Например 25С.,120С.
Здравствуйте!
Библиотека позволяет выводить одновременно десятичное число и символы только в случае, если символы расположены перед числом. Число привязано к младшему разряду индикатора.
Попробуйте так.
Сдвиньте число на один десятичный разряд влево.
disp.print(temp * 10, 4, 0);
А затем сверху младшего разряда напечатайте нужный символ.
disp.tetradToSegCod(0, 0xc);
Или делайте двоично-десятичное преобразование числа сами и выводите методом tetradToSegCod.
Понял. Спасибо.
поставить max7219 и ваша библиотека не нужна. И проводов меньше.
Здравствуйте, отличная библиотека Эдуард! Подскажите пожалуста, что нужно изменить в ней чтобы добавить еще разряд? (Нуждаюсь в 6ти разрядах)
Заранее благодарю!
Здравствуйте!
Надо переписывать библиотеку. В принципе, там формальные переделки. Надо изменить количество переменных, число проходов цикла регенерации и т.п.
Очень нуждаюсь в примере как это можно сделать, в коле не силён
Эдуард, как вот эту позицию кода перевести на 6 разрядов?
// перегрузка и гашение незначащих разрядов
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);
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 >4, i); //ЗДЕСЬ БУДЕТ ОШИБКА! ПЕРВЫЙ ПАРАМЕТР НЕ МОЖЕТ БЫТЬ БОЛЬШЕ ЧИСЛО ИНДИКАТОРОВ-1
delay(250);
}
}
void loop() {
for (int i = 0; i >4, i);
delay(250);
}
Еще и фрагмент кода не правильно в комментарии вставляется… Короче посмотрите вызов tetradToSegCod где первый аргумент в конце цикла будет 63 сдвинутый вправо на 4 позиции…
Здравствуйте, не могу получить незначищии нули вроде всё делаю как в описании меняя в библиотеке blank != 0 на blank = 0, или чего я не понял правильно?
Здравствуйте!
А мой пример из урока, если в disp.print(i, 4, 1); последний параметр задать 0.