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

08.10.2016

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

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

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

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

Теперь перед нами стоит ещё одна нелёгкая задача — возможность редактировать значения в регистрах микросхемы реального времени DS1307. Редактировать мы будем с помощью кнопок, вернее даже с помощью одной кнопки, так как у нас больше и ножек портов-то собственно не осталось. Ну и хорошо, что так, заодно и однокнопочный интерфейс изучим немного.

Посмотрим фрагмент схемы, где у нас подключена кнопка, остальное у нас ничего не меняется (нажмите на картинку для увеличения изображения)

Мы видим, что кнопка наша подключена к ножке PB5.

Чтобы нам определить долгое нажатие, нам либо нужно будет какой-то длинный цикл организовывать, что очень расточительно, либо подключить оставшийся последний нулевой таймер, ну и третий вариант — переходить на другой контроллер, в котором больше пинов. Ну будем стараться всё-таки оставить Atmega8 и задействовать таймер.

Первый таймер у нас занят динамической индикацией, второй таймер занят ШИМом, остается только нулевой. Можно конечно сделать другой счетчик в первом таймере, может в будущем мы так и будем делать, но нам всё же интересно попробовать и нулевой таймер.

У нулевого восьмибитного таймера существует только один режим — прерывание вызывается только по переполнению, причём это переполнение никак не регулируется и считает таймер только до 255. Но я думаю, нам этого хватит, точность нам не нужна.

Настраивается у таймера практически только делитель

Создадим ещё одну библиотеку специально для кнопки, так как чем меньше кнопок. тем больше кода. Состоять она будет из пары файлов — button.c и button.h

Подключим её в main.h

#include «DS18B20.h»

#include «button.h»

Также для порядка давайте все манипуляции в main() с настройкой портов оформим в функцию port_ini, которую создадим в самом начале главного модуля

//———————————————

void port_ini(void)

DDRD = 0xFF;

DDRB = 0b00011111;//3 ножки оставляем на вход для кнопок

PORTD = 0b11111111;

DDRC &= ~(1<<DDRC3);

PORTC &= ~(1<<PORTC3);

PORTB = 0b00100000;

//———————————————

А вместо всего этого в main() добавим вызов данной функции

timer_ini();

port_ini();

init_PWM_timer();

В файле button.c добавим инициализацию нашего таймера, взяв за основу готовую функцию нашего первого таймера и немного подправив её

#include «button.h»

//———————————————

void init_button_timer(void)

TIMSK |= (1<<TOIE0); //устанавливаем бит разрешения прерывания 0-ого счетчика

TCCR0 |= (1<<CS02)|(1<<CS00); // устанавливаем предделитель 1024

Также пропишем прототип в хедер-файле для данной функции и вызовем её в main()

init_PWM_timer();

init_button_timer();

ADC_Init();

Теперь в button.c добавим обработчик прерывания от таймера

ISR (TIMER0_OVF_vect)

Добавим переменную в main.h

unsigned int adc_value,adc_counter,adc_tmp;

unsigned int button_cnt;

Подхватим её в button.c

#include «button.h»

//———————————————

extern unsigned int button_cnt;

И проинициализируем её в main()

unsigned char clockmode=MODETIMEVIEW;//обычный режим показаний дисплея

button_cnt = 0; //измеритель времени нажатия кнопки

А в button.c в обработчике таймера будем её наращивать циклически, пока просто чтобы проверить, работает ли таймер

ISR (TIMER0_OVF_vect)

if(button_cnt<10000) button_cnt++;

else button_cnt=0;

Всё отображение пока в бесконечном цикле в main() закомментируем (строки где встречается ledprint()), а вместо этого выведем значение нашего счётчика

ledprint(button_cnt,MODETIMEVIEW);

Попробуем собрать код и прошить контроллер.

Всё работает, циферки бегут, кому интересно посмотреть, как они бегут, посмотрите видеоверсию урока, размещённую внизу страницы.

Вернём всё в бесконечном цикле на место, убрав комментарий и отображение счётчика.

Добавим ещё в главном модуле режимы для редактирования. Пока добавим только два, а остальные допишем позже

#define MODEDAYVIEW 103

//———————————————

#define MODENONEEDIT 0

#define MODEMINEDIT 1

Самый первый режим — это режим обычный, когда часы просто ходят и мы ничего не редактируем, а второй, когда редактируем значение минут в регистре микросхемы.

То же самое напишем в button.c

#include «button.h»

//———————————————

#define MODENONEEDIT 0

#define MODEMINEDIT 1

Также нам нужно будет определённый режим проинициализировать при старте, для этого должна быть ещё и переменная, которая должна быть ещё
и видна на только в одном главном модуле. Поэтому объявим её глобально в main.h

unsigned int button_cnt;

unsigned char clockeditmode;

И подхватим в button.c

extern unsigned int button_cnt;

extern unsigned char clockeditmode;

Ну и проинициализируем в main()

unsigned char clockmode=MODETIMEVIEW;//обычный режим показаний дисплея

clockeditmode=MODENONEEDIT;

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

Пока мы будем кнопку отслеживать при условии, что мы ничего не редактируем, а просто часы у нас ходят и мы решили отредактировать что-то

ISR (TIMER0_OVF_vect)

if(clockeditmode==MODENONEEDIT)

Для того, чтобы нам поудобнее писалось и читалось, добавим дефайны для ножек порта, к которому подключена кнопка в файл button.h

#include «main.h»

//—————————————-

#define BUTTONPORT PORTB

#define BUTTONPORT1 PORTB5

#define BUTTONPIN PINB

#define BUTTONPIN1 PINB5

#define BUTTONDDR DDRB

#define BUTTONDDR1 DDRB5

Добавим код отслеживания нажатой кнопки в обработчик прерывания от таймера в button.c

if(clockeditmode==MODENONEEDIT)

if((!(BUTTONPIN&(1<<BUTTONPIN1)))&&(buttonstat==0))//Кнопка 1 нажата

И теперь мы, если у нас кнопка будет нажата, то мы будем счётчик наращивать, а если нет, то обнулять

if((!(BUTTONPIN&(1<<BUTTONPIN1)))&&(buttonstat==0))//Кнопка 1 нажата

button_cnt++;

else button_cnt=0;

Ниже код удалим.

Также в button.c настроим ножку для кнопки на вход, добавив для этого функцию

void init_button_port(void)

BUTTONDDR &= ~(1<<BUTTONDDR1);/ножка кнопоки на вход

BUTTONPORT |= (1<<BUTTONPORT1);//подтянем резисторы к лапкам кнопок

Добавим для данной функции прототип в хедер-файле и вызовем её в main()

init_PWM_timer();

init_button_port();

init_button_timer();

Проверим код на работоспособность, собрав его и прошив контроллер.

Теперь наш счётчик набирает значение только по нажатию и удержанию кнопки. Ну думаю 60 нам хватит, чтобы считать нажатие долгим.

Продолжим код в обработчике от таймера в файле button.c, не выходя из условия, когда мы ничего не редактируем

else button_cnt=0;

if(button_cnt>60) clockeditmode=MODEMINEDIT;

Опять проверим наш код, собрав его и прошив контроллер.

У нас всё работает. Если мы держим кнопку и отпустим её, когда она ещё не досчитает до 60, то значение сбросится, а если дождёмся. когда досчитает, то у нас значение счетчика остается, равным 61, и код уже больше на кнопку не реагирует.

Теперь нам нужно по кнопке не только менять режим, но ещё и управлять отображением на дисплее, чтобы было видно, что мы собрались редактировать что-то. Например, если мы редактируем минуты, то у нас два правых разряда должны мигать. Мигание нам также будет обеспечивать выход SQW микросхемы.

Пока потренеруемся и попробуем просто помигать самым младшим разрядом. Для этого мы будем время от времени подавать единицу на его анод, хотя у нас он и анод, то тем не менее за счёт транзисторной инверсии единица у нас будет тушить разряд. Допишем код в led.c в функции обработчика таймера

if(n_count==0)

PORTB&=~(1<<PORTB0);PORTB|=(1<<PORTB1)|(1<<PORTB2)|(1<<PORTB4);

if (!(PINC&0b00001000)) PORTB|=(1<<PORTB0);

Соберём код, прошьём контроллер — у нас мигает последний разряд. Уже хорошо.

А чтобы нам сделать зависимость от режима редактирования, нам нужно будет объявить нашу глобальную переменную и дефайны в led.c

#define MODEDAYVIEW 103

//———————————————

#define MODENONEEDIT 0

#define MODEHOUREDIT 1

. . . . . .

extern unsigned char clockeditmode;

Ну и расширим теперь наше условие в обработчике

if ((clockeditmode==MODEMINEDIT)&&(!(PINC&0b00001000))) PORTB|=(1<<PORTB0);

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

Таким же образом мы заставим замигать следующий разряд

if(n_count==1)

PORTB&=~(1<<PORTB1);PORTB|=(1<<PORTB0)|(1<<PORTB2)|(1<<PORTB4);segchar(R2);

if ((clockeditmode==MODEMINEDIT)&&(!(PINC&0b00001000))) PORTB|=(1<<PORTB1);

Опять проверим, также собрав код и прошив контроллер. У нас теперь по долгому нажатию мигают два младших разряда.

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

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

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

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

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

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

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

Источник: narodstream.ru

Читайте также:

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

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