Attiny85 Таймер 1 компаратор B не работает должным образом (в то время как A работает)

Я пишу простую программу, которая использует таймер 1 компаратор B для генерации прямоугольной волны на DEBUG_PIN.

Поэтому мой код сначала включает таймер 1 с прескалером 8192, так что один тик составляет примерно 1 мс. Затем , когда таймер достигает 100 я выключаю все таймеры, чем включить timer1 CompB и диск DEBUG_PIN high. Когда происходит прерывание timer1B, то оно приводит DEBUG_PIN к низкому значению и отключает прерывания TIMER1B.

Проблема в том, что всякий раз, когда я запускаю код, состояние DEBUG_PIN всегда высокое. Вот странная вещь: когда я меняю компаратор с B на A на том же таймере, все работает нормально! Вот код:

#include "avr/interrupt.h"

#define DEBUG_PIN 4

volatile bool flag = false;
volatile int counter = 0;

ISR (TIMER1_COMPB_vect){
  digitalWrite( DEBUG_PIN, LOW );
  bitClear(TIMSK, OCIE1B);
}

void setup() {
  cli();

  pinMode( DEBUG_PIN, OUTPUT );

  digitalWrite( DEBUG_PIN, HIGH );
  //stop TIMER1
  TCCR1 = 0;
  //prescaler is 8192 sot that 1 tick is 1ms, enable timer1
  TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);
  sei();
}

void loop() {

    if( TCNT1 >=100 ){
      cli();
      counter = 0;
      //disable compB
      bitClear(TIMSK, OCIE1B);

      digitalWrite( DEBUG_PIN, HIGH );

      /* enable compB */
      //set comparatorB value
      OCR1B = 70;
      //enable compA interrupts
      bitSet(TIMSK, OCIE1B);

      TCCR1 = 0 ;

      TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);

      TCNT1 = 0;

      //сброс флага прерывания OCF1A на всякий случай
      bitSet(TIFR,OCF1B);
      sei();
    }
}

Кто-нибудь знает, откуда это взялось?!?!

, 👍0

Обсуждение

Я протестировал вашу программу, и она работает так, как ожидалось: примерно 70 мс до каждых 100 мс. Какое ядро вы используете?, @Edgar Bonet


2 ответа


-1

Вот код:

этот код может быть значительно улучшен:

1) разбейте свою задачу на логические блоки;

2) закодируйте каждый блок в соответствии с таблицей данных с комментариями;

3) расскажите своим читателям, для чего вы предназначали свой код и что он делал.

4) прочитайте таблицу данных.

редактировать: ваш код, следуя описанным выше шагам, настроенный на переворачивание PB4 при OCR1B = 70, при частоте 85 @ 8 МИПС, привел к следующему.

вы близки, так что продолжайте работать над этим.

правка 2: после настройки код довольно прост.

ISR (TIMER1_COMPB_vect){
  //bitClear(TIMSK, OCIE1B);
    //обновите следующую точку совпадения для таймера 1, сн b
    OCR1B +=(IO_GET(DEBUG_PORT, 1<<DEBUG_PIN))?(DEBUG_PR - DEBUG_DC):DEBUG_DC;
    IO_FLP(DEBUG_PORT, 1<<DEBUG_PIN);   //flip the output pin
}

void loop() {

}

приведенный выше код генерирует последовательность импульсов с рабочим циклом DEBUG_DC / DEBUG_PR. В цикле ничего нет (), поэтому он полностью прозрачен для пользователя.

,

1) Я думаю, что эта программа довольно прямолинейна, поэтому ее не нужно больше разбивать, @Em Ka

3) Итак, мой код сначала включает таймер 1 с прескалером 8192, так что один тик составляет примерно 1 мс. Затем , когда таймер достигает 100, я отключаю все таймеры, затем включаю timer1 CompB и устанавливаю DEBUG_PIN на высокий уровень. Когда происходит прерывание timer1B, оно снижает значение DEBUG_PIN и отключает прерывания TIMER1B., @Em Ka

4) Я очень внимательно прочитал техническое описание, @Em Ka

Вы пытались запустить программу на физическом аттине, а не в симуляции?, @Em Ka


0

Хорошо, я устранил проблему. Существует какая-то проблема с генерацией шим-оборудования с помощью таймеров на ATTINY85. Хотя я им не пользуюсь, я попытался сбросить весь регистр GTTCR перед включением прерывания COMPB, и это сработало! Вот рабочий код:

#include "avr/interrupt.h"

#define DEBUG_PIN 4

volatile bool flag = false;
volatile int counter = 0;

ISR (TIMER1_COMPB_vect){
  digitalWrite( DEBUG_PIN, LOW );
//  flag = false;
//  TCNT1 = 0;
  bitClear(TIMSK, OCIE1B);
}

void setup() {
  cli();

  // put your setup code here, to run once:


  pinMode( DEBUG_PIN, OUTPUT );

  digitalWrite( DEBUG_PIN, HIGH );
  TCCR1 = 0;
  TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);
  sei();
}

void loop() {

    if( TCNT1 >=100 ){
      cli();
      counter = 0;
      //disable compB
      bitClear(TIMSK, OCIE1B);

      digitalWrite( DEBUG_PIN, HIGH );

      /* enable compB */
      //set comparatorB value
      OCR1B = 70;
      //enable compA interrupts
      bitSet(TIMSK, OCIE1B);

      TCCR1 = 0 ;

      GTCCR = 0;

      TCCR1 |= (1<<CS13)|(1<<CS12)|(1<<CS11)|(0<<CS10);

      TCNT1 = 0;

      //reset OCF1A interrupt flag, just in case
      bitSet(TIFR,OCF1B);
      sei();
    }
}

Забавно, что вам не нужно этого делать, если вы используете COMPA. Не знаю, почему, хотя...

ПРАВИТЬ: Я попытался очистить биты GTCCR один за другим, и оказалось, что бит, вызывавший проблемы, был битом PWM1B. Таким образом, вместо GTCCR = 0 Я использую bitClear(GTCCR, PWM1B); и все работает нормально:)

Похоже, PWM1B включен по умолчанию, не знаю, почему...

,

Какое ядро вы используете?, @Edgar Bonet