"В предыдущей серии" было выяснено, что основной датчик топлива не врёт. Подозрения пали на дополнительный. Разобрал, протер, прозвонил, собрал. Тоже не врёт. Есть одна особенность: сама полоска с сопротивлениями на нём расположена ПОД МЕТАЛЛИЧЕСКОЙ КРЫШКОЙ, поэтому там действительно есть грязь!

Полез смотреть схемы:

Опытным путем определил, что А15 - это земля, А18 - примерно +5в, а с А16 и с А17 снимаются напряжения. Включил зажигание, замеряю напряжение между землей и A16, смотрю на табличку:

Смотрю на индикатор, снова на табличку, снова на индикатор и О НЕТ, ПРИБОРНАЯ ПАНЕЛЬ ОТ 2WD!!
Как так получилось и почему - неясно. Может быть, потому что машина конструктор, может быть предыдущий хозяин хотел панель с multivision. Так или иначе - "я его слепила из того что было"
Поиски того, в чем отличия приборной панели от 2wd от приборной панели от 4wd ни к чему не привели. На форуме увидел сообщения людей с такой же проблемой. Если взглянуть на табличку, то можно увидеть, что нет никакой линейной зависимости, соответсвенно что-то совсем простое спаять не получится. Но искать приборку 4wd, дорестайловую, да еще и с multivision как-то не особо хотелось. Если кратко, то нужно было снимать напряжения с контактов A16 и c A17 (двух датчиков) и выдавать третье напряжение согласно табличке.
Недолго думая заказал
Arduino Duemilanove, к ней LCD на 4 строчки по 20 символов, arduino sensor shield v5, два датчика напряжения, которые работают со значениями от милливольт до 25в, плату с просверленными дырочками, провода. Всё заказывал в магазине dvrobot.ru. По деньгам вышло около 2300р. Если Вам кажется, что цель не оправдывает средства, то вот Вам перпектива: подключение к диагностическому разъему OBD-II и считывание по K-Line чего угодно. Примерно так, как это сделал
человек на Subaru 1998.
Вкратце про ардуино: имеет 14 цифровых входов и 6 аналоговых. Напряжение, которые можно вывести на цифровой выход равняется как раз 5 вольтам

На два из аналоговых входа я повесил датчики напряжения.
Так как сопротивление реостатов в родных датчиках топлива максимум равняется 200 Ом, то я поехал и купил штук 15 подстроечных резисторов такого же номинала, диоды у меня уже были. В итоге спаял следующую схему:

Дальше я разбирался с arduino, в частности как всё выводить на экранчик. Решено было, что определять кол-во топлива надо по сумме напряжений с двух датчиков, то есть 9в максимум (в теории). На экранчике я хотел аналогичную полосочку-индикатор уровня топлива. Для этого пришлось рисовать свои 8 спецсимволов - кусочков одного рисунка

Получилось вот что:

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

На плате ещё нет вторых диодов, потому что я про них забыл!
Дальше было вот что: снял я приборную панель, номер у неё оказался
32010 (боюсь соврать, номер точно не помню, но панель от sv50). Разобрал,
всё зафотал. Так что
если кому нужны подробные фотографии внутренностей приборной панели с мултивижн, пишите!Рядом с разъемом A:

С 16ой ножки (с основного датчика) дорожка идет на ёмкость С118, резистор R146 и R150 и на ещё одну ёмкость С13..
(наверно тут 132, но история об этом умалчивает). Видно, что япы оставили место для аналогичных компонентов: С112, R142, R151, C133, еще справа вроде F103, но там уже дорожку не разглядеть, поэтому без схемы ничего нельзя точно сказать.
Чтобы резать как можно меньше проводов, я припаялся прям к ножкам на плате:

Весь оголённый страх закрылся термоусадочными трубками, а то мало ли.
Слева направо: А15 - земля, А16 - первый датчик топлива, A17 - второй
(ножка просто висит в воздухе).Таким образом отрезать у самого разъёма мне придется только А16.
Короче если представить схематично, то будет вот так:

Дальше я всё собрал на коленке, начал тестировать и УРА, ОНО ИЗМЕНЯЕТСЯ!!
Пустой бак:

Бак заполнен на 62%

:

На 83% :

Один нюанс - так как я пока не придумал, как питать ардуину в машине, то питается она пока от нетбука

По-хорошему, надо бы ардуине давать 10-12в, а не 5 от usb. Из-за низкого напряжения питания, ардуина не могёт обеспечить нужное напряжение на своих выходах, отсюда и неточности. В дальшейшем планирую взять какой-нибудь dc-dc преобразователь, а то пишут, что при напряжении >12в ардуина греется и может выйти из строя

(хотя предел у неё - 20в).
Итак, начинаем собирать более-менее по-человечески: ардуина нашла себе место возле монтажного блока со стороны водителя:
Ведь там же рядом диагностический разъём!Время тест-драйва
После того, как завел двигатель, напряжение немного упало: стало 5.55v, написало, что 55% и 33.53л.
Проехал вокруг стоянки 4,5км, показания немного изменились: 5.46v, 54%, 32.75л. Посчитав, что расход получился 17л / 100км, а также учтя все погрешности, делаем вывод, что оно работает!
Теперь хочу подцепиться к диагностическому разъему, чтобы считало расход по-русски - в литрах на 100км. А может там еще какие плюшки обнаружатся. Например парктроник самодельный. На dvrobot.ru есть симпатичный датчик за 220р - от 2 до 450см, угол 15 градусов.
К тому же, в совсех дальних планах - повесить на ардуину gsm/gprs shield, понавешать на неё всяких датчиков движения, пусть работает еще как сигналка.
Щас я больше обеспокоен питанием ардуины в машине, а также тем, как закрепить мой экранчик. Очень хочется вот так (чуть правее, чтобы по центру было):

Пока еще не знаю, как
UPDATE от 07.08.2012
Фотографии, как всё уложилось и планы на будущееПитаться ардуина стала от прикуривателя через кренку. Вот она, повесил её на радиатор (просто потому, что он у меня был

)

Общий вид окрестностей монтажного блока со стороны водителя:

Плата с подстроечными резисторами и диодами спряталась сюда:

Вместе с ней там нашел себе место usb-кабелёк, вдруг нужно будет что-то залить:

Экранчик крепится на держалку для смартфонов:

Окончательный вариант

:
Теперь о планахВедутся переговоры с dvrobot.ru о возможности привезти gps-модуль в Хабаровск. Параллельно с этим думается, как ардуина может выходит в интернет (gsm/gprs шилд, телефон, usb-модем

)
Думается медленно

НО! имея gps модуль можно определять скорость => можно доделать расходометр. К тому же, если суметь послать координаты машины через инет, то можно написать программку, которая бы их ловила и, используя API яндекс.карт, строила бы маршрут на карте. В общем-то самодельный gps-трекер. Толкьо стоят они от 7 тысяч, а самодельный будет стоить 3-4.
Но тогда придется прятать все провода питания, чтобы угонщик первым делом gps-трекер не выключил. Но это всё в будущем

С нуля написанный код
Нету среди доступных bbcod'ов подсветки с++ синтаксиса, нельзя прикрепить ни pde, ни txt-файл, поэтому вот так вот сплошным текстомКоннектор rj45 обжался хреново из-за старой обжимки - она смяла крайнюю ножку чуть вбок. Поэтому один из проводов как бы оборван. Приходится он на девятый пин. То есть, когда надо включить 9 пин, напряжение на выходе = 0. Таким образом, если надо включить 9 пин, включается десятый (показывает меньше литров, чем есть). Такой вот аппаратный баг ) Код:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);
int pinTurnedOn=2; //for starting
//special symbols: used for displaying fuel bar
uint8_t stripe_begining_full [8] = {0x1f,0x10,0x17,0x17,0x17,0x10,0x1f};
uint8_t stripe_begining_empty [8] = {0x1f,0x10,0x15,0x12,0x15,0x10,0x1f};
uint8_t stripe_midde_full [8] = {0x1f,0x0,0x1f,0x1f,0x1f,0x0,0x1f};
uint8_t stripe_midde_empty [8] = {0x1f,0x0,0x0,0x0,0x0,0x0,0x1f};
uint8_t stripe_midde_warning [8] = {0x1f,0x4,0x4,0x4,0x0,0x4,0x1f};
uint8_t stripe_midde_happy [8] = {0x1f,0x0,0x11,0x4,0x13,0x0,0x1f};
uint8_t stripe_end_full [8] = {0x1f,0x1,0x11,0x5,0x19,0x1,0x1f};
uint8_t stripe_end_empty [8] = {0x1f,0x1,0x1,0x1,0x1,0x1,0x1f};
void setup()
{
lcd.init(); // initialize the lcd
lcd.backlight();
lcd.createChar(0,stripe_begining_empty);
lcd.createChar(1,stripe_begining_full);
lcd.createChar(2,stripe_midde_full );
lcd.createChar(3,stripe_midde_empty );
lcd.createChar(4,stripe_midde_warning);
lcd.createChar(5,stripe_midde_happy);
lcd.createChar(6,stripe_end_full);
lcd.createChar(7,stripe_end_empty);
//0 and 1st pins reserved for TX - RX
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
}
void loop()
{
float voltage_sum = 0;
float max_voltage = 9.5;
/*
//EMULATING GETTING SENSOR DATA
while (voltage_sum<=max_voltage)
{
DisplayFuelData(0, voltage_sum, max_voltage, 8);
delay(500);
// lcd.clear();
digitalWrite(pinTurnedOn, LOW);
pinTurnedOn = GetPinNumber(voltage_sum);
if (pinTurnedOn==9){pinTurnedOn=10;} //bug, lol
digitalWrite(pinTurnedOn, HIGH);
lcd.setCursor(0,3);
lcd.print("Pin is on: ");
lcd.print(pinTurnedOn);lcd.print(" ");
voltage_sum+=0.02;
}
*/
// /*
///////////////////
//FRONT-END VERSION
////////////////////
// turning off previous pin
digitalWrite(pinTurnedOn, LOW);
//getting sensors data
float sum1,sum2,sum3;
sum1 = GetSensorsDataSum(0,2);
delay(200);
sum2 = GetSensorsDataSum(0,2);
delay(200);
sum3 = GetSensorsDataSum(0,2);
voltage_sum = (sum1+sum2+sum3) / 3;
pinTurnedOn = GetPinNumber(voltage_sum); //analyzing sensor data, choosing new pin
if (pinTurnedOn==9){pinTurnedOn=10;} //bug, lol
digitalWrite(pinTurnedOn, HIGH); //turning it on
lcd.setCursor(0,3);
lcd.print("Pin is on: ");
lcd.print(pinTurnedOn);lcd.print(" ");
//displaying additional info
DisplayFuelData(0, voltage_sum, max_voltage, 8);
delay (7000); //waiting 7 seconds
// */
}
float GetSensorsDataSum (int first_sensor_pin, int second_sensor_pin)
{
float U1 = analogRead(first_sensor_pin)/40.92;
float U2 = analogRead(second_sensor_pin)/40.92;
return U1+U2;
}
void DisplayFuelData(int row, float voltage_sum, float max_voltage, int numberOfCells)
{
int column=0;
lcd.setCursor(column,row);
////////////////////////////
//STARTING DRAWING FUEL BAR
////////////////////////////
float one_cell_voltage;
if (numberOfCells!=0)
{ one_cell_voltage = max_voltage/numberOfCells;} //8 cells
else {lcd.setCursor(0,3); lcd.print ("DIVISION BY ZERO!!"); return;}
int full_cells;
if (one_cell_voltage!=0)
{ full_cells = (int)(voltage_sum/one_cell_voltage);}
else {lcd.setCursor(0,3); lcd.print ("DIVISION BY ZERO!!"); return;}
////////////
//PERCENTAGE
////////////
int percents;
if (max_voltage!=0)
{ percents = (int) ((voltage_sum*100)/max_voltage);}
else {lcd.setCursor(0,3); lcd.print ("DIVISION BY ZERO!!"); return;}
if (percents <= 10 ) //empty
{
lcd.write(0);
lcd.setCursor(1,row);
lcd.print("\4\3\3\3\3\3\7");
lcd.setCursor(2,2); lcd.print("I drew empty bar");
}
if (percents >= 85)//full
{ lcd.print("\1\2\2\2\2\2\5\6"); lcd.setCursor(2,2); lcd.print("I drew full bar");}
if ((percents>10)&&(percents<85))
{
lcd.write(1); //first cell
column++;
lcd.setCursor(column,row);
for(int i=0; i<numberOfCells-2;i++) //-2, first and last cell
{
if (i<full_cells-1){lcd.write(2);}
else {lcd.write(3);}
column++;
lcd.setCursor(column,row);
}
lcd.write(7); //last cell
lcd.setCursor(2,2); lcd.print("I drew normal bar");
}
//FINISHED DRAWING FUEL BAR
//SHOWIG PERCENTAGE AFTER BAR
lcd.setCursor(numberOfCells,row);
lcd.print(percents);
lcd.print("% ");
/////////
//VOLTAGE
/////////
lcd.print(voltage_sum);
lcd.print("v ");
////////////////////
//CAPACITY IN LITRES
/////////////////////
lcd.setCursor(0,row+1);
float litres =(voltage_sum / (max_voltage/60)); //60 litres maximum
lcd.print(litres); lcd.print(" litres");
}
int GetPinNumber(float sum)
{
int pin_number = 0;
if (sum>=8.71) {pin_number = 2;} //10 сегментов
if ((sum<8.71)&&(sum>=7.95)) {pin_number = 3;} //9 segments
if ((sum<7.95)&&(sum>=7.19)) {pin_number = 4;} //8 segments
if ((sum<7.19)&&(sum>=6.42)) {pin_number = 5;} //7 segments
if ((sum<6.42)&&(sum>=5.66)) {pin_number = 6;} //6 segments
if ((sum<5.66)&&(sum>=4.9)) {pin_number = 7;} //5 segments
if ((sum<4.9)&&(sum>=4.5)) {pin_number = 8;} //4 segments
if ((sum<4.5)&&(sum>=3.39)) {pin_number = 9;} //3 segments
if ((sum<3.39)&&(sum>=1.99)) {pin_number = 10;} //2 segments
if ((sum<1.99)&&(sum>=0.58)) {pin_number = 11;} //1 segments
if (sum<0.58) {pin_number = 12;} //0 segments
return pin_number;
}
UPD от 06.11.2012
К вопросу о работоспосоности arduino в морозС наступлением даже небольших похолоданий (-5..0 градусов) стали чаще вылезать такие вот ништяки:

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