Урок 23
Часть 8
Собираем часы на DS1307 и LED индикаторе
В прошлой части нашего занятия мы «научили» наш контроллер «ждать» некоторое время, чтобы ему стало понятно, что у нас произошло долгое нажатие кнопки и он нам сменил режим.
Сегодня мы продолжим совершенствовать механизм работы кнопки и также добавим ещё несколько режимов.
Откроем главный модуль и добавим макросы для данных режимов, в том числе и для переключения редактирования часов и минут будильника
#define MODENONEEDIT 0
#define MODEHOUREDIT 1
#define MODEMINEDIT 2
#define MODEDATEEDIT 3
#define MODEMONTHEDIT 4
#define MODEYEAREDIT 5
#define MODEDAYEDIT 6
#define MODEALARMHOUREDIT 7
#define MODEALARMMINEDIT 8
//———————————————
Минуты мы сдвинули часами, так как обычно часы редактируют сначала, ну типа справа налево.
Также всё это хозяйство нам необходимо перенести в файлы button.c и в led.c.
Дальше мы кое-что поменяем. В процедуре обработчике от таймера кнопки мы немного переработаем свой код. Мы не будем отсдеживать что у нас режим обычный, иначе получится слишком много вложенности. Удалим там весь код, чтобы не запутаться, ну или скопируем в какой-нибудь редактор, чтоб не писать заново, ну или закомментируем.
Вернём обработчик нажатой кнопки на верхний уровень
ISR (TIMER0_OVF_vect)
{
if(!(BUTTONPIN&(1<<BUTTONPIN1)))//Кнопка 1 нажата
{
}
}
И в обработчике прибавим счётчик независимо ни от чего другого
if(!(BUTTONPIN&(1<<BUTTONPIN1)))//Кнопка 1 нажата
{
button_cnt++;
}
А если кнопка не нажата, то мы счётчик сбросим
button_cnt++;
}
else button_cnt=0;
Дальше пойдёт обработчик того, что счётчик всё таки досчитал до 60
else button_cnt=0;
if(button_cnt>60)
{
}
Здесь мы пока уйдём в другой режим и также обнулим здесь наш счётчик, чтобы он дальше 60 не уходил
if(button_cnt>60)
{
clockeditmode=MODEMINEDIT;
button_cnt=0;
Проверим, собрав код и прошив контроллер. Всё должно быть как и было, за исключением того, что счётчик у нас сбросился и замигали нули. Это хорошо.
Теперь сходим в led.c в процедуру таймера. Нам ведь ещё реагировать надо на изменение режимов. Да и здесь я тоже подумал и решил кардинально всё поменять. Не нужно нам играть тут с портом B, который занимается нашими анодами, потому что это влияет пагубно на двоеточие. Поэтому начнём обрабатывать данное условие в сначала в самом младшем разряде. Мы даже проще поступим. Мы по импульсам будем отображать символ пустого места. Это и заставит мигать разряд
if ((clockeditmode==MODEMINEDIT)&&(!(PINC&0b00001000)))
{
segchar(11); // пустое место
}
То же самое мы напишем и в следующем разряде. Затем соберём код и прошьём контроллер, чтобы убедиться, что у нас всё также будет работать.
Вернёмся в нашу библиотеку кнопки и продолжим там писать обработчик кнопки. В условии, что мы досчитали до 60, что говорит о том, что мы долго жали кнопку, напишем ещё алгоритм цикличной смены режимов по очередным долгим нажатиям кнопки. Мы не будем писать отдельное условие для каждого режима, а придумаем что-нибудь поумнее, так как каждому режиму у нас соответствует целое число и расположены у нас они уже в умном порядке. Поэтому мы будем просто данные режимы инкрементировать. Включение именно режима минут удалим
if(button_cnt>60)
{
clockeditmode=MODEMINEDIT;
if(clockeditmode<MODEALARMMINEDIT) clockeditmode++;
else clockeditmode=MODENONEEDIT;
button_cnt=0;
То есть мы проверяем, что режим у нас ещё не последний и прибавляем его, а если последний то переходим в нулевой — режим обычный, когда мы ничего на редактируем.
Теперь нам нужно будет как-то проверить, что у нас меняются режимы.
Зайдём в бесконечный цикл функции main() и там, где мы отображаем режимы, отобразим цифру режима
ledprint(clockeditmode,MODETIMEVIEW);
Проверим всё это, также собрав код и прошив контроллер.
Идём дальше.
Теперь мы должны обеспечить мигание старших двух разрядов в случае редактирования часов
if((clockeditmode==MODEHOUREDIT)&&(!(PINC&0b00001000)))
{
segchar(11); // пустое место
}
else segchar(R3);
if((clockeditmode==MODEHOUREDIT)&&(!(PINC&0b00001000)))
{
segchar(11); // пустое место
}
else segchar(R4);
Опять проверим на практике. Если всё работает, движемся дальше.
Также нам надо заставить мигать дату и месяц в случае их редактирования. Работаем с теми же разрядами, только добавим режимы
В младших двух разрядах:
if(((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEMONTHEDIT))&&(!(PINC&0b00001000)))
В старших двух разрядах:
if(((clockeditmode==MODEHOUREDIT)||(clockeditmode==MODEDATEEDIT))&&(!(PINC&0b00001000)))
Теперь работаем с режимом года, тут четырёхзначная величина, пусть мигают все четыре разряда. Исправим те же строки
В младших двух разрядах
if (((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEMONTHEDIT)
||(clockeditmode==MODEYEAREDIT))&&(!(PINC&0b00001000)))
В старших двух разрядах
if (((clockeditmode==MODEHOUREDIT)||(clockeditmode==MODEDATEEDIT)
||(clockeditmode==MODEYEAREDIT))&&(!(PINC&0b00001000)))
С двоеточием мы разберемся позже, пусть пока мигает.
Теперь день недели. Тут мы будем мигать только разрядом вторым справа, в котором у нас отображается непосредственно день недели, минусами мы мигать не будем, пусть они светятся, поэтому подправим второй справа разряд
if(n_count==1)
{
PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0)|(1<<PORTB2)|(1<<PORTB4);segchar(R2);
if(((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEMONTHEDIT)
||(clockeditmode==MODEYEAREDIT)||(clockeditmode==MODEDAYEDIT))&&(!(PINC&0b00001000)))
Ну и также мигаем разрядами часов и минут в режиме редактирования будильника
Идем справа налево, потому что у нас так написан код:
1 разряд
if(((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEMONTHEDIT)
||(clockeditmode==MODEYEAREDIT)||(clockeditmode==MODEALARMMINEDIT))&&(!(PINC&0b00001000)))
2 разряд
if(((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEMONTHEDIT)
||(clockeditmode==MODEYEAREDIT)||(clockeditmode==MODEDAYEDIT)
||(clockeditmode==MODEALARMMINEDIT))&&(!(PINC&0b00001000)))
3разряд
if(((clockeditmode==MODEHOUREDIT)||(clockeditmode==MODEDATEEDIT)
||(clockeditmode==MODEYEAREDIT)||(clockeditmode==MODEALARMHOUREDIT))&&(!(PINC&0b00001000)))
4разряд
if(((clockeditmode==MODEHOUREDIT)||(clockeditmode==MODEDATEEDIT)
||(clockeditmode==MODEYEAREDIT)||(clockeditmode==MODEALARMHOUREDIT))&&(!(PINC&0b00001000)))
Чтобы у нас во время редактирования значения года не мигало двоеточие, давайте добавим макрос для года, так как когда мы добавляли макросы для отображений часов, даты, дня недели и температуры, мы для года такой макрос не делали, так как у нас он в обычных условиях никогда не показывается, ну как бы год-то мы и так помним нормально. А теперь нужно будет добавиь его в главном модуле и в модуле led.c
#define MODEDAYVIEW 103
#define MODEYEARVIEW 104
Ну и теперь пора нам показывать не номера режимов, с этим мы отладились, а реальные показания времени, даты и т.д. Делаем это мы, как мы помним в бесконечном цикле функции main(). Пока раскомментируем то, что у нас уже было, но добавим возможность работы данного кода только в зависимость от условия, что мы ничего не редактируем
if(clockeditmode==MODENONEEDIT)
{
if(clockmode==MODETIMEVIEW) ledprint(hour*100+min,MODETIMEVIEW);
if(clockmode==MODETEMPERVIEW) ledprint((tt>>1)*10+((tt%2)*5),MODETEMPERVIEW);
if(clockmode==MODEDAYVIEW) ledprint(day*10,MODEDAYVIEW);
if(clockmode==MODEDATEVIEW) ledprint(month + date*100,MODEDATEVIEW);
}
Также нам потребуется ещё несколько условий и реакция на них. Продолжаем код дальше
if(clockmode==MODEDATEVIEW) ledprint(month + date*100,MODEDATEVIEW);
}
else if ((clockeditmode==MODEMINEDIT)||(clockeditmode==MODEHOUREDIT))
{
ledprint(hour*100+min,MODETIMEVIEW);
}
else if ((clockeditmode==MODEDATEEDIT)||(clockeditmode==MODEMONTHEDIT))
{
ledprint(date*100+month,MODEDATEVIEW);
}
else if (clockeditmode==MODEDAYEDIT)
{
ledprint(day*10,MODEDAYVIEW);
}
else if (clockeditmode==MODEYEAREDIT)
{
ledprint(year+2000,MODEYEARVIEW);
}
else if ((clockeditmode==MODEALARMMINEDIT)||(clockeditmode==MODEALARMHOUREDIT))
{
ledprint(0,MODETIMEVIEW);
}
Пока будильника у нас нет, покажем нули. Позже у нас обязательно будет будильник и его показания мы, скорей всего, будем хранить во внутреннем EEPROM, так как работать мы с ним умеем. В микросхеме хранилища такого нет.
Проверим код на практике, прошив контроллер и увидим ,что вроде всё работает но как-то не так. В некоторых разрядах вместо if нужно было писать else if, а именно во всех, кроме второго справа, поэтому у нас нашим новым кодом отменялся предыдущий код, вернее затирался его результат на разряде. Расставим else по местам и, проверив ещё раз, убедимся, что теперь всё нормально.
Теперь у нас всё корректно отображается. Цель данной части достигнута.
Теперь у нас задача — переводить показания, а то мы пока ими только мигать умеем. Также нужен код отслеживания короткого нажатия на кнопку, пока она «знает» только длинное Но с этим мы займёмся в следующей части нашего занятия.
Предыдущая часть Программирование МК AVR Следующая часть
Программатор, модуль RTC DS1307 с микросхемой памяти и индикатор можно приобрести здесь:
Программатор USBASP USBISP с адаптером USBASP USBISP 3.3 с адаптером
Модуль RTC DS1307 с микросхемой памяти
Семисегментный чертырехразрядный индикатор красный (с общим анодом или катодом на выбор) 10 шт
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)
Редактирование справа налево в режиме часов — не совсем правильно. В начале было правильнее. Потому что пока час ставишь — минуты могут уйти, т.к. изменяются быстрее. Вспоминаю, что везде в технике сначала час задается.