Страница 1 из 1
Помогите сделать часы
Добавлено: Вт июл 23, 2013 20:39:16
Dreenpeace
Доброго времени суток, уважаемые Коты!
Очень прошу вас помочь мне в написание кода часов для Atmega8 на языке C (CVAVR), мне не нужны часы с термометрами и прочей приблудой, мне нужны обыкновенные часы. Более того мне нужна помощь в написание только той части кода, которая отвечает за отсчёт секунд, проще говоря код, который каждую секунду будет инкрементировать переменную "s". Выводить время, настраивать его с помощью кнопок и всё прочее необходимое я уже умею и сделаю сам, просто я не умею работать с таймерами и посмотрев множество примеров так и не понял ничего. Имеется часовой кварц
Извиняюсь если тема уже существует.
Заранее всем спасибо за ответы, очень на вас надеюсь.
Re: Помогите сделать часы
Добавлено: Ср июл 24, 2013 09:12:51
metan
Re: Помогите сделать часы
Добавлено: Ср июл 24, 2013 09:18:58
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");
}
}
Re: Помогите сделать часы
Добавлено: Ср июл 24, 2013 14:45:56
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кГц
Re: Помогите сделать часы
Добавлено: Ср июл 24, 2013 16:09:00
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
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 02:21:36
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 то отстают сильнее то вовсе спешат. Никак не могу понять вообще что к чему

Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 08:16:33
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 тиков в секунду
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 13:44:26
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-сегментный индикатор
}
}
Скажите пожалуйста что я сделал не так?
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 14:23:32
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-сегментный индикатор
}
}
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 16:24:51
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();
}
Из фьюзов выставлял только:

Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 16:52:16
metan
Dreenpeace писал(а):Может это из за использование delay_us(250); ?
Навряд ли. На этот раз вроде все внешне правильно. 3 секунды в минуту это ни в какие ворота конечно

Кварц попробовать поменять. И да, конденсаторы у вас при кварце в наличии?
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 17:04:29
Dreenpeace
metan писал(а):Кварц попробовать поменять.
Сейчас поменяю, зная себя я специально прикупил 2 штуки
metan писал(а):конденсаторы у вас при кварце в наличии?
Нету, я когда только планировал делать часы где-то читал что конденсаторы к часовому кварцу не нужны...
Сейчас попробую с кондёрами, но тут 3 вопроса: конденсаторы по 22пика пойдут? корпус кварца всё равно заземлять? если заземлять, то можно ли к нему припаять проводок, или не стоит его греть?
Re: Помогите сделать часы
Добавлено: Чт июл 25, 2013 17:30:18
Dreenpeace
Спасибо вам огромное! часы стали идти правильно после того как я повесил на ноги кварца конденсаторы по 22 пика, менять сам кварц не пришлось
За 15 минут время не сбилось ни на секунду, надеюсь и дальше не собьётся

Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 09:17:15
metan
Dreenpeace писал(а):корпус кварца всё равно заземлять? если заземлять, то можно ли к нему припаять проводок, или не стоит его греть?
Я рекомендую всегда заземлять. Я просто притягиваю его к плате кусочком неизолированного провода, припаяв этот провод к плате как вывод обычного элемента. И требования к разводке платы под кварц / конденсаторы тоже желательно соблюсти (не допускать прохождения тока через дорожку, к которой припаяны конденсаторы, минимальная длина и т.д.).
Dreenpeace писал(а):За 15 минут время не сбилось ни на секунду, надеюсь и дальше не собьётся
Прекрасно!
Удачи.
Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 10:26:21
Dreenpeace
Доброго времени суток.
Чтобы не открывать новую тему и не засорять форум спрошу здесь.
Когда работа часов была налажена и отработаны все режимы (ММ.СС, ЧЧ.ММ, ДД.ММ, ГГГГ) пришло время настраивать часы не через константы прошивая их в нужный момент, а кнопками управления на самих часах, тут то я и столкнулся с новыми проблемами...
В общем для проверки нажатия кнопки пробовал использовать ф-цию:
Код: Выделить всё
while((PINC & (1<<PINC4)) == 0)
{
hour++;
delay_ms(100);
}
Но после прошивки часы стали мерцать и самостоятельно прибавлять часы не реагируя на нажатие кнопки
Я пробовал проверить работоспособность кнопки следующим образом:
Код: Выделить всё
while (1)
{
time();
//buttons();
while(PINC.4){}
if (mode==0) print(hour*100+min);
...
Как и должно выть при старте индикатор не горит, но когда я дотрагиваюсь до кнопки (не нажимаю а дотрагиваюсь) индикатор вновь начинает мерцать и загорается полностью при удерживание кнопки (как и планировалось)
Грешить на плату (плохой контакт, что-то там с дорожками и т.п.) не приходится т.к. это уже вторая плата и на обоих тоже самое
Подскажите в чём может быть проблема?
Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 11:22:51
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; //Если отпущена то сбрасываем флаг
всякие задержки для антидребезга скорее всего не понадобятся, пока у вас индикация будет крутиться в главном цикле
Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 16:12:27
Dreenpeace
metan писал(а):Скорее всего, не подтянули вход резистором, внутренним или внешним.
А как его подтянуть внутренним резистором?
Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 18:06:11
eess9
В этом куске весь порт D настроен на вход (DDRD в 0) и включены подтягивающие резисторы (PORTD в 1). Остальное за вами...
Re: Помогите сделать часы
Добавлено: Пт июл 26, 2013 20:00:49
Dreenpeace
Благодарствую
Все проблемы решены. Часы на полочке тикают себе спокойненько
