Обсуждаем контроллеры компании Atmel.
Ответить

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 10:26:00

Вот весь код:
Спойлер
Код:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char bin[64] = {

0b00000000,
0b00100000,
0b00010000,
0b00110000,
0b00001000,
0b00101000,
0b00011000,
0b00111000,
0b00000100,
0b00100100,
0b00010100,
0b00110100,
0b00001100,
0b00101100,
0b00011100,
0b00111100,
0b00000010,
0b00100010,
0b00010010,
0b00110010,
0b00001010,
0b00101010,
0b00011010,
0b00111010,
0b00000110,
0b00100110,
0b00010110,
0b00110110,
0b00001110,
0b00101110,
0b00011110,
0b00111110,
0b00000001,
0b00100001,
0b00010001,
0b00110001,
0b00001001,
0b00101001,
0b00011001,
0b00111001,
0b00000101,
0b00100101,
0b00010101,
0b00110101,
0b00001101,
0b00101101,
0b00011101,
0b00111101,
0b00000011,
0b00100011,
0b00010011,
0b00110011,
0b00001011,
0b00101011,
0b00011011,
0b00111011,
0b00000111,
0b00100111,
0b00010111,
0b00110111,
0b00001111,
0b00101111,
0b00011111,
0b00111111,
};




//переменные
unsigned char hour, min, sec;

ISR(TIMER2_COMP_vect){
sec++;
if (sec > 59) { min ++; sec = 0;};
if (min > 59) { hour ++; min = 0;};
if (hour > 23) {hour = 0;};
}



void ShowTime(char h, char m, char s){
PORTB = bin[h];
PORTD |= (1 <<PD5);
_delay_ms(1);
PORTD &= ~(1 <<PD5);
PORTB = bin[m];
PORTD |= (1 <<PD6);
_delay_ms(1);
PORTD &= ~(1 <<PD6);
PORTB = bin[s];
PORTD |= (1 <<PD7);
_delay_ms(1);
PORTD &= ~(1 <<PD7);
}


int main(void) {
//SetUp
DDRB = 0b11111111;
DDRD = 0b11100000;
DDRC|= (0 << PC2)|(0<<PC3);
PORTC |= (1 << PC2)|(1<<PC3);

 asm ("cli");
ASSR |= (1 << AS2);
  while (ASSR != (0b00001000))
 {
 asm ("nop");
 }
TCCR2 |= (1<<CS20) | (1<<CS22) | (1<<WGM21);
OCR2 = 255;
TIMSK |= (1<<OCIE2);
TIFR = 0;
 asm ("sei"); 

while(1){


if((PINC & (1<<PC2)) == 0){
_delay_ms(50);
while((PINC & (1<<PC2)) == 0){}
min++;
if (min > 59) min = 0;
}

if((PINC & (1<<PC3)) == 0){
_delay_ms(50);
while((PINC & (1<<PC3)) == 0){}
hour++;
if (hour > 23) hour = 0;
}

ShowTime(hour, min, sec);
}
return 0;
}


Я уменьшил убегание (проблема была в минутах, последняя минута сбрасывалась в 0 за одно прерывания)
было так:
Код:
ISR(TIMER2_COMP_vect){
if (sec++ >= 59) { min ++; sec = 0;};
if (min >= 59) { hour ++; min = 0;};
if (hour >= 23) {hour = 0;};
}


Теперь они спешат на 20 секунд в час, все еще много, но лучше чем на 1,5 минуты.
При этом запускал параллельно с секундомером на ноутбуке, и заметно что одна секунда на часах отображается немного быстрее чем нужно.

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 11:26:47

Я думаю, нужно переделать на прерывание по переполнению, и всё наладится
У меня в CodeVision вот так

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

while(ASSR & (1<<TCN2UB | 1<<OCR2UB | TCR2UB));

TIFR  |= 1<<OCF2 | 1<< TOV2;      // Сбрасываем флаги прерываний, на всякий случай.


// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK |= 1<< TOIE2 | 1<<TOIE0;   


////////////////////////

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

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 12:43:13

Я изначально и пытался делать по переполнению (посмотри самый первый код в шапке)

Добавлено after 8 minutes 18 seconds:
Еще вопрос, в прерывания по переполнение, в какой тик происходит прерывание? В 256 или 257?

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 12:53:36

Jack-Sidr писал(а):в какой тик происходит прерывание? В 256 или 257?
при переходе из 255 в 0

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 16:04:01

Тогда какая разница в прерывания по совпадению с 255 и прерыванию по переполнению?

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 16:35:17

Jack-Sidr писал(а):какая разница в прерывания?

1

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 16:59:18

На тик дольше или меньше?

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 20:57:51

меньше

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 21:29:18

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

Re: Помогите с асинхронным таймером на AtMega8a

Пн фев 19, 2018 21:48:24

Спойлер
Код:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char bin[64] = {

0b00000000,
0b00100000,
0b00010000,
0b00110000,
0b00001000,
0b00101000,
0b00011000,
0b00111000,
0b00000100,
0b00100100,
0b00010100,
0b00110100,
0b00001100,
0b00101100,
0b00011100,
0b00111100,
0b00000010,
0b00100010,
0b00010010,
0b00110010,
0b00001010,
0b00101010,
0b00011010,
0b00111010,
0b00000110,
0b00100110,
0b00010110,
0b00110110,
0b00001110,
0b00101110,
0b00011110,
0b00111110,
0b00000001,
0b00100001,
0b00010001,
0b00110001,
0b00001001,
0b00101001,
0b00011001,
0b00111001,
0b00000101,
0b00100101,
0b00010101,
0b00110101,
0b00001101,
0b00101101,
0b00011101,
0b00111101,
0b00000011,
0b00100011,
0b00010011,
0b00110011,
0b00001011,
0b00101011,
0b00011011,
0b00111011,
0b00000111,
0b00100111,
0b00010111,
0b00110111,
0b00001111,
0b00101111,
0b00011111,
0b00111111,
};




//переменные
unsigned char hour, min, sec;

ISR(TIMER2_COMP_vect)
{
    sec++;
    if (sec == 60)
      {
          sec = 0;
          min ++;
      };

    if (min == 60)
      {
          min = 0;
          hour ++;
      };
    if (hour > 23)
      {
         hour = 0;
      };
}

void ShowTime(char h, char m, char s){   // Не очень понятно как работает эта функция. Можно подробней её описать?
PORTB = bin[h];
PORTD |= (1 <<PD5);
_delay_ms(1);
PORTD &= ~(1 <<PD5);
PORTB = bin[m];
PORTD |= (1 <<PD6);
_delay_ms(1);
PORTD &= ~(1 <<PD6);
PORTB = bin[s];
PORTD |= (1 <<PD7);
_delay_ms(1);
PORTD &= ~(1 <<PD7);
}


int main(void) {
//SetUp
DDRB = 0b11111111;
DDRD = 0b11100000;
DDRC|= (0 << PC2)|(0<<PC3);
PORTC |= (1 << PC2)|(1<<PC3);

 asm ("cli");

                                                           // 
ASSR |= (1 << AS2);                   // Разрешаем тактирование  таймера Т2 от кварца 32768 (асинхронный режим)
  while (ASSR != (0b00001000))    // Ожидаем разрешения записи 
 {
     asm ("nop");
 }
TCCR2 |= (1<<CS21) | (1<<CS22) | (1<<WGM21);    //  Тактирование: 32768 делим на предделитель (256) = 128. Сброс по совпадению.
OCR2 = 127;                                                            //  В регистр сравнения заносим 127! При совпадении, таймер перейдёт в вектор
                                                                               //  прерывания на следующем такте, итого = 128. 
TIMSK |= (1<<OCIE2);                                             //  Разрешаем прерывание по совпадению T2
TIFR = 0;                                                                 //  Сброс флагов.

 asm ("sei"); 

while(1){


if((PINC & (1<<PC2)) == 0){                                    //  Кнопки
_delay_ms(50);
while((PINC & (1<<PC2)) == 0){}
min++;
if (min > 59) min = 0;
}

if((PINC & (1<<PC3)) == 0){                                   //  Кнопки
_delay_ms(50);
while((PINC & (1<<PC3)) == 0){}
hour++;
if (hour > 23) hour = 0;
}

ShowTime(hour, min, sec);
}
return 0;
}

Код немного причесал, но есть ещё вопросы- в частности: весь проект выложить можно?- и интересует выставление фьюзов контролёра.

Re: Помогите с асинхронным таймером на AtMega8a

Вт фев 20, 2018 06:56:38

Может, я и не логичен, конечно. Но я ответил на вопрос
Jack-Sidr писал(а):какая разница в прерывания по совпадению с 255 и прерыванию по переполнению?

Разумеется имея в виду первую часть фразы "по совпадению с 255"
Дальше думайте сами. Тем более что я вам дал 100% рабочий код.

Re: Помогите с асинхронным таймером на AtMega8a

Вт фев 20, 2018 07:22:57

-Valerius- писал(а):Код немного причесал, но есть ещё вопросы
вот-вот, вопросы есть. например, вот это вот что такое и зачем?
-Valerius- писал(а):unsigned char bin[64] = {
0b00000000,
0b00100000,
0b00010000,
0b00110000,

Re: Помогите с асинхронным таймером на AtMega8a

Вт фев 20, 2018 07:57:12

1.Фьюзы я не менял, только внутрение конденсаторы отключил.
2. Пробовал я по совпадению с 127, но так как часы спешили, решил попробовать с 128, ведь это по идее должно замедлить ход.
3.
Код:
void ShowTime(char h, char m, char s){   // функция динамической индикации
PORTB = bin[h]; //выводы PB0-5 подключены к светодиодами, выставляем часы двоичным кодом.
PORTD |= (1 <<PD5);  //открываем n-p-n транзистор столбика с часами
_delay_ms(1); //без задержки транзистор не успевает полностью закрыться, и светятся все столбики
PORTD &= ~(1 <<PD5); //закрываем транзистор часов
PORTB = bin[m];  // выставляем минуты
PORTD |= (1 <<PD6); // открываем транзистор минут
_delay_ms(1);
PORTD &= ~(1 <<PD6); // закрываем
PORTB = bin[s]; //секунды
PORTD |= (1 <<PD7);
_delay_ms(1);
PORTD &= ~(1 <<PD7);
}


4. Почему именно предделитель на 256 и сравнение с 127, а не предделитель на 128 и сравнение с 255, разве во втором случае не точнее будет?
Последний раз редактировалось Jack-Sidr Вт фев 20, 2018 08:01:50, всего редактировалось 1 раз.

Re: Помогите с асинхронным таймером на AtMega8a

Вт фев 20, 2018 07:58:45

В идеальных условиях, если по совпадению
Код:
OCR2=0x7E; 1 секунда

OCR2=0x80; 1,0078 секунды

OCR2=0x7E; 0,99219 секунды
В последних двух видим что за 3600 секунд +-28секунд набегает.

Я делал так (кварц китайский, по всей видимости не на 32768)
Спойлер
Код:
// Timer/Counter 2 initialization
// Clock source: Crystal on TOSC1 pin
// Clock value: PCK2/128
// Mode: Normal top=0xFF
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=(0<<EXCLK) | (1<<AS2);
TCCR2A=(0<<COM2A1) | (0<<COM2A0) | (0<<COM2B1) | (0<<COM2B0) | (0<<WGM21) | (0<<WGM20);
TCCR2B=(0<<WGM22) | (1<<CS22) | (0<<CS21) | (1<<CS20);
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;


interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
// Place your code here
TCNT2 = 128;
   if(++t_milli ==2)
   {t_milli=0;
   if (++t_second==60)
   {
      t_second=0;
      if (++t_minute==60)
      {
       TCNT2--; // здесь вношу корректировку
       t_minute=0;
       if (++t_hour==24)
       {
        t_hour=0;
       }
      }
   }
   }
}
В результате за 72 часа убежали на 0,5-1 секунды.

Re: Помогите с асинхронным таймером на AtMega8a

Вт фев 20, 2018 12:44:13

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

Добавлено after 4 hours 35 minutes 33 seconds:
-Valerius- писал(а):Код немного причесал, но есть ещё вопросы
вот-вот, вопросы есть. например, вот это вот что такое и зачем?
-Valerius- писал(а):unsigned char bin[64] = {
0b00000000,
0b00100000,
0b00010000,
0b00110000,


Часы выводят время двоичным кодом, а поскольку у меня не получилось развести выводы в правильном порядке, это по сути костыль, а вообще посмотрев в шапку, можно найти фото часов, и понять это)

Re: Помогите с асинхронным таймером на AtMega8a

Ср фев 21, 2018 07:13:08

Код немного причесал, но есть ещё вопросы- в частности: весь проект выложить можно?- и интересует выставление фьюзов контролёра.


Не знаю как, но ваше "причесевание" помогло, оставлял на ночь, и за 8,5 часов набежало лишних 30 секунд, что, безусловно шаг вперед.

Re: Помогите с асинхронным таймером на AtMega8a

Ср фев 21, 2018 09:36:57

лишних 30 секунд за 8,5 часов - это примерно 0,1%. но для часов это плохо...

Re: Помогите с асинхронным таймером на AtMega8a

Ср фев 21, 2018 09:47:49

Jack-Sidr писал(а): это по сути костыль
я подозревал, что связано с разводкой. но 64 комбинации зачем?! или у вас нетрадиционные часы? ;)

Re: Помогите с асинхронным таймером на AtMega8a

Ср фев 21, 2018 10:52:02

Именно, они отображают время не на индикаторах, а на светодиодных столбиках двоичным кодом, поэтому и нужны числа от 0 до 59 в двоичном коде. (Пожалуйста, посмотри в шапку, там есть фото собранных часов, и они никак не похожи на обычные часы)

Re: Помогите с асинхронным таймером на AtMega8a

Ср фев 21, 2018 11:06:09

Jack-Sidr писал(а):поэтому и нужны числа от 0 до 59 в двоичном коде
а 64 варианта зачем? :)))
Ответить