Arduino + ATTiny2313 компаратор

Esteriman

✩✩✩✩✩✩✩
4 Июн 2025
4
0
Приветствую форумчан!
Я новичок, поэтому сильно тапками не кидайтесь.
Подключил сабж, т.е. ATTiny 2313, шью через ардуино уно, всё шьётся замечательно. Написал скетч для дисплея 1602, работает. Есть идея сделать из аттини2313 вольтметр-амперметр для лаб. БП. Пытаюсь понять встроенный компаратор. Но не срабатывает прерывание. Использую инфу отсюда http://www.gaw.ru/html.cgi/txt/app/micros/avr/AVR400.htm
Прикладываю код (модуль для LCD не стал приводить, чтобы не загружать излишне). Подскажите, пожалуйста как правильно включить прерывания от компаратора с учетом того, что это компилятор ардуино. Да, и не предлагайте внешние АЦП и другой камень.

C++:
// ATTiny2313
// LCD 4 bit
// D4 = PB4, D5 = PB5, D6 = PB6, D7 = PB7
// E  = PD5, RS = PD6
//
// компаратор
// 12-я нога — RC-цепочка
// 13-я нога — измеряемый сигнал
// 14-я нога PB2 — выход вкл. заряда конденсатора


const byte opwait = 2; // универсальная задержка в мс
unsigned long m;

void setup () {
    lcdInit();
  lcdCursor(0, 0);
  lcdPrint('T');lcdPrint('=');
  lcdCursor(1, 0);
  lcdPrint('U');lcdPrint('=');
  ACSR = 0x0b;
  TIMSK = 0x02;
  DDRB |= 0x04; // включаем pb2 на выход
  PORTB |= 0;
  delay(50);
  sei();
}

SIGNAL (SIG_COMPARATOR) {
  m = micros - m;
  PORTB |= 0x0; // выкл зарядку конд.
  lcdCursor(0,4);
  lcdPrint('*');
  lcdCursor(1,4);
  lcdPrintNum(m);
  delay(5);
}


void loop () {
  adcStart();
  delay(500);

}

void adcStart () {
  m = micros();
  PORTB |= 0x04; // вкл зарядку конденсатора
}
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
603
178
@Esteriman,
В инете есть примеры для прерываний компаратора.
Но даташит в любом случае полезно прочитать.
Поиск по словам "Arduino ATTiny2313 ISR(ANALOG_COMP_vect)" Дает в том числе ссылку
Принцип работы похож на другие 8 битAVR, поэтому для понимания можно почитать информацию по ним (учитывая разницу между МК).
Поиск по "arduino ISR(ANALOG_COMP_vect)"

Дополнение. По моему, при работе в среде Arduino, не стоит отказываться от digitalRead и прочих функций работы с портами, пока в этом не возникнет необходимость, и должно быть понимание, что именно делает код без arduino функций.

Дополнение. Возможно вам лучше подойдет возможность "The comparator’s output can be set to trigger the Timer/Counter1 Input Capture function."
Примеры в инете тоже должны быть.

Дополнение. Даже если в своем устройстве вы планируете использовать ATTiny2313, отрабатывать алгоритмы НАМНОГО удобнее на UNO, а потом перенести алгоритм на ATTiny2313.
 
Изменено:

Esteriman

✩✩✩✩✩✩✩
4 Июн 2025
4
0
@Bruzzer, благодарю за обстоятельный ответ. Ушел в поисковик.
P. S. Не подумал о том, чтобы отработать проект на Уно, а затем перенести на 2313. Благодарю за отличный совет, попробую.
 

Esteriman

✩✩✩✩✩✩✩
4 Июн 2025
4
0
C++:
// Definition of interrupt names
#include <avr/io.h>
// ISR interrupt service routine
#include <avr/interrupt.h>
const int pAIN0 = 6; // AIN0 at Pin6
const int pAIN1 = 7; // AIN1 at Pin7
const int pCharge = 8; // линия зарядки конденсатора
boolean iflag = false;
uint32_t m = micros();
uint32_t tCharge; // время зарядки конденсатора


//
ISR(ANALOG_COMP_vect) {
  iflag = true;
  digitalWrite(pCharge, LOW); // выключить зарядку С
  noInterrupts();
}

void setup() {
  Serial.begin(9600);
  pinMode(pCharge, OUTPUT);
  digitalWrite(pCharge, HIGH); // 1-е включение
  /*
  //pinMode(pAIN0, INPUT);
  //pinMode(pAIN1, INPUT);
  cli();
  ADCSRA &= ~(1<<ADEN); // ADC disabled
  ADCSRB |= ~(1<<ACME); // AMUX enabled
  ACSR = (1<<ACBG) | (1<<ACIE); // ACOMP Interrupt enabled
  DIDR1 = (1<<AIN1D) | (1<< AIN0D);
  sei();*/

  DIDR1 |= (1<<AIN0D) | (1<<AIN1D); // Disable Digital Inputs at AIN0 and AIN1
  ADCSRB &= ~(1<<ACME);    //Clear ACME bits in ADCSRB to use external input at AIN1 -ve input
  ACSR =
  (0 << ACD) |    // Analog Comparator: Enabled
  (0 << ACBG) |   // Clear ACBG to use external input to AIN0 +ve input
  (0 << ACO) |
  (1 << ACI) |    // Clear Pending Interrupt by setting the bit
  (1 << ACIE) |   // Analog Comparator Interrupt Enabled
  (0 << ACIC) |   // Analog Comparator Input Capture Disabled
  (0 << ACIS1) | (0 << ACIS0);   // Analog Comparator Interrupt Mode
  interrupts();
}

long vMeter;
void loop() {
if (iflag) {
    digitalWrite(pCharge, LOW);
    tCharge = micros() - m;
    vMeter = map(tCharge, 92, 1292, 125, 1840);
    //vMeter = constrain( vMeter, 125, 200);
    Serial.print(tCharge);
    Serial.print(' ');
    Serial.println(float(vMeter)/100);
    delay(500);
    iflag = false;
    m = micros();
    digitalWrite(pCharge, HIGH); // вкл зарядку конденсатора
    interrupts();
  }

}
В данный момент пришел к этому. Конденсатор 0,1мкф, резистор 33КОм. Подключал через делитель 1/10 100КОм и 10КОм. Есть некоторая нелинейность и показания слегка «плавают».
Это на плате Уно. Теперь буду переносить.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
603
178
@Esteriman,
У вас interrupts(); и noInterrupts(); неправильно поставлены. Это сразу бросается в глаза, остальное не смотрел.
noInterrupts(); в ISR не имеет смысла, т.к. они и так запрещены в прерывании.
В loop нет noInterrupts(); и поэтому interrupts(); не имеет смысла. И может быть дополнительно надо сбрасывать аппаратный флаг прерывания, т.к. если он установлен, то сразу вызовется ISR.
В общем изучайте прерывания. Или может быть вам вообще они не нужны. Можно сбрасывать аппаратный флаг прерывания руками и в цикле ждать его установки.

И желательно расчетами и (или) опытом определить требуемую точность измерения времени.
 

Esteriman

✩✩✩✩✩✩✩
4 Июн 2025
4
0
Я полагаю, что noInterrupts сбрасывает флаг разрешения прерываний, чтобы не сработало еще раз пока не пройдут команды в loop после if. Если это не так, то я не знаю как еще.
 

Sergo_ST

★★★★★★✩
15 Мар 2020
1,063
877
@Esteriman, Ничего эта процедура не сбрасывает, только лишь запрещает все прерывания глобально.

Если вам нужно вкл/выкл прерывания от компаратора, то это делается так:
C++:
//Выключить прерывания компаратора
ACSR &= ~(0x01 << ACIE); //запретить прерывания компаратора

//Включить прерывания компаратора
ACSR |= (0x01 << ACI); //сбросить флаг прерывания компаратора
ACSR |= (0x01 << ACIE); //разрешить прерывания от компаратора