Калибровка напряжения при измерении температуры

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Добрый день коллеги! Вопрос изъезженный, но полного решения я все так и не нашел. Задача простая - измерять тепературу датчиком LM335.  Сам скеч простой:

val = analogRead(lm335); // чтение
voltage = val*5.0/1024; // перевод в вольты
temp = voltage*100 - 273.15; // в градусы Цельсия  

В формуле используется значение опорного напряжения 5.0, но по факту питание может колебаться, +- от 0.1 до 0.5В. А в градусах это порядка 6-8 цельсия. Это большая погрешность, т.к. задача стоит держать температуру 3 градуса и не больше и не меньше. Понимаю что тут нужно еще и мерить входное напряжение на ардуину. Сначала думал - впаять переменный резистор и им юстировать напряжение. Но если оно будет менятся, то этот вариант не пойдет. Смотрю схему с делителем, но не уверен что она даст то значение которе действительно будет, ведь на резисторе будет падать напряжение от исходного... Поэтому думаю над тем как мерить его правильно и подставлять значение в эту формулу.  В

evgta
Offline
Зарегистрирован: 02.09.2016

используйте вход AREF, в качестве источника резистор и стабилитрон, или кренка.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Сделайте опорное от внешнего источника TL431 вам в помощь

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

evgta пишет:

используйте вход AREF, в качестве источника резистор и стабилитрон, или кренка.

Т.е использовать функцию analogReference с параметром EXTERNAL и на aref подать питание?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

А почему Вы просто программно не измерите напряжение питания? Если есть подозрение что питание не очень стабильно, то его можно хоть каждую секунду заново мерять. Там это можно сделать достаточно точно, если заранее точно измерить внутреннее опорное (оно от экземрляра микросхемы зависит и может быть 1,0-1,2 вольта).

Вы знаете как это делается или найти ссылку?

evgta
Offline
Зарегистрирован: 02.09.2016

да, на aref подать опорное напряжение(которое всегда стабильно), например 4,3(чтобы ниже минимального) и соответрственно датчик не должен будет выдавать напряжение выше опорного 

4,3В будут равны 1023

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

ЕвгенийП пишет:

А почему Вы просто программно не измерите напряжение питания? Если есть подозрение что питание не очень стабильно, то его можно хоть каждую секунду заново мерять. Там это можно сделать достаточно точно, если заранее точно измерить внутреннее опорное (оно от экземрляра микросхемы зависит и может быть 1,0-1,2 вольта).

Вы знаете как это делается или найти ссылку?

От ссылки не откажусь конечно )) я попробовал установить Ref в режим Intrnal, но датчик то дает от 0 до 5 вольт, придется что-то еще допилить?

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Забыл сказать что у меня Arduino Pro-Mini ))) Смотрю схему и не вижу вывода AREF )) Вижу что контакт процессора 20-й соединен с массой через кондер и все)

evgta
Offline
Зарегистрирован: 02.09.2016

Тогда . Либо припаиваться к ноге либо делать стабильное питание ардуины черерез пин +5

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

evgta пишет:

да, на aref подать опорное напряжение(которое всегда стабильно), например 4,3(чтобы ниже минимального) и соответрственно датчик не должен будет выдавать напряжение выше опорного 

4,3В будут равны 1023

Вы не поняли. Речь идёт не о том, чтобы подать всегда стабильное напряжение на Aref (его ещё надо где-то взять), а о том, чтобы измерить текущее напряжение питания и уже его (какое бы оно ни было) считать за 1023

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Техника измерения текущего напряжения питания основана на том, что внутри контроллера есть источник опорного напряжения 1,1В. В реальности он от 1,0В до 1,2В и зависит от экземпляра микросхемы. Это опорное напряжение необходимо измерить для конкретного экземпляра (как это делается описано по ссылкам ниже) и забить константой (назовём Uреал). Оно стабильно по температуре и т.п. Единожды измерив, можно пользоваться. После этого можно измерять напряжение питания таким образом:

1.    Используя напряжение питания в качестве Reference, и считая его пока 5В, программно измеряем опорное (это можно делать почти во всех ATMega'х и в большинстве ATTiny). То, что получилось назовём Uоп

2.    Поскольку реальное опорное мы знаем, то из нашего измеренного можем посчитать настоящее напряжение питания. Оно будт равно 5В *  Uреал / Uоп.

Собственно теперь мы знаем настоящее напряжение питания. Просто подставляем его вместо 5В в известную формулу и все дела.

Техника описана (с примерами кода)

1.    Плохо, но по-русски

2.    Хорошо, но по-английски. Здесь надо поиском по странице найти "Detecting low voltage"

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот вам для Нанки (328p) функция getVcc(), старую не нашел, только сейчас новую накатал.

И пример программы для измерения напряжения, с использованием этой функции.

Измеряем на А3, пересчитываем с учетом правильного значения напряжения питания.

В программе все ясно? Все комментарии я писал на аглицком, уж простите. Задержку в 120 мкс только сейчас подобрал, без нее даже два измерения выдают мусор, при первом вызове. Если Вам время не критично, то еще больше можно делать, меньше - нельзя. Или вызывайте фунцию перед измерением своего сигнала - пару-тройку раз, для верности. ;)

float getVcc(void)
{
  float V=0;
  
  for (byte i = 0; i < 2; i++){ //do 2 times first isnt good
  ADMUX = 0B01001110; //refs=ext;Adjust=r;mux=1.1;
  delayMicroseconds(120);
  ADCSRA = B11000111; //enbl, start, no trig, no int, div=128
  while (ADCSRA & (1 << ADSC)); //wait for conv
  V= ADC;
  }
return (1126.0f/V);
  
}


void setup() {
  Serial.begin(19200);
}

void loop() {
  int tv;
  float vcc;
  Serial.print("======Vcc voltage is:");
  Serial.println(vcc=getVcc(),3);

  Serial.print("Test voltage ADC is:");
  Serial.print(tv=analogRead(A3));
  Serial.print(" value is:");
  Serial.println(tv*vcc/1024.0f+1.0f/2048.0);
  
  
  delay(2000);
}


 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

калибровке, о которой написал Евгений, подлежит "магическое" число 1126 (==1.1*1024) в функции getVcc();

Если есть хороший прибор - его можно подогнать. Без подгонки у меня отличие от мультиметра в 4-ом знаке. Но и мультиметр надо сказать г... - китаец 838. У Вас датчик давления? Подгоняйте все в целом, по манометру. От колебаний питания мы с вами избавились моей функцией getVcc(). Температурные колебания меньше 0.01% на градус, забудьте.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

А объяснить почему именно так:

vcc/1024.0f+1.0f/2048.0)

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ua6em пишет:

А объяснить почему именно так:

vcc/1024.0f+1.0f/2048.0)

 

читаем ОЧЕНЬ длинный диспут в теме "программирование 32-х разрядных..."  в разделе "отвлеченные".

Читаем, запоминаем результат и НИЧЕГО из того матерного холивара сюда не несем.

По результату холивара - именно ЭТА формула самая точная. На этом в теме АЦП поставлена точка и возврат к этой теме приравнивается к измене Родине, Партии, Жене и всем любовницам сразу! ;)

===============

За сам вопрос - уже ставим на заметку по подозрению в попытке троллинга. ;) ;) ;)

Волшебник
Offline
Зарегистрирован: 22.12.2016

wdrakula пишет:
ua6em пишет:

А объяснить почему именно так:

vcc/1024.0f+1.0f/2048.0)

читаем ОЧЕНЬ длинный диспут в теме "программирование 32-х разрядных..."  в разделе "отвлеченные".

Читаем, запоминаем результат и НИЧЕГО из того матерного холивара сюда не несем.

По результату холивара - именно ЭТА формула самая точная. На этом в теме АЦП поставлена точка и возврат к этой теме приравнивается к измене Родине, Партии, Жене и всем любовницам сразу! ;)

===============

За сам вопрос - уже ставим на заметку по подозрению в попытке троллинга. ;) ;) ;)

Мне тоже не понятно, (измена родине у меня уже в зачёте давно), почему делится на 1024 а не на 1023, и прабавлять 1/2048 как округление целой величины вообще не уместно для АЦП.

evgta
Offline
Зарегистрирован: 02.09.2016

Потому что отчет идет с 0 а не с 1 т.е 0-1023, а чисел(значений)то 1024

Волшебник
Offline
Зарегистрирован: 22.12.2016

evgta пишет:
Потому что отчет идет с 0 а не с 1 т.е 0-1023, а чисел(значений)то 1024

Да пофиг, если на аналоговый вход подать 5В, ацп выдаст 1023 (он никогда больше 1023 не пишет), и по формуле /1023 будет правильный результат, а вот по /1024 заниженый.

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

туда, туда...в ..... тему с холиваром. Там есть моя программа, моделирующая SAR ADC и делающая 10000 случайных измерений.

Вот ссылка на сообщение, там все есть. это холивар реально задолбал. Проверяйте программу, подбирайте формулы.

=====================

только дерьмо из той темы сюда не тащите, плз.!!!!!!

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Воо! Похоже то что надо!)) Вот еще статейку нашел, как раз про 1024 там ))) и более подробно на пальцах расписано что и как )) http://robotclass.ru/tutorials/arduino_adc/

Спасибо всем! Буду пробовать)

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

wdrakula пишет:

ua6em пишет:

А объяснить почему именно так:

vcc/1024.0f+1.0f/2048.0)

читаем ОЧЕНЬ длинный диспут в теме "программирование 32-х разрядных..."  в разделе "отвлеченные".

Читаем, запоминаем результат и НИЧЕГО из того матерного холивара сюда не несем.

По результату холивара - именно ЭТА формула самая точная. На этом в теме АЦП поставлена точка и возврат к этой теме приравнивается к измене Родине, Партии, Жене и всем любовницам сразу! ;)

===============

За сам вопрос - уже ставим на заметку по подозрению в попытке троллинга. ;) ;) ;)

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

Сейчас вот упёрся с датчиком ina219 - выходит в измерениях на 800 попугает, а дальше не меряет, хотя ток растёт до ампера

скетч простой:

#include <Wire.h>
#include "ina219.h"

INA219 monitor;

void setup() {
  Serial.begin(9600);
  monitor.begin(64); // i2c address 64=0x40
  monitor.configure(0, 1, 3, 3, 7);
 
  /*  конфигурируем режим датчика тока INA219
   *  range, gain, bus_adc, shunt_adc, mode
   *  range = 1 (0-32V bus voltage range)
   *  gain = 3 (1/8 gain - 320mV range)
   *  bus adc = 3 (12-bit, single sample, 532uS conversion time)
   *  mode = 7 (continuous conversion)
   */

  monitor.calibrate(0.100, 0.075, 16, 3); 
 //R_шунта, напряж_шунта, макc_напряж, макс_ток
  }

  
void loop() {

 for (int i=1; i<16; i++){
 delay(300);
 Serial.print(monitor.busVoltage()); Serial.println(" - v");
 Serial.print(monitor.shuntCurrent() * 1000,0);Serial.print(" - ");
}
Serial.println();
}

Платка с алиэкспресс, на резисторе шунта маркировка - 100

Волшебник
Offline
Зарегистрирован: 22.12.2016
                            V AIN ( 2^N – 1 )
Digital code = ---------------------------------- , where N is the resolution of the ADC (in our case N = 12).
                                  V REF+
 
Прежде чем конкурсы проводить, надо было ознакомиться с документом от самой эСТиэМ, той которая 32-битник делает.
Бумага называется AN2834 Application note How to get the best ADC accuracy  in STM32 microcontrollers

www.st.com/resource/en/application_note/cd00211314.pdf

 

  1.  

Приведённая формула взята оттуда.  От себя добавлю, что попытки "округлить" величину которая по своей природе всегда целочисленная похожи как если всех баб считать наполовину беременными, а чё по вероятности они же могут забеременить? Так и к результату ацп половину LSB добавлять, по теории вероятности правильно, только не применимо. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Чародей - лучше с датчиком INA219 помоги
 

Волшебник
Offline
Зарегистрирован: 22.12.2016

ua6em пишет:
Чародей - лучше с датчиком INA219 помоги
Не могу, у меня датчика такого нет. По опыту, там может быть что угодно, опечатка в ДШ, баг /брак, или софт кривой, без такого же датчика на руках можно только предполагать. 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

На адафрутовском скетче и библиотеке заработало и показания вроде бы соответствующие. только скачут )))
Надо читать доку, а читалка что-то не воспринимает )))

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Если питание датчика и AREF - объеденены в одну цепь, то вовсе не важно какое там будет напряжение :)  Естественно как опорное использовать AREF, правильнее будет использовать не AnalogRead, а читать данные напрямую из портов ADC.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

brokly пишет:

 правильнее будет использовать не AnalogRead, а читать данные напрямую из портов ADC.

А разница в чём?

a5021
Offline
Зарегистрирован: 07.07.2013

ua6em пишет:
На адафрутовском скетче и библиотеке заработало и показания вроде бы соответствующие. только скачут )))

Делайте несколько измерений, вычисляйте среднее. Во время измерений по возможности ногами МК не трясти, особливо, если на них висит ощутимая нагрузка. По входу АЦП можно прикрутить простейший RC фильтр нижних частот.

Волшебник
Offline
Зарегистрирован: 22.12.2016

Совет хороший, только датчик у него цифровой по I2C...

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Волшебник пишет:

Совет хороший, только датчик у него цифровой по I2C...

Ага и у него уже встроено усреднение измерений, я о том как этим воспользоваться )))
 

    I2C ADDRESS/BITS
    -----------------------------------------------------------------------*/
    #define INA219_ADDRESS                         (0x40)    // 1000000 (A0+A1=GND)
    #define INA219_READ                            (0x01)
/*=========================================================================*/

/*=========================================================================
    CONFIG REGISTER (R/W)
    -----------------------------------------------------------------------*/
    #define INA219_REG_CONFIG                      (0x00)
    /*---------------------------------------------------------------------*/
    #define INA219_CONFIG_RESET                    (0x8000)  // Reset Bit
	
    #define INA219_CONFIG_BVOLTAGERANGE_MASK       (0x2000)  // Bus Voltage Range Mask
    #define INA219_CONFIG_BVOLTAGERANGE_16V        (0x0000)  // 0-16V Range
    #define INA219_CONFIG_BVOLTAGERANGE_32V        (0x2000)  // 0-32V Range
	
    #define INA219_CONFIG_GAIN_MASK                (0x1800)  // Gain Mask
    #define INA219_CONFIG_GAIN_1_40MV              (0x0000)  // Gain 1, 40mV Range
    #define INA219_CONFIG_GAIN_2_80MV              (0x0800)  // Gain 2, 80mV Range
    #define INA219_CONFIG_GAIN_4_160MV             (0x1000)  // Gain 4, 160mV Range
    #define INA219_CONFIG_GAIN_8_320MV             (0x1800)  // Gain 8, 320mV Range
	
    #define INA219_CONFIG_BADCRES_MASK             (0x0780)  // Bus ADC Resolution Mask
    #define INA219_CONFIG_BADCRES_9BIT             (0x0080)  // 9-bit bus res = 0..511
    #define INA219_CONFIG_BADCRES_10BIT            (0x0100)  // 10-bit bus res = 0..1023
    #define INA219_CONFIG_BADCRES_11BIT            (0x0200)  // 11-bit bus res = 0..2047
    #define INA219_CONFIG_BADCRES_12BIT            (0x0400)  // 12-bit bus res = 0..4097
    
    #define INA219_CONFIG_SADCRES_MASK             (0x0078)  // Shunt ADC Resolution and Averaging Mask
    #define INA219_CONFIG_SADCRES_9BIT_1S_84US     (0x0000)  // 1 x 9-bit shunt sample
    #define INA219_CONFIG_SADCRES_10BIT_1S_148US   (0x0008)  // 1 x 10-bit shunt sample
    #define INA219_CONFIG_SADCRES_11BIT_1S_276US   (0x0010)  // 1 x 11-bit shunt sample
    #define INA219_CONFIG_SADCRES_12BIT_1S_532US   (0x0018)  // 1 x 12-bit shunt sample
    #define INA219_CONFIG_SADCRES_12BIT_2S_1060US  (0x0048)	 // 2 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_4S_2130US  (0x0050)  // 4 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_8S_4260US  (0x0058)  // 8 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_16S_8510US (0x0060)  // 16 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_32S_17MS   (0x0068)  // 32 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_64S_34MS   (0x0070)  // 64 x 12-bit shunt samples averaged together
    #define INA219_CONFIG_SADCRES_12BIT_128S_69MS  (0x0078)  // 128 x 12-bit shunt samples averaged together
	
    #define INA219_CONFIG_MODE_MASK                (0x0007)  // Operating Mode Mask
    #define INA219_CONFIG_MODE_POWERDOWN           (0x0000)
    #define INA219_CONFIG_MODE_SVOLT_TRIGGERED     (0x0001)
    #define INA219_CONFIG_MODE_BVOLT_TRIGGERED     (0x0002)
    #define INA219_CONFIG_MODE_SANDBVOLT_TRIGGERED (0x0003)
    #define INA219_CONFIG_MODE_ADCOFF              (0x0004)
    #define INA219_CONFIG_MODE_SVOLT_CONTINUOUS    (0x0005)
    #define INA219_CONFIG_MODE_BVOLT_CONTINUOUS    (0x0006)
    #define INA219_CONFIG_MODE_SANDBVOLT_CONTINUOUS (0x0007)	

 

Волшебник
Offline
Зарегистрирован: 22.12.2016

ua6em    У меня складывается впечатление,  что вы угоняете чужой топик, и хотя ТС не топает ногами, но на других форумах за это обычно наказывают. Может перенести обсуждение 219-ой в новый трэд? 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Волшебник пишет:

ua6em    У меня складывается впечатление,  что вы угоняете чужой топик, и хотя ТС не топает ногами, но на других форумах за это обычно наказывают. Может перенести обсуждение 219-ой в новый трэд? 

В какой то мере пожалуй да, новый топик не заводил, спрашивал у DIMAX по этому датчику, ГУРУ молчат

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