AVR Урок 23. Собираем часы на DS1307 и LED индикаторе. Часть 9



 

Урок 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);

  }

}

 

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

 

 

Соберём код и прошьём контроллер. После входа в редактирование любой величины нажмём коротко на кнопку. И вот результат

 

image38

 

Всё у нас работает по короткому нажатию.

Для составления и добавления следующего кода мы возьмём за основу проект, где мы подключили кнопки к часам на 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;

}

 

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

Теперь соберём код, прошьём контроллер и посмотрим, переводятся ли у нас часы.

 

image39

 

Часы нормально редактируются.

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

 

  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;

 

Проверим код

 

image40

 

Всё работает — минуты переводятся. Думаю, на сегодня достаточно.

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

 

 

Предыдущая часть Программирование МК AVR Следующая часть

 

Программатор, модуль RTC DS1307 с микросхемой памяти и индикатор можно приобрести здесь:

Программатор (продавец надёжный) USBASP USBISP 2.0

Модуль RTC DS1307 с микросхемой памяти

Семисегментный чертырехразрядный индикатор красный с общим анодом 10 шт

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR Собираем часы на DS1307 и LED индикаторе

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*