Динамическая индикация на светодиодных 7-сегментных индикаторах с программной регулировкой яркости

Часы на 2.7 дюймовых индикаторах своими руками

Я уже писал подобный обзор здесь. Было сделано 2 экземпляра часов как в том обзоре, но с одними случилось что-то непонятное, и я, обрадовавшись поломке, решил радикально переделать их.

Что-то непонятное — это убегание на 2 минуты, которое я не смог связать ни с наводками, ни с неисправностью микроконтроллера, ни с неисправностью таймера ds1307. Видимо виной всему плата, так как на плате второго экземпляра контроллер с таймером работали исправно.

К моменту поломки я активно игрался с ардуино нано, поэтому мозгом будет служить она.

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

Поигрался с прототипом ардуиночасов с написанным мной кодом в протеусе, убедился, что код и аналоговая часть худо бедно работают, и заказал нужные детали. Главный герой — микросхема MAX7219. Это драйвер, позволяющий управлять семисегментными индикаторами (с общим катодом), светодиодными линейками или просто отдельными светодиодами.

Максимум к нему можно подключить 64 светодиода (ну или, соответственно, восемь семисегментных односимвольных индикаторов). Драйвер управляется по интерфейсу SPI, а так же имеет программное управление яркостью свечения индикаторов или светодиодов.

Эти микросхемы можно подключать каскадно, увеличивая количество управляемых светодиодов или семисегментников.

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

Вот посылка пришла. Так же в посылке, помимо MAX7219, были smd транзистоы MMBT3906 и MMBT3904, позже я использую их для изготовления конечного устройства, и еще четырехсимвольные 7-сегментные индикаторы с общим катодом, которые будут служить временным дисплеем для отладки часов.

Большие индикаторы покупал когда-то давно здесь. На фото прототип, собранный мной для отладки программы, которая будет управлять всем этим хозяйством. Вторая arduino nano в верхнем правом углу макетки не относится к проекту и торчит там просто так, внимание на нее можно не обращать.

Немного о принципе работы: ардуино берет данные у таймера DS323, перерабатывает их, определяет уровень освещенности с помощью фоторезистора, затем все посылает на MAX7219, а она в свою очередь зажигает нужные сегменты с нужной яркостью. Так же с помощью трех кнопок можно выставить год, месяц, день, и время по желанию. На фото индикаторы отображают время и температуру, которая взята с цифрового термодатчика ds18s20

Основная сложность в моем случае — это то, что 2.7 дюймовые индикаторы с общим анодом, и их надо было во первых как то подружить с max7219, которая заточена под индикаторы с общим катодом, а во вторых решить проблему с их питанием, так как им нужно 7,2 вольта для свечения, чего одна max7219 обеспечить не может.

Попросив помощи на одном форуме я получил таки ответ. Решение на скриншоте:
К выходам сегментов из max7219 цепляется микросхемка uln2003a, которая инвертирует сигнал, а к каждому выводу, который должен подключаться к общему катоду дисплея цепляется схемка из трех транзисторов, которые так же инвертируют его сигнал и повышают напряжение.

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

Часы будут состоять из блока дисплея и блока питания и управления. Последний было решено собрать первым. Эстетов и бывалых радиолюбителей прошу не падать в обморок из-за жестокого обращения с деталями.

Покупать принтер ради ЛУТа нет никакого желания, поэтому делаю по старинке — тренируюсь на бумажке, сверлю отверстия по шаблону, рисую маркером дорожки, затем травлю.

Принцип крепления индикаторов оставил тот же, как и на прошлом экземпляре.

Размечаем положение индикаторов и компонентов, с помощью шаблона из оргстекла, сделанного для удобства.

Процесс разметки

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

Ещё

купание в хлорном железе
готово! плата управления:плата индикации:
Плата управления получилась отлично, на плате индикации не критично сожрало дорожку, это поправимо, настало время паять.

В этот раз я лишился SMD-девственности, и включил 0805 компоненты в схему. Худо-бедно первые резисторы и конденсаторы были припаяны на места. Думаю дальше набью руку, будет легче.

Для пайки использовал флюс, который купил здесь.

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

Вот готовые платы.

На плате управления имеется посадочное место для ардуино нано, часов, а так же выходы для подключения к плате дисплея и датчики (фоторезистор для автояркости и цифровой термометр ds18s20) и блок питания на lm317 с регулировкой выходного напряжения (для больших семисегментников) и l7805 для питания часов и ардуино, на плате индикации находятся посадочные гнезда для дисплеев, панельки для max2719 и uln2003a, решение для питания четырех больших семисегментников и куча перемычек.

Ещё

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

Не светился последний большой индикатор, а остальные светились тускло. С первой проблемой расправился пропаиванием ножки смд-транзистора, со второй — регулировкой напряжения, выдаваемого lm317.

ОНО ЖИВОЕ!

Делаем подставку

Изначально решил не мудрить с корпусом, а оставить как есть. Просто прикрепил ножки из алюминиевого профиля к плате. Сзади на куске оргстекла крепится плата управления

Ну вот и всё. Осталось только причесать код.Некоторые наверное скажут, что легче купить и вид эстетичнее, и будут правы, но это же хобби.

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

Традиционное животное

Источник: https://mysku.ru/blog/ebay/32542.html

Alex_EXE

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

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

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

Семисегментный индикатор

На примере обновлённого вольтметра сделанном на микроконтроллере PIC16F676 в этой статье расскажу о динамической индикации семисегментных индикаторов.

Для динамической индикации понадобиться таймер, в котором будет постоянно крутиться функция вывода значения на дисплей. Обычно микроконтроллеры содержат несколько таймеров, под динамическую индикацию подойдёт самый простой из них. В примере использован первый 8 битный таймер TMR0.

Для начала таймер нужно сконфигурировать:

OPTION=0b00000000; // Настройка TMR0 INTCON=0b10100000; // Прерывания разрешены и только от TMR0

Для работы понадобятся следующие глобальные переменные:

unsigned char v1,v2,v3, vn;

Первые три отвечают за значения соответствующих сегментов, а последняя за номер горящего сегмента в данный момент (динамическая индикация).

Обработчик прерываний занят обработкой таймера, который постоянно по очереди сменяет сегменты.

void interrupt isr(void) { if(T0IF) // при переполнение TMR0 { vn++; // переключение сегмента switch(vn) // выбор сегмента { case 1:seg7(v1,1);break; case 2:seg7(v2,2);break; case 3:{seg7(v3,3);vn=0;}break; } TMR0=100; // установка таймера не на начало T0IF=0; // сбрасываем флаг } }

Для вывода значения символа семисегментного индикатора с общим анодом используется следующая функция:

void seg7(unsigned char c, unsigned char s) { unsigned char t=0; // g сегмент PORTA=0b00000000; // сброс порта A switch(s) // выбор анода { case 1 :{t=1;}break; case 2 :{t=2;}break; case 3 :{t=32;}break; } switch(c%10) // выбор сегментов (катодов) { // 00bfaed g case 0 : {PORTC=0b00000000;PORTA=t+4;}break; case 1 : {PORTC=0b00011110;PORTA=t+4;}break; case 2 : {PORTC=0b00010001;PORTA=t;}break; case 3 : {PORTC=0b00010100;PORTA=t;}break; case 4 : {PORTC=0b00001110;PORTA=t;}break; case 5 : {PORTC=0b00100100;PORTA=t;}break; case 6 : {PORTC=0b00100000;PORTA=t;}break; case 7 : {PORTC=0b00010110;PORTA=t+4;}break; case 8 : {PORTC=0b00000000;PORTA=t;}break; case 9 : {PORTC=0b00000100;PORTA=t;}break; } }

У PIC16F676 неполный порты вывода, поэтому все сегменты на порт C не влезли, сегмент g пришлось разместить на порте A, а точку приходиться подключать схематически к одному из общих анодов через инвертор. Схема такого подключения выглядит следующим образом:

Схема вольтметра

Если использовать другой микроконтроллер, у которого есть хотя бы один полноценный порт, например PIC16F628A

Схема цифрового термометра

функция примет следующий вид:

void seg7(unsigned char c, unsigned char s) { unsigned char t=0; switch(c%10) // выбор сегментов (катодов) { // gcPdeafb case 0 : {t=0b10100000;}break; case 1 : {t=0b10111110;}break; case 2 : {t=0b01100010;}break; case 3 : {t=0b00101010;}break; case 4 : {t=0b00111100;}break; case 5 : {t=0b00101001;}break; case 6 : {t=0b00100001;}break; case 7 : {t=0b10111010;}break; case 8 : {t=0b00100000;}break; case 9 : {t=0b00101000;}break; } PORTA=0b00000000; // сброс порта A switch(s) // выбор анода { case 1 :{ PORTA =4;}break; case 2 :{ PORTA =8;}break; case 3 :{ PORTA =64;}break; } PORTB=t; if(c>9) { PORTB=t&0b11011111; } }

Точка у символа загорается, если с больше 9, значение на индикатор выводиться всё равно будет, т.е. будет выводиться только младший разряд, остальное всё отбрасываться (например: 19, 39 = 9. ).

В основной функции (main) МК спокойно выполняет свою работу, для вывода новой информации на дисплей ему достаточно изменить значения переменных v1,v2,v3, но изменять их следует одновременно, что бы избежать неразберихи на индикаторе.

Скачать исходник вольтметра

Alex_EXE | 01.12.2011 | Микроконтроллеры |

Источник: https://alex-exe.ru/radio/microcontrollers/dynamic-7seg-indication/

Делаем цифровую шкалу — Сообщество «Электронные Поделки» на DRIVE2

Немножко теорииНаверное нет необходимости рассказывать, что такое 7-сегментные индикаторы. Как сложно и представить область техники, где они не применяются.

Соответственно по их подключению написано масса статей, но попробую все таки написать свою :)Итак: что же такое 7-сегментный индикатор?Обратимся к Википедии: “Семисегме́нтный индика́тор — устройство отображения цифровой информации. Это — наиболее простая реализация индикатора, который может отображать арабские цифры.

Семисегментный индикатор, как говорит его название, состоит из семи элементов индикации (сегментов), включающихся и выключающихся по отдельности. Включая их в разных комбинациях, из них можно составить упрощённые изображения арабских цифр. Часто семисегментные индикаторы делают в курсивном начертании.”

Сегменты обозначаются буквами от A до G; восьмой сегмент — десятичная точка (decimal point, DP), предназначенная для отображения дробных чисел.По сути говоря данный индикатор — это 8 светодиодов расположенных на панели определенным образом.

Соответственно самая простая схема включения — подсоединить все 8 ножек на выводы микроконтроллера (микросхемы — дешифратора) через балластные резисторы, а на общий провод подавать либо “+” (для индикаторов с общим анодом) либо “-” (для индикаторов с общим катодом).

Пример подключения индикатора с общим анодом для схемы индикации включенной передачи АКПП Лансера приведен нижеА как быть, если нужно выводить не 1 цифру, а 2,3,4 и более?И вот тут на помощь приходит человеческая психика.

Если мозгу показать несколько быстросменяющихся изображений, то он не успев обработать каждое по отдельности “сольет” их вместе. Этот принцип лег в основу мультипликации. Т.е. для вывода нескольких разрядов (нескольких цифр) нужно подключить к микроконтроллеру не только провода сегментов, но и общие провода каждого из разрядов.

Тогда чтобы вывести первый разряд (опять же для схемы с общим анодом) нужно подать “+” только на общий провод первого разряда и “-” на нужные провода сегментов. Задержать изображение на 2-3 милисекунды, переключится на второй разряд и проделать то же самое с ним, поле чего перейти на третий (четвертый и т.д.) или вернутся к первому.

Проделывая все это достаточно быстро мы получим в мозгу единую картинку, где все разряды горят одновременно. Для схемы с общим катодом, соответственно, перекидывать нужно “-“.

Кстати, транзисторы в этой схеме необязательны — можно подключить выводы индикатора непосредственно к выводам микроконтроллера и затем не подавать на них напряжение (выводы 8-10 данной схемы), а наоборот “притягивать к земле” выводя на них “низкое” напряжение или попросту говоря 0. А “высокое” напряжение (или 1) подается на общие выводы разрядов, которые не должны в данный момент гореть.

Более подробно о таком способе подключения написано здесь — arduino-kit.com.ua/instru…-indikator-i-arduino.html

В чем же “бяка” данной схемы? А в том, что для вывода например трехразрядного числа нужно задействовать 11 ножек микроконтроллера, причем 7 из них, чтобы не раздувать программу, должны относится к одному порту.Все это хорошо, но, например, у Attiny2313 такой только порт В на котором “висят” и оба входа аналогового компаратора.И вот тут на помощь приходят специальные драйверы.

Чаще всего применяют драйвера MAX7219 и MAX7221, управляемые по SPI. Материал по работе с этими драйверами разместил недавно serdgos тут — www.drive2.ru/c/2812487/. Поэтому повторятся не буду — желающие могут почитать.

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

А есть ли более “хардкорные” решения? Оказывается есть — драйвер CD4026.

Описание ДрайвераЧип CD4026 предназначен для управления 7-сегментными индикаторами и представляет собой счётчик до десятка с встроенным сдвиговым регистром.

Счётчик увеличивается на единицу всякий раз, когда контакт «clock» становится HIGH (на восходящем фронте). Выходы a-g становятся HIGH в соответствии со значением счётчика, и отражают его значение арабской цифрой при подключении 7-сегментного индикатора с общим катодом.

Контакт «reset» должен быть притянут к земле в общем случае. Когда он становится HIGH, счётчик сбрасывается в ноль.Контакт «disable clock» также должен быть притянут к земле в общем случае. На время пока он HIGH сигналы на контакт «clock» игнорируются.

Контакт «enable display» должен снабжаться напряжением питания. Иначе выходы a-g будут выставлены в LOW. Контакт «enable out» возвращает его значение с небольшой задержкой.Контакт «÷10» (обозначен как h в таблице) принимает HIGH для значений 0-4 и LOW для 5-9.

Его выход может быть отправлен на вход «clock» следующего 7-сегментного драйвера, чтобы организовать счётчик числа с несколькими разрядами.Контакт «not 2» принимает значениние LOW тогда и только тогда, когда значение счётчика — 2. В остальных случаях он HIGH.

Рабочее напряжение питания: 3—15 В.

ПодключениеС этим все просто: смотрим даташит на индикатор. Я использовал 3х- разрядный, но принципиально разницы с четырехразрядным нет, — для подключения четвертого разряда нужно будет еще задействовать вывод 6 индикатора (сейчас он “пустой”).

Сопоставив даташиты у меня получилась такая схема подключенияи после распайки

В качестве источника сигнала выступал Arduino Pro Micro c задействованными выводамиPin2 Выход на счетчикPin3 Сброс счетчикаPin4 Подключение разряда 1Pin6 Подключение разряда 2Pin9 Подключение разряда 3

Точку не подключал, ибо сейчас ненужно, а принцип подключения тот же.

ПрограммаТак как задействовано Arduino. то и язык соответствующий — модифицированный С.

Прога секундомера, считающего секунды с момента включения, “накидана по быстрячку” чтобы проверить работоспособность, поэтому слегка корява — уж извините.

#define CLOCK_PIN 2#define RESET_PIN 3#define DIGIT_1PIN 4#define DIGIT_2PIN 6

#define DIGIT_3PIN 9

void resetNumber(){// Для сброса на мгновение ставим контакт// reset в HIGH и возвращаем обратно в LOWdigitalWrite(RESET_PIN, HIGH);digitalWrite(RESET_PIN, LOW);digitalWrite(DIGIT_1PIN, HIGH);digitalWrite(DIGIT_2PIN, HIGH);digitalWrite(DIGIT_3PIN, HIGH);}void showNumber(float t){ int n;// Первым делом обнуляем текущее значениеresetNumber();// Выводим первый разрядdigitalWrite(DIGIT_1PIN, LOW);n=int(t-int(t/10)*10);// Далее быстро «прокликиваем» счётчик до нужного// значенияwhile (n–) {digitalWrite(CLOCK_PIN, HIGH);digitalWrite(CLOCK_PIN, LOW);}delay(2);// Обнуляем счетчикresetNumber();// Выводим второй разрядdigitalWrite(DIGIT_2PIN, LOW);n=int(t/10-int(t/100)*10);// Далее быстро «прокликиваем» счётчик до нужного// значенияwhile (n–) {digitalWrite(CLOCK_PIN, HIGH);digitalWrite(CLOCK_PIN, LOW);}delay(2);// Обнуляем счетчикresetNumber();// Выводим третий разрядdigitalWrite(DIGIT_3PIN, LOW);n=int(t/100);// Далее быстро «прокликиваем» счётчик до нужного// значенияwhile (n–) {digitalWrite(CLOCK_PIN, HIGH);digitalWrite(CLOCK_PIN, LOW);}

delay(2);

}void setup() {pinMode(RESET_PIN, OUTPUT);pinMode(CLOCK_PIN, OUTPUT);pinMode(DIGIT_1PIN, OUTPUT);pinMode(DIGIT_2PIN, OUTPUT);

pinMode(DIGIT_3PIN, OUTPUT);

// Обнуляем счётчик при старте, чтобы он не оказался// в случайном состоянииresetNumber();

}

// Основной циклvoid loop(){showNumber((millis() / 1000));}

Ну и результат

Можно еще сократить количество выводов, задействовав сдвиговые регистры, но об этом мы поговорим отдельно 🙂

Источник: https://www.drive2.ru/c/2827146/

Arduino. Динамическая индикация

Динамическая индикация — это метод отображения целостной картины путем последовательного отображения отдельных элементов этой картины.
Эта статья научит вас выводить на дисплее сегментного индикатора одновременно несколько цифр. Достигается это за счет «инерционности» человеческого зрения.

Подготовка к работе

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

Увеличить количество разрядов можно, если использовать еще один дисплей и еще семь выводов микроконтроллера, но гораздо выгоднее отображать разряды индикатора по очереди с высокой скоростью.

Так, чтобы это стало не заметно для глаза.
Для этого на индикаторе должны быть объединены аноды разрядов и катоды сегментов.

Индикатор с динамической индикацией

Все примеры выполнены с использованием EduBoard и TutorShield. На нашем шилде именно такой индикатор. Для его использования установите перемычки, выделенные на рисунке:

Перемычки для включения индикатора

Принципиальная схема подключения индикатора:

Принципиальная схема подключения индикатора

Первый пример

Для начала выведите два разных числа на индикаторе, используя следующий код:

#define DIG1 4 #define DIG2 5 #define A 6 #define B 7 #define C 8 #define D 9 #define E 10 #define FF 11 #define G 12 #define TAKT 1000 void setup() { pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); pinMode(E, OUTPUT); pinMode(FF, OUTPUT); pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT); pinMode(DIG2, OUTPUT); digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); } void loop() { digitalWrite(DIG1,LOW); Show(3); delay(TAKT); Clean(); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,LOW); Show(4); delay(TAKT); Clean(); digitalWrite(DIG2,HIGH); } void Show(int digit) { switch(digit) { case 0: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); } break; case 1: { digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 2: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(G,LOW); } break; case 3: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(G,LOW); } break; case 4: { digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 5: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 6: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 7: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 8: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 9: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; } } void Clean() { digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); }

Основной цикл этого примера линеен и прост. Сначала в первом разряде на одну секунду выводится цифра 3, затем во втором 4.
Если уменьшить интервал TAKT, то можно добиться того, чтобы за счет инерционности зрения казалось, что цифра 34 горит непрерывно.

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

Эмпирическим путем установлено, что обновления изображения с частотой 50 раз в секунду вполне достаточно для приемлемого восприятия. Это значит, что идентификатор TAKT должен иметь значение меньше 10мс.

Попробуйте запустить программу с этим числом, а затем попробуйте увеличить его до 20мс и понаблюдайте за разницей.
Не забудьте после оставить значение TAKT 10.

Управление яркостью

При динамической индикации разряды горят не на протяжении всего времени и светятся лишь на половину (при двух разрядах). Это нужно учитывать при подборе токоограничивающих резисторов индикатора.
Также можно управлять яркостью. В предыдущем примере добавьте еще один идентификатор BRIGHT и замените основной цикл:

#define BRIGHT 2 void loop() { digitalWrite(DIG1,LOW); Show(3); delay(BRIGHT); Clean(); digitalWrite(DIG1,HIGH); delay(TAKT-BRIGHT); digitalWrite(DIG2,LOW); Show(4); delay(BRIGHT); Clean(); digitalWrite(DIG2,HIGH); delay(TAKT-BRIGHT); }

Переопределение идентификатора BRIGHT от 0 до 10 будет приводить к изменению яркости. На время BRIGHT индикатор будет включен, а на время TAKT-BRIGHT выключен. Надо понимать, что эта константа будет справедлива только для ситуаций, когда TAKT равен 10мс.

Упрощение использования

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

В нем блок АЦП микроконтроллера периодически делает замер и сохраняет результат в память. Это результат можно из памяти вытащить и показать на индикаторе. То есть желательно иметь функцию, которая будет разделять двухразрядные числа две цифры.

Назовем эту функцию DisplayMath():

void DisplayMath(int data) { dig1 = dig2 = 0; if (data = 10) { data -= 10; dig1++; } dig2 = data; } }

В эту функцию будет передаваться число, которое нужно разобрать по разрядам. Результат обработки функция записывает в глобальные переменные dig1 и dig2.
Для начала происходит проверка входных данных.

Если переданное значение больше 100, то функция не будет делать ничего и переменные dig1 и dig2 обнулятся. Если меньше 100, то запускается пересчет.
Далее локальная переменная data декрементируется с шагом 10 и подсчитывается количество итераций.

Например, если функции передано значение 48 цикл while будет выполнен 4 раза и концу его выполнения переменные будут иметь состояние dig1=4, data=8. Далее остается только записать остаток data в переменную dig2.

В итоге после запуска этой функции в переменных dig1 и dig2 окажутся значения разрядов.
Сам вывод цифр на дисплей тоже лучше вынести в отдельную функцию. Назовем ее DisplayShow():

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

Окончательный код с использованием этих функций:

#define DIG1 4 #define DIG2 5 #define A 6 #define B 7 #define C 8 #define D 9 #define E 10 #define FF 11 #define G 12 #define TAKT 10 #define BRIGHT 2 int dig1 = 0; int dig2 = 0; void setup() { pinMode(A, OUTPUT); pinMode(B, OUTPUT); pinMode(C, OUTPUT); pinMode(D, OUTPUT); pinMode(E, OUTPUT); pinMode(FF, OUTPUT); pinMode(G, OUTPUT); pinMode(DIG1, OUTPUT); pinMode(DIG2, OUTPUT); digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); digitalWrite(DIG1,HIGH); digitalWrite(DIG2,HIGH); } void loop() { DisplayMath(34); DisplayShow(); } void DisplayMath(int data) { dig1 = dig2 = 0; if (data = 10) { data -= 10; dig1++; } dig2 = data; } } void DisplayShow() { digitalWrite(DIG1,LOW); Show(dig1); delay(BRIGHT); Clean(); digitalWrite(DIG1,HIGH); delay(TAKT-BRIGHT); digitalWrite(DIG2,LOW); Show(dig2); delay(BRIGHT); Clean(); digitalWrite(DIG2,HIGH); delay(TAKT-BRIGHT); } void Show(int digit) { switch(digit) { case 0: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); } break; case 1: { digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 2: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(G,LOW); } break; case 3: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(G,LOW); } break; case 4: { digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 5: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 6: { digitalWrite(A,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 7: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); } break; case 8: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(E,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; case 9: { digitalWrite(A,LOW); digitalWrite(B,LOW); digitalWrite(C,LOW); digitalWrite(D,LOW); digitalWrite(FF,LOW); digitalWrite(G,LOW); } break; } } void Clean() { digitalWrite(A,HIGH); digitalWrite(B,HIGH); digitalWrite(C,HIGH); digitalWrite(D,HIGH); digitalWrite(E,HIGH); digitalWrite(FF,HIGH); digitalWrite(G,HIGH); }

Обратите внимание насколько прост основной цикл loop(). В нем всего две строки. Если вы измените значение 34 на любое другое, то оно будет отображено на индикаторе.
Для демонстрации работы индикатора запустим счетчик с произвольной скоростью и будем выводить его состояние. Замените основной цикл и добавьте две переменных:

int value = 0; int i = 0; void loop() { i++; if (i == 7) { i = 0; value ++; if (value == 100) value = 0; } DisplayMath(value); DisplayShow(); }

Вы увидите как на экране побегут цифры от 0 до 99.

Заключение

В результате выполнения работы вы написали еще две функции для работы с индикатором. В перспективе мы уберем ее в отдельный файл, который легко будет подключить и начать работать с сегментным индикатором.

Индивидуальные задания

  1. Увеличьте модуль счета. Подключите четыре дополнительных светодиода на выводах A0-A5 и допишите программу так, чтобы счетчик считал от 0 до 699.
  2. Если в старшем разряде 0, то его нет смысла показывать.

    Доработайте программу так, чтобы старший разряд был погашен, если нужно показать число меньше 10

  3. Сделайте так, чтобы если функции DisplayMath() передано число больше 99 на дисплее отображалось -0 (overflow, переполнение)

Остальные статьи цикла можно найти здесь.

Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.

Источник: http://www.customelectronics.ru/arduino-dinamicheskaya-indikatsiya/

Управление драйвером семисегментных индикаторов MAX7219

В этой статье хочу показать как программно управлять модулем с драйвером MAX7219 и восемью семисегментными индикаторами. Довелось пообщаться с этим модулем и надо сказать, мне он очень понравился.

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

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

В общем то управление драйвером простое, как сдвиговым регистром по трехпроводной схеме (3-Wire). Вернее он и имеет как раз в своем составе сдвиговый регистр. Алгоритм управления такой. Низким уровнем на входе CS разрешаем принимать данные. Данные отсылаются по 16 бит, старшим битом вперед.

Биты с 15 по 8 это или адрес знакоместа (значения от 1 до 8), или служебная команда (значения от 9 до 15). Биты с 7 по 0 это данные, либо для инструкции, либо образ (маска) символа. Каждый выставленный бит на входе DIN записывается в регистр по фронту тактового импульса на входе CLK.

После того как все биты переданы, “защелкиваем” их, выставив единичку на входе CS.

Управляет драйвер восемью светодиодными семисегментными индикаторами с общим катодом. Это означает, что чтобы погасить все сегменты индикатора, надо прописать в него 0, а что бы зажечь, нужно прописать 255. Каждый из разрядов индикатора имеет независимую адресацию и его содержимое может быть обновлено без необходимости перезаписи всего индикатора.

Внешний вид модуля MAX7219.

Сама плата выполнена качественно, а вот индикаторы на ней припаяны кривовато. Подключение индикаторов странное. Ожидалось, что под номером 1 будет индикатор расположенный слева, но как видим слева идут 8, 7, 6 и т. д.. Почему-то распаяны они именно так, хоть это и не критично, и легко корректируется в коде программы.

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

А так индикаторы смотрятся через светофильтр. Яркость свечения не уменьшилась, а вот незасвеченные сегменты уже не видно.

Код “демки” на языке Си.

/**************************************************************/ /*** Управление драйвером семисегментных индикаторов MAX7219 **/ /************** нагруженным на восемь индикаторов. ************/ /************ Микроконтроллер: PIC16F628A *********************/ /************ Среда разработки MPLAB IDE v8.89 – язык C *******/ #include pic.h // нужен для HI-TECH C компилятора #include htc.h // для работы с функцией задержки #define _XTAL_FREQ 4000000 // прописываем частоту генератора /************* прописали выводы микроконтроллера **************/ #define knopkaup RA0 // кнопка больше #define knopkadown RA1 // кнопка меньше #define DIN RB0 // определение ввод данных #define CLK RB1 // определение тактирующего сигнала #define CS RB2 // определение выбор устройства #define DIN_OFF() DIN = 0; // данные в ноль #define DIN_ON() DIN = 1; // данные в еденичку #define STR_OFF() CLK = 0; // Строб в ноль #define STR_ON() CLK = 1; // Строб в еденичку #define WR_OFF() CS = 0; // начало передачи #define WR_ON() CS = 1; // завершение передачи /******************* логические операции **********************/ #define TestBit(x,y) (x & (1 0;i –) { if(TestBit(adres, i – 1)) { DIN_ON(); // выставили единичку } else { DIN_OFF(); // выставили нолик } STR_ON(); // такт в единичку __delay_us(5); // длительность строба STR_OFF(); // такт в ноль } for(i = 8; i > 0; i –) { if(TestBit(data, i – 1)) { DIN_ON(); // выставили единичку } else { DIN_OFF(); // выставили нолик } STR_ON(); // такт в единичку __delay_us(5); STR_OFF(); // такт в ноль } WR_ON(); // завершение передачи } void clear(void) { char i; for(i = 8; i > 0; i –) { w3_write(i, cifra[10]); // гасим все индикаторы } } void inic7219(void) { w3_write(0x0F, 0x00); // тест выключен w3_write(0x0C, 0x01); // нормальный режим w3_write(0x0B, 0x07); // кол-во знаков 8 w3_write(0x09, 0x00); // дешифраторы отключены w3_write(0x0A, bright_indik); // яркость свечения clear(); } void klava(void) { if(knopkaup == 0 && bright_indik != 15) { bright_indik ++; clear(); w3_write(0x0A, bright_indik); // яркость свечения hg1 = bright_indik / 10; // значение первой цифры hg2 = bright_indik % 10; // значение второй цифры hhg1 = cifra[hg1]; // маска первой цифры hhg2 = cifra[hg2]; // маска второй цифры w3_write(5, hhg1); // прописали первую цифру w3_write(4, hhg2); // прописали вторую цифру __delay_ms(1500); clear(); return; } if(knopkadown == 0 && bright_indik != 0) { bright_indik –; clear(); w3_write(0x0A, bright_indik); hg1 = bright_indik / 10; hg2 = bright_indik % 10; hhg1 = cifra[hg1]; hhg2 = cifra[hg2]; w3_write(5, hhg1); w3_write(4, hhg2); __delay_ms(1500); clear(); } } /******************* основная программа ***********************/ void main(void) { podgot(); bright_indik = 8; // яркость по умолчанию inic7219(); __delay_ms(500); while(1) { for(c = 0; c

Источник: http://naladchikkip.ru/upravlenie-drajverom-semisegmentnyh-indikatorov-max7219

Ссылка на основную публикацию
Adblock
detector
",css:{backgroundColor:"#000",opacity:.6}},container:{block:void 0,tpl:"
"},wrap:void 0,body:void 0,errors:{tpl:"
",autoclose_delay:2e3,ajax_unsuccessful_load:"Error"},openEffect:{type:"fade",speed:400},closeEffect:{type:"fade",speed:400},beforeOpen:n.noop,afterOpen:n.noop,beforeClose:n.noop,afterClose:n.noop,afterLoading:n.noop,afterLoadingOnShow:n.noop,errorLoading:n.noop},o=0,p=n([]),h={isEventOut:function(a,b){var c=!0;return n(a).each(function(){n(b.target).get(0)==n(this).get(0)&&(c=!1),0==n(b.target).closest("HTML",n(this).get(0)).length&&(c=!1)}),c}},q={getParentEl:function(a){var b=n(a);return b.data("arcticmodal")?b:(b=n(a).closest(".arcticmodal-container").data("arcticmodalParentEl"),!!b&&b)},transition:function(a,b,c,d){switch(d=null==d?n.noop:d,c.type){case"fade":"show"==b?a.fadeIn(c.speed,d):a.fadeOut(c.speed,d);break;case"none":"show"==b?a.show():a.hide(),d();}},prepare_body:function(a,b){n(".arcticmodal-close",a.body).unbind("click.arcticmodal").bind("click.arcticmodal",function(){return b.arcticmodal("close"),!1})},init_el:function(d,a){var b=d.data("arcticmodal");if(!b){if(b=a,o++,b.modalID=o,b.overlay.block=n(b.overlay.tpl),b.overlay.block.css(b.overlay.css),b.container.block=n(b.container.tpl),b.body=n(".arcticmodal-container_i2",b.container.block),a.clone?b.body.html(d.clone(!0)):(d.before("
"),b.body.html(d)),q.prepare_body(b,d),b.closeOnOverlayClick&&b.overlay.block.add(b.container.block).click(function(a){h.isEventOut(n(">*",b.body),a)&&d.arcticmodal("close")}),b.container.block.data("arcticmodalParentEl",d),d.data("arcticmodal",b),p=n.merge(p,d),n.proxy(e.show,d)(),"html"==b.type)return d;if(null!=b.ajax.beforeSend){var c=b.ajax.beforeSend;delete b.ajax.beforeSend}if(null!=b.ajax.success){var f=b.ajax.success;delete b.ajax.success}if(null!=b.ajax.error){var g=b.ajax.error;delete b.ajax.error}var j=n.extend(!0,{url:b.url,beforeSend:function(){null==c?b.body.html("
"):c(b,d)},success:function(c){d.trigger("afterLoading"),b.afterLoading(b,d,c),null==f?b.body.html(c):f(b,d,c),q.prepare_body(b,d),d.trigger("afterLoadingOnShow"),b.afterLoadingOnShow(b,d,c)},error:function(){d.trigger("errorLoading"),b.errorLoading(b,d),null==g?(b.body.html(b.errors.tpl),n(".arcticmodal-error",b.body).html(b.errors.ajax_unsuccessful_load),n(".arcticmodal-close",b.body).click(function(){return d.arcticmodal("close"),!1}),b.errors.autoclose_delay&&setTimeout(function(){d.arcticmodal("close")},b.errors.autoclose_delay)):g(b,d)}},b.ajax);b.ajax_request=n.ajax(j),d.data("arcticmodal",b)}},init:function(b){if(b=n.extend(!0,{},a,b),!n.isFunction(this))return this.each(function(){q.init_el(n(this),n.extend(!0,{},b))});if(null==b)return void n.error("jquery.arcticmodal: Uncorrect parameters");if(""==b.type)return void n.error("jquery.arcticmodal: Don't set parameter \"type\"");switch(b.type){case"html":if(""==b.content)return void n.error("jquery.arcticmodal: Don't set parameter \"content\"");var e=b.content;return b.content="",q.init_el(n(e),b);case"ajax":return""==b.url?void n.error("jquery.arcticmodal: Don't set parameter \"url\""):q.init_el(n("
"),b);}}},e={show:function(){var a=q.getParentEl(this);if(!1===a)return void n.error("jquery.arcticmodal: Uncorrect call");var b=a.data("arcticmodal");if(b.overlay.block.hide(),b.container.block.hide(),n("BODY").append(b.overlay.block),n("BODY").append(b.container.block),b.beforeOpen(b,a),a.trigger("beforeOpen"),"hidden"!=b.wrap.css("overflow")){b.wrap.data("arcticmodalOverflow",b.wrap.css("overflow"));var c=b.wrap.outerWidth(!0);b.wrap.css("overflow","hidden");var d=b.wrap.outerWidth(!0);d!=c&&b.wrap.css("marginRight",d-c+"px")}return p.not(a).each(function(){var a=n(this).data("arcticmodal");a.overlay.block.hide()}),q.transition(b.overlay.block,"show",1*")),b.overlay.block.remove(),b.container.block.remove(),a.data("arcticmodal",null),n(".arcticmodal-container").length||(b.wrap.data("arcticmodalOverflow")&&b.wrap.css("overflow",b.wrap.data("arcticmodalOverflow")),b.wrap.css("marginRight",0))}),"ajax"==b.type&&b.ajax_request.abort(),p=p.not(a))})},setDefault:function(b){n.extend(!0,a,b)}};n(function(){a.wrap=n(document.all&&!document.querySelector?"html":"body")}),n(document).bind("keyup.arcticmodal",function(d){var a=p.last();if(a.length){var b=a.data("arcticmodal");b.closeOnEsc&&27===d.keyCode&&a.arcticmodal("close")}}),n.arcticmodal=n.fn.arcticmodal=function(a){return e[a]?e[a].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof a&&a?void n.error("jquery.arcticmodal: Method "+a+" does not exist"):q.init.apply(this,arguments)}}(jQuery)}var debugMode="undefined"!=typeof debugFlatPM&&debugFlatPM,duplicateMode="undefined"!=typeof duplicateFlatPM&&duplicateFlatPM,countMode="undefined"!=typeof countFlatPM&&countFlatPM;document["wri"+"te"]=function(a){let b=document.createElement("div");jQuery(document.currentScript).after(b),flatPM_setHTML(b,a),jQuery(b).contents().unwrap()};function flatPM_sticky(c,d,e=0){function f(){if(null==a){let b=getComputedStyle(g,""),c="";for(let a=0;a=b.top-h?b.top-h{const d=c.split("=");return d[0]===a?decodeURIComponent(d[1]):b},""),c=""==b?void 0:b;return c}function flatPM_testCookie(){let a="test_56445";try{return localStorage.setItem(a,a),localStorage.removeItem(a),!0}catch(a){return!1}}function flatPM_grep(a,b,c){return jQuery.grep(a,(a,d)=>c?d==b:0==(d+1)%b)}function flatPM_random(a,b){return Math.floor(Math.random()*(b-a+1))+a}