Ошибка в программе или особенность Протеус?

kolyn
Offline
Зарегистрирован: 18.01.2019

Пытаюсь сделать датчик уровня воды в емкости. Принцип действия основан на измерении емкости конденсатора, который представляет собой медную трубу диам. 15мм (1-я обкладка) и изолированного провода, размещенного внутри этой трубки (2-я обкладка) и погруженного в воду. Емкость датчика меняется от 20pF (пустая) до 1700pF (полная).

Схема

Работает (по моей задумке) так: изначально РВ0, РВ1, РВ2 - выходы  с низким уровнем, датчик С1 разряжен. Перед началом измерения РВ2 переключаем на высокий уровень, а РВ1 и РВ2 на входы компаратора. Через R3 начинается заряд конденсатора. Запускаем таймер Т2 , по прерыванию от компаратора останавливаем. Время пропорционально емкости. R1,R2 - делитель, подает на инвертирующий вход компаратора Uпит/2.

Код ( компилировал в Атмел Студио 8.0)

#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <string.h>
#include <avr/power.h>
#include <util/atomic.h>

uint8_t temp, count, start;
volatile uint8_t c;

#define BAUD_C 101
#define TxD PB4

#define T_START TCCR0B = (1 << CS01) // F_CPU/8
#define T_STOP TCCR0B = 0
//#define T_RESET TCNT0 = 0

ISR(TIM0_COMPA_vect){
	OCR0A += BAUD_C;
	c = 1;
	//T_RESET;
}

void send(uint8_t data) { 
	if (count >= 8) {
		PORTB |= (1<<TxD);
		start = 0; temp = 0; c = 0; count = 0;
		T_STOP;
		OCR0A = 0;
		return;
	}
	if(c == 1) {
		if (start == 0) {
			temp = 0x80;
			start = 1;
			count--;
		}
		else {
			temp = data;
			temp = temp >> count;
			temp = temp << 7;
		}
		switch(temp) {
			case 0x80 : PORTB &= ~(1 << TxD);	break;
			case 0 : PORTB |= (1 << TxD);	break;
		}
		count++;
		c = 0;
	}
}

void send_ch(uint8_t data){
	uint8_t f;
	data = ~data;
	T_START;
	for(f = 0; f < 10; f++){
		while(c == 0);
		send(data);
	}
}

void send_str(char *text){
	while(*text) {
		send_ch(*text++);
	}
}

void itoa(uint16_t n, char s[]) {
	uint8_t i = 0;
	do { s[i++] = n % 10 + '0'; }
	while ((n /= 10) > 0);
	s[i] = '\0';
	// Reversing
	uint8_t j;
	char c;
	for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}

void send_num(char *text, uint16_t n){
	char s[6];
	itoa((uint16_t)n, s);
	send_str(text);
	send_str(s);
}

volatile uint16_t capt;
volatile uint8_t ovf_cnt, measured_flag, ovf_flag;

uint16_t Measure()
{
	DDRB &= ~(1<<PB0);                          //включаем входы компаратора
	DDRB &= ~(1<<PB1);
	_delay_ms(5);                               //даем устаканиться переходным процессам
	TCNT1 = 0;                                  //сбрасываем таймер1
	measured_flag = 0;
	ovf_flag = 0;
	ovf_cnt = 0;
	
	capt = 0;
	//TCCR1 |= (1 << CS12);     // старт таймера1 F_CPU/8
	TCCR1 |= (1 << CS10);                        // старт таймера1 F_CPU
	PORTB |= 1<<PB2;                             // начинаем заряд конденс
	ACSR |= (1<<ACIE);                           //разрешаем прерывание компаратора)
	while (!measured_flag)                     // ждем поднятия флага от обработчика компаратора     
	      {
			capt = ((uint16_t)ovf_cnt) << 8;     //умножаем количество переполнений таймера1 на 256
			capt |= TCNT1;                       //прибавляем то, что на счетчике таймера1
		  }
	ACSR &= ~(1<<ACIE);                          //запрет прерывание компаратора)
    DDRB |= 1<<PB0;                              //входы компаратора ставим выходами
    DDRB |= 1<<PB1;
	PORTB &= ~(1<<PB2);                          // сброс низкий
	return capt;	
}

ISR(TIM1_OVF_vect)                                //обработчик таймера1 : инкрементир. переменную при переполнении
{
	ovf_cnt++;
		if (ovf_cnt == UINT8_MAX)
		{
			ovf_flag = 1;                          //если переполнение - поднимаем флаг
			ovf_cnt = UINT8_MAX - 1;
		}
}

ISR(ANA_COMP_vect)                                 //обработчик  компаратора 
{
	TCCR1 = 0;                                     // останов таймер1
	measured_flag = 1;
}

int main(void){

	DDRB |= (1 << TxD);
	TIMSK |= (1 << OCIE0A);                        // разрешение прерывания таймера0 по совпадению А
	sei();
	DDRB |= 1<<PB0;                                //выход низкий
	DDRB |= 1<<PB1;
	DDRB |= 1<<PB2;
	TIMSK |= (1 <<TOIE1 );                         //разрешаем прерывание по переполнению таймера1
	DIDR0 |= (1<<AIN1D)|(1<<AIN0D);                //откл. цифровых буферов на входах компаратора
	ACSR |= (1<<ACIS0)|(1<<ACIS1);                 //преривание компаратора при смене с 0 на 1
	

	while(1){
		_delay_ms(1000);
		uint16_t a = Measure();                    
		if(!ovf_flag)
		{send_num("Norm:",a);}                      //выводим  верные показания
			else
			{send_num("Over:",a);}                  //Было переполнение ovf_cnt, показания неверные
	//send_num("  A :",(uint16_t)ovf_cnt);
	//send_num("  b :",(uint16_t)TCNT1);
			
	}
}

Пояснения по коду: строки 10-90 - программный ЮАРТ, честно сколипизжен тут. Остальное мое. Пока жду ATtiny решил смоделировать в Протеусе. И все вроде работает, но есть одно НО! В сериал иногда выводятся различные значения, для этого примера в основном выводится

Norm:46802

Но иногда (примерно каждое 10 - 15 значение) выводится другое , например 

Norm:47194 или Norm:46907

Иногда разница показаний доходит до 500. Я так понимаю, модели Протеус не могут допускать таких отклонений и ошибку надо искать в пограмме? Или в Протеусе могут наблюдаться подобные странности? Собственно это и есть вопрос.

Ну о попутно просьба к знающим - может кого не обременит глянуть код и указать на ошибки. Буду очень признателен:))

 

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы ведь это не arduino IDE компилируете? Чем? Или ею?

kolyn
Offline
Зарегистрирован: 18.01.2019

Я выше писал - компилировал в Атмел Студио 8.0

KindMan
Offline
Зарегистрирован: 19.12.2018

kolyn пишет:
модели Протеус не могут

Один раз целый день потратил на поиск ошибки в программе при моделирование в Протеус. В железе проверил - всё норм.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

 

kolyn  ошибок особо не видно

так размышления

а РВ1 и РВ2 на входы компаратора - надо читать как а РВ0 и РВ1 на входы компаратора

111-114 зачем то попали внутрь цикла ожидания

 

SLKH
Offline
Зарегистрирован: 17.08.2015

kolyn пишет:

Пытаюсь сделать датчик уровня воды в емкости. Принцип действия основан на измерении емкости конденсатора, который представляет собой медную трубу диам. 15мм (1-я обкладка) и изолированного провода, размещенного внутри этой трубки (2-я обкладка) и погруженного в воду. Емкость датчика меняется от 20pF (пустая) до 1700pF 

...................
Norm:46802

Но иногда (примерно каждое 10 - 15 значение) выводится другое , например 

Norm:47194 или Norm:46907

Иногда разница показаний доходит до 500.

Ну о попутно просьба к знающим - может кого не обременит глянуть код и указать на ошибки. Буду очень признателен:))

отклонение 500 попугаев от номинала 50тыс - это 1%

Очень приличный результат для простейшего измерителя емкости.

kolyn
Offline
Зарегистрирован: 18.01.2019

Komandir пишет:

111-114 зачем то попали внутрь цикла ожидания

Я их вначале в прерываннии делал, а потом решил перенести в основной цикл. И не те скобки убрал...

Komandir, огромное спасибо!

kolyn
Offline
Зарегистрирован: 18.01.2019

SLKH пишет:

отклонение 500 попугаев от номинала 50тыс - это 1%

Очень приличный результат для простейшего измерителя емкости.

Да в железе меня и 10% устроят, я не об этом.

Протеус создает цифровую модель. А от модели я ожидал 100% повторяемости - если в нее специально не  внесен элемент случайности. 

SLKH
Offline
Зарегистрирован: 17.08.2015

kolyn пишет:

SLKH пишет:

отклонение 500 попугаев от номинала 50тыс - это 1%

Очень приличный результат для простейшего измерителя емкости.

Да в железе меня и 10% устроят, я не об этом.

Протеус создает цифровую модель. А от модели я ожидал 100% повторяемости - если в нее специально не  внесен элемент случайности. 

имхо, если модель аналогового устройства дает 100% повторяемость - модель недостаточно точная

kolyn
Offline
Зарегистрирован: 18.01.2019

Пришли ATtiny85, испытал в железе. Разброс показаний не превышает 1,3%. Результат удовлетворительный применительно к моей задаче.