Помогите сделать часы

Обсуждаем контроллеры компании Atmel.
Ответить
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Помогите сделать часы

Сообщение Dreenpeace »

Доброго времени суток, уважаемые Коты!
Очень прошу вас помочь мне в написание кода часов для Atmega8 на языке C (CVAVR), мне не нужны часы с термометрами и прочей приблудой, мне нужны обыкновенные часы. Более того мне нужна помощь в написание только той части кода, которая отвечает за отсчёт секунд, проще говоря код, который каждую секунду будет инкрементировать переменную "s". Выводить время, настраивать его с помощью кнопок и всё прочее необходимое я уже умею и сделаю сам, просто я не умею работать с таймерами и посмотрев множество примеров так и не понял ничего. Имеется часовой кварц :)
Извиняюсь если тема уже существует.
Заранее всем спасибо за ответы, очень на вас надеюсь.
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Помогите сделать часы

Сообщение eess9 »

ATmega8 подойдет?

Код: Выделить всё

#include <avr/io.h>
#include <avr/interrupt.h>


ISR(TIMER2_OVF_vect)//вызывается 1 раз в секунду
{

}

int main(void)
{
   //T2 на счет секунды, на TOSC1, TOSC2 - часовой кварц (32.768кГц)
   TIMSK &= ~(_BV(TOIE2) | _BV(OCIE2));
   ASSR |= _BV(AS2);
       TCNT2 = 0x00;
       TCCR2 = 0x05;
       OCR2  = 0x00;
       while (ASSR & (_BV(TCN2UB) | _BV(OCR2UB) | _BV(TCR2UB)));
       TIMSK |= _BV(TOIE2);

   sei();

   while (1)
   {
      asm("nop");
   }
}
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Спасибо конечно за ссылочку и за пример, но и там и там рассматривается код на AVR Studio, а мне нужно код для CodeVision AVR :)
Я так понимаю по прерыванию срабатывает функция

Код: Выделить всё

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
    ...
}

а сам таймер настраивается как-то так:

Код: Выделить всё

    TCCR1A=0x00;
    TCCR1B=0x05;
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x1E;
    OCR1AL=0x85;
    OCR1BH=0x00;
    OCR1BL=0x00;

    TIMSK=0x10;

Но я пока не понял, как именно настроить таймер, чтобы он срабатывал 1 раз в секунду, при частоте в 32.768кГц
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Dreenpeace писал(а):я пока не понял, как именно настроить таймер

Вы по ссылочке - то только сходили, или почитали, что DI HALT пишет?
DI HALT писал(а):

Код: Выделить всё

TCCR2 = 5<<CS20;    // Предделитель на 128 на 32768 даст 256 тиков в секунду
                                 // Что даст 1 прерывание по переполнению в секунду.


Dreenpeace писал(а):там и там рассматривается код на AVR Studio, а мне нужно код для CodeVision AVR

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

Вот тут еще гляньте
http://forum.cxem.net/index.php?showtopic=119284
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

metan писал(а):Разницы в данном случае почти никакой, только некоторые макроопределения, типа CS20, нужно посмотреть в даташите и заменить на номера битов, ну и названия процедуры - обработчика поменять.


Понимаете, Metan, я новичок в программирование контроллеров, да и в программирование на языке C тоже, для меня ближе мой родной Delphi :) поэтому разница для меня огромная. Есть у меня перевод даташита, так вот я там нашёл одно упоминание CS20:
Изображение
Как эти биты привести к шестнадцатеричному коду, да и как вообще всё это:

Код: Выделить всё

TIMSK &=~(1<<OCIE2 | 1<< TOIE2);   // Запрещаем прерывания таймера 2
ASSR  = 1<<AS2;            // Включаем асинхронный режим
TCNT2 = 0;
TCCR2 = 5<<CS20;          // Предделитель на 128 на 32768 даст 256 тиков в секунду

будет выглядеть на CVAVR я не понимаю :(

Проанализировав код который я выкладывал ранее у меня получилось сделать часы, НО каждую минуту они отстают на секунду и нечего поделать не могу.
Корпус кварца заземлён. Пробовал менять OCR1AL, TIMSK и ACSR нечего не даёт, а вот при изменении OCR1AH то отстают сильнее то вовсе спешат. Никак не могу понять вообще что к чему :( :( :(
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Dreenpeace писал(а):Проанализировав код который я выкладывал ранее у меня получилось сделать часы, НО каждую минуту они отстают на секунду и нечего поделать не могу.

Ошибка в том, что вы пытаетесь использовать 16 битный Timer1, а он тактируется у вас скорее всего от внутреннего генератора, а не от кварца на 32768. Нужно использовать 8 битный Timer2, тогда при предделителе 128 он будет переполняться 1 раз в секунду. Смотрите сообщение eess9.

Dreenpeace писал(а):будет выглядеть на CVAVR

Код: Выделить всё

TIMSK &=~(1<<7 | 1<< 6);   // Запрещаем прерывания таймера 2
ASSR  = 1<<3;            // Включаем асинхронный режим
TCNT2 = 0;
TCCR2 = 5;          // Предделитель на 128 на 32768 даст 256 тиков в секунду
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Сделал всё как вы сказали, но часы теперь вообще стоят на месте и не тикают :( , вот код:

Код: Выделить всё

interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    TCNT2=0;
    s++;
}

void main(void)
{         
    TIMSK &=~(1<<7 | 1<< 6);    // Запрещаем прерывания таймера 2
    ASSR  = 1<<3;               // Включаем асинхронный режим
    TCNT2 = 0;                 
    TCCR2 = 5;                   // Предделитель на 128 на 32768 даст 256 тиков в секунду
    OCR2  = 0;                 
    while (ASSR & (1 << 2 | 1 << 1 | 1 << 0));
        TIMSK |= 1 << 6;
       
    #asm("sei");
       
    while (1)
    {
        print(s); // Моя ф-ция для вывода на 7-сегментный индикатор
    }
}


Скажите пожалуйста что я сделал не так?
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Код: Выделить всё

interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
  s++;
}

void main(void)
{         
    TIMSK &=~(1<<7 | 1<< 6);    // Запрещаем прерывания таймера 2
    ASSR  = 1<<3;               // Включаем асинхронный режим
    TCNT2 = 0;                 
    TCCR2 = 5;                   // Предделитель на 128 на 32768 даст 256 тиков в секунду
    OCR2  = 0;                 
    while (ASSR & (1 << 2 | 1 << 1 | 1 << 0));
     TIMSK |= 1 << 6;
       
    #asm("sei");
       
    while (1)
    {
        print(s); // Моя ф-ция для вывода на 7-сегментный индикатор
    }
}

Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Спасибо огромное за вашу помощь и ваши ответы! :)
Исправил как вы сказали, часы за работали, но теперь спешат на 3 секунды в минуту :(
Может это из за использование delay_us(250); ?
Вот весь код полностью:
Спойлер

Код: Выделить всё

#include <mega8.h>
#include <delay.h>
#include <print.c>

int t=0; // Время в 4х значном формате
int s=0; // Секунды
int m=0; // Минуты
int h=0; // Часы

interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
    s++;  // Инкрементируем s
    if(p==1) p=0; else p=1;
}

void main(void)
{   
    PORTC=0x00;
    DDRC=0x20;

    PORTD=0x00;
    DDRD=0x19;
       
    TIMSK &=~(1<<7 | 1<< 6);                    // Запрещаем прерывания таймера 2
    ASSR  = 1<<3;                               // Включаем асинхронный режим
    TCNT2 = 0;                 
    TCCR2 = 5;                                  // Предделитель на 128 на 32768 даст 256 тиков в секунду
    OCR2  = 0;                 
    while (ASSR & (1 << 2 | 1 << 1 | 1 << 0));  // Сбрасываем флаги прерываний
        TIMSK |= 1 << 6;                        // Разрешаем прерывание по переполнению     
                                                           
    #asm("sei");
       
    while (1)
    {
        // Условия времени
        if (s==60)
        {
            s=0;
            m++;
        }
        if (m==60)
        {
            m=0;
            h++;
        }
        if (h==24)
        {
            h=0;
        }
        t=m*100+s;  // Преобразовываем время в формат ММ.СС
        print(t);   // Выводим время на 7-сегментный индикатор
    }
}

Файл print.c
Спойлер

Код: Выделить всё

int h1,h2,m1,m2;
bit p;

void off()
{
    // Делаем задержку перед тем как всё отключить и перейти к следующему разряду
    delay_us(250);
    // Гасим всё
    DDRD.1=0; // A
    DDRD.5=0; // B
    DDRC.1=0; // C
    DDRC.3=0; // D
    DDRC.4=0; // E
    DDRD.2=0; // F
    DDRC.0=0; // G
    DDRC.2=0; // .         
    PORTD.0=0; // 1
    PORTD.3=0; // 2
    PORTD.4=0; // 3
    PORTC.5=0; // 4
}

void prs(int a)
{
    // Определяем параметры портов для выведения цифр
    switch (a)
    {
        case 0:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRC.4=1; // E
            DDRD.2=1; // F
            break;
        case 1:
            DDRD.5=1; // B
            DDRC.1=1; // C
            break;
        case 2:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.3=1; // D
            DDRC.4=1; // E
            DDRC.0=1; // G
            break;
        case 3:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRC.0=1; // G
            break;
        case 4:
            DDRD.5=1; // B
            DDRC.1=1; // C
            DDRD.2=1; // F
            DDRC.0=1; // G
            break;
        case 5:
            DDRD.1=1; // A
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRD.2=1; // F
            DDRC.0=1; // G
            break;
        case 6:
            DDRD.1=1; // A
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRC.4=1; // E
            DDRD.2=1; // F
            DDRC.0=1; // G
            break;
        case 7:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.1=1; // C
            break;
        case 8:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRC.4=1; // E
            DDRD.2=1; // F
            DDRC.0=1; // G
            break;
        case 9:
            DDRD.1=1; // A
            DDRD.5=1; // B
            DDRC.1=1; // C
            DDRC.3=1; // D
            DDRD.2=1; // F
            DDRC.0=1; // G
            break;     
    }
}

void divider(int a)
{   
    //Разлаживаем число
    if (a<10)
    {
        h1=0;
        h2=0;
        m1=0;
        m2=a;
    }
    else if (a<100)
    {
        h1=0;
        h2=0;
        m1=a/10;
        m2=a%10;
    }
    else if (a<1000)
    {
        h1=0;                           
        h2=a/100;
        m1=(a%100)/10;
        m2=(a%100)%10;
    }
    else if (a<10000)
    {
        h1=a/1000;         
        h2=(a%1000)/100;
        m1=((a%1000)%100)/10;
        m2=((a%1000)%100)%10;
    }   
    else
    {
        h1=0;
        h2=0;
        m1=0;
        m2=0;
    }
}

void print(int a)
{
    divider(a); // Разложим число
    PORTD.0=1; // 1 разряд
    prs(h1);
    off();
    PORTD.3=1; // 2 разряд
    prs(h2);
    if (p==1) DDRC.2=1; else DDRC.2=0; // 1 раз в секунду зажигаем/гасим точку
    off();
    PORTD.4=1; // 3 разряд
    prs(m1);
    off();
    PORTC.5=1; // 4 разряд
    prs(m2);                                   
    off();
}

Из фьюзов выставлял только:
Изображение
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Dreenpeace писал(а):Может это из за использование delay_us(250); ?

Навряд ли. На этот раз вроде все внешне правильно. 3 секунды в минуту это ни в какие ворота конечно :(
Кварц попробовать поменять. И да, конденсаторы у вас при кварце в наличии?
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

metan писал(а):Кварц попробовать поменять.

Сейчас поменяю, зная себя я специально прикупил 2 штуки :))
metan писал(а):конденсаторы у вас при кварце в наличии?

Нету, я когда только планировал делать часы где-то читал что конденсаторы к часовому кварцу не нужны...
Сейчас попробую с кондёрами, но тут 3 вопроса: конденсаторы по 22пика пойдут? корпус кварца всё равно заземлять? если заземлять, то можно ли к нему припаять проводок, или не стоит его греть?
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Спасибо вам огромное! часы стали идти правильно после того как я повесил на ноги кварца конденсаторы по 22 пика, менять сам кварц не пришлось :)
За 15 минут время не сбилось ни на секунду, надеюсь и дальше не собьётся :)
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Dreenpeace писал(а):корпус кварца всё равно заземлять? если заземлять, то можно ли к нему припаять проводок, или не стоит его греть?

Я рекомендую всегда заземлять. Я просто притягиваю его к плате кусочком неизолированного провода, припаяв этот провод к плате как вывод обычного элемента. И требования к разводке платы под кварц / конденсаторы тоже желательно соблюсти (не допускать прохождения тока через дорожку, к которой припаяны конденсаторы, минимальная длина и т.д.).
Dreenpeace писал(а):За 15 минут время не сбилось ни на секунду, надеюсь и дальше не собьётся

Прекрасно!
Удачи.
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Доброго времени суток.
Чтобы не открывать новую тему и не засорять форум спрошу здесь.
Когда работа часов была налажена и отработаны все режимы (ММ.СС, ЧЧ.ММ, ДД.ММ, ГГГГ) пришло время настраивать часы не через константы прошивая их в нужный момент, а кнопками управления на самих часах, тут то я и столкнулся с новыми проблемами...
В общем для проверки нажатия кнопки пробовал использовать ф-цию:

Код: Выделить всё

    while((PINC & (1<<PINC4)) == 0)
    {
        hour++;
        delay_ms(100);
    }

Но после прошивки часы стали мерцать и самостоятельно прибавлять часы не реагируя на нажатие кнопки :(
Я пробовал проверить работоспособность кнопки следующим образом:

Код: Выделить всё

    while (1)
    {
        time();
        //buttons();
        while(PINC.4){}
        if (mode==0) print(hour*100+min);
        ...

Как и должно выть при старте индикатор не горит, но когда я дотрагиваюсь до кнопки (не нажимаю а дотрагиваюсь) индикатор вновь начинает мерцать и загорается полностью при удерживание кнопки (как и планировалось)
Грешить на плату (плохой контакт, что-то там с дорожками и т.п.) не приходится т.к. это уже вторая плата и на обоих тоже самое :(
Подскажите в чём может быть проблема?
metan
Вымогатель припоя
Сообщения: 593
Зарегистрирован: Ср янв 06, 2010 10:01:46

Re: Помогите сделать часы

Сообщение metan »

Dreenpeace писал(а):Подскажите в чём может быть проблема?

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

Код: Выделить всё

     if ((PIND & 1<<0) == 0 && button_pressed1 == 0)                     //Если нажата кнопка 1
      { 
        hours++;
        button_pressed1 = 1;
      } else button_pressed1=0;                          //Если отпущена то сбрасываем флаг
     
     
      if ((PIND & 1<<1) == 0 && button_pressed2 == 0)                     //Если нажата  кнопка 2
      {
        minutes++;
        button_pressed2 = 1;
      } else button_pressed2=0;                          //Если отпущена то сбрасываем флаг

всякие задержки для антидребезга скорее всего не понадобятся, пока у вас индикация будет крутиться в главном цикле
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

metan писал(а):Скорее всего, не подтянули вход резистором, внутренним или внешним.


А как его подтянуть внутренним резистором?
Аватара пользователя
eess9
Вымогатель припоя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Re: Помогите сделать часы

Сообщение eess9 »

Код: Выделить всё

DDRD = 0x00;
PORTD = 0xFF;


В этом куске весь порт D настроен на вход (DDRD в 0) и включены подтягивающие резисторы (PORTD в 1). Остальное за вами...
Dreenpeace
Первый раз сказал Мяу!
Сообщения: 28
Зарегистрирован: Вт июл 23, 2013 20:22:43

Re: Помогите сделать часы

Сообщение Dreenpeace »

Благодарствую :)
Все проблемы решены. Часы на полочке тикают себе спокойненько :)
Ответить

Вернуться в «AVR»