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: Как точно вычислить температуру со штатного датчика двигателя?
Уже обновил. "Научил" ЖК показывать русские буквы чтобы было понятнее.
Завтра попробую зацепить на машину для мониторинга температуры... буду ставить в паре с обычной термопарой на мультиметре - буду сравнивать значения :)
Скорее всего, выложу видео т.к. все равно снимать, чтобы от дороги не отвлекаться.