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



 

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

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

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

 

 

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

 

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

Один комментарий на “AVR Урок 23. Собираем часы на DS1307 и LED индикаторе. Часть 8
  1. Алексей:

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

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

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

*