реклама на сайте
подробности

 
 
5 страниц V  < 1 2 3 4 5 >  
Reply to this topicStart new topic
> Измеритель уровня топлива, Первый проект на AVR
Vladimir Chekin
сообщение Mar 26 2007, 09:54
Сообщение #31


Участник
*

Группа: Новичок
Сообщений: 29
Регистрация: 16-03-07
Из: МО, г.Балашиха
Пользователь №: 26 210



Из буфера интегратора ничего выкидывать не надо. Фильтр мин/макс организуется дополнительно.

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

Код
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 искомое


Сообщение отредактировал Vladimir Chekin - Mar 26 2007, 09:56
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 26 2007, 12:31
Сообщение #32


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Если резистор не трогать, то показания АЦП теперь стоят как вкопаные, но стоит его тронуть и значения начинают скакать sad.gif думаю из-за дребезга... Может просто поставить RC цепочку секунды на две?
И еще остается открытым вопрос с калибровкой. Как её организовать?
Go to the top of the page
 
+Quote Post
Demeny
сообщение Mar 26 2007, 13:13
Сообщение #33


Знающий
****

Группа: Свой
Сообщений: 648
Регистрация: 11-02-06
Из: Санкт-Петербург
Пользователь №: 14 237



Цитата(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


--------------------
Сделано в Китае. Упаковано в России.
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 27 2007, 14:30
Сообщение #34


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Цитата
Составляем две таблицы равной длины. В одной храним показания АЦП, в другой "литры". Заполняем таблицу опытным путём - от пустого бака к полному.


Прикрутил я к своему "девайсу" кнопочку и теперь если при включении питания удерживать кнопку, то попадаем в режим калибровки smile.gif в этом режиме заполняется массив в eeprom из N значений, которые соответствуют литрам (от 0 до N-1). Вроде все корректно заполняется.
Только как теперь этот массив использовать? На индикаторе хочу получить целое кол-во литров. Еще нужно предусмотреть какое-то округление до целой части, т.е. если значение АЦП соответсвует 13,6 литрам, то на индикатор выводилось бы 14, а если 13,4 то 13. Поможете? cheers.gif
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 29 2007, 21:11
Сообщение #35


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Собрал я свой измеритель и окончательно убедился, что датчик в виде поплавка с резистором абсолютно не подходит sad.gif
Наверное нужно сооружать в баке конденсатор и мерять его емкость.

Подскажите наиболее простой вариант реализации.
Go to the top of the page
 
+Quote Post
Vladimir Chekin
сообщение Mar 30 2007, 01:18
Сообщение #36


Участник
*

Группа: Новичок
Сообщений: 29
Регистрация: 16-03-07
Из: МО, г.Балашиха
Пользователь №: 26 210



Цитата
датчик в виде поплавка с резистором абсолютно не подходит


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

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


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

Рекомендованный программный фильтр "мин/макс" делал?
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 30 2007, 08:26
Сообщение #37


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Вот так провожу измерение

Код
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
Go to the top of the page
 
+Quote Post
Vladimir Chekin
сообщение Mar 30 2007, 09:31
Сообщение #38


Участник
*

Группа: Новичок
Сообщений: 29
Регистрация: 16-03-07
Из: МО, г.Балашиха
Пользователь №: 26 210



Я задавал вопросы про времена, ты привёл код. Как по этому коду мне получить ответы? Не зная тактовой частоты твоего камня, да и АВР я не знаю, поэтому участок кода работы с АЦП проверить не могу, может знатоки АВР проверят. Так что, мои вопросы остались без ответа.

По проге. На первый взгляд вроде всё правильно. На данном этапе это главное, а красота придёт с опытом. Навскидку, в твоей проге
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);
}


>> С пузырьковой сортировкой пробывал, но что-то не заработало.
Не заработало что? Я привёл полностью рабочий код. Надо было просто скопировать его в свою прогу и всё.
Go to the top of the page
 
+Quote Post
muravei
сообщение Mar 30 2007, 10:07
Сообщение #39


Гуру
******

Группа: Свой
Сообщений: 2 538
Регистрация: 13-08-05
Пользователь №: 7 591



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

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

А "Схемотехника" чем не угодила? Или надо самостоятельно на грабли наступать?
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 30 2007, 10:29
Сообщение #40


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



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
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 30 2007, 12:02
Сообщение #41


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Получилась у меня пузырьковая сортировка! 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.

Сообщение отредактировал alex2103 - Mar 30 2007, 12:02
Go to the top of the page
 
+Quote Post
muravei
сообщение Mar 30 2007, 12:16
Сообщение #42


Гуру
******

Группа: Свой
Сообщений: 2 538
Регистрация: 13-08-05
Пользователь №: 7 591



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

Главное, чтобы грабли не были детскими... wink.gif
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 30 2007, 12:31
Сообщение #43


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



muravei, ну так и раздел форума для "детей" smile.gif

ОФФ: многим обитателям форума мои вопросы могут показаться очень простыми, на которые даже отвечать не хочется smile.gif Для меня любой ваш ответ - неоценимая помощь в освоении МК!
Когда-то прогуливал лекции по МК, было неинтересно... А теперь сам пытаюсь обучиться, причем не потому, что "надо", а просто для себя...
Go to the top of the page
 
+Quote Post
Vladimir Chekin
сообщение Mar 30 2007, 12:40
Сообщение #44


Участник
*

Группа: Новичок
Сообщений: 29
Регистрация: 16-03-07
Из: МО, г.Балашиха
Пользователь №: 26 210



>> Clock frequency, АDC Clock frequency...
Я оценил юмор smile.gif Мож заодно пришлёшь мне компилятор и симулятор или макет с эмулятором/дебагером, чтоб я смог откомпилить и прогнать твою прогу, чтоб узнать сколько времени между измерениями и выводом на экран на самом деле?

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

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

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

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

Кстати, а что за экран? Судя по "плаванию" в элементарном есть подозрение в корректном написании процедуры преобразования целого в ASCI и собственно вывод. Может поэтому показания "скачат"?
Go to the top of the page
 
+Quote Post
alex2103
сообщение Mar 30 2007, 13:24
Сообщение #45


Частый гость
**

Группа: Свой
Сообщений: 135
Регистрация: 7-03-07
Из: г. Запорожье
Пользователь №: 25 945



Цитата
Хм, у тебя только 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
Go to the top of the page
 
+Quote Post

5 страниц V  < 1 2 3 4 5 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 6th July 2025 - 14:36
Рейтинг@Mail.ru


Страница сгенерированна за 0.01538 секунд с 7
ELECTRONIX ©2004-2016