Урок 23
Часть 9
Собираем часы на DS1307 и LED индикаторе
В прошлой части урока мы добавили все режимы и «научили» кнопку переходить по ним циклично, реагируя на длинные нажатия.
Теперь нам нужно «научить» кнопку отличать короткие нажатия от длинных и также «научить» её переводить значения определённых регистров микросхемы DS1307.
Но тут будут свои трудности. Когда мы долго держим кнопку, счётчик у нас сбрасывается в ноль, и, если мы добавим код для короткого нажатия, то в этом уже случае код сразу продолжит свою работу и счётчик начнёт сразу считать и сгенерирует тут же нам короткое нажатие. Поэтому с этим делом нам нужно будет провести некоторую борьбу.
Для этого мы добавим ещё два макроса для режимов инкрементирования и неинкрементирования показателей
#define MODEYEARVIEW 104
//———————————————
#define MODEINC 201 //инкрементирование показателя
#define MODENOINC 202 //не меняем показатель
//———————————————
И то же самое мы пропишем в модуль button.c.
Добавим ещё одну глобальную переменную для хранения наших новых режимов в памяти в main.h
unsigned char clockeditmode,clockincmode;
Также подхватим её в button.c
extern unsigned char clockeditmode,clockincmode;
Также в функции main() мы инициализируем один из этих режимов при старте программы
clockeditmode=MODENONEEDIT;
clockincmode=MODENOINC;
Пройдём теперь в button.c в обработчик прерывания от таймера и, прежде чем добавлять реакцию на короткое нажатие, поработаем с дребезгом контактов данной кнопки.
В обработчике тело оператора else оформим в фигурные скобки и добавим туде ещё одно условие
else
{
((button_cnt>3)&&(button_cnt<=60)) //если будет до 3 — то считаем это дребезгом
{
clockincmode=MODEINC;//включаем прибавление значения показателя
}
button_cnt=0;
}
То есть мы будем включать режим добавления показателей, только если мы досчитаем до трех, меньше — дребезг.
Также для изменения и хранения режима состояния кнопки мы добавим ещё одну переменную в модуле button.c
extern unsigned char clockeditmode,clockincmode;
unsigned char buttonstat=0;
В обработчик нажатия (в условие в обработке прерывания от таймера) ещё вот такой код
if((!(BUTTONPIN&(1<<BUTTONPIN1)))&&(buttonstat==0))//Кнопка 1 нажата и это не продолжение нажатия
И теперь мы в тело данного условия зайдём только тогда, когда данный статус будет равен нулю.
Теперь нам нужно когда-то статус этот выставить в единицу. А вот когда
if(button_cnt>60)
{
if(clockeditmode<MODEALARMMINEDIT) clockeditmode++;
else clockeditmode=MODENONEEDIT;
clockincmode=MODENOINC;//выключаем прибавление значения показателя
button_cnt=0;
buttonstat=1;
}
Вот тут то мы его и выставим, чтобы сразу не зайти в обработчик и короткое нажатие обрабатывать только после отпускания кнопки, а не сразу по кругу. Также мы здесь отключили режим инкрементирования.
Добавим ещё одну переменную в данный модуль
unsigned char buttonstat=0,cnt=0;
Это ещё один счётчик.
Перед первым нашим условием в этом же обработчике напишем ещё одно условие
if(buttonstat==1) cnt++;
if((!(BUTTONPIN&(1<<BUTTONPIN1)))&&(buttonstat==0))//Кнопка 1 нажата и это не продолжение нажатия
То есть мы всё равно начнём наращивать счетчик. Но не до бесконечности, и не тот счётчик. Поэтому дальше ещё одно условие
if(buttonstat==1) cnt++;
if(cnt>30)
{
buttonstat=0;
cnt=0;
}
if((!(BUTTONPIN&(1<<BUTTONPIN1)))&&(buttonstat==0))//Кнопка 1 нажата и это не продолжение нажатия
То есть подождём ещё 30 циклов и опять установим статус и сбросим этот новый счётчик.
Теперь наша кнопка опять начнёт реагировать нормально на нажатие. Я думаю, придумано неплохо.
Теперь в бесконечный цикл в главный модуль добавим ещё код в самый конец цикла
else if ((clockeditmode==MODEALARMMINEDIT)||(clockeditmode==MODEALARMHOUREDIT))
{
ledprint(0,MODETIMEVIEW);
}
if(clockincmode==MODEINC) ledprint(1111,MODETIMEVIEW);
}
}
Это у нас временный код, чтобы проверить, зашли ли мы в режим инкрементирования.
Соберём код и прошьём контроллер. После входа в редактирование любой величины нажмём коротко на кнопку. И вот результат
Всё у нас работает по короткому нажатию.
Для составления и добавления следующего кода мы возьмём за основу проект, где мы подключили кнопки к часам на LCD.
И будем частями добавлять оттуда, подправляя понемногу, функцию редактирования показателей ModifyRTC.
Возьмём пока сам каркас, начало и конец функции. Здесь мы ничего не исправляем, единственное, выкинем из неё вообще все входные аргументы, режим нам передавать на надо, он у нас глобален, а также направление тоже нам не нужно, оно у нас только вперёд.
//———————————————
void ModifyRTC(void)
{
I2C_StartCondition();
I2C_SendByte(0b11010000);
I2C_StopCondition();
}
//———————————————
Добавим переключатель режимов и попробуем написать пока кейс для перевода часов
I2C_SendByte(0b11010000);
switch(clockeditmode){
case MODEHOUREDIT: //часы
I2C_SendByte(2);//Переходим на 0x02 — байт часов
if(hour<23) I2C_SendByte(RTC_ConvertFromBinDec(hour+1));
else I2C_SendByte(RTC_ConvertFromBinDec(0));
break;
}
I2C_StopCondition();
Перед тем как собрать проект, не забудем убрать из бесконечного цикла вот это безобразие
if(clockincmode==MODEINC) ledprint(1111,MODETIMEVIEW);
А добавим мы в бесконечный код вызов нашей функции редактирования, причём вызывать мы её будем при услвии, можно и всегда заходить в неё, но это будут лишние кодовые циклы, зачем они нам
tt = converttemp(dt_check());
if((clockeditmode!=MODENONEEDIT)&&(clockincmode==MODEINC))
{
ModifyRTC();
clockincmode=MODENOINC;
}
Тут, я думаю, всё понятно. Условие для вызова — режим редактирования и режим инкрементирования, и здесь же мы его и сбросим.
Теперь соберём код, прошьём контроллер и посмотрим, переводятся ли у нас часы.
Часы нормально редактируются.
Ну и сразу, чтобы не париться и не перепутать ничего, вставим заготовки кейсов для остальных показателей
case MODEHOUREDIT: //часы
I2C_SendByte(2);//Переходим на 0x02 — байт часов
if(hour<23) I2C_SendByte(RTC_ConvertFromBinDec(hour+1));
else I2C_SendByte(RTC_ConvertFromBinDec(0));
break;
case MODEMINEDIT: // минуты
break;
case MODEDATEEDIT: // дата
break;
case MODEMONTHEDIT: // месяц
break;
case MODEYEAREDIT: // год
break;
case MODEDAYEDIT: // день недели
break;
case MODEALARMHOUREDIT: // часы будильника
break;
case MODEALARMMINEDIT: // минуты будильника
break;
}
Теперь напишем тело кейса для редактирования минут, также используя код из другого урока и немного подправляя его
case MODEMINEDIT: // минуты
I2C_SendByte(1);//Переходим на 0x01 — байт минут
if(min<59) I2C_SendByte(RTC_ConvertFromBinDec(min+1));
else I2C_SendByte(RTC_ConvertFromBinDec(0));
break;
Проверим код
Всё работает — минуты переводятся. Думаю, на сегодня достаточно.
В следующей части нашего занятия продолжим нашу работу, надеясь, что она будет такой же успешной.
Предыдущая часть Программирование МК AVR Следующая часть
Программатор, модуль RTC DS1307 с микросхемой памяти и индикатор можно приобрести здесь:
Программатор (продавец надёжный) USBASP USBISP 2.0
Модуль RTC DS1307 с микросхемой памяти
Семисегментный чертырехразрядный индикатор красный с общим анодом 10 шт
Смотреть ВИДЕОУРОК (нажмите на картинку)
Добавить комментарий