Ардуино и датчики температуры LM35 и DS18B20. Опорное напряжение контроллера AREF. 21

Разберем на примере  и 

1. Подключение датчика LM35 к Ардуино

Схема подключения датчика LM35 к Ардуино:

lm35.png

LM35 — Аналоговый датчик
Стандартный пример для преобразования аналогового сигнала, снятого с аналогового входа Ардуино, в температуру

1
2
3
4
5
6
7
8
9
10
11
12
13
14
float tempC;
int reading;
int tempPin = 0;
 
void setup()
{
analogReference(INTERNAL);
}
 
void loop()
{
reading = analogRead(tempPin);
tempC = reading / 9.31;
}
float tempC;
int reading;
int tempPin = 0;

void setup()
{
analogReference(INTERNAL);
}

void loop()
{
reading = analogRead(tempPin);
tempC = reading / 9.31;
}

Рассмотрим функцию analogReference(INTERNAL);

Данная функция устанавливает опорное напряжение для analogRead и преобразует его к значению от 1 до 1024

Что же это означает?

Предположим, наше опорное напряжение равно 5V(по умолчанию для UNO), следовательно при подаче напряжения на аналоговый вход 5v функция analogRead вернет значение 1024.
Разделим значение 5V на 1024 , получаем 0.0049V = 4.9mV. Это означает, что функция analogRead позволяет получать значение с точностью до 4.9mv

Настройки analogReference позволяют установить опорное напряжение отличное от 5v, тем самым увеличить точность измерений.

analogReference(INTERNAL); //включает использование встроенного опорного напряжения 1.1V для контроллеров ATmega168 и ATmega328, и 2.56 В на ATmega8

Таблица зависимости точности измерения(LSB, младший значащий бит результат преобразования) от опорного напряжения:

Опорное напряжение — Точность измерений
5.00V — 4.9mV
2.56V — 2.5mV
1.10V — 1.0mV

analogReference(EXTERNAL); //включает возможность подключения внешнего опорного напряжения от 0 до 5 на вывод AVCC или AREF

Из даташита LM35 на выходе мы имеем диапазон в 1В.

Вернемся к нашему примеру, к строке analogReference(INTERNAL);

Мы включаем внутреннее опорное напряжение 1.1 , что позволяет повысить точность измерения температуры.
При использовании стандартного опорного напряжения в 5V точность измерений составила бы 24.5mV

Основным недостатком использования аналогового датчика является отсутствие АЦП. Любые помехи или скачки напряжения ведут к неверным измерениям.
Плюсом этих датчиков является скорость получения температуры и простота использования контроллером, имея один аналоговый вход и минимум кода программы.

2. Подключение датчика DS18B20 к Ардуино

Схема подключения DS18B20 к Ардуино:

DS18B20.jpg

 Рассмотрим один из самых распространенных цифровых датчиков DS18B20

Библиотека для подключения Dallas Temperature Control Library
Пример кода

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <OneWire.h>
#include <.h>
 
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
 
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
 
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
 
// arrays to hold device address
DeviceAddress insideThermometer;
 
void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control  Demo");
 
// locate devices on the bus
Serial.print("Locating devices...");
sensors.begin();
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");
 
// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");
 
// assign address manually. the addresses below will beed to be changed
// to valid device addresses on your bus. device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
//insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };
 
// Method 1:
// search for devices on the bus and assign based on an index. ideally,
// you would do this to initially discover addresses on the bus and then
// use those addresses and manually assign them (see above) once you know
// the devices on your bus (and assuming they don't change).
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");
 
// method 2: search()
// search() looks for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are no devices,
// or you have already retrieved all of them. It might be a good idea to
// check the CRC to make sure you didn't get garbage. The order is
// deterministic. You will always get the same devices in the same order
//
// Must be called before search()
//oneWire.reset_search();
// assigns the first address found to insideThermometer
//if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");
 
// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();
 
// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(insideThermometer, 9);
 
Serial.print("Device 0 Resolution: ");
Serial.print(sensors.getResolution(insideThermometer), DEC);
Serial.println();
}
 
// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
// method 1 - slower
//Serial.print("Temp C: ");
//Serial.print(sensors.getTempC(deviceAddress));
//Serial.print(" Temp F: ");
//Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit
 
// method 2 - faster
float tempC = sensors.getTempC(deviceAddress);
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}
 
void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");
 
// It responds almost immediately. Let's print out the data
printTemperature(insideThermometer); // Use a simple function to print out the data
}
 
// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");

// locate devices on the bus
Serial.print("Locating devices...");
sensors.begin();
Serial.print("Found ");
Serial.print(sensors.getDeviceCount(), DEC);
Serial.println(" devices.");

// report parasite power requirements
Serial.print("Parasite power is: ");
if (sensors.isParasitePowerMode()) Serial.println("ON");
else Serial.println("OFF");

// assign address manually. the addresses below will beed to be changed
// to valid device addresses on your bus. device address can be retrieved
// by using either oneWire.search(deviceAddress) or individually via
// sensors.getAddress(deviceAddress, index)
//insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 };

// Method 1:
// search for devices on the bus and assign based on an index. ideally,
// you would do this to initially discover addresses on the bus and then
// use those addresses and manually assign them (see above) once you know
// the devices on your bus (and assuming they don't change).
if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");

// method 2: search()
// search() looks for the next device. Returns 1 if a new address has been
// returned. A zero might mean that the bus is shorted, there are no devices,
// or you have already retrieved all of them. It might be a good idea to
// check the CRC to make sure you didn't get garbage. The order is
// deterministic. You will always get the same devices in the same order
//
// Must be called before search()
//oneWire.reset_search();
// assigns the first address found to insideThermometer
//if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer");

// show the addresses we found on the bus
Serial.print("Device 0 Address: ");
printAddress(insideThermometer);
Serial.println();

// set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
sensors.setResolution(insideThermometer, 9);

Serial.print("Device 0 Resolution: ");
Serial.print(sensors.getResolution(insideThermometer), DEC);
Serial.println();
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
// method 1 - slower
//Serial.print("Temp C: ");
//Serial.print(sensors.getTempC(deviceAddress));
//Serial.print(" Temp F: ");
//Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit

// method 2 - faster
float tempC = sensors.getTempC(deviceAddress);
Serial.print("Temp C: ");
Serial.print(tempC);
Serial.print(" Temp F: ");
Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print("Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.println("DONE");

// It responds almost immediately. Let's print out the data
printTemperature(insideThermometer); // Use a simple function to print out the data
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
if (deviceAddress[i] < 16) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
}
}

Единственный недостаток использования данного датчика с данной библиотекой — это скорость обмена данными с датчиком.

Высокая помехоустойчивость, АЦП, подключение по 1 — wire(достаточно иметь 1 цифровой вход для работы с одним или несколькими датчиками).

Источники:
http://playground.arduino.cc/Main/LM35HigherResolution
http://arduino.cc/en/Reference/AnalogReference
http://www.ti.com/lit/ds/symlink/lm35.pdf

21 комментс для “Ардуино и датчики температуры LM35 и DS18B20. Опорное напряжение контроллера AREF.

  1. Ответить ПАвел Окт 15, 2014 22:28

    Проверял LM35, проверял на балконе, рядом поставил метио станцию и термометр за окном, на метио станции показывал температура 15 гр по цельсию, уличный 10, а этот аж 27. Кто то врет. Проверял на коде который здесь на сайте.

  2. Ответить Пётр Ноя 22, 2014 06:58

    На cхеме подключения DS18B20 к Ардуино цоколёвка не правильная. Датчик нужно повернуть на 180 градусов.

  3. Ответить Artur Дек 24, 2014 17:29

    А можно ли подключить какой нибудь фильтр на вход А0?
    У меня датчик LM35dz и бывает такое что после 5-10 значений выскакивает одно превышаемое на 3-4 градуса. Можно ли с этим как то бороться?

    • Ответить Slava Дек 24, 2014 20:42

      Проверьте все соединения с датчиком, если плохой контакт — возможны и скачки.
      А фильтр я бы написал программный. Если известна максимальная скорость изменения температуры то при ее превышении просто пропускать данное значение

      • Ответить Artur Дек 25, 2014 00:39

        То есть только в скетче делать это?
        Просто странно, скачок не критичен, но немного бесит когда строю график выходит некий шум.
        А в даташит при внешнем источнике питания нужно (вроде) ставить фильтр (резистор последовательно с конд. подключен между землей и вых. з LM35dz)… можно ли такой же подключить используя всс ардуино.
        Страшно пробовать:)

        • Ответить Slava Дек 25, 2014 11:30

          Если в даташит есть — то чего бояться? ))) Ардуине ничего не будет!

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

          • Ответить Artur Янв 31, 2015 22:44

            игрался, игрался..:))

            Вот мои выводи. Обязательно:
            Кабель должен быть с экраном. Питания я брал с контролера. И дал между землей и выводом датчика 104 конденсатор. Шумы явно уменьшились.

            И в скетч мы добавили пару фильтров — и ляпота!:) спасибо, вы вдохновили меня!:)

  4. Ответить Andrey Фев 14, 2016 19:26

    Доброго времени суток! Помогите, пожалуйста оптимизировать код.

    #include
    #include
    LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x20 for a 16 chars and 2 line display
    int tempPin = A1; // the output pin of LM35
    int fan = 11; // the pin where fan is
    int led = 8; // led pin
    int temp;
    int tempMin = 30; // the temperature to start the fan
    int tempMax = 70; // the maximum temperature when fan is at 100%
    int fanSpeed;
    int fanLCD;

    void setup() {
    analogReference(INTERNAL);
    pinMode(fan, OUTPUT);
    pinMode(led, OUTPUT);
    pinMode(tempPin, INPUT);
    lcd.init(); // initialize the lcd
    lcd.backlight();
    }

    void loop() {
    temp = readTemp(); // get the temperature
    if (temp = tempMin) && (temp tempMax) { // if temp is higher than tempMax
    digitalWrite(led, HIGH); // turn on led
    } else { // else turn of led
    digitalWrite(led, LOW);
    }

    lcd.print(«TEMP: «);
    lcd.print(temp); // display the temperature
    lcd.print(«C «);
    lcd.setCursor(0, 1); // move cursor to next line
    lcd.print(«FANS: «);
    lcd.print(fanLCD); // display the fan speed
    lcd.print(«%»);
    delay(200);
    lcd.clear();
    }

    int readTemp() { // get the temperature and convert it to celsius
    temp = analogRead(tempPin);
    //return temp * 0.48828125;
    return temp / 9.31;
    }

  5. Ответить Alex76 Мар 3, 2016 07:31

    Походу здесь температура управляет скоростью вращения вентилятора (fan), .Самому нужно построить такую штуку,где уставки можно было бы вводить кнопками (локальная клавиатура) и отображать все через 7-ми сегментные индикаторы, но я еще нубик в кодинге и пока «тренируюсь на кошках» :)). Жаль пропал вопрошающий, может совместно что нить и получилось.

    P.S. Пользуясь случаем просьба — в какую сторону мне копать для моей задачи?

  6. Ответить Alex76 Мар 3, 2016 07:37

    Походу идет управление скоростью вращения вентилятора от температуры. Самому нужна такая штука, только с вводом уставки с кнопок (пленочная клавиатура) и отображением всего через 7-сегментный индикатор. Но я пока нубик в кодинге и тренируюсь пока «на кошках» :)) Жаль пропал спрашивающий, полезно было бы и мне.

  7. Ответить Роман Апр 21, 2016 19:46

    Одно не могу понять почему датчик ds18b20 работает через цыфровой вход а не аналоговый?

    • Ответить Slava Апр 22, 2016 12:24

      Это цифровой датчик, а следовательно управляется импульсами 0 и 1.
      Аналоговый датчик результат замера передает в виде перепада напряжения, либо изменения сопротивления, либо тока.

      В принципе любой аналоговый вход является дискретным, но не наоборот. Соответственно можно цифровой датчик подключать к любому входу, а аналоговый только на аналоговый вход.

  8. Ответить Владислав Май 23, 2016 14:55

    Вставил этот код в Ардуино:

    float tempC;
    int reading;
    int tempPin = 0;

    void setup()
    {
    analogReference(INTERNAL);
    }

    void loop()
    {
    reading = analogRead(tempPin);
    tempC = reading / 9.31;
    }

    После компиляции выдает ошибку:

    «sketch_may23a.ino: In function ‘void setup()’:
    sketch_may23a.ino:7:19: error: ‘INTERNAL’ was not declared in this scope
    Ошибка компиляции.»

    Подскажите, что сделать нужно???

  9. Ответить Александр Июн 21, 2016 20:07

    Разделим значение 1024 на 5V, получаем 0.0049V = 4.9mV.

    В какой вселенной такая математика? Что курил автор?

  10. Ответить Владимир Июл 7, 2016 14:10

    Я в этом нуб, но мне нужно сделать программно фильтр аналоговый. Низкочастотный или полосовой. Не могу понять как мне написать скетч. Проверка будет осуществляться так: на вход подключается аналоговый генератор, а на выходе осциллограф. Делаю на Arduino uno r3

Добавить комментарий