Предсатвляем очередную схему часов на микронтроллере Atmega16.Для этого заблаговременно выпаял индикатор из 7-ми сегментов из нерабочей микроволновки. После чего, направился к компьютеру искать в сети схему устройства.

И вот, планомерно изучая, огромные мануалы технических текстов с характеристиками часов с многообразием полезных функциональных возможностей, среди которых: будильник, календарь, таймер и температурный датчик задаюсь вопросом. Необходимо ли мне исключительно отображение временного интервала? В моих настенных часах это уже есть, не хватает лишь подсветки.

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

Во имя оптимизации схемы микросхемы, отображающие показатели времени я не брал, а выполнил все на едином микроконтроллере. Рассмотрев даташиты, мой выбор стал на ATmega16 выполненный в корпусе TQFP, он собственно у меня и имелся.

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

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

В итоге получил схему:

Часы на микроконтроллере Atmega16

Индикатор, снабженный единым анодом подключенным прямиком к порту микоконтроллера. Резистор каждого сегмента выдает 220 Ом, чуть меньше либо немного больше в нашем случае не критично, ночью светятся довольно ярко (Проще говоря, подойдут и менее яркие, но меньше 100 Ом ставить не советую, так как на каждую опору порта придется всего 35мА, а по даташиту должно быть не менее 40мА). В расчетах я ошибся. Надо существенно больше. Скорректировал по 560 Ом, что превысило требование по даташиту. Но часы работают.

На самом транзисторе воплощен детектор входящего напряжения. Он, к слову, как и кнопки, подсоединен на протяжении прерываний их всего 3.
Часы функционируют при помощи Тimer2 работающего асинхронным способом. В данном режиме таймер берет свой такт от кварца на 32768 Гц установленного извне и не прекращает работу даже в ждущем режиме, этот принцип мы и возьмём за основу при программировании устройства для работы на резервном питании. Вот собственно и все.

Семисегментный индикатор выполнен с общим анодом, его аноды непосредственно законнектины с портом C микрокнтроллера, на каждый сегмент был установлен резистор на 220 Ом, можно конечно и по меньше при этом свечение сегментов будет ярче, здесь самое главное не переусердствовать а то можно нафик спалить сам порт микронтроллера,нужно смотреть какой максимальный ток может выдержить порт. 

 Транзистор Q1 выполняет своего рода дектор напряжения. Также как и кнопки он подлючается к линии внешних прерываний, в Atmega16 их всего 3.

Код программы часов на микронтроллере




// ANTONLUBA 2013
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "bits_macros.h"

typedef struct{ 
    unsigned char second;
    unsigned char minute;
//    unsigned char hour;
//    unsigned char date;
//    unsigned char month;
//    unsigned int year;
}time;

time t;

uint8_t segment[] = 
                //pgfedcba
                {
                0b00111111,     //0
                0b00000110,     //1
                0b01011011,     //2
                0b01001111,     //3
                0b01100110,     //4
                0b01101101,     //5
                0b01111101,     //6
                0b00000111,     //7
                0b01111111,     //8
                0b01101111      //9
                };

#define SEG_PORT PORTA  
#define SEG_DDR DDRA
#define SEG_CONN 0b01111111

#define DRV_PORT PORTC  
#define DRV_DDR DDRC
#define DRV_CONN 0b00011111

uint8_t digits[5];
uint8_t current_digit;

void BIN2BCD(uint8_t *buffer, unsigned int n)
{
        buffer[1]=0;
        while(n>=10) {buffer[1]++;n-=10;}
        buffer[0]=n;
}

uint8_t power_on = 1;           //питание есть
uint8_t m_pressed = 0, h_pressed=0; //нажаты кнопки
uint8_t button_delay;           //счетчик цикла задержки
int main(void)
{ 
    // Ждем стабилизации внешнего резонатора.
    _delay_ms(500);

    // Конфигурируем порты семисегментника
        SEG_PORT=0xFF;
        SEG_DDR=SEG_CONN;

        DRV_PORT=0x00;
        DRV_DDR=DRV_CONN;

        PORTD|= 0b1100;         //Это подтяжка для кнопок
        DDRD=0;

        SetBit(PORTB,2);        //Это подтяжка для датчика питания
        DDRB=0;
        //таймер0 для динамической индикации
        TCCR0 = (1<<CS01)|(1<<CS00);//3
        
        //внешние прерывания
        MCUCR |= (0<<ISC11)|(1<<ISC10)|(0<<ISC01)|(1<<ISC00);//прерывания INT0 и INT1 по изменению
        MCUCSR |= (1<<ISC2); //прерывание 2 по нарастанию
        GICR |= (1<<INT1)|(1<<INT0)|(1<<INT2); //включить внешние прерывания

    // Отключаем прерывания Таймера 2.
    TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2));

    // Переводим Таймер 2 в асинхронный режим (тактирование от
    // часового кварцевого резонатора).
    ASSR |= _BV(AS2);

    TCNT2 = 0x00;
    TCCR2 = 0x05; //Устанавливаем коэффициент деления равным 128.
    OCR2  = 0x00;

    // Ждем готовности таймера.
    while (ASSR & (_BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB)));

    // Разрешаем прерывание от Таймера 2.
    TIMSK |= _BV(TOIE2);
        // И таймера0
        TIMSK |= (1<<TOIE0);

    // Разрешаем прерывания глобально.
    sei();

    while(1)
    {
        if (power_on)
        {       
                BIN2BCD(&*digits, t.minute);
                BIN2BCD(&*digits+2, t.hour);
        }
        sleep_enable();
        sleep_cpu();
        sleep_disable();

        // Не понял, что это, но без него работает
       // TCCR2=0x05;           // Write dummy value to Control register
        // Ждем готовности таймера 2.
       // while (ASSR & (_BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB)));
    }

    return 0;
}


ISR(TIMER2_OVF_vect) //overflow interrupt vector
{       
        //Это просто взято из аппноута, кроме суток, месяцев и лет
    if (++t.second==60)     //keep track of hours minutes
    {
        t.second=0;
        
                if (++t.minute==60)
        {
            t.minute=0;

            if (++t.hour==24)
            {
                t.hour=0;
            }
        }
    } 
}

ISR(INT0_vect)
{
h_pressed=(BitIsClear(PIND, 2)); //нажатие кнопки часов
}

ISR(INT1_vect)
{
m_pressed=(BitIsClear(PIND, 3)); //нажатие кнопки минут
}

ISR(INT2_vect)
{
ClearBit(GICR,INT2);            //отключим прерывание INT2

InvBit(MCUCSR,ISC2);            //переключим на ожидание спада
power_on=(BitIsSet(MCUCSR,ISC2));//установим переменную

if (power_on)           //если питание есть
        {
        DRV_DDR=DRV_CONN;       //включаем аноды
        TCCR0 |= (1<<CS01)|(1<<CS00);//включаем таймер0
        }
else                    //если питания нет
        {
        DRV_DDR=0;      //отключаем аноды
        TCCR0 &= ~((1<<CS01)|(1<<CS00)); //выкл таймер0
        }

SetBit(GICR,INT2);      //вкл прерывание INT2

}

ISR(TIMER0_OVF_vect)
{
        if (power_on) // если питание включено
        {
                DRV_PORT=0;     //выкл все разряды
                if (current_digit==4)   //если точечки
                {
                        if (BitIsSet(t.second,0)) //включить-выключить точечки
                        {
                                SEG_PORT=0b01111001;
                        }
                        else
                        {
                                SEG_PORT=0b01111111;
                        }
                }
                else            //если цифра
                {
                        SEG_PORT=~segment[digits[current_digit]]; //вывести цифру
                }
                SetBit(DRV_PORT, current_digit);    //включить текущий разряд
                if (++current_digit==5)         //если прошли все разряды                               
                {
                        current_digit=0;        //сначала
                        
                        if (++button_delay==20) // с задержкой
                        {
                                button_delay=0;
                                if (h_pressed)  //если нажата кнопка часов
                                {
                                        if (++t.hour==24)//корректировать часы
                        {
                                t.hour=0;
                        }
                                }
                                if (m_pressed) //если нажата кнопка минут
                                {
                                        if (++t.minute==60) //корректировать минуты
                                {
                                t.minute=0;
                                        }
                                }
                        }
                }
        }
}

Комментарии   

0
Подскажите пожалуйста, а что значит вот это выражение? SEG_PORT=0b01111111;

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


Защитный код
Обновить