-
Вложений: 1
Как точно вычислить температуру со штатного датчика двигателя?
Добрый день! Как вычислить точную температуру с термистора на двигателе? Я снял с него параметры падения напряжения с увеличением температуры - они нелинейны. Собственно, об этом говорят и графики зависимости сопротивления от температуры.
Каким образом (какой формулой) вычислить точное значение температуры в коде ардуины? Линейные приближения дают большую погрешность.
.................................................. .................................................. ...
Чтобы вам не читать все, выкладываю здесь результат.
Подключение к Ардуино ШИМ ключа и остального не рассматриваю, т.к. этого достаточно в других темах. Но если все же будет необходимость - выложу. Система будет затачиваться под мониторинг и регулировку температуры ОЖ, масла ДВС, масла АКПП, масла ГУР и может еще чего.
PHP код:
/*
Программа термоконтроля за системой охлаждения ДВС. Использует плавную регулировку по ШИМ.
Может применяться и в других проектах, где исходные данные будет выдавать термистор (терморезистор).
В качестве исходных данных - 1 проводной температурный датчик (термистор(терморезистор))
двигателя с которого берется информация на штатную приборную панель автомобиля.
Т.к. датчик имеет нелинейную зависимость сопротивления (падения напряжения),
то необходима аппроксимация по заранее известным точкам. Чем выше температура,
тем ниже сопротивление и больше падение напряжения.
Для достоверной работы программы нужно ввести значения проходящего через датчик напряжения при
различных температурах, желательно во всем диапазоне его работы.
За аппроксимацию спасибо SBorovkov.
*/
#include <MyLiquidCrystalRus.h>
#include <avr/pgmspace.h>
#define Temp1Count 10 //Количество точек аппроксимации
#define DestinationEngineTemp 90 //Определяем нужную температуру двигателя
#define EngineTempSensorPin 0 // Аналоговый вход для температурного датчика ОЖ ДВС
#define PowerVentPin 6 //ШИМ выход на вентиляторы основного радиатора ДВС
MyLiquidCrystalRus lcd(12, 11, 10, 5, 4, 3, 2); //Используем ЖК дисплей
//Задаем точки аппроксимации. Первая цифра - разность из 1024 и значения на входе от датчика
//(сделано для того чтобы развернуть график зависимости и сделать так чтобы с ростом температуры значение увеличивалось)
//не переводил в напряжение чтобы не морочиться и оперировать целыми числами с достаточной точностью;
//вторая цифра - значение температуры (заранее измеренное) при данном значении на выходе с датчика.
uint16_t Temp1[Temp1Count][2] PROGMEM = {{0,0}, {471,46}, {655,58}, {713,65}, {772,74}, {775,80}, {850,100}, {864,110}, {874, 120}, {883, 130}};
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("****************");
lcd.setCursor(0,1);
lcd.print("****************");
delay(1000);
}
void loop() {
int i;
int Count = 10; //Количество значений для усреднения
int In = 0; //Начальная точка суммирования
int InSrednee; //Усредненное значение со входа
int PowerAir; //Мощность вентиляторов
uint16_t InTemp; //Входное значение с датчика температуры
uint16_t RealTemp; //Расчетное значение реальной температуры
uint16_t InLeftTemp;
//Начало цикла усреднения значения
for (i = 0; i < Count; i++) {
In = In + analogRead(EngineTempSensorPin);
}
//Конец цикла усреднения значения
InSrednee = In / Count; //Вычисляем среднее значение
InTemp = 1024 - InSrednee; //Переворачиваем график падения напряжения
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp); //Вычисление значения реальной температуры
float VoltIn = (5.00 / 1024.00 * InSrednee); //Переводим входные данные к абсолютному значению напряжения для мониторинга
//Если температура входит в определнные значения - запускаем вентиляторы на определенную мощность.
if (RealTemp >= DestinationEngineTemp - 5 && RealTemp < DestinationEngineTemp + 1) PowerAir = 255 - 42.50 * (DestinationEngineTemp - RealTemp + 1);
else if (RealTemp >= DestinationEngineTemp + 1) PowerAir = 255;
else PowerAir = 0;
analogWrite (PowerVentPin, PowerAir); //Запускаем выход ШИМ на необходимую мощность
int PowerVentPercent = 100.00/255.00*PowerAir; //Вычисляем значение в процентах текущей мощности вентиляторов
//Выводим все что нам нужно на ЖК дисплей
lcd.clear();
lcd.setCursor(0,0);
lcd.print("ВЛТ:");
lcd.setCursor(4,0);
lcd.print(VoltIn); //Входное напряжение с датчика
lcd.setCursor(8,0);
if (VoltIn > 2.70) {
lcd.print(" ТМП:");
lcd.setCursor(13,0);
lcd.print("MIN"); //Ниже минимальной точки аппроксимации
}
else if (VoltIn < 0.85){
lcd.print(" ТМП:");
lcd.setCursor(13,0);
lcd.print("MAX"); //Выше максимальной точки аппроксимации
}
else {
lcd.print(" ТМП:");
lcd.setCursor(13,0);
lcd.print(RealTemp); //Аппроксимированная температура
}
lcd.setCursor(0,1);
lcd.print("МОЩНОСТЬ:");
lcd.setCursor(9,1);
lcd.print(PowerVentPercent); //Мощность вентиляторов
lcd.print("%");
delay(250);
}
Код буду постепенно совершенствовать и увеличивать функционал.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Лучше всего сделать таблицу из нескольких замеров.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Я думал об этом. Но во первых не хотелось бы раздувать код ардуины подобной матрицой значений, а во вторых нет возможности охладить датчик до тех же -20. Как то проще должно быть по моим ощущениям.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
скорее всего, в самом блоке управления двигателем используется кусочно-линейная аппроксимация. То есть берется график зависимости напряжения от температуры, затем он заменяется на ломанную (от количества значений и их выбора зависит точность). Кода - 5 строчек на С (поиск нужного отрезка ломанной+вычисление значения), ломанную хранить - два байта на точку (температура и напряжение), хранить лучше прямо в flash памяти. Займет все это очень немного в результате.
Да, советую использовать целочисленные операции, будет и меньше памяти занимать и работать быстрее.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Можно аппроксимировать экспонентой.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Соглсен, неплохой метод с точки зрения облегчения математики и программного кода.. Но опять же нужно сделать все замеры и в т.ч. при отрицательных температурах, что не совсем удобно в домашних условиях. Я нашел небольшую статью, проливающую свет на математическое моделирования зависимости:
http://www.kit-e.ru/articles/elcomp/2007_6_32.php
Буду сегодня пробовать... Отпишусь о результатах чуть позже.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
По статье что я обозначил выше, результаты неплохие, но все равно расходятся с фактически измеренной кривой. По этой формуле вполне можно аппроксимировать определенные диапазоны. Разве так работают "мозги" машин? Что у них заложена какая-то аппроксимация изначально???
И так ли работают "гаджеты" что ставятся отдельно? И у них аппроксимация?
Конечно можно пойти путем инсталляции цифрового датчика типа DS1820 или аналогового типа LM335, но у полупроводников ограничение 120-125 градусов. А мне нужно увидеть температуры выше, если речь пойдет о температуре масла, воздуха из турбины или температуре выхлопных газов.. В последнем случае будет стоять датчик до 900-1000 градусов.
-
Вложений: 1
Re: Как точно вычислить температуру со штатного датчика двигателя?
Вот графики:
Верхний - реальные замеры с датчика;
Нижний - построение по формуле из статьи с опорным значением на 46 градусах.
Как видно что очень похоже на правду, но чем дальше от опорной температуры - тем больше разбег, поэтому однозначно нужно бить на отрезки и аппроксимировать.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Зачем бить на отрезки? В статье же все черным по белому, всего 1 коэффициент надо найти.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Ну конечно я нашел... еще раз повторюсь, что расчетные отличается от реальных значений.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Только что по приколу попробовал оба вида расчета.
Подключение библиотеки math.h и расчет экспоненты съедает 4к флеша и порядка 250 байт оперативной памяти.
Код:
#include <math.h>
...
uint8_t i;
double d;
double volatile p=0;
d=1.545444342+i;
p=p+exp(d);
if (p==0)
p=1;
}
Выполняется примерно 5300 тактов процессора. А там еще наверняка надо будет выполнить кучу действий, кроме вычисления экспоненты (умножения, деления..).
Код с аппроксимацией 16-битных значений
Код:
#define Temp1Count 5
uint16_t Temp1[Temp1Count][2] PROGMEM =
// первое значение - абсцисса, второе - ордината
{
{0,40},
{5,80},
{26,200},
{42,300},
{70,400},
};
...
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp=5;
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==81)
...
Основное затраченное время - выполнение умножений и делений. Выполняется порядка 350 тактов при 4х попаданиях в цикл (20 тактов на цикл). Съедает порядка 160 байт флеш-памяти, не ест оперативную память.
Тут правда надо четко просчитать, чтобы не было переполнений при умножении, либо вычисление RealTemp делать в int32.
В общем все зависит от необходимой точности и наличия ресурсов.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Цитата:
Сообщение от
SBorovkov
Только что по приколу попробовал оба вида расчета.
Подключение библиотеки math.h и расчет экспоненты съедает 4к флеша и порядка 250 байт оперативной памяти.
Код:
#include <math.h>
...
uint8_t i;
double d;
double volatile p=0;
d=1.545444342+i;
p=p+exp(d);
if (p==0)
p=1;
}
Выполняется примерно 5300 тактов процессора. А там еще наверняка надо будет выполнить кучу действий, кроме вычисления экспоненты (умножения, деления..).
Код с аппроксимацией 16-битных значений
Код:
#define Temp1Count 5
uint16_t Temp1[Temp1Count][2] PROGMEM =
// первое значение - абсцисса, второе - ордината
{
{0,40},
{5,80},
{26,200},
{42,300},
{70,400},
};
...
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp=5;
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==81)
...
Основное затраченное время - выполнение умножений и делений. Выполняется порядка 350 тактов при 4х попаданиях в цикл (20 тактов на цикл). Съедает порядка 160 байт флеш-памяти, не ест оперативную память.
Тут правда надо четко просчитать, чтобы не было переполнений при умножении, либо вычисление RealTemp делать в int32.
В общем все зависит от необходимой точности и наличия ресурсов.
Спасибо огромнейшее! Вечером буду пробовать. Отпишусь о результатах.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Не получается второй скетч запустить...
Компилятор выдает:
In function 'void setup()':
error: expected initializer before 'PROGMEM
Вот полный код:
PHP код:
#define Temp1Count 5
void setup() {
uint16_t Temp1[Temp1Count][2] PROGMEM = {{0,40}, {5,80}, {26,200}, {42,300}, {70,400},};
}
void loop() {
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp=5;
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==81)
}
Где я накосячил? :confused:
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Да и с первой я не совсем понял каким местом ее прикручивать.. Вы уж простите, не гуру я в программировании. Помогите пожалуйста действующим скетчем.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Пропиши
#include <avr/pgmspace.h>
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Ну не выходит "цветок каменный"..
PHP код:
#define Temp1Count 5
#include <avr/pgmspace.h>
int i;
void setup() {
uint16_t Temp1[Temp1Count][2] PROGMEM = {{0,40}, {5,80}, {26,200}, {42,300}, {70,400},};
}
void loop() {
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp=5;
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==81)
}
Матерится:
In function 'void loop()':
error: 'Temp1' was not declared in this scope
Если я пытаюсь прописать в начале Temp1 (int Temp1), то матерится что типа это array и все такое :(
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
порядок такой:
сначала объявляешь константу, потом массив (массив использует константу). И то и другое - вне функций, если собираешься использовать их более чем в одной функции.
Код:
#include <avr/pgmspace.h>
#define Temp1Count 5
uint16_t Temp1[Temp1Count][2] PROGMEM = {{0,40}, {5,80}, {26,200}, {42,300}, {70,400}};
void setup() {
}
void loop() {
...
// тут располагать что угодно, в том числе - аппроксимацию.
}
Еще, мой тебе совет - не объявляй лишних глобальных переменных. И уж точно - не используй глобальные переменные в качестве переменных цикла без большой необходимости.
У каждого идентификатора (переменной, функции...) есть область видимости. Это область, в которой этот идентификатор можно использовать.
К примеру:
...
{
int i;
// тут можно использовать переменную i
}
// а вот тут ее уже нет, ибо скобка закрыта и область видимости вместе с ней.
собственно то, что ты пишешь именно на область видимости и указывает.
In function 'void loop()': error: 'Temp1' was not declared in this scope
Массив Temp1 объявлен в твоем коде внутри функции Setup(), как следствие, вне Setup() этот массив недоступен.
(добавлено)
Ты когда написал после #define и #include (вне функций)
int i;
сделал переменную глобальной. Это означает, что эта переменная существует везде внутри этого модуля. Соответственно, изменение этой переменной в любой функции поменяет ее значение. Такое можно делать, если переменная хранит какое-то текущее состояние системы, к примеру, но тогда переменной дают какое-то разумное название:
int CurrentState;
Если же сделать как у тебя написано, то это может привести к ошибке. Нижеприведенный цикл будет выполняться вечно, поскольку переменная i одна и та же для цикла и в функции cаlc:
Код:
int i;
void setup() {
}
void calc(){
i=5;
}
void loop() {
for (i=0;i<10;i++)
calc();
}
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Спасибо SBorovkov, с синтаксисом разобрался. Запустил код. Есть чему учиться. :)
Вывел на серийный порт переменную RealTemp. Число 80 на выходе.
А куда мне подставить значения с аналогового входа 0 чтобы на выходе получить реальную температуру?
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
И по абсциссе и ординате, я так понимаю мне нужно поставить какие-то мои точки аппроксимации? Т.е. например соответствие значения на входе и температуры?
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Подставил значение на:
InTemp = 5.00 / 1024.00 * analogRead(0);
На выходе ( Serial.println(RealTemp); ) какие-то дискретные значения от 40 до 72 с шагом 8.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
В массиве Temp1[Temp1Count][2] PROGMEM = {{0,40}, {5,80}, {26,200}, {42,300}, {70,400}}
находятся соответствия значений для аппроксимации. Для значения 0 результат - 40. Для 5 - 80. И так далее. Соответственно, для входного значения 1, выходное значение должно быть 48. Для 2 - 56, для 5 - 80.
Вообще я бы рекомендовал любые алгоритмы тестировать и отлаживать в каких-нибудь средах разработки (можно не привязанных к микроконтроллерам). Тем более, что С - он и в африке С (wiring - это С с несколькими функциями и макросами). В среде ардуино отсутствует возможность отладки, поэтому в ней невозможно разработать что-либо сложное.
Есть куча проблем, с которыми можно столкнуться: в реализации С для микроконтроллеров AVR отсутствует контроль результата на предмет его попадания в допустимый диапазон значений переменной. К примеру, если написать
uint8_t i; // это восьмибитая беззнаковая переменная. значения 0..255
i=200;
i=i+150;
то i будет равно 94. И никаких ошибок в процессе работы программы не возникнет, ибо ошибки банально некуда выдавать.
Но это еще ладно, такую ситуацию можно предусмотреть и ею пользоваться. А можно обратиться в массив по некорректному индексу:
int16_t ar[10];
uint16_t i=15;
uint16_t j;
j=ar[i];
И эта ситуация, понятная компилятору на стадии компиляции не вызывает предупреждений.
Поэтому очень рекомендую все минимально сложные куски кода отлаживать проходом по коду в отладчике и просмотром переменных.
(добавлено)
В массиве первое значение - считанное значение считанное с датчика (при помощи того же AnalogRead() ), второе - выходное значение температуры.
Да, учти, что при подсчете значения не должно произойти переполнения uint16 - у него максимальное значение 65536. Либо в формуле расчета надо принудительно производить расчет в 32х битах.
Имеется ввиду эта строка:
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
При вычислении (OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp) а конкретно - при вычислении произведения может произойти переполнение через 65535. В Сях тип выражения берется из первого участника выражения.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
SBorovkov, спасибо за информацию.
Честно скажу, большинство я не понял того что вы написали... Не хватает базы, но интуитивно все получилось. :) Единственное, нужно будет все же сделать реальные замеры вплоть до крайних точек температурного диапазона и увеличить до 16-20 точек аппроксимацию.
Ниже текущий код.. может есть у кого что добавить/изменить?
PHP код:
#include <LiquidCrystal.h>
#include <avr/pgmspace.h>
#define Temp1Count 10 //Увеличил до 10 значений
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
int analog = 0; // Аналоговый вход для температурного датчика
int K = 1; //Калибровочный коэффициент по входу от датчика
int t; //Температура
int P; //Мощность вентиляторов
int V; //Значение напряжения на входе
int T = 75; //Определяем нужную температуру двигателя
uint16_t Temp1[Temp1Count][2] PROGMEM = {{471,46}, {655,58}, {713,65}, {772,74}, {775,80}, {802,90}, {823,100}, {839,110}, {852, 120}, {861, 130}}; //Точки аппроксимации
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.print(" WELCOME TO ");
lcd.setCursor(0,1);
lcd.print("*THERMOCONTROL*");
delay(2000);
lcd.clear();
}
void loop() {
int i;
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp = 1024 - analogRead(0);
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==130);
//Спасибо SBorovkov
float V = (5.00 / 1024.00 * analogRead(analog)) * K; //Переводим входные данные к абсолютному напряжению
if (t < T - 5) P = 0;
if (t >= T - 5) P = 50;
if (t >= T - 4) P = 70;
if (t >= T - 3) P = 90;
if (t >= T - 2) P = 120;
if (t >= T - 1) P = 160;
if (t >= T) P = 200;
if (t >= T + 1) P = 255;
analogWrite (6, P); //Запускаем вентиляторы
Serial.println(P, DEC); //Выводим информацию на всякий случай
lcd.clear();
lcd.setCursor(0,0);
lcd.print("VLT:");
lcd.setCursor(4,0);
lcd.print(V);
lcd.setCursor(8,0);
lcd.print("*TP:");
lcd.setCursor(12,0);
lcd.print(RealTemp);
lcd.setCursor(15,0);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print("PWR:");
lcd.setCursor(4,1);
lcd.print(100.00/255.00*P);
// lcd.setCursor(7,1);
lcd.print("%");
delay(300);
}
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Прошу прощения, подкорректировал код.. теперь все работает:
PHP код:
#include <LiquidCrystal.h>
#include <avr/pgmspace.h>
#define Temp1Count 10 //Увеличил до 10 значений
int t; //Температура
int P; //Мощность вентиляторов
int T = 75; //Определяем нужную температуру двигателя
int i;
LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
uint16_t Temp1[Temp1Count][2] PROGMEM = {{471,46}, {655,58}, {713,65}, {772,74}, {775,80}, {802,90}, {823,100}, {839,110}, {852, 120}, {861, 130}}; //Точки аппроксимации
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.print(" WELCOME TO ");
lcd.setCursor(0,1);
lcd.print("*THERMOCONTROL*");
delay(2000);
lcd.clear();
}
void loop() {
uint16_t InTemp;
uint16_t RealTemp;
uint16_t InLeftTemp;
InTemp = 1024 - analogRead(0);
i=Temp1Count;
do
{
i--;
InLeftTemp=pgm_read_word(&Temp1[i][0]);
}
while ((i>=0)&&(InTemp<InLeftTemp));
uint16_t InRightTemp=pgm_read_word(&Temp1[i+1][0]);
uint16_t OutLeftTemp=pgm_read_word(&Temp1[i][1]);
uint16_t OutRightTemp=pgm_read_word(&Temp1[i+1][1]);
RealTemp=OutLeftTemp+(OutRightTemp-OutLeftTemp)*(InTemp-InLeftTemp)/(InRightTemp-InLeftTemp);
if (RealTemp==130);
float V = (5.00 / 1024.00 * analogRead(0)); //Переводим входные данные к абсолютному напряжению
if (RealTemp < T - 5) P = 0;
if (RealTemp >= T - 5) P = 50;
if (RealTemp >= T - 4) P = 70;
if (RealTemp >= T - 3) P = 90;
if (RealTemp >= T - 2) P = 120;
if (RealTemp >= T - 1) P = 160;
if (RealTemp >= T) P = 200;
if (RealTemp >= T + 1) P = 255;
analogWrite (6, P); //Запускаем вентиляторы
Serial.println(P, DEC); //Выводим информацию на всякий случай
lcd.clear();
lcd.setCursor(0,0);
lcd.print("VLT:");
lcd.setCursor(4,0);
lcd.print(V);
lcd.setCursor(8,0);
lcd.print("*TP:");
lcd.setCursor(12,0);
lcd.print(RealTemp);
lcd.setCursor(15,0);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print("PWR:");
lcd.setCursor(4,1);
lcd.print(100.00/255.00*P);
// lcd.setCursor(7,1);
lcd.print("%");
delay(300);
}
-
Вложений: 1
Re: Как точно вычислить температуру со штатного датчика двигателя?
Вот фотка того что на дисплее:
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Вообще все нормально.
Я бы маленько подправил, но это на работу не повлияет.
Строку
if (RealTemp==130);
можно убрать, все равно ничего не делает.
Строку
int T = 75;
если значение менять в коде не будешь, лучше заменить на
#define T 75
а еще лучше - сразу назвать понятно, что-то вроде
#define DestinationEngineTemp 75
обрати внимание, что в строке с #define точку с запятой в конце не ставят!
Таким образом можно объявить константу.
Объявление
int i;
перенеси в то место, где эта переменная используется - в loop()
Еще совет - не заводи переменных, отличающихся регистром.
int t; //Температура
int T = 75;
Запаришься искать ошибку, если ошибешься регистром при их использовании.
Лучше всего все переменные, смысл которых сложнее, чем переменная цикла называть так, чтобы было понятно что в ней хранится. Хотя бы 2-3 символа, если использование локальное. Если же переменная или константа используется в нескольких функциях, то полноценное имя, иначе потом забудешь что за переменная, или будешь путаться.
И еще - все, что касается выводов МК лучше складывать в #define
То есть вместо AnalogRead(0)
надо написать примерно так, как ты писал выше:
в начале
#define EngineTempSensorPin 0
А дальше везде
AnalogRead(EngineTempSensorPin)
Связано это с тем, что если вдруг тебе надо будет потом поменять выводы ардуино, не придется искать все упоминания вывода, а достатоно тупо поменять константу.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Цитата:
Сообщение от
SBorovkov
И еще - все, что касается выводов МК лучше складывать в #define
То есть вместо AnalogRead(0)
надо написать примерно так, как ты писал выше:
в начале
#define EngineTempSensorPin 0
А дальше везде
AnalogRead(EngineTempSensorPin)
Связано это с тем, что если вдруг тебе надо будет потом поменять выводы ардуино, не придется искать все упоминания вывода, а достатоно тупо поменять константу.
Так еще намного понятнее что ты считываешь, чем конструкция AnalogRead(0)
Код как правило пишется для людей, чтобы потом можно было понять что к чему. Компилятор "дурак", что напишешь то и будет делать :)
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Цитата:
Сообщение от
SBorovkov
Вообще все нормально.
Я бы маленько подправил, но это на работу не повлияет.
Строку
if (RealTemp==130);
можно убрать, все равно ничего не делает.
Строку
int T = 75;
если значение менять в коде не будешь, лучше заменить на
#define T 75
а еще лучше - сразу назвать понятно, что-то вроде
#define DestinationEngineTemp 75
обрати внимание, что в строке с #define точку с запятой в конце не ставят!
Таким образом можно объявить константу.
Объявление
int i;
перенеси в то место, где эта переменная используется - в loop()
Еще совет - не заводи переменных, отличающихся регистром.
int t; //Температура
int T = 75;
Запаришься искать ошибку, если ошибешься регистром при их использовании.
Лучше всего все переменные, смысл которых сложнее, чем переменная цикла называть так, чтобы было понятно что в ней хранится. Хотя бы 2-3 символа, если использование локальное. Если же переменная или константа используется в нескольких функциях, то полноценное имя, иначе потом забудешь что за переменная, или будешь путаться.
И еще - все, что касается выводов МК лучше складывать в #define
То есть вместо AnalogRead(0)
надо написать примерно так, как ты писал выше:
в начале
#define EngineTempSensorPin 0
А дальше везде
AnalogRead(EngineTempSensorPin)
Связано это с тем, что если вдруг тебе надо будет потом поменять выводы ардуино, не придется искать все упоминания вывода, а достатоно тупо поменять константу.
Спасибо за дельные советы. Буду учиться делать код красиво и правильно.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Цитата:
Сообщение от
-= Nicki =-
Так еще намного понятнее что ты считываешь, чем конструкция AnalogRead(0)
Код как правило пишется для людей, чтобы потом можно было понять что к чему. Компилятор "дурак", что напишешь то и будет делать :)
Понял.. Сегодня сделаю для людей и выложу в шапку код. Может кому пригодится.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Выложил в первый пост результат работы. Буду постепенно совершенствовать и обновлять. Если где ошибся - говорите. Код работает.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Уже обновил. "Научил" ЖК показывать русские буквы чтобы было понятнее.
Завтра попробую зацепить на машину для мониторинга температуры... буду ставить в паре с обычной термопарой на мультиметре - буду сравнивать значения :)
Скорее всего, выложу видео т.к. все равно снимать, чтобы от дороги не отвлекаться.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Ребята, а как прописать в скетче чтобы не дискретно значения на ШИМ выдавались 50,100, 250.... и т.д., а плавно изменялись от 50 к 100, от 100 к 150? ну т.е. значения те же, но переход от одного к другому - плавно?
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
в цикле изменяй хоть от 0 до 255
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Хм. Ты имеешь ввиду выполнять цикл при росте температуры на 1 градус? Ну хорошо, а в обратную сторону если температура пойдет? Мне думается как то проще должно быть.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Можно повеситься на прерывание таймера и в отдельных переменных хранить текущее состояние шима и необходимое состояние шима. И по таймеру текущее сдвигать к необходимому.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
А можно пример кода? А то я не силен в таком подходе.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
В общем, в рабочем режиме выявлен недостаток "плавания" напряжения на датчике температуры которое показывает ардуина. В то время как обычный мультиметр показывает стабильно. Думаю нужно перейти на усредненное значение за определенное время. Сегодня буду дорабатывать скетч. В т.ч. попробую сделать плавный ШИМ.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Не знаю как повесить на таймер в ардуине функцию. Я разрабатываю не в среде ардуино, а в AVR Studio. Для обработки прерываний в Arduino есть какие-то функции, поищи, тут на форуме было обсуждение таймера.
Ну а осуществить плавную регулировку просто
int CurrentVentPWM;
int TargetVentPWM;
void Timer(void) // эта функция должна вызываться определенное количество раз в секунду (сколько - сам считай, 10-20-50?)
{
if (CurrentVentPWM>TargetVentPWM)
{
CurrentVentPWM--;
AnalogOutput(CurrentVentPWM,???) // не помню что туда надо писать
}
if (CurrentVentPWM<TargetVentPWM)
{
CurrentVentPWM++;
AnalogOutput(CurrentVentPWM,???) // не помню что туда надо писать
}
}
Теперь по поводу дрожания.
Причины может быть две:
1. На самом деле вольтметр не ловит какую-то быструю помеху. Он ведь измеряет постоянное напряжение и если есть постоянная помеха с частотой 100 герц, он ее показать не должен. А ардуина очень быстро выполняет преобразование и помеху даже в 2000Гц она поймает по-полной. Решение - пустить сигнал с датчика через RC цепочку. Что это такое можешь почитать на сайте easyelectronics.ru. Я перед тамошним автором кепку снимаю, насколько доступно он умудряется объяснять.
2. Может быть так, что помеха идет по питанию ардуины. Для того, чтобы таких помех не ловить, надо задемфировтаь вывод aRef и переключить АЦП, чтобы он в качестве опорного напряжения брал не Vcc (напряжение питания МК), а этот aRef. Цепочку, которую надо на aRef включать, в интернете тоже легко найти.
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Вот так можно отфильтровать помеху
Цитата:
sensor = analogRead(EngineTempSensorPin); // замер
delay(1);
sensor_crt = analogRead(EngineTempSensorPin); // контрольный замер
if(sensor == sensor_crt) // если замеры равны, то значит нет ошибки
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Обновил скетч в первом посте. Добавил усредненное значение от датчика, упростил код для ШИМ вычисления, ну и так по мелочи подправил...
Цитата:
Сообщение от
Chip
Вот так можно отфильтровать помеху
Попробовал, но все таки остановился на усредненном значении и скорее всего добавлю РЦ фильтр по входу.
Цитата:
Сообщение от
SBorovkov
Не знаю как повесить на таймер в ардуине функцию...
Спасибо. Смысл понятен, но прикрутить с пол пинка не удалось. Может подскажет кто-нибудь как работать с функциями таймера?
-
Re: Как точно вычислить температуру со штатного датчика двигателя?
Выполнение процедуры по таймеру.
PHP код:
//Выполнение процедуры по таймеру.
#include <MsTimer2.h>
static boolean output = HIGH;
void flash_led()
{
digitalWrite(13, (output==HIGH) ? output=LOW : output=HIGH);
}
void setup()
{
MsTimer2::set(500, flash_led); // 500ms интервал вызова процедуры
MsTimer2::start();
}
void loop()
{
//Здесь будет ваш код
}