Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Измеритель уровня топлива
Форум разработчиков электроники ELECTRONIX.ru > Аналоговая и цифровая техника, прикладная электроника > АВТО электроника
Страницы: 1, 2
alex2103
Очень хочется разобраться в МК... Для этого был куплен ATmega8 и поставлена перед собой задача собрать устройство контроля уровня бензина в баке. smile.gif В баке стоит переменный резистор с поплавком, диапазон примерно 0-60 Ом. Зависимость сопротивление/литры неизвестна angry.gif
К МК подключен сдвоенный семисегментный индикатор от старого системного блока (показывал раньше крутые мегагерцы). У этого индикатора выводы общих анодов запараллелены...из-за этого динамической индикации не получилось и индикатор занимает 14 ног smile.gif
Устройство должно мереть падение напряжения на резисторе в баке и выводить результат в литрах на индикатор.
Сам пока написал функцию для вывода числа 0-99 на индикатор.

Подскажите пожалуйста:
1) как организовать подключение резистора к АЦП (с учетом того, что резистор в баке и токи там должны быть маленькие)
2) как интерпретировать значение АЦП с учетом нелинейности сопротивление/литры?
Спасибо.

З.Ы.:не пинайте сильно...это мой первый опыт работы с МК.
alex2103
С подключением датчика вроде все понятно. Нужно сделать делитель и выбрать номиналы сопротивлений такими, чтоб максимальный ток был не больше 10 мА например...
А каким образом мне перевести результат АЦП в литры?
alex2103
неужели никто мне не поможет?
Massi
ну для начала...смотреть какой ток должен быть...это бензобак...искра и привет...больше писать здесь не придется...
а далее стандарт...делитель...фильтр герц на 10...оцифровка....накопление и усреднение....
для перевода...есть процедура калибровки...налей воды...100 литров...спусти 3 литра в банку...считай значения...слей 3 литра...считай значения...и так далее...по другому никак...

и делитель запитывать от высокоточного опорника...ну типа высокоточного...ща блин заклюют...REF19x...и придет к тебе щастя

теперь самое веселое...это питание...оно скачет аки собака...шпильки до 300 в есть...искровые разряды дают до гиг полосу грязи...итак...фильтр мощнейший на вход...с супрессорами и катушками...через резистор цементовый в 10-25 ом..дросселя россыпями ставить...конденсаторов по питанию не жалеть...перед опорниками фильтр...после тоже...сам ставлю типа LQH32...перед питанием меги и после тоже...корпус металл...
alex2103
Massi, калибровку так себе и представлял. Бак всего 38 литров и заливать буду по литру и снимать значения. В итоге получу некую таблицу соответствия результата АЦП и литров. Как потом в проге реализовать эту таблицу? неужели через IF... smile.gif Хотелось бы чтоб на индикатор выводилась челая часть литров, а дробная с округлением до 0,5 литра обозначалась запятой. Можно где-нибудь посмотреть на примеры?

Насчет токов в баке:
В заводской системе они там нехилые. В цепи резистора там бывает до 0,1А и еще есть контакт, который моммутирует лампу на 2Вт (замыкается если меньше 5 литров). Ничего не взрывается (да и взрываться там ИМХО нечему-это отдельный разговор).
Насчет опорного. Нужна ли в такой задаче высокая точность? Что получится если использовать Uпит.?
Прочитав про фильтрацию питания стало страшно smile.gif Вот сейчас на столе лежит автомобильный тахометр/вольтметр и т.д. и питание там на 7805 в стандартной обвязке. Расчитывал сделать также. Это возможно? Где можно подсмотреть примеры готовых решений с питанием для авто?

З.Ы.: извиняюсь что много написАл. Просто тема очень интересна для меня и многое еще непонятно. Надеюсь на помощь!
Massi
можно функцию написать...а поправочные коэфициенты хранить в памяти...прогу тебе никто не напишет кроме тебя самого...помочь с затыком да...а работу твою никто выполнять не станет...идею подбросить можно...реализацию тоже...тоесть куда бежать и где рыть...
тахометр система инерционная...стрелка там тяжелая...она фильтр сама по себе...тахометры на мотиках горят на три пятнадцать...особенно на ижах и днепрах...
и дубовые они...они просто копят импульсы на конденсаторе...посему и 7805 стоит...шумы там по барабану...но 7805 всего 35 в максимум...как повезет...
я тебе уже ответил...цементовый резистор...предохранитель...конденсатор на 1 кВ 10 нан...дроссель
типа PLT09HN2003R0P1B...супресор 1,5КЕ18СА конденсатор пленка на 1 мкф и єлектролит на 470 мкф 50 в...далее дроссель типа CDR27 на 22микрогенри и конденсаторы впаралель 100 мкф и 1 мкф...вот теперь можно и на 7805 подавать...после 7805 конденсатор 50 мкф и 1 мкф керамика...далее дроссель и опять конденсатор 50 мкф...вот теперь можно брать питание...
далее...АЦП надо вывести к 8 разрядам...ибо потом усреднять будет нечего...а это опорник нужен какой нибудь...
все остальное от лукавого...
ибо лучче перебдеть чем недобдеть...
alex2103
Прогу за меня писать не надо, мне самому интересно smile.gif Просто хочется посмотреть чей-то исходник...
Под тахометром я имел ввиду МК устройство (часы, будильник, тахометр и т.д.).
Совет по питанию постараюсь реализовать. Но что-то мне кажется что он уж очень навороченый...у будущего устройства в принципе функция не особо ответсвенная - просто показывать сколько у меня еще в баке бензина.
Что такое супресор? smile.gif
Massi
а хаотичные ресеты и подвисания проца это тоже будет заложено в функции устройства...
супрессор...защитный мощный стабилитрон...СА двуханодный...
Валентиныч
Цитата(alex2103 @ Mar 19 2007, 14:03) *
...у будущего устройства в принципе функция не особо ответсвенная - просто показывать сколько у меня еще в баке бензина.

Если с точностью до 0,5 литра - то, скорее всего, не получится (да и зачем?). При движении авто уровень бензина в баке непостоянен, также будут меняться и показания уровнемера.
Выход - многократные измерения в течение нескольких секунд (мо-быть - десятков секунд) с последующим усреднением значений.
Что касается требований по питанию, то они не так сташны, как описано выше, но проблемы, все таки, могут быть.
Занимаюсь разработкой автоэлектроники много лет (на уровне "для души"), опыт использования AVR показывает, что желательно развязывать бортовую сеть и питание контроллера LC-фильтром с последующей стабилизацией параметрикой. И кренки 78хх - не лучший вариант. Предпочтительнее что-нить более интересное.
muravei
Цитата(alex2103 @ Mar 19 2007, 12:03) *
Прогу за меня писать не надо, мне самому интересно smile.gif Просто хочется посмотреть чей-то исходник...

В "Схемотехнике 1-07" - "Датчик уровня топлива на АВР -микроконтроллере"
Принцип основан на измерении емкости датчика , сравниваются частоты двух RC генераторов на 555 таймерах, образцового и измерит.
Достоинство- ни каких движущихся деталей.
alex2103
muravei, спасибо! Жаль что в сети в свободном доступе только оглавление этого журнала sad.gif Статью так и не получилось найти.
У вас случаем нет ее?
muravei
Цитата(alex2103 @ Mar 20 2007, 09:32) *
У вас случаем нет ее?

Есть, но нет сканера.sad.gif
Схема там простая, можно на пальцах, рисунок конструкции датчика обещан на сайте, но там пока ничего не нашел.
Old1
Цитата(alex2103 @ Mar 20 2007, 10:32) *
... Жаль что в сети в свободном доступе только оглавление этого журнала sad.gif Статью так и не получилось найти.
У вас случаем нет ее?

Схемотехника 2007_01
alex2103
Old1, спасибо огромное, читаю...

Вот так собираюсь сделать питание... Какие будут замечания?
Валентиныч
Цитата(alex2103 @ Mar 20 2007, 15:27) *
Вот так собираюсь сделать питание... Какие будут замечания?

Пожалуй, схема близка к оптимальной.
alex2103
Валентиныч, ОК! Значит сегодня травлю платку smile.gif

Еще вопрос по ИОН. Если верхнее плечо делителя питать от VCC и вход AREF АЦП соединить с VCC, то как я понимаю возможные скачки напряжения не будут влиять на результат АЦП?
Валентиныч
Цитата(alex2103 @ Mar 20 2007, 19:36) *
Если верхнее плечо делителя питать от VCC и вход AREF АЦП соединить с VCC, то как я понимаю возможные скачки напряжения не будут влиять на результат АЦП?

Не стоит AREF цеплять на VCC, лучше использовать внутренний ИОН. На делитель можно подать VCC через дополнительный R, равный сопротивлению делителя. К этой же точке можно прилепить еще одну емкость - получившаяся RC цепочка не будет лишней в цепи питания делителя.
Кроме того, я бы несколько увеличил номинал R1 в Вашей схеме стабилизации питания (ом до 50-100).
alex2103
спаял я платку... подключил вместо датчика в баке переменный резистор и покрутил его руками... Вроде АЦП работает-значения на индикаторе меняются (могу наблюдать значения от 0 до 99, потом старшие разряды не влазят). Не понравилось что даже при 8бит АЦП значение мл. разряда скачут +/- 2 единицы. Так и должно быть? (делитель питается от ACC? а опора используется внутренняя).

Валентиныч, резистор поставил 47Е.

Как произвести калибровку? Индикатор же у меня на 2 разряда... Пока только приходит мысль отсылать результат АЦП через УАРТ на компьютер...но как-то неохочется компьютер в гараж тащить smile.gif Может подскажите другую реализацию? Например при нажатии кнопки записать округленное значение АЦП в епром, а потом считать все эти значение программатором? Можно такое реализовать?
Oldring
Цитата(alex2103 @ Mar 22 2007, 23:03) *
Не понравилось что даже при 8бит АЦП значение мл. разряда скачут +/- 2 единицы. Так и должно быть? (делитель питается от ACC? а опора используется внутренняя).


При аккуратно спроектированной схеме и правильно написанной программе, у ATMega8 на столе шум 10-битного АЦП получается заметно меньше единицы младшего разряда.
alex2103
меня вот такая мысль посетила... Конструктивно датчик уроня топлива есть переменный резистор на оси которого заркеплен рычаг с поплавком. Ход у оськи резистора 0-90 градусов. Бак на 38 литров. Получается что одному литру примерно соответствует 2,4 градуса поворота оси резистора. Вообще реально ли достоверно определить кол-во литров при такой характеристике датчика? Или это пустая трата времени?
Валентиныч
Цитата(alex2103 @ Mar 23 2007, 17:32) *
Конструктивно датчик уроня топлива есть переменный резистор на оси которого заркеплен рычаг с поплавком. Ход у оськи резистора 0-90 градусов. Бак на 38 литров. Получается что одному литру примерно соответствует 2,4 градуса поворота оси резистора. Вообще реально ли достоверно определить кол-во литров при такой характеристике датчика?

Не факт, что характеристика этого потенциометра типа "А". Может быть, и скорее всего, она не линейная. Это связано с нелинейностью электромеханики штатного прибора, отображающего уровень топлива в баке.
alex2103
Валентиныч, изначально в баке был проволочный резистор наверное с логарифмической характеристикой, но я туда приспособлю обычный переменник, т.к. заводского резистора хватает максимум на пару месяцев...потом он рассыпается, витки сползают и т.п.

Вот в CV хотел сделать округление рез-та АЦП...не получилось smile.gif
Без округления вроде все адекватно, но скачет мл. разряд. С округлением вообще непонятно что показывает sad.gif Помогите найти ошибку.
Код
unsigned char t[10];
while (1)
      {
unsigned char out=0;
unsigned char n=0;
unsigned int sum=0;
n=0;
sum=0;
while(n<10)        
        {
        t[n]=read_adc(0); // читаем АЦП
         n++;
         }  
n=0;
while(n<10)
{
    sum+=(unsigned int)t[n];
    n++;
}
out=(unsigned char)sum/10;

        leds(out); //выводим на индикатор
        
        delay_ms(1000);  
           }
vooon
приведу ваш код, немного лучьше форматированный и с моими комментами
Код
unsigned char t[10];
while (1)
{
    unsigned char out=0;
    unsigned char n=0;
    unsigned int sum=0;

    n=0;        // ненужно, и так 0
    sum=0;

    while(n<10) // для этих целей for боьше подходит
    {
        t[n] = read_adc(0); // читаем АЦП
        n++;
    }
    n=0;
    while(n<10) // for(n = 0; n < 10; n++)
    {
        sum+=(unsigned int)t[n]; // приведение типа ненужно, автоматически это сделают
        n++;
    }
    out=(unsigned char)sum/10; // тоже самое

    leds(out);                 //выводим на индикатор

    delay_ms(1000);            // вместо задержки моглибы еще что нибудь сделать, ну да ладно :)
                               // да и лучьше сделать задержку между read_adc()
}
Massi
ставьте фильтр активный на вход...вытянете все разряды...
вначале сигнал получите чистый...ибо будете писать писать...воевать с мельницами...если все проблемы можно решить одним операционником....возьмите даташит на AD629...там есть фильт на 10 50 100 Гц...пощитанный...вместо этого опера ставить AD820...на вход защитный стабилитрон и RC 100 R 50 pF...от ВЧ помех...вытянешь все 10 разрядов...

и от калибровки не уйти...однозначно...
Сергей Борщ
Цитата(Massi @ Mar 24 2007, 09:21) *
ставьте фильтр активный на вход...вытянете все разряды...
вначале сигнал получите чистый...ибо будете писать писать...воевать с мельницами...
Вот получение чистого сигнала с потенциометра с помощью активных фильтров и хитрых операционников как раз и является войной с мельницами, а также пальбой из пушки по воробъям. Чтобы получить нормальные отсчеты с потенциометра необходимо и достаточно обеспечить хорошее питание и грамотную разводку:
Цитата
спаял я платку... подключил вместо датчика в баке переменный резистор и покрутил его руками...
alex2103
vooon, за подправленный код спасибо. Как я понял в моем коде ошибок нет? Я вот думаю может действительно нужно делать задержки между чтением АЦП? Пойду курить даташит...

Massi, операционник нежелателен - места для него не хватает...да и на радиорынок ехать не хочется smile.gif

Сергей Борщ,
Цитата
Чтобы получить нормальные отсчеты с потенциометра необходимо и достаточно обеспечить хорошее питание и грамотную разводку

Питание пытался сделать по совету Massi. Схемка есть на предыдущей странице. Такого питания будет достаточно? Что вы имеете ввиду под грамотной разводкой?
Vladimir Chekin
> Не понравилось что даже при 8бит АЦП значение мл. разряда скачут +/-
> 2 единицы. Так и должно быть?

Ещё одна возможная причина (помимо упомянутого питания): при перемещении движка механического потенциометра из-за дребезга механики вы можете получать случайные, в том числе и краевые, значения АЦП. Наличие программного интегратора в какой-то степени спасает ситуацию, но результат интегрирования и последующего деления однозначно будет искажён этими случайными измерениями, что отразится в гулянии младших разрядов.

Рекомендую циклически пропускать полученные значения через фильтр "минимум/максимум", а уж только затем складывать среднее значение этого фильтра в интегратор. Для начала достаточно буфера на 3 значения и обычной пузырьковой сортировки. Если потенциометр совсем хреновый, то длину буфера можно увеличить.

Данный метод обработки потенциометров был использован в системе "Астролябия", изготовленного под руководством С.Борщ smile.gif
alex2103
Обвешал по питанию всё КМками и мл. разряд вроде устаканился smile.gif

Код
for(n=0;n<10;n++)
        {
        t[n]=read_adc(0); // Измерить напряжение на нулевом входе АЦП (линия РАО порта А)
        }  
for(n=0;n<10;n++)
        {
        sum+=t[n];
        }
out=sum/10; //среднее <--
leds(out);
delay_ms(1000);


по-моему понял почему у меня округление не работает... В out получается дробное число smile.gif как из него получить только целую часть? help.gif
Demeny
Код
out=(unsigned char)sum/10;

Так делать категорически нельзя - именно в этом ошибка. Здесь к типу unsigned char приводится только переменная sum, а не sum/10, как может показаться, то есть от накопленной суммы программа оставит младшие 8 байт, и уже их поделит на 10.
Обойдитесь корректно без деления и дробных чисел. Возьмите фильтр по 16 значениям, и вместо деления на 16 примените сдвиг вправо на 4 разряда.
Код
sum = sum>>4;
out=(unsigned char)sum;

Ну и таймаут между чтениями АЦП сделать обязательно, и анализ считанного значения на диапазон, как советовали выше, просто необходимо.
alex2103
Demeny, спасибо! сделал как вы посоветовали. Теперь среднее правильно считает. Сейчас разбираюсь как выкинуть из буфера минимальные и максимальные значения...
Vladimir Chekin
Из буфера интегратора ничего выкидывать не надо. Фильтр мин/макс организуется дополнительно.

Пример. Конечно коряво, но смысл видно:

Код
uint8_t i, k, temp;
uint8_t filt_res[3];
uint16_t integrator;

for (i=0; i < 16; i++)
{
  for (k=0; k < 3; k++)
  {
    filt_res[k] =  read_adc(0); // читаем АЦП
    delay (xxx);
  }

  // Пузырьковая сортировка
  if (filt_res[0] > filt_res[1])
  {
    temp = filt_res[1];
    filt_res[1] = filt_res[0];
    filt_res[0] = temp;
  }

  if (filt_res[1] > filt_res[2])
  {
    temp = filt_res[2];
    filt_res[2] = filt_res[1];
    filt_res[1] = temp;
  }

  if (filt_res[0] > filt_res[1])
  {
    temp = filt_res[1];
    filt_res[1] = filt_res[0];
    filt_res[0] = temp;
  }

  // В filt_res[1] - среднее (не путать с усреднённым) по величене значение
  integrator += filt_res[1];
}

  temp = (uint8_t)(integrator >> 4); // В temp искомое
alex2103
Если резистор не трогать, то показания АЦП теперь стоят как вкопаные, но стоит его тронуть и значения начинают скакать sad.gif думаю из-за дребезга... Может просто поставить RC цепочку секунды на две?
И еще остается открытым вопрос с калибровкой. Как её организовать?
Demeny
Цитата(alex2103 @ Mar 26 2007, 13:31) *
Если резистор не трогать, то показания АЦП теперь стоят как вкопаные, но стоит его тронуть и значения начинают скакать sad.gif думаю из-за дребезга... Может просто поставить RC цепочку секунды на две?

Это можно сделать и программно. Программным аналогом RC-цепочки можно считать усреднение, он же фильтр низкой частоты, он же апериодическое звено первого порядка. Если постоянную времени RC-цепи принять за Т, то для аналогичного программного эффекта вам нужно усреднять все значения измерения на временном интервале примерно 3*T, то есть в вашем случае около 6 с. Чем больше показаний АЦП за этот интервал вы успеете накопить - тем точнее будет измерение.
Чтобы не хранить огромный массив значений, каждый раз не считать сумму всех значений (если, допустим, вы усредняете по 1024 точкам) , ведь разрядности переменной может не хватить, есть простой программный приём. При усреднении по N точкам достаточно хранить только само СРЕДНЕЕ значение, и на каждом цикле съёма данных с АЦП к этому среднему прибавлять разницу нового и среднего, делённую на N.
Код
..........
Uaverage = Uaverage + (Ucurrent - Uaverage)/N
..........

Если N точек у вас равномерно распределены по временному интервалу 6 секунд, вы получаете классический фильтр с постоянной времени 2 секунды.

Цитата(alex2103 @ Mar 26 2007, 13:31) *
И еще остается открытым вопрос с калибровкой. Как её организовать?

Тоже просто. Составляем две таблицы равной длины. В одной храним показания АЦП, в другой "литры". Заполняем таблицу опытным путём - от пустого бака к полному. Дальше всё решает линейная интерполяция. Чем больше точек вы можете себе позволить хранить в программе - тем точнее будет измерение.
Если же вы примените квадратичную интерполяцию - ну тогда вааще... tort.gif
alex2103
Цитата
Составляем две таблицы равной длины. В одной храним показания АЦП, в другой "литры". Заполняем таблицу опытным путём - от пустого бака к полному.


Прикрутил я к своему "девайсу" кнопочку и теперь если при включении питания удерживать кнопку, то попадаем в режим калибровки smile.gif в этом режиме заполняется массив в eeprom из N значений, которые соответствуют литрам (от 0 до N-1). Вроде все корректно заполняется.
Только как теперь этот массив использовать? На индикаторе хочу получить целое кол-во литров. Еще нужно предусмотреть какое-то округление до целой части, т.е. если значение АЦП соответсвует 13,6 литрам, то на индикатор выводилось бы 14, а если 13,4 то 13. Поможете? cheers.gif
alex2103
Собрал я свой измеритель и окончательно убедился, что датчик в виде поплавка с резистором абсолютно не подходит sad.gif
Наверное нужно сооружать в баке конденсатор и мерять его емкость.

Подскажите наиболее простой вариант реализации.
Vladimir Chekin
Цитата
датчик в виде поплавка с резистором абсолютно не подходит


По какому критерию не подходит? Мож я чего пропустил... Какой в программе период опроса АЦП (время между измерениями)? Какой период вывода инфы на индикатор?

Цитата
Если резистор не трогать, то показания АЦП теперь стоят как вкопаные, но стоит его тронуть и значения начинают скакать


Конкретнее, что значит "скакать"? Вроде бы всё логично, двигаешь резистор, показания индикатора меняются. Что не так?

Рекомендованный программный фильтр "мин/макс" делал?
alex2103
Вот так провожу измерение

Код
unsigned char read_adc(unsigned char adc_input)
{
unsigned char out=0;
unsigned char n=0;
unsigned char i=0;
unsigned int sum=0;

for(i=0;i<16;i++)
{
for(n=0;n<16;n++)
        {
        ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
        // Start the AD conversion
        ADCSRA|=0x40;
        // Wait for the AD conversion to complete
        while ((ADCSRA & 0x10)==0);
        ADCSRA|=0x10;
        t[n]=ADCH;
        delay_us(30);
        }  
for(n=0;n<16;n++)
        {
        sum+=t[n];
        }
sum = sum>>4;
t1[i]=(unsigned char)sum;
}
for(n=0;n<16;n++)
        {
        sum+=t1[n];
        }
        sum = sum>>4;
        out=(unsigned char)sum;


return out;}


Вот так вывожу:
Код

while (1)
      {
unsigned char out=0;
unsigned char n=0;
out=read_adc(0);

for (n=9;n>0;n--)
{
if (out>=kalibr[n]-((kalibr[n]-kalibr[n-1])>>2))
if (out<=kalibr[n]+((kalibr[n+1]-kalibr[n-1])>>2))
leds(n);
}
     }

kalibr хранит значения полученные при калибровке. Не нравится мне конструкция из if, но в силу своей неопытности ничего лучшего не придумал. biggrin.gif

Проблема в том, что 1 литр = 2 градуса поворота резистора. Испытание в баке еще не проводил, но что-то кажется что точность будет никакая...
С пузырьковой сортировкой пробывал, но что-то не заработало. unsure.gif
Vladimir Chekin
Я задавал вопросы про времена, ты привёл код. Как по этому коду мне получить ответы? Не зная тактовой частоты твоего камня, да и АВР я не знаю, поэтому участок кода работы с АЦП проверить не могу, может знатоки АВР проверят. Так что, мои вопросы остались без ответа.

По проге. На первый взгляд вроде всё правильно. На данном этапе это главное, а красота придёт с опытом. Навскидку, в твоей проге
delay_us(30);
Сделай побольше порядка на 3, не микросекунды, а мили. Тогда и появится нужная плавность в показаниях.

Зачем ты заводишь массивы? В данной проге они не нужны совсем. Достаточно накапливать сумму в одном unsigned int sum с последующим делением, как было в моём примере выше.

Показалось мало 16 раз, ты сделал 256. Пусть так. 16 * 16 = 256. Не нужно 2 цикла. Т.к. ты нигде кроме этой процедуры не используешь промежуточный результат после 16 первых "оборотов", то достаточно одного цикла 256 раз с последующим делением на 256 (сдвиг вправо на 8 разрядов). Смысл не изменится.

А это куда вывод?
Код
for (n=9;n>0;n--)
{
if (out>=kalibr[n]-((kalibr[n]-kalibr[n-1])>>2))
if (out<=kalibr[n]+((kalibr[n+1]-kalibr[n-1])>>2))
leds(n);
}


>> С пузырьковой сортировкой пробывал, но что-то не заработало.
Не заработало что? Я привёл полностью рабочий код. Надо было просто скопировать его в свою прогу и всё.
muravei
Цитата(alex2103 @ Mar 29 2007, 22:11) *
Собрал я свой измеритель и окончательно убедился, что датчик в виде поплавка с резистором абсолютно не подходит sad.gif
Наверное нужно сооружать в баке конденсатор и мерять его емкость.

Подскажите наиболее простой вариант реализации.

А "Схемотехника" чем не угодила? Или надо самостоятельно на грабли наступать?
alex2103
Vladimir Chekin , спасибо за внимание к теме smile.gif
Clock frequency : 1,000000 MHz
ADC Clock frequency: 125,000 kHz

Зачем заводил массив не объясню...сам незнаю зачем blink.gif Обязательно исправлю.

Цитата
А это куда вывод?

Это вывод на индикатор целого кол-ва литров.
Если значение АЦП лежит в пределах n-0.25литра<n<n+0.25литра , то на индикатор выводится n.

С пузірьковой сортировкой попробую еще.

muravei, наступание на грабли хороший метод обучения smile.gif

muravei, наступание на грабли хороший метод обучения smile.gif
alex2103
Получилась у меня пузырьковая сортировка! smile.gif
Код
unsigned char i, k, temp;
unsigned char filt_res[3];
unsigned int integrator=0;

for (i=0; i < 16; i++)
{
  for (k=0; k < 3; k++)
  {
    filt_res[k] =  read_adc(0); // ÷èòàåì ÀÖÏ
    delay_ms (10);
  }

  // Ïóçûðüêîâàÿ ñîðòèðîâêà
  if (filt_res[0] > filt_res[1])
  {
    temp = filt_res[1];
    filt_res[1] = filt_res[0];
    filt_res[0] = temp;
  }

  if (filt_res[1] > filt_res[2])
  {
    temp = filt_res[2];
    filt_res[2] = filt_res[1];
    filt_res[1] = temp;
  }

  if (filt_res[0] > filt_res[1])
  {
    temp = filt_res[1];
    filt_res[1] = filt_res[0];
    filt_res[0] = temp;
  }

  //  filt_res[1] - ñðåäíåå (íå ïóòàòü ñ óñðåäí¸ííûì) ïî âåëè÷åíå çíà÷åíèå
  integrator += filt_res[1];
}

  temp = integrator >> 4; // Â temp èñêîìîå


сразу неработало из-за того, что перед началом нового отсчета нужно было обнулить integtator.
muravei
Цитата(alex2103 @ Mar 30 2007, 11:29) *
muravei, наступание на грабли хороший метод обучения smile.gif

Главное, чтобы грабли не были детскими... wink.gif
alex2103
muravei, ну так и раздел форума для "детей" smile.gif

ОФФ: многим обитателям форума мои вопросы могут показаться очень простыми, на которые даже отвечать не хочется smile.gif Для меня любой ваш ответ - неоценимая помощь в освоении МК!
Когда-то прогуливал лекции по МК, было неинтересно... А теперь сам пытаюсь обучиться, причем не потому, что "надо", а просто для себя...
Vladimir Chekin
>> Clock frequency, АDC Clock frequency...
Я оценил юмор smile.gif Мож заодно пришлёшь мне компилятор и симулятор или макет с эмулятором/дебагером, чтоб я смог откомпилить и прогнать твою прогу, чтоб узнать сколько времени между измерениями и выводом на экран на самом деле?

>> Это вывод на индикатор целого кол-ва литров
Хм, у тебя только 9 градаций? Странно, вроде изначально речь шла о 40-литровом. Чего-то я не пойму тогда изначальной затеи.

Пока нет опыта сделать нормальную процедуру калибровки, можно пойти более долгим, менее универсальным, но более простым путём: сперва сделать вывод на индикатор значения отфильрованного АЦП, т.е. out. Наливать в бак по литру и записывать показания индикатора на бумажку.

Затем в программе объявить массив, инициализированный данными с бумажки: uchar table [40] = {x0, x1,... x39};

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

Кстати, а что за экран? Судя по "плаванию" в элементарном есть подозрение в корректном написании процедуры преобразования целого в ASCI и собственно вывод. Может поэтому показания "скачат"?
alex2103
Цитата
Хм, у тебя только 9 градаций? Странно, вроде изначально речь шла о 40-литровом. Чего-то я не пойму тогда изначальной затеи.

9 градаций сделано на время отладки. Потом будет 40.

Цитата
Наливать в бак по литру и записывать показания индикатора на бумажку.

Алгоритм у меня такой же. Только индикатор у меня на 2 символа и out для калибровки я записываю в епром. Налил литр - нажал кнопку, налил еще - нажал. smile.gif

Цитата
В цикле путём сравнения значений таблицы с out находишь номер члена таблицы меньше или больше out, как удобнее, и уже его выводишь на экран.

Вот как это красиво организовать?

Цитата
Кстати, а что за экран? Судя по "плаванию" в элементарном есть подозрение в корректном написании процедуры преобразования целого в ASCI и собственно вывод.


"Экран" от старого системника...на 2 с половиной разряда smile.gif
Вот так с ним работаю:
Код
void leds(char a)
{
unsigned char digits[2];
if(a>=99) // если больше 99, то на индикаторе "Er"-типа ошибка.
{
PORTD=0x86;
PORTB=0x5F;
return;
}
digits[0] =a % 10;
digits[1] =a / 10 % 10;
switch(digits[1])  // в led[] и led1[] храняться коды индикаторов.
{
case 0: PORTD=led[0]; break;
case 1: PORTD=led[1]; break;
case 2: PORTD=led[2]; break;
case 3: PORTD=led[3]; break;
case 4: PORTD=led[4]; break;
case 5: PORTD=led[5]; break;
case 6: PORTD=led[6]; break;
case 7: PORTD=led[7]; break;
case 8: PORTD=led[8]; break;
case 9: PORTD=led[9]; break;
default: PORTD=0xBF;break;
}
switch(digits[0])
{
case 0: PORTB=led1[0]; break;
case 1: PORTB=led1[1]; break;
case 2: PORTB=led1[2]; break;
case 3: PORTB=led1[3]; break;
case 4: PORTB=led1[4]; break;
case 5: PORTB=led1[5]; break;
case 6: PORTB=led1[6]; break;
case 7: PORTB=led1[7]; break;
case 8: PORTB=led1[8]; break;
case 9: PORTB=led1[9]; break;
default: PORTB=0xBF;break;
        }  
}


Еще раз спасибо за содействие! a14.gif
vooon
Цитата(alex2103 @ Mar 30 2007, 14:24) *
Код
...
...
switch(digits[1])  // в led[] и led1[] храняться коды индикаторов.
{
case 0: PORTD=led[0]; break;
case 1: PORTD=led[1]; break;
case 2: PORTD=led[2]; break;
case 3: PORTD=led[3]; break;
case 4: PORTD=led[4]; break;
case 5: PORTD=led[5]; break;
case 6: PORTD=led[6]; break;
case 7: PORTD=led[7]; break;
case 8: PORTD=led[8]; break;
case 9: PORTD=led[9]; break;
default: PORTD=0xBF;break;
}
switch(digits[0])
{
case 0: PORTB=led1[0]; break;
case 1: PORTB=led1[1]; break;
case 2: PORTB=led1[2]; break;
case 3: PORTB=led1[3]; break;
case 4: PORTB=led1[4]; break;
case 5: PORTB=led1[5]; break;
case 6: PORTB=led1[6]; break;
case 7: PORTB=led1[7]; break;
case 8: PORTB=led1[8]; break;
case 9: PORTB=led1[9]; break;
default: PORTB=0xBF;break;
}


не лучьше ли сдалать так:
Код
// старшее знакоместо
if (digits[1] < 10)
  PORTD = led[digits[1]];
else
  PORTD = 0xBF;

// младшее знакоместо
if (digits[0] < 10)
  PORTB = led1[digits[0]];
else
  PORTB = 0xBF;


кстати зачем заводить два массива-знакогенератора?
лучше сделать подключение сегментов одинаково на обоих портах.
Vladimir Chekin
>> Вот как это красиво организовать?
Дык написано ж было... "В цикле путём сравнения значений таблицы с out находишь номер члена таблицы меньше или больше out, как удобнее, и уже его выводишь на экран." Или надо код написать? Может стоит хотя б какую-нить книжку по Си почитать, там обычно примеров разных циклов предостаточно. В книгах однозначно основы разжеваны куда более чётко и методично, чем наши несвязные советы.

По процедуре вывода, сорри, был неправ, вроде бы работать должно. Про оптимизацию кода уже подсказали выше.

После увеличения паузы между измерениями и фильтра "мин/макс" изменилось ли что-то? Или всё равно показания скачат?
alex2103
Цитата
После увеличения паузы между измерениями и фильтра "мин/макс" изменилось ли что-то? Или всё равно показания скачат?

С показаниями все отлично! Спасибо.
Цитата
Может стоит хотя б какую-нить книжку по Си почитать, там обычно примеров разных циклов предостаточно.

Читаю Шпак Ю.А. Программирование на языке С для AVR и PIC микроконтроллеров.

Наверное ненадолго я перестану вас мучать глупыми вопросами...на выходных доделаю датчик и проведу эксперимент, сниму зависимость литры/ацп...

Кстати никто не подскажет как поведет себя пепроволочный переменный резистор в баке? Бензин резистивный слой не погубит?
alex2103
Прикрутил я переменник СП-3 smile.gif Качесто сего резистора неприятно удивило...показывает все что хочет. Все-таки надо датчик какой-то хитрый делать. Либо емкостный, либо кучу герконов с резисторами smile.gif От поплавка с резистором получается Указатель, а не Измеритель sad.gif
sensor_ua
Недавно видел схему простого емкостного уровнемера - идея датчика следующая - (генератор на 555) задающий конденсатор представлят собой цепочку последовательнго включенных конденсаторов, располагаемых на планке, ну а с другой стороны отводы типа иголочек.
И мне кажется, что опорный генератор (конденсатор) нужен, если его пластина также есть часть сенсора, но в неосушаемой области.
Посмотрите по линкам - может что покажется интересным
http://www.merl.com/projects/iGlassware/
http://www.discovercircuits.com/PDF-FILES/capgage.pdf
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.