Урок 11
Часть 2
Динамическая индикация
В прошлой части нашего занятия мы познакомились с принципом динамической индикации, собрали схему в протеусе.
Теперь закончим со сборкой и перейдём в проект, так как без соответствующего кода ничего работать на будет.
Начнем с порта B. Он у нас был сконфигурирован весь полностью на вход, но теперь так дело не пойдёт. Давайте половину порта сделаем на вход, а ту половину, где у нас подключены через транзисторы аноды индикаторов, сконфигурируем на выход. А подтягивающий резистор на ножке порта B переместим на другую ножку, к которой мы переподключили кнопку
DDRD = 0xFF;
DDRB = 0b00001111;
PORTB = 0b00100000;
Теперь, если мы соберём код и запустим его в протеусе, то у нас будут работать одновременно два индикатора. Это нам не подходит. Поэтому думаем дальше.
Прибавим разрядность переменной i. Пока под две цифры нам и char подойдёт, но на будущее нам этого не хватит. Поэтому сделаем это заранее
//———————————————
unsigned int i;
И ещё нам под цифры каждого разряда потребуются также переменные
unsigned int i;
unsigned char R1=0, R2=0;
//———————————————
Также добавим ещё одну функцию, которая будет заниматься выводом двухзначной цифры на дисплей. Поэтому в качестве входного параметра здесь будет unsigned int. Добавим данную функцию перед функцией main()
//———————————————
void ledprint(unsigned int number)
{
}
//———————————————
В данной функции мы распределим всю двухзначную цифру по разрядам.
Для этого мы применим математическую операцию, которая вычисляет остаток от деления. Обозначается она знаком %. Через данную операцию мы вычислим единицы. А затем, чтобы вычислить десятки, мы просто поделим на 10 входной параметр. Но так как у нас везде целочисленные операнды, то в результате получится целое число с выброшенным остатком, что и будет соответствовать десяткам, так как число у нас двухзначное
void ledprint(unsigned int number)
{
R1 = number%10;
R2 = number/10;
}
А таймер мы сегодня применим не для того, чтобы он наращивал цифры, а для того, чтобы он поочерёдно зажигал цифры на индикаторах. Добавим ещё одну переменную. Добавить мы её также можем необязательно в начале файла, а можем непосредственно перед кодом функции-обработчика прерываний, главное чтобы переменная в функции уже была определена
//———————————————
unsigned char n_count=0;
//———————————————
ISR (TIMER1_COMPA_vect)
И в зависимости от значения данной переменной, мы будем включать определённую ножку порта B, разрешая при этом вывод цифры на соответствующем индикаторе. Другую ножку порта мы будем отключать. Таже в том же условии мы будем вызывать функцию, которая будет включать комбинацию сегментов в зависимости от посланной переменной. Но так как определённая ножка порта B будет у нас отключена, то сегменты другого индикатора светиться на будут. Затем после всего этого мы будем прибавлять на 1 (инкрементировать) данную переменную. Но делать мы это будем до тех пор, пока она не достигнет значения 1. Вообщем, в связи с этим, переменная n_count будет равна либо 1, либо 0, так как пока у нас только 2 индикатора и соответственно будет только 2 варианта
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);segchar(R2);}
n_count++;
if (n_count>1) n_count=0;
}
Теперь нам осталось только лишь в функцию ledprint() отправить какую-нибудь цифру. Давайте пока подадим любую и наращивать её пока не будем. Для этого мы вызовем функцию в main() после всех инициализаций, отправив в неё, например, число 97
sei();
ledprint(97);
while(1)
Попробуем собрать проект и запустить его в протеусе. Мы видим, что код работает, динамическая индикация присутствует, но слишком наглядно, так как цифры светятся по очереди раз в 2 секунды.
Для наглядности работы динамической индикации это хорошо, но для постоянной работы не пойдёт. Глаз вообще не должен видимть динамику индикации. Должно быть впечатление, что цифры светятся постоянно.
Поэтому нам нужно настроить таймер на другую частоту. Попробуем порегулировать частоту делителем. Сделаем делитель 8 вместо 256 и, произведя нехитрые расчеты мы получим частоту 32. но так как у нас индикатора два, то получится на каждый по 16 герц. Этого конечно маловато, но попробовать можно. Чтобы нам выставить делитель 8, то мы в регистре TCCR1B должны включить бит CS11
Так и поступим
OCR1AL = 0b01000010;
TCCR1B |= (1<<CS11);//установим делитель
}
Соберём код и посмотрим работу в протеусе. Вроде бы не мерцает. На живых индикаторах пока смотреть не будем. Если что, то потом подравим частоту. Пока займёмся счетчиком, нам нужно будет считать до 99, а затем начинать с нуля. Для этого раскомментируем весь код в бесконечном цикле, также раскомментируем переменные для кнопки
int main(void)
{
unsigned char butcount=0, butstate=0;
Также, раз уж считать мы будем до 99, то также исправим код вот здесь
while(1)
{
for(i=0;i<100;i++)
{
То есть мы попробуем также кнопкой обнулять счётчик. Но так как мы кнопку переключили на другой пин, то нужно немного подправить проверяемое значение
if (!(PINB&0b00100000))
Также вместо функции segchar будет функция ledprint
ledprint(i);
_delay_ms(500);
Ну, собственно, и всё.
Соберём наш код и проверим его сначала в протеусе. Всё у нас считается и сбрасывается кнопкой. Отлично!
Теперь прошьём контроллер и посмотрим на живых индикаторах работу кода.
Код работает, но индикаторы мерцают. Поэтому немножко ещё поиграем с частотой в таймере. Если убрать делитель совсем, то эксперементальным путём было выявлено, что наши индикаторы перестанут светиться вообще. Этот эксперимент вы можете увидеть во второй части видеоурока (ссылки на видеоурок внизу, достаточно кликнуть по нужной картинке, в принципе, как и в любом уроке). Поэтому придется нам поиграть с цифрой в регистре OCR1A. Причём мы докажем, что виновата не слишком высокая частота, а то, что без делителя просто отказывается работать таймер. Поэтому цифру мы рассчитаем так, чтобы частота при делителе была примерно такая же как и без делителя, но на предыдущем значении в OCR1A. Цифру мы получим примерно 3906. Превратим её в двоичный вид и занесём в регистровую пару OCR1A. Код станет вот таким
OCR1AH = 0b00001111; //записываем в регистр число для сравнения
OCR1AL = 0b01000010;
Теперь, если собрать код и прошить контроллер, мы увидим, что всё работает как надо
Предыдущая часть Программирование МК AVR Следующий урок
Программатор и индикаторы можно приобрести здесь:
Программатор USBASP USBISP с адаптером USBASP USBISP 3.3 с адаптером
Семисегментный чертырехразрядный индикатор красный (с общим анодом или катодом на выбор) 10 шт
Смотреть ВИДЕОУРОК в RuTube
Смотреть ВИДЕОУРОК в YouTube
Подскажите, нам обязательно нужно использовать прерывание для смены индикатора для отображения. Можем ли мы просто давать команду на включение и выключение соответствующего порта, который через транзистор питает наш индикатор в общем цикле программы? Нечто подобное для числа, скажем, "88":
PORTC |= (1<<PC0); Зажигаем старший разряд
PORTB = 0b00000000;
PORTC &= ~(1<<PC0); Тушим старший разряд
PORTC |= (1<<PC1); Зажигаем младший разряд
PORTB = 0b00000000;
PORTC &= ~(1<<PC1); Тушим младший разряд
По идее частоты в 8МГц должно хватить для того, что бы индикация не мерцала. У меня Т0 и Т1 в программе задействованы для других задач.
Прервывание от таймера помогает достичь постоянной частоты.
Я так и полагал. Тем более, что моя схема при симуляции в Протеусе не отображает динамичискую индикацию в общем цикле без прерываний (я имею ввиду визуально). Загрузка процессора при этом колеблется в пределах 70-80%, о чём я получаю предупредительное сообщение. Но если запустить пошаговый режим симуляции — динамическая индикация присутствует. Но частоста отображения не стабильна в ходе последовательности шагов. Надо будет собрать реальное устройство и посмотреть как глаз будет воспринимать такой режим динамической индикации.
вот кусок тестового кода, который у меня работает отлично:
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);PORTB|=(1<<PORTB2);PORTB|=(1<<PORTB3);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);PORTB|=(1<<PORTB2);PORTB|=(1<<PORTB3);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB|=(1<<PORTB1);PORTB|=(1<<PORTB3);segchar(R3);}
if(n_count==3) {PORTB&=~(1<<PORTB3);PORTB|=(1<<PORTB0);PORTB|=(1<<PORTB1);PORTB|=(1<3) n_count=0;
}
//———————————————
void ledprint(unsigned int number)
{
R2=number%1000; // 1234%1000=234
R1=number/1000; // 1234/1000=1
R3 = R2%100; // 234%100=34
R2 = R2/100; // 234/100=2
R4 = R3/10; // 34%10=4
R3 = R3%10; // 34/10=3
}
Здравствуйте, не могу сообразить как добавить еще один индикатор
По идее так же как и все остальные.
void ledprint(unsigned int number)
{
// сделаем пересчет для трехзначного числа
R1 = number%10;
R2 = number/10;
R3 = R2/10
R2 = R2%10
}
unsigned char R1=0, R2=0; R3=0; //Добавим переменную R3
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);PORTB&=~(1<<PORTB2);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше
//С портами какие выключать и включать не разобрался просто не понял какие отвечают за включение какие за выключение,если интересно кому будет протестирую и сделаю правильно
}
//Блин математику понял хотя не дружу с ней и опыта ноль начал с этих уроков. боялся что такая схема для двухзначного коряво получится. но по расчетам все правильно на практике завтра проверю. Прям заинтересовался а смогу я без дальнейших уроков сам сделать третий индикатор для двух и трехзначных чисел))
{
R1 = number%10;
R2 = number/10;
R3 = R2/10;
R2 = R2%10;
}
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB1);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB&=~(1<<PORTB1);PORTB|=(1<2) n_count=0;
}
unsigned char R1=0, R2=0, R3=0;
Приветствую
Подскажите у меня проблема.Решил добавить еще одну пару дисплеев с таким же тамером и кнопкой. Оба таймера должны работать независимо друг от друга. В коде получилось два цикла, один из которых отказывается работать
я пересчитал частоту индикации 50 гц на канал — все работает отлично
//Странно писал все правильно а отобразилось с косяком, даже скопировал чтоб не потерять этот текст
// короче поправка
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);PORTB&=~(1<<PORTB2);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше
Админ. У меня часть текста не отправляется
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);PORTB&=~(1<<PORTB2);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше
«if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB0);PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше»
Пробую так. если что скобки убрать
Да простит меня Модератор:
if(n_count==2) {PORTB&=~(1<<PORTB2); PORTB|=(1<<PORTB0); PORTB&=~(1<2) n_count=0; //Сброс счетчика индикаторов на один выше
Да простит меня Модератор Еще раз:
if(n_count==2) {PORTB&=~(1< <PORTB2); PORTB|=(1< <PORTB0); PORTB&=~(1< 2) n_count=0; //Сброс счетчика индикаторов на один выше
Пробелы между стрелочками и плюсиками убрать
Администратор! у меня проблема! Часть кода в тексте пропадает! И не понятно откуда «2» взялось. Как будто текст перерабатывается в комментарии в код и удаляется
»
1)
«
У меня между скобками текст а отправилось только
«1)»
Попробую через пробелы написать, где пробелы та часть текста не отправляется, какаято она специфическая видимо
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB&=~(1<<PORTB0);PORTB|=(1 < 1 ) n_count=0;
Я в шоке но даже так не отправилось, напишите мне свой Мейл. Я скриншот пришлю.
{
R1 = number%10;
R2 = number/10;
R3 = R2/10;
R2 = R2%10;
}
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB0);PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB1);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);segchar(R3);}
n_count++;
if (n_count x 2) n_count=0; //Где x Заменить на знак больше. Просто так комментарий не отправлялся получалось скобка открывается а после n_count Закрывается и HTML Видимо его кушал. Спасибо Брату подсказал
}
unsigned char R1=0, R2=0, R3=0;
Это для трехзначной Индикации. Администрацию Попрошу Удалить мои комментарии. Я потом заново отвечу А то я засрал сайт.
Добрый день, я переписывал код по ходу урока, собрал схему в проеусе.
на индикаторах цифры обозначаются не верно, т.е. 1 нормально а потом на 2 один сегмент не горит, средний и так на всех цифрах, и на 2 один лишний!
подскажите что проверить!
Для динамической индикации 6 цифр, счет до 235960
подойдет такой код, по вашему примеру
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB3);segchar(R3);}
if(n_count==3) {PORTB&=~(1<<PORTB3);PORTB|=(1<<PORTB4);segchar(R4);}
if(n_count==4) {PORTB&=~(1<<PORTB4);PORTB|=(1<<PORTB5);segchar(R5);}
if(n_count==5) {PORTB&=~(1<<PORTB5);PORTB|=(1<5) n_count=0;
}
//———————————————
void ledprint(unsigned int number)
{
// R1 = number%10;
// R2 = number/10;
R1 = number%10; // единицы
R2 = number/10; // десятки
R3 = number/100; // сотни
R4 = number/1000; // тысячи
R5 = number/10000;
R6= number/100000;
}
Отличное решение!
Добрый день! Не хочу сильно Вас отвлекать, подскажите пожалуйста где найти подробное описание Таймера ?
Не понял какое число мне записать для сравнения в этот таймер для счета до 235959.
TIMSK |= (1<<OCIE1A); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)
OCR1AH = 0b10000000; //записываем в регистр число для сравнения
OCR1AL = 0b00000000;
TCCR1B |= ();//установим делитель.
Что-то не то в ledprint. R2 какое будет при number = 123, например?
Автор, добавьте в статью понятную методу расчета таймера(а не «делаем нехитрые вычисления в уме».Выкладка всех математических действий. Это важно в самом начале. То, что очевидно для вас, у других может вызывать вопросы.
Здраствуйте,я в этом деле пока навичок,Большое спасибо! всем кто создаль этот проект.но в деле у меня до этого урока все шел отлично,сделал все как указано но много ошибок
#include
#include
void ledprint(unsigned int number)
{
unsigned int i;
unsigned char R1=0,R2=0;
R1 = number%10;
R2 = number/10;
}
unsigned char n_count=0;
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<1) n_count=0;
}
sei();
ledprint(97);
while(1)
{
OCR1AL = 0b01000010;
TCCR1B |= (1<<CS11);//установим делитель
}
int main(void)
{
unsigned char butcount=0, butstate=0;
DDRD = 0xFF;
DDRB = 0b00001111;
PORTB = 0b00100000;
while(1)
{
for(i=0;i<100;i++)
{
if(!(PINB&0b00100000))
ledprint(i);
_delay_ms(500);
}
}
}
Помогите пожалуста дайте узнать как должен выглядить чтобы сравнивать и изучать на дальнейшем
Здраствуйте!наверно неразборчево обьяснил что пока нет ответов,ниже написано собранный мною программа согласно данного урока
#include
#include
unsigned int i;
unsigned char R1=0, R2=0;
void ledprint(unsigned int number)
{
R1 = number%10;
R2 = number/10;
}
unsigned char n_count=0;
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<1) n_count=0;
}
int main(void)
{
DDRB=0b00001111;
PORTB=0b00100000;
DDRD=0xFF;
PORTD=0b00000000;
while(1)
{
for(i=0;i<100;i++)
{
if(!(PINB&0b00100000))
ledprint(i);
_delay_ms(500);
{
PORTD = ~0b00000110;
_delay_ms(2500);
PORTD = ~0b01011011;
_delay_ms(2500);
PORTD = ~0b01001111;
_delay_ms(2500);
PORTD = ~0b01100110;
_delay_ms(2500);
PORTD = ~0b01101101;
_delay_ms(2500);
PORTD = ~0b01111101;
_delay_ms(2500);
PORTD = ~0b00000111;
_delay_ms(2500);
PORTD = ~0b01111111;
_delay_ms(2500);
PORTD = ~0b01101111;
_delay_ms(2500);
PORTD = ~0b00111111;
_delay_ms(2500);
}
/* else
{
PORTD=0b11111111;
}*/
}
}
}
выдает нижеследуюшие ошибки
Warning 1 return type defaults to 'int' [enabled by default] C:\novaya\Test06\Test06\Test06.c 19 1 Test06
Warning 2 type of '__vector_6' defaults to 'int' [enabled by default] C:\novaya\Test06\Test06\Test06.c 19 1 Test06
Warning 3 implicit declaration of function 'segchar' [-Wimplicit-function-declaration] C:\novaya\Test06\Test06\Test06.c 21 2 Test06
Warning 4 control reaches end of non-void function [-Wreturn-type] C:\novaya\Test06\Test06\Test06.c 25 2 Test06
Помогите пожалюста правильний как будеть напсано,
За раннее БОЛЬШОЕ СПАСИБО!
Когда о чём то знаешь — всё понятно. А как в реальном времени по порядку кода выполняется динамическая индикация? Подключен соответсвующий порт, подключено число это понятно, а число 91 при одноразовому отображению в switch (seg) только одной цифры и при задержке 500 мс между цифрами как отобразится или есть последовательное повторение switch (seg)? Объясните пожалуйста.
М-да, программирование — это весело, интересно и мозговыносяще. Странные штуки порой происходят, не всегда всё сразу получается, порой из-за невнимательности, порой из-за неточностей, а порой даже не понятно из-за чего вообще. Иногда вот делаешь всё по уроку, но проект не собирается — ошибки, долго ищешь их, а когда находишь, не понимаешь, как это у автора с таким проект собрался вообще. С одной стороны это хорошо, что приходится самому думать, но иногда это просто вынос мозга..
Чтобы не быть голословным, вот часть кода из данного проекта, где мы включаем определённые ножки порта В:
if(n_count==0) {PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0);segchar(R2);}
Моя студия ругается на PORTB0 и на PORTB1, видит это как текст и подчёркивает красным. Долго ломал мозг, в итоге заменил на PINB0 и 1:
if(n_count==0) {PORTB&=~(1<<PINB0);PORTB|=(1<<PINB1);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PINB1);PORTB|=(1<<PINB0);segchar(R2);}
Теперь всё работает, но вот что интересно, если взять исходный код автора вместе с проектом, то там всё работает и никаких ошибок, а если вставлять исходный код в свой проект — опять ошибка.
Может надо в настройки лезть какие, не знаю, пока это остаётся загадкой.
Тем не менее, спасибо автору, в основном всё довольно доходчиво.
Не понимаю, как при счете вычисляются единицы остатком при делении. Гугл не помог.
0%10=0; 1%10=0; 2%10=0. Везде будет нуль до окончания первого десятка.
Начиная со второго десятка R1 = number%10; R2 = number/10; понятно, что
11%10=1; 11(12,13,14 и т.д.)/10=1
разобрался вроде) 0%10 = нуль целых, остаток нуль; 1%10=нуль целых, остаток 1…
тяжко же без каких-то базовых знаний в си…
Не могу понять, почему происходит следующее при добавлении еще одного индикатора:
начинается отсчет, до сотни все нормально, после сотни десятки и единицы начинают отсчитываться совместно(единовременно).
Я использовал индикаторы с общим катодом и NPN транзисторы, поэтому код «зеркален» вашему.
//—————обработчик прерывания от таймера по совпадению
ISR (TIMER1_COMPA_vect)
{
if(n_count==0) {PORTB&=~(1<<PORTB2);PORTB|=(1<<PORTB1);PORTB|=(1<<PORTB0);segchar(R1);}
if(n_count==1) {PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB2);segchar(R2);}
if(n_count==2) {PORTB&=~(1<<PORTB0);PORTB|=(1<2) n_count=0;
}
void ledprint(unsigned int number)
{
R1 = number%10;
R2 = number/10;
R3 = R2/10;
//R4 = R3/10;
}
И еще вопрос. При делителе 8 частота маловата для трех индикаторов. Меньшего делителя нет. Как установить частоту повыше? Я просто избавился от делителя TCCR1B |= (1<<CS10).
Далее, не совсем ясно, из каких соображений выбран именно этот таймер. То есть не совсем понятно, в каких случаях какой таймер\счетчик необходимо использовать.Или это по ходу обучения станет ясным?
Присоединяюсь к Сергей
Автор, добавьте в статью понятную методу расчета таймера(а не «делаем нехитрые вычисления в уме».Выкладка всех математических действий. Это важно в самом начале. То, что очевидно для вас, у других может вызывать вопросы.
как добавить в этот код еще одну кнопку и семисегментник, которые должны работать независимо от другой кнопки. То есть две кнопки и два дисплея