Проблема с компаратором
- Войдите на сайт для отправки комментариев
Чт, 12/09/2019 - 13:44
Решил добавить к универсальному пробнику режим измерения конденсаторов по http://digitrode.ru/computing-devices/mcu_cpu/816-izmeritel-emkosti-na-arduino-svoimi-rukami.html первые два скетча работают нормально, третий неустойчиво. От него отказался. Первый скетч в конструкцию вписался хорошо, в схеме ничего переделывать не нужно. Со вторым проблема. Необходим отдельный вход для измерения. Попытался переназначить вход компаратора на один из аналоговых. Эффект нулевой. Как измерял с 6 пина так и осталось. Переключение на аналоговый вход никак не влияет. Вроде почитал теорию, но что-то недопонимаю. Вот сам скетч:
/* Для измерения используем компаратор ардуино
* На вход D7 подаем напряжение = 1,58(62%) от питания
* С делителя напряжения питания из резисторов 1,8 и 3,1 КОм
* Конденсатор подключаем между D6 и землей
* Заряжаем конденсатор через резистор 10 КОм c 13 пина пока не сработает компаратор
* Дальше считаем исходя из времени заряда и резистора
* Емкость в RC-цепочке связана с постоянной времени по уравнению: Tc = R* C
* Соответственно, емкость определится как: C = Tc/R.
*/
const byte pulsePin = 13; //Пин подачи напряжения заряда
const unsigned long resistance = 9100; //Сопротивление зарядной цепи (9.1 KOm)
volatile boolean triggered;
volatile boolean active;
volatile unsigned long startTime;
volatile unsigned long duration;
// Обработчик прерывания аналогового компаратора
ISR (ANALOG_COMP_vect)
{
unsigned long now = micros ();
if (active)
{
duration = now - startTime;
triggered = true;
digitalWrite (pulsePin, LOW); // Снимаем напряжение заряда
}
}
void setup ()
{
pinMode(pulsePin, OUTPUT);
digitalWrite(pulsePin, LOW);
Serial.begin(9600);
Serial.println("Started.");
// Настраиваем компаратор
//ADCSRB = 0;
ADCSRB |=(1<<ACME); // enable multiplexer
ADMUX = 3;
ACSR = _BV (ACI) //флаг прерывания. Устанавливается по событию,сбрасывается после ухода на обработчик либо программно, записью в него 1.
| _BV (ACIE) //бит разрешения прерывания от компаратора.
| _BV (ACIS0) | _BV (ACIS1);
}
/*
Биты ACIS1:ACIS0 определяет условие возникновения прерывания от компаратора:
00 — любое изменение на входе.
01 — зарезервировано для следующих поколений
10 — переход с 1 на 0
11 — переход с 0 на 1
*/
void loop ()
{
if (!active)
{
active = true;
triggered = false;
digitalWrite (pulsePin, HIGH); // Включаем напряжение заряда
startTime = micros ();
}
if (active && triggered)
{
active = false;
Serial.print ("Capacitance = ");
Serial.print (duration * 1000 / resistance);
Serial.println (" nF");
triggered = false;
delay (1000);
}
}
Ощущение, что строк 40 и 41 не существует.
А разве вход компаратора можно на аналоговый пин переназначить? ЕМНИП он там намертво зашит AIN0 и AIN1. Хотя ... Вы же не сказали, что за контроллер, вангую, что мы о разных вещах говорим.
А разве вход компаратора можно на аналоговый пин переназначить? ЕМНИП он там намертво зашит AIN0 и AIN1. Хотя ... Вы же не сказали, что за контроллер, вангую, что мы о разных вещах говорим.
Обычный 168, но когда начал разбираться, в десятке публикаций прочитал, что достаточно в регистр ADCSRB установить в единицу бит ACME и мультиплексор с АЦП переключается на инвертирующий вход компаратора. ADMUX выбирает на какой. Правда есть сомнение, что кристалл не совсем живой, так как я ему спалил А6. Но остальное все работает. Так-что ХЗ. Толь лыжи не едут, толь я ....... Напрямую с регистрами работаю, только если сильно приспичит. Поэтому грешу на больше на свои знания.
достаточно в регистр ADCSRB установить в единицу бит ACME и мультиплексор с АЦП переключается на инвертирующий вход компаратора. ADMUX выбирает на какой.
Всё верно. А неинвертирующий вход так и остаётся на PD6. Но его можно перекинуть на опорное битом ACBG.
достаточно в регистр ADCSRB установить в единицу бит ACME и мультиплексор с АЦП переключается на инвертирующий вход компаратора. ADMUX выбирает на какой.
Всё верно. А неинвертирующий вход так и остаётся на PD6. Но его можно перекинуть на AREF битом ACBG.
Так значит мой косяк, у меня опорное подается на PD7 а измеряемая величина на PD6. Если не сложно гляньте скетч. Правильно-ли я пытаюсь переключить вход? И если поменять местами PD6 и PD7 для сохранения логики работы достаточно изменить условие срабатывания компаратора? Это влет, а вообще подумать надо. Но уж очень хочется добавить в пробник измерение конденсаторов не ставя дополнительных разъемов и не меняя схему. В него уже не влезешь. В более крупном варианте, http://arduino.ru/forum/proekty/universalnyi-arduino-probnik?page=5#comment-477987 лишний разъем не критичен. А сейчас пошли эти подлые CMD конденсаторы, по размерам и внешнему виду которых емкость не определишь.
svm, да я уже посмотрел, всё правильно. По крайней мере на беглый взгляд. Только наверное АЦП по умолчанию дуней включен, и перехватывает MUX надо его выключить.
svm, да я уже посмотрел, всё правильно. По крайней мере на беглый взгляд. Только наверное АЦП по умолчанию дуней включен, и перехватывает MUX надо его выключить.
и изменить условия прерывания компаратора и все прекрасно работает. Инверсный вход компаратора подключается к А3.
В таком виде.для измерения емкости конденсаторов, ставить дополнительный разъем и изменять схему входной цепи пробника не придется, достаточно изменить программу. Вот два варианта измерителя, первый - с использованием стандартных процедур и второй с использованием таймера. Если честно, то разницы не заметил. Какой применять будет ясно по результатам теста, когда залью в реальную конструкцию.
/* Для измерения используем компаратор ардуино * На вход D6 подаем напряжение = 62% от питания * С делителя напряжения питания из резисторов 1,8 и 3,1 КОм * Конденсатор подключаем между A5 и землей * Заряжаем конденсатор через резистор 10 КОм c 3 пина пока не сработает компаратор * Дальше считаем исходя из времени заряда и резистора * Емкость в RC-цепочке связана с постоянной времени по уравнению: Tc = R* C * Соответственно, емкость определится как: C = Tc/R. */ const byte pulsePin = 3; //Пин подачи напряжения заряда const byte LedPin = 4; //Отладочный светодиод контроля подачи напряжения заряда const unsigned long resistance = 10000; //Сопротивление зарядной цепи (10 KOm) volatile boolean triggered; volatile boolean active; volatile unsigned long startTime; volatile unsigned long duration; // Обработчик прерывания аналогового компаратора ISR (ANALOG_COMP_vect) { unsigned long now = micros (); // Фиксируем время срабатывания if (active) // Если был икл измерения { duration = now - startTime; // Считаем длительность заряда triggered = true; // Фиксируем конец измерения digitalWrite (pulsePin, LOW); // Включаем разряд конденсатора } } void setup () { pinMode(LedPin, OUTPUT); pinMode(pulsePin, OUTPUT); digitalWrite (LedPin, LOW); digitalWrite(pulsePin, LOW); // Контрольный разряд конденсатора Serial.begin(9600); Serial.println("Started."); // Настройка АЦП и мультиплексора ADCSRA &= ~ (1 << ADEN); // Отключаем АЦП ADCSRB |=(1<<ACME); // Подключаем мультиплексор ADMUX = 5; // ADC5 к инверсному входу компаратора // Настройка компаратора ACSR = _BV (ACI) // Флаг прерывания | _BV (ACIE) // Разрешение прерывания & ~_BV (ACIS0) // Прерывание при переходе с 1 на 0 | _BV (ACIS1); // -------------------------------- /* Биты ACIS1:ACIS0 условие прерывания компаратора: 00 — любое изменение на входе. 01 — зарезервировано для следующих поколений 10 — переход с 1 на 0 11 — переход с 0 на 1 */ } void loop () { if (!active) //Ели не идет измерение - старт нового измерения { active = true; triggered = false; digitalWrite (pulsePin, HIGH); // Включаем заряд конденсатора digitalWrite (LedPin, HIGH); startTime = micros (); } if (active && triggered) //Если прерывание зафиксировало время заряда, отображаем результат { active = false; triggered = false; digitalWrite (pulsePin, LOW); digitalWrite (LedPin, LOW); Serial.print ("Capacitance = "); Serial.print (duration * 1000 / resistance); Serial.println (" nF"); delay (200); } }/* Для измерения используем компаратор ардуино * На вход D6 подаем напряжение = 62% от питания * С делителя напряжения питания из резисторов 1,8 и 3,1 КОм * Конденсатор подключаем между A5 и землей * Заряжаем конденсатор через резистор 10 КОм c 3 пина пока не сработает компаратор * Дальше считаем исходя из времени заряда и резистора * Емкость в RC-цепочке связана с постоянной времени по уравнению: Tc = R* C * Соответственно, емкость определится как: C = Tc/R. */ const byte LedPin = 4; const byte pulsePin = 3; //Пин подачи напряжения заряда const unsigned long resistance =10000; //Сопротивление зарядной цепи (10 KOm) volatile boolean triggered; volatile boolean active; volatile unsigned long startTime; volatile unsigned long duration; volatile unsigned long timerCounts; volatile unsigned long overflowCount; ISR (TIMER1_OVF_vect) { ++overflowCount; // считаем количество переполнений счетчика 1 } // end of TIMER1_OVF_vect // Обработчик прерывания аналогового компаратора ISR (ANALOG_COMP_vect) { // фиксируем актуальное значение счетчика, прежде чем он изменится unsigned int timer1CounterValue; timer1CounterValue = TCNT1; unsigned long overflowCopy = overflowCount; if (active) { // Если просто пропустил переполнение if ((TIFR1 & bit (TOV1)) && timer1CounterValue < 256) overflowCopy++; // Считаем общее количество timerCounts = (overflowCopy << 16) + timer1CounterValue; // Каждое переполнение составляет 65536 больше triggered = true; digitalWrite (pulsePin, LOW); // Включаем разряд конденсатора digitalWrite (LedPin, LOW); } } // end of ANALOG_COMP_vect void setup () { pinMode(pulsePin, OUTPUT); pinMode(LedPin, OUTPUT); digitalWrite (LedPin, LOW); digitalWrite (pulsePin, LOW); //Включаем разряд конденсатора Serial.begin(9600); Serial.println("Started."); ADCSRA &= ~ (1 << ADEN); // Отключаем АЦП ADCSRB |=(1<<ACME); // Подключаем мультиплексор ADMUX = 5; // ADC5 к инверсному входу компаратора //DIDR1 |= _BV(AIN1D) | _BV(AIN0D); ACSR = _BV (ACI) | _BV (ACIE) & ~_BV (ACIS0) | _BV (ACIS1); } void loop () { if (!active) startTiming (); //Ели не идет измерение - старт нового измерения if (active && triggered) finishTiming (); //Если прерывание зафиксировало время заряда, отображаем результат } //**************************************************************************************************************** void startTiming () { active = true; triggered = false; // prepare timer overflowCount = 0; // no overflows yet // reset Timer 1 TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; // Обнуляем счетчик TIFR1 = bit (TOV1); // Очистить бит переполнения // Таймер 1- подсчет тактовых импульсов TIMSK1 = bit (TOIE1); // прерывание по переполнению таймера 1 // смирись с этим digitalWrite (pulsePin, HIGH); // Включаем заряд конденсатора digitalWrite (LedPin, HIGH); // Запуск таймера 1, Без прескалера TCCR1B = bit (CS10); // end of startTiming } //************************************************************************************** void finishTiming () { active = false; Serial.print ("Capacitance = "); float capacitance = (float) timerCounts * 1000.0 / 16.0 / resistance; Serial.print (capacitance); Serial.println (" nF"); triggered = false; delay (500); } // end of finishTiming