Время выполнения команды

nazzik
Offline
Зарегистрирован: 05.08.2013

Вопрос такой: почему время выполнения команды в ардуино разное при тех же условиях?

Например вот такой скетч

#include <analogComp.h>
#include <CyberLib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(14,15,16,17,18,19);
unsigned int t_1 = 0; // переменная для хранения времении работы программы в мкс
unsigned int t_2 = 0; // переменная для хранения времении работы программы в мкс
unsigned int R = 3607; // сопротивление резистора заряда конденсатора в kОмах
volatile float T = 0.0; // время заряда конд. плюс входная емкость плюс время виполнения команд
volatile float C = 0.0; // вычесленное значение емкости
void setup() 
{
lcd.begin(16,2);
}
void loop() 
{  
       D8_Out; // назначаем D8 на выход 
       D8_Low; // на D8 устанавливаем 0  (минус конденсатора)
       D9_Out; // назначаем D9 на выход
       D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
       delay(500); // ждем пока розрядится конд.
       D9_In; // делаем D9 входом, что б не мишать измерениям
       delayMicroseconds(100); // небольшея пауза
       t_1 = micros(); // засекаем время t_1
       if (analogComparator.waitComp(0)) // если на компараторе напражение више установленого...
        {
         t_2 = micros(); // засекаем время t_2
        }
      T = (t_2 - t_1); // время заряда конденсатора, показывает разные значения (без конд. 12 - 14 мкС)
      C = ((T - 12.0)/R*1000); // вычисление емкости в пф. (12.0 -  см. выше)
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print ("Capacitance: ");
      lcd.setCursor(0,1);
      lcd.print (C); // вывод значения емкости на экран
      lcd.print (" pF "); 
}  

Вот схема. Это измеритель емкости. Меряет время заряда конд. резистором 3.6М.

Таким образом, значение емкости постоянно прыгают. Как с этим бороться? Подскажите пожалуйста.

nazzik
Offline
Зарегистрирован: 05.08.2013

Принцип взят отсюда http://easyelectronics.ru/kondensator-i-rc-cepochka.html

dtvims
Offline
Зарегистрирован: 26.11.2012

функция micros() дает результат кратный 4мкс, на малых емкостях скакать тока в путь...

nazzik
Offline
Зарегистрирован: 05.08.2013

Спасибо dtvims! Это объясняет многое. А как тогда засечь 1 мкс? Таймер-то 16 битный, межет есть какие-то другие способы? TimerOne например. Я новичок в контроллерах, поетому спрашиваю у профи на форуме, если такие есть, конечно :-)

__Alexander
Offline
Зарегистрирован: 24.10.2012

работайте с таймером непосредственно через его регистры.

dtvims
Offline
Зарегистрирован: 26.11.2012

micros() использует счетчик от WatchDog, вернее его прерывание, в котором инкрементирует 32-х разрядный счетчик (переменную типа unsigned long). Если чаще вызывать прерывание, то дуинка тупо будет сидеть в обработчике данного прерывания. см. исходники arduino IDE.

Можно попробовать 2 решения: или использовать непосредственно 8-ми битный счетчик (перед началом измерения сбрасывать его, а в конце читать, прерывание не  включать), Вам же надо не так много мкс отсчитать; или делать свои задержки из расчета 16 тактов на 1мкс (если у Вас кварц на 16MHz), но при этом не забудте отключить WatchDog, иначе он своим прерыванием, раз в 4мкс, будет вносить доп. погрешность, а чтение портов необходимо делать напрямую, НЕ используя Arduino IDE, иначе опять получите задержку до 4 мкс (чет накрутили они там, чтобы сделать сплошную нумерацию пинов).

nazzik
Offline
Зарегистрирован: 05.08.2013

Да! Варианты есть. Но авторы Дуины их не предусмотрели! Я только начинаю в этом разбираться. Хорошо-бы примеры какие-то увидеть с коментариями. Буду признателен!

step962
Offline
Зарегистрирован: 23.05.2011

dtvims пишет:

micros() использует счетчик от WatchDog, вернее его прерывание,  ...

Разве???

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
	cli();
	m = timer0_overflow_count;
#if defined(TCNT0)
	t = TCNT0;
#elif defined(TCNT0L)
	t = TCNT0L;
#else
	#error TIMER 0 not defined
#endif
#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t < 255))
		m++;
#else
	if ((TIFR & _BV(TOV0)) && (t < 255))
		m++;
#endif
	SREG = oldSREG;	
	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

dtvims пишет:

...

не забудте отключить WatchDog, иначе он своим прерыванием, раз в 4мкс

...

WatchDog'у, работающему от собственного 128-килогерцового осциллятора, до микросекундной скорострельности как до Парижу раком:

dtvims
Offline
Зарегистрирован: 26.11.2012

Щас сам покапался в исходниках. Теперь думаю, где же я видел перенастроенный WatchDog?

Не суть, значит надо таймер 0 отключить

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
SIGNAL(TIM0_OVF_vect)
#else
SIGNAL(TIMER0_OVF_vect)
#endif
{
	// copy these to local variables so they can be stored in registers
	// (volatile variables must be read from memory on every access)
	unsigned long m = timer0_millis;
	unsigned char f = timer0_fract;

	m += MILLIS_INC;
	f += FRACT_INC;
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
		m += 1;
	}

	timer0_fract = f;
	timer0_millis = m;
	timer0_overflow_count++;
}

И речь тут не о самой скорострельности, а о том, что обработка этого прерывания как раз около 1 мкс, если не больше, посчитайте сколько тактов на вход в прерывание, сохранить регистры, обработка и выход.

nazzik
Offline
Зарегистрирован: 05.08.2013

Уважаемые step962 и dtvims! Вы, наверное, понимаете друг друга, а я вас нет! Как мне использовать это в моей программе? Я схемотехник и только-только начинаю программировать, ПАМАГИТЕ пожалуйста!!!

nazzik
Offline
Зарегистрирован: 05.08.2013

Для меня это темный лес! А если использовать библиотеку TimerOne https://code.google.com/p/arduino-timerone/downloads/list, тока я не знаю как, нету примера подходящего. Может ви подскажите примером или ссилкой на него. 

nazzik
Offline
Зарегистрирован: 05.08.2013

Нашел пример, но как его переделать что б  в мою прогу вставить??? http://justforduino.blogspot.com/2013/05/arduino-2.html

dtvims
Offline
Зарегистрирован: 26.11.2012

По последней Вашей ссылке отличный пример, только Вам и одного таймера будет достаточно я думаю, собственно автор там и использует таймер1. А вот зачем он инициализировал таймер 0, я что-то не понял.

nazzik
Offline
Зарегистрирован: 05.08.2013

Да, я вижу, что это почти то что надо, но мозгов не хватает что б использовать в моей программе! Помогииииииииите! Пожалуйста!

dtvims
Offline
Зарегистрирован: 26.11.2012
"TCCR1B = (1<<CS10);" - запускает таймер на отсчет с пределителем 1

"TCCR1B = 0;" - выключает таймер

"TCNT1 = 0;" - сброс счетчика

в общем цикле он забирает значение TCNT1 - это и есть счетчик таймера 1. Поскольку настройки все по нулям, он по сути должен отсчитывать такты, т.е. 1мкс = 16 тактов.

"#include <util/delay.h>" - стандартная билиотека AVR, где есть функция "_delay_ms(800); // wait 800 ms", которая реализует простой цикл с известным числом тактов, т.е. Если какие-то прерывания не прервут его работу, то отсчет будет точным. 

более детально про настройку таймера тут http://www.atmel.com/Images/doc8161.pdf , а по русски вот тут неплохо http://mainloop.ru/avr-atmega/avr-timer-counter.html 

nazzik
Offline
Зарегистрирован: 05.08.2013

Спасибо! Буду разбираться, то есть учиться!

nazzik
Offline
Зарегистрирован: 05.08.2013

Новый код:

#include <util/delay.h>
#include <analogComp.h>
#include <CyberLib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(14,15,16,17,18,19);
unsigned long t_1 = 0; // переменная для хранения времении работы программы в мкс
unsigned long t_2 = 0; // переменная для хранения времении работы программы в мкс
unsigned int R = 4274; // сопротивление резистора заряда конденсатора в kОмах
volatile float T = 0.0; // время заряда конд. плюс входная емкость плюс время виполнения команд
volatile float C = 0.0; // вычесленное значение емкости
                  
  void Timer1_Init( void )  // Timer/Counter 1 initialization
   {
    TCNT1 = 0;
    TCCR1A = 0;  // Bits: COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
    TCCR1B = 0; // Bits: ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
    TCCR1C = 0; // Bits: FOC1A FOC1B - - - - - -
    TIMSK1 = 0; // Bits: - - ICIE1 - - OCIE1B OCIE1A TOIE1
    TIFR1 = 0;  // Bits: – – ICF1 – - OCF1B OCF1A TOV1
  }

void setup() 
{
 lcd.begin(16,2); 
 
 cli(); // Global disable interrupts
 Timer1_Init(); // Timer/Counter 1 initialization
 sei(); // Global enable interrupts
}

void loop() 
{  
       D8_Out; // назначаем D8 на выход 
       D8_Low; // на D8 устанавливаем 0  (минус конденсатора)
       D9_Out; // назначаем D9 на выход
       D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
       _delay_ms(500);// ждем пока розрядится конд.
       D9_In; // делаем D9 входом, что б не мишать измерениям
       _delay_us(100);// небольшея пауза
       TCCR1B = (1<<CS10); // запускаем таймер
       if (analogComparator.waitComp(0)) // если на компараторе напражение више установленого...
        {
         TCCR1B = 0; // останавливаем таймер
        }
         T = TCNT1; // забираем значение таймера
         TCCR1B = 0; // выключаем таймер
         TCNT1 = 0; // сброс счетчика
      C = ((T - 379)/R*1000) / 16; // вычисление емкости в пф. 
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Capacitance: ");
      lcd.setCursor(0,1);
      lcd.print(C);
} 
Тут тоже есть проблемы, хотя работает лучше!
 
Во первых - значения дальше прыгают, но не так хаотично как раньше (наверное из за компаратора, точнее библиотеки analogComp.h) 
 
Во вторых - не меряет больше чем 500 пФ, раньше было до 1 мкФ (наверное таймер ме может столько посчитать).
 
Как тут быть?
dtvims
Offline
Зарегистрирован: 26.11.2012

надо смотреть, что у Вас в "analogComp.h", в стандартных ее не нашел :(

похорошему, действительно лучше самому читать и писать в порт. Для цифровых портов: "DDRD" - регистр режима порта "D", если соответсвующий бит выставляете 0, то вход, если 1 выход. "PORTD" - что на выходе, а через "PIND" читать состояние. Тут детально http://easyelectronics.ru/avr-uchebnyj-kurs-ustrojstvo-i-rabota-portov-vvoda-vyvoda.html

С аналоговым входом не помню деталей :( Вот тут нашел детально http://dfe.petrsu.ru/koi/posob/avrlab/mega16adc.html, где, кстати, описана серьезная задержка в 13-25 тактов на преобразование.

Можно дожидаться, когда когда на цифровом входе будет логический переход с 0 на 1 или наоборот, может пошустрее и по точнее выйдет, тут, кстати, и на прерывание можно повесить такой переход (int0), т.е. сработало прерывание, в нем и замер времени сделали, чтобы не делать постоянные замеры в цикле, от чего и результат вероятно плавает.

Чтобы учитывать переполнение, т.е. измерять большую емкость, придется таки использовать прерывание или уменьшать резистор :)

volatile byte TimC=0; // 255 переполнений, если надо больше, то меняем на uint и т.п.

ISR (TIMER1_OVF_vect){
  TimC++; //инкрементируем счечик переполнения
  /*код обработчика*/
}

void setup(){
 //... что-то еще 
  TIMSK1 = (1 << TOIE1); // Включаем прерывание по переполнению
}

вот тут есть инфа по таймеру http://dfe.petrsu.ru/koi/posob/avrlab/mega16tcnt1.html

UPD, а я понял зачем в том примере инициализировали таймер 0 - это его выключили :) дабавте туже функцию к себе в "setup()", возможно уже чуть меньше скакать будет.

dtvims
Offline
Зарегистрирован: 26.11.2012

В дополнение. В случае с измерениями емкости, где-то читал, что все-равно скакать будет. Для точных имерений, схемка нужна по сложнее, чтобы стабилизировать процес. Можно делать несколько измерений, запоминать их, а потом выдавать среднее значение как результат :)

nazzik
Offline
Зарегистрирован: 05.08.2013
Спасибо за ссылки. Но я не использую АЦП, а аналоговый компаратор, он по шустрее. Библиотека тут http://www.leonardomiliani.com/2012/analogcomp-una-libreria-per-gestire-il-comparatore-analogico/?lang=en
 
Компаратор нужен что бы задать точное напряжение срабатывания. Пробовал с АЦП - гиблое дело.
 
На малых емкостях пробовал делать 1000 измерений и считать среднее значение, и каждое такое значение было разным!
 
Тут есть готовый прибор http://radioded.ru/skhema-na-mikrokontrollere/tsifrovoy-izmeritel-yomkosti но я хочу Ардуину использовать, у меня все есть, а там покупать надо :(
dtvims
Offline
Зарегистрирован: 26.11.2012

Вообще analogComp и использует ацп в чистом виде :) причем для ожидания она использует отсчет millis(), где, если максимальное время ожидания не задано, используется 5 секунд. Т.е. при отключении тамера 0, работать перестанет. Правда там можно задать некую userFunction(), которая будет срабатывать по прерыванию. Собственно, погрешность во времени измерения от такого использования по любому в 1.5мкс есть.

Мне кажется, что если Вы это все аккуратно под свою задачу сами напишите, уже будет точнее, т.к. вы не будете вызывать никакие доп. функции, один только вызов, которых Вам будет стоить по 1мкс.

Можно еще какой-нибудь фильтр наложить типа Калмана, на пачку измерений :) Может Еще увеличить время разряда?

nazzik
Offline
Зарегистрирован: 05.08.2013

А как же аппаратный компаратор? Выводы AIN0 и AIN1, они же Digital pin 6 и Digital pin 7, они же 12 и13 ноги Dip корпуса Atmega.

Он, вроде, независимо от АЦП работает.

nazzik
Offline
Зарегистрирован: 05.08.2013

Вот ище нашел http://www.rigexpert.com/index?s=articles&f=cmeter&l=ru Этот прибор так же работает, только контроллер ATmega16 и дисплей простой. Вот его код (длинний зараза). Может одтуда отковырять часть таймер-компаратор.



//
// The most simple digital capacitance meter
//
// Original idea - <a data-cke-saved-href="http://elm-chan.org/works/cmc/report.html" href="http://elm-chan.org/works/cmc/report.html" rel="nofollow">http://elm-chan.org/works/cmc/report.html</a>
//
// C source code - UU9JDR, <a data-cke-saved-href="http://www.rigexpert.com" href="http://www.rigexpert.com" rel="nofollow">http://www.rigexpert.com</a>
//

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>
#include <string.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <stdio.h>

#include "defines.h"

uint32_t calib_low, calib_high;
uint32_t zero_low, zero_high;


void ReadEeprom(void)
{
	eeprom_read_block(&calib_low, (const uint8_t *)0, 4);
	eeprom_read_block(&calib_high, (const uint8_t *)4, 4);
	eeprom_read_block(&zero_low, (const uint8_t *)8, 4);
	eeprom_read_block(&zero_high, (const uint8_t *)12, 4);

	if (calib_low==0xFFFFFFFFL)
	{
		calib_low = 0x074D;
		calib_high = 0x06E7;
		zero_low = 0x00C3;
		zero_high = 0;
	}
}

void WriteEeprom(void)
{
	eeprom_write_block(&calib_low, (uint8_t *)0, 4);
	eeprom_write_block(&calib_high, (uint8_t *)4, 4);
	eeprom_write_block(&zero_low, (uint8_t *)8, 4);
	eeprom_write_block(&zero_high, (uint8_t *)12, 4);
}

void LcdInit(void)
{
	DDRA |= 0b11111111;
	PORTA &= ~0b11111111;

	DDRB |= 0b11100000;
	PORTB &= ~0b11100000;

	DDRC |= 0b11111111;
	PORTC &= ~0b11111111;

	DDRD |= 0b11111111;
	PORTD &= ~0b11111111;

	// Setup ~76 Hz timer

	TCNT0 = 128;
	TCCR0 = 0b00000101;

	TIMSK |= 1;
}

volatile uint8_t A=0,B=0,C=0,D=0; // Port values to put to the LCD

SIGNAL (SIG_OVERFLOW0) 
{
	TCNT0 = 128;

	static uint8_t phase = 0;

	phase = !phase;

	if (phase)
	{
		PORTA = (PORTA & ~0b11111101) | A;
//		PORTB = (PORTB & ~0b11110000) | B;
		PORTC = (PORTC & ~0b11111111) | C;
		PORTD = (PORTD & ~0b10111111) | D;

		// Force cbi/sbi instructions
		if (B & 128)
			PORTB |= 128;
		else
			PORTB &= ~128;
		if (B & 64)
			PORTB |= 64;
		else
			PORTB &= ~64;
		if (B & 32)
			PORTB |= 32;
		else
			PORTB &= ~32;
	
		if (B & 1)
			PORTD |= 64;
		else
			PORTD &= ~64;

		clrbit(PORTA,1);
	}
	else
	{
		PORTA = (PORTA | 0b11111101) & ~A;
//		PORTB = (PORTB | 0b11110000) & ~B;
		PORTC = (PORTC | 0b11111111) & ~C;
		PORTD = (PORTD | 0b10111111) & ~D;

		// Force cbi/sbi instructions
		if (B & 128)
			PORTB &= ~128;
		else
			PORTB |= 128;
		if (B & 64)
			PORTB &= ~64;
		else
			PORTB |= 64;
		if (B & 32)
			PORTB &= ~32;
		else
			PORTB |= 32;
		
		if (B & 1)
			PORTD &= ~64;
		else
			PORTD |= 64;

		setbit(PORTA,1);
	}

}


void NrOut(uint8_t n1, uint8_t n2, uint8_t n3, uint8_t dot_pos, uint8_t units)
{
	A = B = C = D = 0;

	switch (n1)
	{
		case 0:
			A |= 0b00111001;
			B |= 0b00100001;
			break;
		case 1:
			A |= 0b00100000;
			B |= 0b00100000;
			break;
		case 2:
			A |= 0b00110101;
			B |= 0b00000001;
			break;
		case 3:
			A |= 0b00110100;
			B |= 0b00100001;
			break;
		case 4:
			A |= 0b00101100;
			B |= 0b00100000;
			break;
		case 5:
			A |= 0b00011100;
			B |= 0b00100001;
			break;
		case 6:
			A |= 0b00011101;
			B |= 0b00100001;
			break;
		case 7:
			A |= 0b00110000;
			B |= 0b00100000;
			break;
		case 8:
			A |= 0b00111101;
			B |= 0b00100001;
			break;
		case 9:
			A |= 0b00111100;
			B |= 0b00100001;
			break;

		case 11: // C
			A |= 0b00011001;
			B |= 0b00000001;
			break;
	}

	switch(n2)
	{
		case 0:
			A |= 0b10000000;
			B |= 0b10000000;
			C |= 0b11000000;
			D |= 0b00000011;
			break;
		case 1:
			C |= 0b01000000;
			D |= 0b00000010;
			break;
		case 2:
			A |= 0b01000000;
			B |= 0b10000000;
			C |= 0b11000000;
			D |= 0b00000001;
			break;
		case 3:
			A |= 0b01000000;
			C |= 0b11000000;
			D |= 0b00000011;
			break;
		case 4:
			A |= 0b11000000;
			C |= 0b01000000;
			D |= 0b00000010;
			break;
		case 5:
			A |= 0b11000000;
			C |= 0b10000000;
			D |= 0b00000011;
			break;
		case 6:
			A |= 0b11000000;
			B |= 0b10000000;
			C |= 0b10000000;
			D |= 0b00000011;
			break;
		case 7:
			C |= 0b11000000;
			D |= 0b00000010;
			break;
		case 8:
			A |= 0b11000000;
			B |= 0b10000000;
			C |= 0b11000000;
			D |= 0b00000011;
			break;
		case 9:
			A |= 0b11000000;
			C |= 0b11000000;
			D |= 0b00000011;
			break;

		case 11: // A
			A |= 0b11000000;
			B |= 0b10000000;
			C |= 0b11000000;
			D |= 0b00000010;
			break;

	}

	switch (n3)
	{
		case 0:
			C |= 0b00011100;
			D |= 0b00111000;
			break;
		case 1:
			C |= 0b00000100;
			D |= 0b00100000;
			break;
		case 2:
			C |= 0b00101100;
			D |= 0b00011000;
			break;
		case 3:
			C |= 0b00101100;
			D |= 0b00110000;
			break;
		case 4:
			C |= 0b00110100;
			D |= 0b00100000;
			break;
		case 5:
			C |= 0b00111000;
			D |= 0b00110000;
			break;
		case 6:
			C |= 0b00111000;
			D |= 0b00111000;
			break;
		case 7:
			C |= 0b00001100;
			D |= 0b00100000;
			break;
		case 8:
			C |= 0b00111100;
			D |= 0b00111000;
			break;
		case 9:
			C |= 0b00111100;
			D |= 0b00110000;
			break;

		case 11: // L
			C |= 0b00010000;
			D |= 0b00011000;
			break;
	}

	switch (dot_pos)
	{
		case 1:
			B |= 0b01000000;
			break;

		case 2:
			D |= 0b00000100;
			break;
	}

	switch (units)
	{
		case 0: // pF
			C |= 0b00000011;
			D |= 0b10000000;
			break;

		case 1: // nF
			C |= 0b00000001;
			D |= 0b10000000;
			break;

		case 2: // uF
			C |= 0b00000011;
			break;
	}


}

volatile uint8_t timeout, measured_flag, ovf_flag, ovf_cnt;
volatile uint32_t capt1,capt2;

uint32_t Measure(uint8_t range)
{
	setbit(DDRB,1); // Set threshhold to 0.17V
	setbit(DDRB,2); // Discharge the capacitor, AIN0 as output

	TCNT1 = 0;

	if (range) // high range
	{
		clrbit(PORTB,0); // Set high range
		timeout = 152; // 1s for high range
	}
	else // low range
	{
		setbit(PORTB,0); // Set low range
		timeout = 20	; // 0.13s for low range
	}

//clrbit(DDRB,1); // Set to 0.5V
	delay_ms(200); // Some delay to discharge the capacitor

	TIFR |= 0b00100100;  // Set capture and overflow interrupts
	TIMSK |= 0b00100100;

	measured_flag = 0;
	ovf_flag = 0;
	ovf_cnt = 0;

	TCCR1B = 0b01000001; // Start timer

	clrbit(DDRB,2); // Start charging

	while( (!measured_flag) && (!ovf_flag)); // Wait until timeout or successfull measurement

	TCCR1B = 0b01000000; // Stop timer

	setbit(DDRB,1); // Set threshhold to 0.17V
	setbit(DDRB,2); // Discharge the capacitor, AIN0 as output

	if (ovf_flag)
		return 0;
	else
		return capt2 - capt1;
}

SIGNAL (SIG_OVERFLOW1) 
{
	ovf_cnt++;

	if (ovf_cnt == timeout)
	{
		ovf_flag = 1;
		TIMSK &= ~0b00000100; // Disable overflow interrupt
	}
}

SIGNAL (SIG_INPUT_CAPTURE1) 
{
	if (getbit(DDRB,1)) // Was 0.17V
	{
		capt1 = ((uint32_t)ovf_cnt) << 16;
		capt1 |= ICR1;
		clrbit(DDRB,1); // Set to 0.5V

		_delay_loop_1(20);
		TIFR |= 0b00100000; // Clear capture interrupt flag
	}
	else
	{
		capt2 = ((uint32_t)ovf_cnt) << 16;
		capt2 |= ICR1;
//		capt2 = ICR1;
//		capt2 |= ((uint32_t)ovf_cnt) << 16;


//		setbit(DDRB,1); // Set threshhold to 0.17V
//		setbit(DDRB,2); // Discharge the capacitor, AIN0 as output

		TIMSK &= ~0b00100000; // Disable capture interrupt


		measured_flag = 1;

//		_delay_loop_1(20);
//		TIFR |= 0b00100000; // Clear capture interrupt flag
	}

}

void DisplayPf(double c)
{
	uint32_t c10 = c*10.0;

	if (c<0.0)
	{
		NrOut(10,0,0,2,0); /// xx.x p
	}
	else
	if (c10<1000) // < 100 nF
	{
		NrOut((c10/100 > 0) ? (c10/100) : 10,(c10/10)%10,c10%10,2,0); /// xx.x p
	}
	else
	if (c10<10000) // < 1 nF
	{
		NrOut(c10/1000,(c10/100)%10,(c10/10)%10,3,0); /// xxx p
	}
	else
	if (c10<100000L) // < 10 nF
	{
		NrOut(c10/10000,(c10/1000)%10,(c10/100)%10,1,1); /// x.xx n
	}
	else
	if (c10<1000000L) // < 100 nF
	{
		NrOut(c10/100000L,(c10/10000)%10,(c10/1000)%10,2,1); /// xx.x n
	}
	else
	if (c10<10000000L) // < 1 uF
	{
		NrOut(c10/1000000L,(c10/100000L)%10,(c10/10000)%10,3,1); /// xxx n
	}
	else
	if (c10<100000000L) // < 10 uF
	{
		NrOut(c10/10000000L,(c10/1000000L)%10,(c10/100000L)%10,1,2); /// x.xx u
	}
	else
	if (c10<1000000000L) // < 100 uF
	{
		NrOut(c10/100000000L,(c10/10000000L)%10,(c10/1000000L)%10,2,2); /// xx.x u
	}
	else
		NrOut(c10/1000000000L,(c10/100000000L)%10,(c10/10000000L)%10,3,2); /// xxx u
}


int main(void)
{
	LcdInit();

	ReadEeprom();

//	NrOut(0,0,0,3,2); /// 000 uF

	// Init other ports

	setbit(PORTB,0); // Set low range
	setbit(DDRB,0);

	clrbit(PORTB, 1);  // Set threshhold to 0.17V
	setbit(DDRB, 1);

	clrbit(PORTB,2); // Discharge the capacitor, AIN0 as output
	setbit(DDRB,2);

	clrbit(PORTB,3); // AIN1 as input
	clrbit(DDRB,3);


	ACSR |= 0b00000100; // Enable comparator capture function

	sei();

	clrbit(DDRB,4); // Input
	setbit(PORTB,4);

	delay_ms(100);

	if (!getbit(PINB,4)) // calibrate
	{
		NrOut(11,11,11,3,3); /// CAL

		Measure(0); // Warm-up
		Measure(1);
		
		while(!getbit(PINB,4)); // Wait until button released
		delay_ms(500);

		// Calibrate at 100 pF

		DisplayPf(100);

		while(getbit(PINB,4)); // Wait until button pressed
		delay_ms(100);

		while(!getbit(PINB,4)); // Wait until button released
		delay_ms(500);

		calib_low = Measure(0); // Measure at low range
		calib_low = Measure(0); // Measure at low range
		WriteEeprom();

		// Calibrate at 100 nF

		DisplayPf(100000);
		delay_ms(100);

		while(getbit(PINB,4)); // Wait until button pressed
		delay_ms(100);

		while(!getbit(PINB,4)); // Wait until button released
		delay_ms(500);

		calib_high = Measure(1); // Measure at high range
		calib_high = Measure(1); // Measure at high range
		WriteEeprom();
	}


	while(1) // Endless while
	{
		if (!getbit(PINB,4)) // Button pressed - set zero
		{
			NrOut(0,0,0,3,3); // 000
			delay_ms(100);

			while(!getbit(PINB,4)); // Wait until button released
			delay_ms(200);

			zero_low = Measure(0); // Measure at low range
			zero_high = Measure(1); // Measure at high range

			WriteEeprom();
		}
		else // normal measurement
		{
		
			uint32_t ticks;
	
			ticks = Measure(0); // Low range

			if (ticks) // Low range OK
			{
				double cpf = (((double)ticks)-zero_low)/(calib_low-zero_low)*100.0;

				DisplayPf(cpf);
			}
			else // Try high range
			{
				ticks = Measure(1); // High range

				if (ticks==0) // Overflow
					NrOut(9,9,9,3,2); // 999 uF
				else
				{
					double cpf = (((double)ticks)-zero_high)/(calib_high-zero_high)*100000.0;

					DisplayPf(cpf);
				}
			}
		}
	}
    return(0);
}

    

 

dtvims
Offline
Зарегистрирован: 26.11.2012

AIN - Analog Input, т.е. аналоговый вход, т.е. и есть АЦП

Вам проще добавить в "setup()" вызов "Timer0_Init();" и "analogComparator.setOn(AIN0, AIN1);", а вместо "if (analogComparator.waitComp(0)) " используйте "while((ACSR && (1<<ACO)) == 0){}"

посути тоже самое но погрешность уменьшиться.

UPD. А вообще именно что-то типа этой схемы, что найдена Вами в последний раз, я и имел ввиду, про посложнее. Там в основе частотомер, а поскольку он, насколько это возможно, стабилизирует колебания, то и результат получается более точный. Можно брать данный вариант почти без переделки, только отображение на дисплей поменять и поотлючать Дуиновские ненужности типа таймера 0.

nazzik
Offline
Зарегистрирован: 05.08.2013

dtvims пишет:

Вам проще добавить в "setup()" вызов "Timer0_Init();" и "analogComparator.setOn(AIN0, AIN1);", а вместо "if (analogComparator.waitComp(0)) " используйте "while((ACSR && (1<<ACO)) == 0){}"

Сделал, не работает!!! Не реагирует на изменение напряжения на входе AIN0. 

dtvims
Offline
Зарегистрирован: 26.11.2012

"while((ACSR && (1<<ACO)) == 0){}" - это должно быть вместо "analogComparator.waitComp(0)", а "if" просто не нужнымм

 после "while((ACSR && (1<<ACO)) == 0){}; Ваш под итог с расчетом времени строго после данного цикла.

Если он зависает до или в этом цикле, то значит я что-то не учел, а в остальном это тоже самое, что и "analogComparator.waitComp(0)", если конечно инициалзацию компоратора не забыли "analogComparator.setOn(AIN0, AIN1);", которая выполняется в "analogComparator.waitComp(0)", если не сделана ранее. 

if (!_initialized) {
		setOn(AIN0, AIN1);
		_initialized = 0;
	}

UPD. Хотя судя по "_initialized = 0;" инициализация происходит перед началом каждого измерения, тогда надо так:

          analogComparator.setOn(AIN0, AIN1);
         TCCR1B = (1<<CS10); // запускаем таймер
         while((ACSR && (1<<ACO)) == 0){}; //ждемс прихода
         T = TCNT1; // забираем значение таймера
         TCCR1B = 0; // выключаем таймер
         TCNT1 = 0; // сброс счетчика

 

nazzik
Offline
Зарегистрирован: 05.08.2013

Да я все правильно понял и сделал. На счет analogComparator.setOn(AIN0, AIN1) - в моем предыдущем коде ее не было и работало, как только вставил в сетап - перестало, хотя больше ничего не менял. Ваш последний вариант тоже не работает, где-то что-то еще спряталось.

П.С. судя по даташиту, компаратор это отдельная схема не зависимая от АЦП, хотя я может не правильно понял.

П.П.С. а зачем Timer0_Init()? Все делает 1-й таймер.

nazzik
Offline
Зарегистрирован: 05.08.2013

Заработало!!!

Оказивается надо еще и analogComparator.setOff() вставить! Методом втыка получилось вот что

       analogComparator.setOn(AIN0, AIN1);
       TCCR1B = (1<<CS10); // запускаем таймер
       while((ACSR && (1<<ACO)) == 0){}
       TCCR1B = 0; // останавливаем таймер
       analogComparator.setOff();
       T = TCNT1; // забираем значение таймера
       TCNT1 = 0; // сброс счетчика
      C = ((T - 5)/R*1000) / 16; // вычисление емкости в пф.

Все равно результат прыгает, хоть и не так сильно.

Надо-бы выкинуть analogComp.h, ее исползуют только analogComparator.setOn и analogComparator.setOff .

Mожно же и без нее обойтись? По моему ето она все портит.

dtvims
Offline
Зарегистрирован: 26.11.2012

Timer0_Init() присутсвует только зануление всех регистров связанных с таймером, т.е. его отключает.

analogComparator.setOn(AIN0, AIN1), ранее выполнялся в analogComparator.waitComp(0), поэтому нужен отдельно. Вот она: 

uint8_t analogComp::waitComp(unsigned long _timeOut) {
	//exit if the interrupt is on
	if (_interruptEnabled) {
		return 0; //error 
	}
	
	//no timeOut?
	if (_timeOut == 0) {
		_timeOut = 5000; //5 secs
	}
	
	//set up the analog comparator if it isn't
	if (!_initialized) {
		setOn(AIN0, AIN1);
		_initialized = 0;
	}
	
	//wait for the comparation
	unsigned long _tempMillis = millis() + _timeOut;
	do {
		if ((ACSR && (1<<ACO)) == 1) { //event raised
			return 1;
		}
	} while ((long)(millis() - _tempMillis) < 0);
	
	//switch off the analog comparator if it was off
	if (!_initialized) {
		setOff();
	}
	return 0;
}

По сути - это тоже самое, что оставил там я. В этой функции только инициализация setOn и ожидание, когда бит ACO примет значение 1, что соответсвует "while((ACSR && (1<<ACO)) == 0){};" - ждать, крутить в цикле, пока не станет бит ACO единицей. Т.е. убрано все лишнее. Т.е. как минимум должен остаться прежний функционал, только таймаут в 5 секунд пропал. Можно поставить "while((ACSR && (1<<ACO)) == 1){};", хотя, если так заработает, то странно, но возможно :)

Я посмотрел детально Вашу схему (Хорошо, Компаратор не совсем АЦП в чистом виде :), по крайней мере, на нем можно его реализовать, но не суть). Вам, по хорошему, между D7 и землей нужен дополнительный конденсатор емкостью около 0.1 мкФ, причем поближе к контактам Контроллера - это уменьшит шумы опорного напряжения.

dtvims
Offline
Зарегистрирован: 26.11.2012

 analogComp.h, Вам нужен, чтобы использовать analogComparator.setOn(AIN0, AIN1). Поставте на опорное конденсатор. И можно попробовать уменьшить/увеличить время разряда измеряемого конденсатора, может хоть повторяемость эксперимента увеличит.

Да, а таймер 0 надо выключить, т.к. он включается одной из стандартных библиотек ардуины, Вам лишние помехи при измерении не нужны, как и сам таймер 0.

dtvims
Offline
Зарегистрирован: 26.11.2012

от сюда http://easyelectronics.ru/avr-uchebnyj-kurs-ispolzovanie-analogovogo-komparatora.html#more-54

При этом наблюдается мерзкий эффект — когда сравниваемые напряжения на входах компаратора очень близки, то возникает дребезг. Т.е. мельчайшие помехи уже начинают играть роль и перевешивают чашу весов компаратора то в одну то в другую сторону. Возникает жуткий дребезг. Этот дребезг надо подавлять программно. Скажем игнорировать изменения сигнала если он чаще чем раз в несколько миллисекунд.

вот Вам и разный результат :(

nazzik
Offline
Зарегистрирован: 05.08.2013

Да! Но как? Непойму. Кстати, кондюк не помог.

dtvims
Offline
Зарегистрирован: 26.11.2012

А в данном случае никак этого "дребезга не избежать". В описании, он идет несколько МИЛИсекунд, а у Вас исчисляется все МИКРО секундами. 

А сильно скачет-то сейчас? Какой разброс?

nazzik
Offline
Зарегистрирован: 05.08.2013

На 100 пФ прыгает +- 1пФ (6913 - 7017 тиков таймера). Разница в 6,5 мкс! 

dtvims
Offline
Зарегистрирован: 26.11.2012

Ну +-1пФ - это супер результат :) у многих и такого достигнуть не получается! По моему, на такой простой схеме результат достойный, можно патентовать :)

nazzik
Offline
Зарегистрирован: 05.08.2013

Не!!! Негодится!!! 1% прыгает плюс 1- 2% погрешность на все остальное. Буду делать чужую схему, покупать контролер, дисплей и все остальное :(

Я еще выкинул <util/delay.h> , а задержки сделал на том же таймере - не помогло. Иногда зависает.

Вот последний код, может чот пропустили?

//#include <util/delay.h>
#include <analogComp.h>
#include <CyberLib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(14,15,16,17,18,19);
unsigned int R = 4274; // сопротивление резистора заряда конденсатора в kОмах
volatile unsigned int T = 0; // время заряда конд. плюс входная емкость плюс время виполнения команд
volatile float C = 0.0; // вычесленное значение емкости
               
  void Timer1_Init( void )  // Timer/Counter 1 initialization
   {
    TCNT1 = 0;
    TCCR1A = 0;  // Bits: COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
    TCCR1B = 0; // Bits: ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
    TCCR1C = 0; // Bits: FOC1A FOC1B - - - - - -
    TIMSK1 = 0; // Bits: - - ICIE1 - - OCIE1B OCIE1A TOIE1
    TIFR1 = 0;  // Bits: – – ICF1 – - OCF1B OCF1A TOV1
   }

void setup() 
{
 lcd.begin(16,2);
 D12_Out; // назначаем D12 на выход 
 D12_High; // на D12 устанавливаем 1  (плюс конденсатора)  
 D8_Out; // назначаем D8 на выход 
 D8_Low; // на D8 устанавливаем 0  (минус конденсатора) 
 
 cli(); // Global disable interrupts
 Timer1_Init(); // Timer/Counter 1 initialization
 sei(); // Global enable interrupts
}

void loop() 
{   
       D9_Out; // назначаем D9 на выход
       D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
           
     for (int i=0; i<20; i++)  // задержка вместо _delay_ms(500);
   {  
       TCCR1B = (1<<CS10); // запускаем таймер
       while( TCNT1 < 65530 ){}
       TCCR1B = 0; //останавливаем таймер
       TCNT1 = 0; // сброс счетчика
   }
       
      // _delay_ms(500);// ждем пока розрядится конд.
       D9_In; // делаем D9 входом, что б не мишать измерениям
       
       TCCR1B = (1<<CS10); // запускаем таймер. Задержка вместо _delay_us(115);
       while( TCNT1 < 1840 ){}
       TCCR1B = 0; //останавливаем таймер
       TCNT1 = 0; // сброс счетчика
       
       //_delay_us(115);// небольшея пауза
       analogComparator.setOn(AIN0, AIN1);
       TCCR1B = (1<<CS10); // запускаем таймер
       while((ACSR && (1<<ACO)) == 0){}
       TCCR1B = 0; //останавливаем таймер
       analogComparator.setOff();
       T = TCNT1; // забираем значение таймера
       TCNT1 = 0; // сброс счетчика
      C = ((T - 5.0)/R*1000) / 16; // вычисление емкости в пф, 5.0 - значение без кондюка
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Capacitance: ");
      lcd.setCursor(0,1);
      lcd.print(C);
} 

Я так понял, что большего не следует ожидать от этой схеми и Arduino IDE.

nazzik
Offline
Зарегистрирован: 05.08.2013

dtvims пишет:

 поотлючать Дуиновские ненужности типа таймера 0.

А есть ли че еще поотключать? АЦП, например. Если да, то как?

dtvims
Offline
Зарегистрирован: 26.11.2012

Таймер 0 все-таки выключите :)

А более навороченная схема врятли лучше результат даст. Где-то читал, что простой схемой можно мерять только приблизительно емкости. Сам заморочился как-то этим вопросом, т.к. на чип-кондерах емкость не пишится из-за конструктивных особенностей, а не нужных плат-доноров полно. Вот и заинтересовался, что у Вас получится :) Чтобы точно мерять, нужны уже ресурсы по круче чем AVR`ка :(

nazzik
Offline
Зарегистрирован: 05.08.2013

Урррра! Все работает и причем точно меряет!!! Я поотключал все лишнее и скачки в измерениях стали предсказуемими, если вывести среднее значение из 1000 измерений то результат стабильный и поразительно точный. Мерял 2%-ные кондюки - правильно показывает!

Чуть подправил схему и прогу, с резистором 4.3М меряет от 1 до 900 пФ. Планирую доделать еще 2 или 3 предела измерений, но это потом, так как мне сейчас нужно пико фарады мерять. Вот че получилось:

#include <analogComp.h>
#include <CyberLib.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(14,15,16,17,18,19);
unsigned int Rp = 4274; // сопротивление резистора заряда конденсатора в kОмах
volatile unsigned int T = 0; // время заряда конд. плюс входная емкость плюс время виполнения команд
volatile float C = 0.0; // вычесленное значение емкости
volatile float T2 = 0.0; // среднее значение времени заряда конд. 
               
  void Timer1_Init( void )  // Timer/Counter 1 initialization
   {
    TCNT1 = 0;
    TCCR1A = 0;  // Bits: COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
    TCCR1B = 0; // Bits: ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
    TCCR1C = 0; // Bits: FOC1A FOC1B - - - - - -
    TIMSK1 = 0; // Bits: - - ICIE1 - - OCIE1B OCIE1A TOIE1
    TIFR1 = 0;  // Bits: – – ICF1 – - OCF1B OCF1A TOV1
   }

void setup() 
{
 lcd.begin(16,2);
 D12_Out; // назначаем D12 на выход 
 D12_High; // на D12 устанавливаем 1  (плюс конденсатора)  
 D8_Out; // назначаем D8 на выход 
 D8_Low; // на D8 устанавливаем 0  (минус конденсатора) 
 
 cli(); // Global disable interrupts
 Timer1_Init(); // Timer/Counter 1 initialization
 TIMSK0 &= ~(1 << TOIE0);   //  Disable Timer 0.
 TIMSK2 &= ~(1 << TOIE2);   //  Disable Timer 2.
 sei(); // Global anable interrupts
 ADCSRA = 0; // Disable ADC
 PRR = B10010111; // Disable USART0, TWI, SPI
}

void loop() 
{   
  for (int i=0; i<1000; i++)
  {
       D9_Out; // назначаем D9 на выход
       D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
       // задержка на разряд конд.
       TCCR1B = (1<<CS10); // запускаем таймер
       while( TCNT1 < 32000 ){}
       TCCR1B = 0; //останавливаем таймер
       TCNT1 = 0; // сброс счетчика
    
       D9_In; // делаем D9 входом, что б не мишать измерениям
       // маленкая пауза
       TCCR1B = (1<<CS10); // запускаем таймер.
       while( TCNT1 < 1840 ){}
       TCCR1B = 0; //останавливаем таймер
       TCNT1 = 0; // сброс счетчика
       
       analogComparator.setOn(AIN0, AIN1); // компаратор вкл.
       TCCR1B = (1<<CS10); // запускаем таймер
       while((ACSR && (1<<ACO)) == 0){}
       TCCR1B = 0; //останавливаем таймер
       analogComparator.setOff();  // компаратор откл.
       T = TCNT1; // забираем значение таймера
       TCNT1 = 0; // сброс счетчика
       T2 = T2 + T; 
  }
      T2 = T2/1000; // считаем среднее
      C = ((T2 - 5.0)/Rp*1000) / 16; // вычисление емкости в пф.
      // на дисплей
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Capacitance: ");
      lcd.setCursor(0,1);
      lcd.print(C);
      lcd.print(" pF");
}

Подстроечником надо выставить на D7  63.5% от напряжения на D12 относительно D8. D8 - земля, D12 - Vcc. Это для того что бы анулирорать влияние падения напряжения на транзисторах.

nazzik
Offline
Зарегистрирован: 05.08.2013
Всем привет!
Вот полностью рабочий вариант с двумя пределами измерений. Точность на первом +-0,25пФ, на втором +-25пФ. Еще в планах сделать измеритель индуктивности на этом принципе http://eelib.narod.ru/toe/Novg_2.01/15/Ct15-3.htm
 
Схема
 
код
 
#include <analogComp.h>  // библиотека для работы с компаратором
#include <CyberLib.h>   // библиотека для ускореной работы с портами
#include <LiquidCrystal.h> // библиотека для LCD
LiquidCrystal lcd(14,15,16,17,18,19); // инициализация LCD
volatile unsigned int R = 1995; // резистор заряда конд. первого предела
volatile unsigned int T = 0; // время заряда конд. плюс входная емкость плюс время виполнения команд
volatile double C = 0.0; // вычесленное значение емкости
  void Timer1_Init( void )  // Timer/Counter 1 initialization
   {
    TCNT1 = 0;
    TCCR1A = 0; // Bits: COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
    TCCR1B = 0; // Bits: ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
    TCCR1C = 0; // Bits: FOC1A FOC1B - - - - - -
    TIMSK1 = 0; // Bits: - - ICIE1 - - OCIE1B OCIE1A TOIE1
    TIFR1 = 0;  // Bits: – – ICF1 – - OCF1B OCF1A TOV1
   }
volatile double calib = 122.0; // значение Т без конденсатора (калибрация)
void setup() 
{
 lcd.begin(16,2); // вкл. LCD
 D8_Out; // назначаем D8 на выход 
 D8_Low; // на D8 устанавливаем 0  (минус конденсатора)
 D12_Out; // назначаем D12 на выход
 D12_High; // на D12 устанавливаем 1  (заряд конд. резистором первого предела)
 D1_Out; // назначаем D1 на выход
 D1_High; // на D1 устанавливаем 1  (заряд конд. резистором второго предела)
 cli(); // Global disable interrupts
 Timer1_Init(); // Timer/Counter 1 initialization
 TIMSK0 &= ~(1 << TOIE0);   //  Disable Timer 0.
 TIMSK2 &= ~(1 << TOIE2);   //  Disable Timer 2.
 sei(); // Global anable interrupts
 ADCSRA = 0; // Disable ADC
 PRR = B10010111; // Disable USART0, TWI, SPI
}

void loop() 
{  
       D9_Out; // назначаем D9 на выход
       D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
    for (int i=0; i<250; i++) // ждем пока разрядится конд. 1 cек
     {
       TCCR1B = (1<<CS10); // запускаем таймер Fxtal/1
       while( TCNT1 < 64000 ){}
       TCCR1B = 0; //останавливаем таймер
       TCNT1 = 0; // сброс счетчика
     }     
       D9_In; // делаем D9 входом, что б не мишать измерениям
       analogComparator.setOn(AIN0, AIN1); // компаратор вкл.
       TCCR1B = (1<<CS11); // запускаем таймер Fxtal/8
       while((((ACSR && (1<<ACO)) == 0))&&(TCNT1<=65530)){} // ждем пока зарядится конд.
       TCCR1B = 0; //останавливаем таймер
       analogComparator.setOff();  // компаратор выкл.
       T = TCNT1; // забираем значение таймера
       TCNT1 = 0; // сброс счетчика   
      C = ((T - calib)/R*1000)/2; // вычисление емкости в пф.
      
       lcd.clear();
       lcd.setCursor(0,0);
      
        if (C >= 14001) // выбираем придел измерений
        {
          D1_Low;
          R = 20;
          calib = 6.0;
          lcd.print("Range 1,4uF");
          lcd.setCursor(0,1);
          lcd.print(C/1000);
          lcd.print("nF ");
         // lcd.print(T); 
        }

       if ( C <= 14000) // выбираем придел измерений
       {
          D1_High;
          R = 1995;
          calib = 122.0;
          lcd.print("Range 14nF");
          lcd.setCursor(0,1);
          lcd.print(C);
          lcd.print("pF ");
         // lcd.print(T);
        }     
} 

dtvims , вам отдельное спасибо!

 

dtvims
Offline
Зарегистрирован: 26.11.2012

Вам, спасибо. Вы собрали очень простую схему, что я как раз и искал для измерения емкости :). Будет время, соберу себе такой приборчик, только пределаю чисто под AVR (без arduino), компактнее получиться. 

Именно в электронике я не силен, потому ищу готовые схемы, а вот код под себя подправить без проблем :)

nazzik
Offline
Зарегистрирован: 05.08.2013

А у меня все наоборот! :) Я и буду делать отдельную плату и корпус. На ATmaga8 под smd.

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

http://www.ebay.com/itm/New-Transistor-Tester-Capacitor-ESR-Inductance-R...

Делайте только корпус- дешевле выйдет.

Кроме кондёров меряет всё!

На борту МЕГА328, smd

Если без ESR, старый вариант на ATmaga8 и выводных резисторах, ещё дешевле.

Где-то на форумах народ прошивки пишет.

dtvims
Offline
Зарегистрирован: 26.11.2012

С таким же успехом, можно купить и дешевенький мультиметр с такой функцией (всего в 2 раза дороже предложенной китайской поделки). Только, мультиметр как правило уже есть, но без данной функции. Во-вторых, сделать самостоятельно по данной схеме обойдется не более 300р, если не покупать детали в чип и дипе. И наконец, гораздо приятнее сделать это самому.