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();
}
}
Кто-нибудь знает, откуда это взялось?!?!
@Em Ka, 👍0
Обсуждение2 ответа
Вот код:
этот код может быть значительно улучшен:
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
Хорошо, я устранил проблему. Существует какая-то проблема с генерацией шим-оборудования с помощью таймеров на 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
- ATtiny85 AC Phase Control для регулировки яркости лампочки
- Прерывать каждую секунду на ATTiny84 (и спать все остальное)
- Как указать имя таймера в зависимости от чипа, в который он будет компилироваться?
- Использование millis() и micros() внутри процедуры прерывания
- Arduino непрерывно считывает значение АЦП с помощью прерывания
- Использование TIMER0_COMPB_vect
- PCINT0, PCINT1, PCINT2 и т. д. на ATtiny45/85
- Как назначить прерывание на нажатие кнопки с помощью ATtiny? (прерывание не срабатывает с моим кодом)
Я протестировал вашу программу, и она работает так, как ожидалось: примерно 70 мс до каждых 100 мс. Какое ядро вы используете?, @Edgar Bonet