Прошу помочь дописать программу

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Я не программист, но пришлось для проекта использовать микроконтроллер, выбор пал на ардуино.

Задача достаточно простая. К аналоговому входу подключен резистивный датчик, к PWM выходу - стрелочный индикатор-логометр. Прибор меряет уровень жидкости, который постепенно уменьшается с ее расходом. 

Заготовку кода взял из обучающего видео Джереми Блюма:

int sensePin = 0; 
int OUTPin = 6;  

void setup()
{
   pinMode(OUTPin, OUTPUT);
}
void loop()
{
int val = analogRead(sensePin); 
val = constrain(val, 45, 540);  
int OUTLevel = map(val, 45, 540, 0, 200); 
analogWrite(OUTPin, OUTLevel);  
}

То есть при изменении значения датчика в пределах от 45 до 540 уровень ШИМ пропорционально меняется от 0 до 200

Так все работает, но жидкость в емкости плескается и вместе с ней скачет стрелка. Нужно как-то добавить сглаживание. Мне предложили использовать для этотого следующий метод:

При включении один раз все делается как в приведенном выше коде значение OUTLevel выводится на стрелку и сохраняется для дальнейшего использования. А дальше датчик снова опрашивается, вычисляется OUTLevel_temp и сравнивается с предыдущим значением. Если новое значение больше чем старое, то к старому прибавляется некая константа инерции, которую нужно будет подобрать эксперементально, если меньше - то соответственно эта константа вычитается из старого значения уровня. Результат этого действия выводится на стрелку, а OUTLevel становится равным OUTLevel_temp И так по кругу до бесконечности. Таким образом стрелка за один такт не сможет изменить свое положение больше чем на значение константы инерции. Если уровень меняется резко - например при доливе жидкости, то нужно выключить питание и включить снова, для задания начального уровня.

Но вот написать скетч по этому алгоритму у меня не получается. Кто-нибудь может помочь?

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Вернее не совсем так, "OUTLevel становится равным OUTLevel_temp"  - это не правильно.

OUTLevel становится равным результату вычисления

 

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Что то как то всё сложно. Предлагаю свою версию. Датчик производит замер раз 10 в 1 минуту а потом вычисляет среднее значение и выводит его на стрелку.

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Ну как вариант я это тоже рассматривал, но есть небольшой ньюанс, этот же контроллер будет еще кое что делать, и если делать паузы между измерениями с помощью Delay, то и все сотальные функции будут тормозить

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Забываем про псевдо-многозадачность))))) можно использовать прерывания по таймеру (пожертвовав 2 шим) или реализовать программно.

Tamer
Tamer аватар
Offline
Зарегистрирован: 24.06.2012

Ну можно и без задержки сделать

http://arduino.cc/en/Tutorial/BlinkWithoutDelay

ma1ex
Offline
Зарегистрирован: 11.07.2012

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

 

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Можно и ваш метод использовать. Только осталось разобраться что вы имеете под словом такт?

ma1ex
Offline
Зарегистрирован: 11.07.2012

Ну я имел ввиду за одно измерение

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Нееее!!!!
Одно измерение будет происходить через определённое время или каждое прохождение Loop()?
 

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Ну я даже не знаю :)

Наверное каждое прохождение Loop()

 

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Я думаю что через чур. Вы получите тоже самое что имеете сейчас. Так что лучше каждый раз опрашивать по времени. И ИМХО лучше вычислять среднее значение. Вроде так меньше кода будет. Хотя надо смотреть. Ещё шим задействованы?

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Да задействован еще один шим  на 5 ножке для второго указателя.

И еще настроен таймер для увеличения частоты ШИМ, в setup добавлена строчка:

TCCR0B = TCCR0B & 0b11111000 | 2;

иначе логометры гудят

maksim
Offline
Зарегистрирован: 12.02.2012

Попробуйте так

int sensePin = 0; 
int OUTPin = 6; 
int Delay = 200;
unsigned long millisDelay, vals = 0;

void setup()
{
  pinMode(OUTPin, OUTPUT);
}
void loop()
{
  if(millis() > millisDelay){
    int val = analogRead(sensePin); 
    val = constrain(val, 45, 540);
    vals = vals*9/10+val;
    int OUTLevel = map(vals/10, 45, 540, 0, 200); 
    analogWrite(OUTPin, OUTLevel); 
    millisDelay = millis() + Delay;
  }
}

Инерция будет пропорционально зависить от переменной Delay. Если хотите то вожно сделать однонапрвленную инерцию....

LEVV2006
LEVV2006 аватар
Offline
Зарегистрирован: 15.04.2011

Блин. Почему я плохо знаю программирование(((((
 

#include <MsTimer2.h>
static boolean output = HIGH;
int sensePin = 0; 
int OUTPin = 6;  
int mass[10];
int i=0;
void setup()
{
  pinMode(OUTPin, OUTPUT);
  MsTimer2::set(100, flash_led); //задержка
  MsTimer2::start();
}
void loop()
{  
  if (i==10)
  {
    i=0; 
    int val=0;   
    for(int j=0; j<=9; j++)
      val=val+mass[i];
    analogWrite(OUTPin, val/10);
  }    
}
void flash_led() 
{
  int val=constrain(analogRead(sensePin), 45, 540);
  mass[i] = map(val, 45, 540, 0, 200);
  i++;
}

 

ma1ex
Offline
Зарегистрирован: 11.07.2012

 ОК ребята спасибо, поробую, попозже отпишусь по результатам теста

ma1ex
Offline
Зарегистрирован: 11.07.2012

 maksim а что подразумевается под однаправленной инерцией?

Попробовал пока на столе, в качестве датчика - переменный резистор, в качестве индикатора - светодиод и еще добавил в код вывод значения OUTLevel в COM порт и смотрю на него через терминал.

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

При таком значении Delay примерно 7 секунд уходит на измение от полного уровня до 0

Вроде как все работает, завтра буду пробовать 

maksim
Offline
Зарегистрирован: 12.02.2012

Значит, что сейчас при изменении в любую сторону значение инерционно, а можно например, чтобы при уменьшении значения была инерция, а при увеличении нет. Но я думаю когда речь идет об изменении уровня жидкости, то нужна инерция и на увеличение и на уменьшение.

maksim
Offline
Зарегистрирован: 12.02.2012

Кстати, можно сделать так, чтобы при включении не было наростания т.е. чтобы при включении инерция отсутствовала. Для этого в функцию setup надо добавить строку:

vals = analogRead(sensePin)*10;

 

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Да, я тоже так думаю, она же плещется во все стороны :)

ОК завтра когда со стрелкой буду тестировать, попробую без наростания и с наростанием 

ma1ex
Offline
Зарегистрирован: 11.07.2012

Теперь нужно добавить еще один датчик с указателем и светодиод низкого уровня
Второй датчик сам по себе инерционный и там стрелка не скачет.
При увеличении частоты ШИМа и время инерции уменьшилось, поэтому сделал Delay = 1000.

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

Где то видимо накосячил:

int sensePin = 0;
int OUTPin = 6;
int sensePin2 = 2;
int OUTPin2 = 5;
int dut = 8;
int Delay = 1000;
unsigned long millisDelay, vals = 0;


void setup()
{
  TCCR0B = TCCR0B & 0b11111000 | 2;
  pinMode(OUTPin, OUTPUT);
  pinMode(OUTPin2, OUTPUT);
}
void loop()
{
  if(millis() > millisDelay)
   {
    int val = analogRead(sensePin);
    val = constrain(val, 45, 540);
    vals = vals*9/10+val;
    int OUTLevel = map(vals/10, 45, 540, 30, 200);
    analogWrite(OUTPin, OUTLevel);
    if (OUTLevel >= 157) {digitalWrite(dut, HIGH);} else {digitalWrite(dut, LOW);}
    millisDelay = millis() + Delay;
    int val2 = analogRead(sensePin2);
    val2 = constrain(val2, 150, 988);
    int OUTLevel2 = map(val2, 150, 988, 30, 230);
    analogWrite(OUTPin2, OUTLevel2);
    }
}

 

Tamer
Tamer аватар
Offline
Зарегистрирован: 24.06.2012

Я так понял добавили светодиод dut = 8; но почему то он завязан на показания первого датчика

Если так задумано прошу прощения)

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Да, этот диод для первого датчика. 

Второй- датчик температуры, потом к нему тоже добавлю пару диодов - прогрев и перегрев 

maksim
Offline
Зарегистрирован: 12.02.2012

 Может что не так подключили?

ma1ex
Offline
Зарегистрирован: 11.07.2012

Да вот как раз сижу смотрю...

Собирал пока на макетке, к машине еще не подключал.  

В коде косяков нет? 

maksim
Offline
Зарегистрирован: 12.02.2012

Вроде бы нет, попробуйте так

int sensePin = 0;
int OUTPin = 6;
int sensePin2 = 2;
int OUTPin2 = 5;
int dut = 8;
int DelayLevel = 1000;
int DelayTemp = 500;
unsigned long millisDelayLevel, millisDelayTemp, vals = 0;


void setup()
{
  TCCR0B = TCCR0B & 0b11111000 | 2;
  pinMode(OUTPin, OUTPUT);
  pinMode(OUTPin2, OUTPUT);
}
void loop()
{
  if(millis() > millisDelayLevel)
  {
    int val = analogRead(sensePin);
    val = constrain(val, 45, 540);
    vals = vals*9/10+val;
    int OUTLevel = map(vals/10, 45, 540, 30, 200);
    analogWrite(OUTPin, OUTLevel);
    if (OUTLevel >= 157) {
      digitalWrite(dut, HIGH);
    } 
    else {
      digitalWrite(dut, LOW);
    }
    millisDelayLevel = millis() + DelayLevel;
  }
  
  if(millis() > millisDelayTemp)
  {
    int val2 = analogRead(sensePin2);
    val2 = constrain(val2, 150, 988);
    int OUTLevel2 = map(val2, 150, 988, 30, 230);
    analogWrite(OUTPin2, OUTLevel2);
    millisDelayTemp = millis() + DelayTemp;
  }
}

тут опрос датчиков производится не зависимо друг от друга.

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Хм, видимо каие-то наводки в самой макетке.

Датчик (переменный резистор) у меня один, подключаю его по почереди то к одному входу то к другому и один из входов остается в воздухе. Если его коснуться пальцем - наводка пропадает.  Надо было подтянуть к земле

maksim еще раз спасибо большое за помощь!!!

Попробую на машине - отпишусь.

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Вобщем все отлично!  

Скетч залил, инерцию при старте убрал, delay еще увеличил до 2000. Машину шатал - стрелка стоит как вкопаная. Поеду с работы домой вечером - проверю на ходу. 

 

maksim
Offline
Зарегистрирован: 12.02.2012

ma1ex пишет:

 Хм, видимо каие-то наводки в самой макетке.

Датчик (переменный резистор) у меня один, подключаю его по почереди то к одному входу то к другому и один из входов остается в воздухе. Если его коснуться пальцем - наводка пропадает.  Надо было подтянуть к земле

Естественно, когда вывод в воздухе значение будет хаотично меняться.

maksim
Offline
Зарегистрирован: 12.02.2012

Так может вместо стрелочных приборов задуматься о цифровых индикаторах? 

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Да не, меня устраивают стрелки :)

Просто поставил приборную панель от другой машины, а там датчик уровня топлива имел другое сопротивление и указатель врал, а указатель температуры вообще информацию получал с мозга в цифровом виде. Пришлось сделать управление этими указателями с отдельного контроллера :)

 

ma1ex
Offline
Зарегистрирован: 11.07.2012

maksim пишет:

Естественно, когда вывод в воздухе значение будет хаотично меняться.

Так в том то и дело что не хаотично, это и сбило меня столку. Кручу резистор и обе стрелки синхронно поднимаются-опускаются.

ma1ex
Offline
Зарегистрирован: 11.07.2012

 Следующий этап - сделать индикатор номера передачи АКПП.

Займусь если получится на следующей неделе, наброски уже есть :)