Таймер на 328p

Тема в разделе "Микроконтроллеры AVR", создана пользователем Danil_2002, 1 май 2019.

  1. Danil_2002

    Danil_2002 Нерд

    Знаю, тема уже избитая, но все таки. Написал небольшую программку, которая должна выводить через usart символ '1' каждую секунд, но выводит за 10 секунд всего 6 единиц.

    Вот код:
    Код (C++):
    #include<avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    volatile unsigned long a = 0;

    ISR(TIMER1_COMPA_vect)
    {
      a++;
    }

    void USART_init(void) // Настраеваем скорость передачи данных
    {
      unsigned int bd = (16000000UL / (16UL * 38400UL) - 1);
      UBRR0L = 103;
      UBRR0H = 0;
      UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);
      UCSR0C = (1<<USBS0)|(3<<UCSZ00);
    }
    void USART_TransmitByte( unsigned char data )
    {
      while ( !( UCSR0A & (1<<UDRE0)) );
      UDR0 = data;
    }
    void T1_init()
    {
      TCCR1A = 2; // CTC
      //TCCR1B |= (1<<CS02)|(1<<CS00); // MK/1024
      TCCR1B |= (1<<CS01)|(1<<CS00); // MK/64
      TCNT1 = 0; // счетный регистр
      OCR1A = 250; // 1 милисекунда
      TIMSK1 |= (1 << OCIE1A); // Разрешаем прерывание по событию совпадение
    }
    int main()
    {
      sei();
      USART_init();
      USART_TransmitByte('J');
      T1_init();
      while(1)
      {
        if(a == 1000)
        {
          USART_TransmitByte('1');
          a = 0;
        }
      }
    }
    Частота МК 16 000 000;
    Делитель 64 => что одна секунда это 250 000 => что одна милисекунда это 250.
    Что я сделал не так?
     
  2. Asper Daffy

    Asper Daffy Гуру

    Ну, понимаешь, МК-то он глупый, он читает то, что ты в коде пишешь, а не в комментариях. А ты пишешь там разные вещи.

    Вот, смотри, я прокомментировал твою инициализацию таймера

    Код (C++):
    /*
    По поводу использования |= с регистрами. Так делают когда
    надо сохранить остальные биты "как были". В данном случае
    ты уверен, что "как были" тебя устраивает?
    Думаю, нет, лучше использовать просто присваивание
    */

    void T1_init()
    {
      TCCR1A = 2; // CTC /* НА САМОМ ДЕЛЕ  PWM, Phase Correct, 9-bit  */
      //TCCR1B |= (1<<CS02)|(1<<CS00); // MK/1024
      TCCR1B |= (1<<CS01)|(1<<CS00); // MK/64 /* здесь делают CS от другого таймера ? */
      TCNT1 = 0; // счетный регистр
      OCR1A = 250; // 1 милисекунда  /* а чего сразу на секунду не настроить ???? */
      TIMSK1 |= (1 << OCIE1A); // Разрешаем прерывание по событию совпадение
    }
     
    Самое критичное, конечно, в первой строке функции (про TCCR1A). С такой настройкой таймера прерывание происходит вдвое реже :(

    Если нормально настроить таймер, то все тикает как надо

    Код (C++):
    void T1_init(void) {
      TCCR1A = 0; // CTC
      TCCR1B = (1<<CS11) | (1<<CS10) | (1<<WGM12); // MK/64 + CTC
      TCNT1 = 0; // счетный регистр
      OCR1A = 250; // 1 милисекунда  /* а чего сразу на секунду не настроить ???? */
      TIMSK1 = (1 << OCIE1A); // Разрешаем прерывание по событию совпадение
    }
     

    Настройку USART не проверял, но там тоже что-то кривовато. например, хитрая переменная bd вычисляется, а потом нигде ни разу не используется.
     
    DetSimen нравится это.
  3. parovoZZ

    parovoZZ Гуру

    5 баллов. Давай зачетку!
     
    BAR__MEN нравится это.
  4. parovoZZ

    parovoZZ Гуру

    конкретно здесь - пох вообще. Я тоже так делаю))) Места у битов совпадают)))
     
  5. Asper Daffy

    Asper Daffy Гуру

    Как раз пох, что совпадают. Это говорит об аккуратности (вернее, неаккуратности) кода.
     
  6. Danil_2002

    Danil_2002 Нерд

    Почему TCCR1A = 0?
    За настройку таймера отвечают два регистра TCCR1A, TCCR1B
    биты WGM10, 11 (TCCR1A) и WGM12,13 отвечают за выбор режима таймера
    СТС это 0100 => TCCR1A = 2. Нет?
     
  7. parovoZZ

    parovoZZ Гуру

    Лучше писать через определения битов.

    Глянул даташит - режима CTC у этого МК два и в обоих режимах оба младших бита равны нулю. Откуда 2?
     
    Последнее редактирование: 10 май 2019
    DetSimen нравится это.
  8. Asper Daffy

    Asper Daffy Гуру

    Конечно, нет! СТС (OCR1A) это когда все WGM1x нули, кроме WGM12. А WGM12 в каком регистре? В TCCR1B! Вот и получается, что TCCR1A у нас 0, а WGM12 взводится в TCCR1B