Яндекс.Метрика


Система Orphus

Arduino - Термометр на DS1621.

С этой статьи начинается цикл материалов на моем сайте, описывающих  в некоторой степени законченные, проекты на базе Ардуино. "Законченным" считаем код, имеющий как некоторый самостоятельный практический смысл, так и ценность возможности использования в более крупных проектах.

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

Arduino & DS1621

И так. Термометр. В качестве базовой платформы используем плату Duemilanove + щит LCD Keypad (которую я уже представлял). Термометр DS1621 распаян безо всякой обвески. За основу описания работы Ардуино с устройствами по шине I2C, и даже более конкретно - с данным термометром был взят алгоритм представленный тут (четвертый пост) ... Там описанна лишь самая "вершинка" того, что можно "взять" от этого датчика (температура с точностью до целого градуса). Руководствуясь документацией можно (и нужно) считывать показания с точностью до половины градуса цельсия. Прибегая же к чтению дополнительных коэффициентов с термометра, расчетным путем можно достигнуть более высокой точности - а именно величины в 1/16 градуса цельсия (все по документации). Оба варианта представлены в моем исходном коде ниже и максимально детально прокомментированы. На этом нюансы работы с термометром DS1621 при помощи Ардуины (да и в целом) можно считать раскрытыми.

// Simple DS1621 Higher resolutions mode
// Пример считывания и декодирования показаний термометра DS1621
// -- by MiGeRA (migera.ru)
// -- 28 NOV 2011

// Схема подключения проста ...
// SDA pin is Analog4
// SCL pin is Analog5
// DS1621 has A2, A1, and A0 pins connected to GND

// Библиотека по работе с шиной I2C
#include <Wire.h>
// Библиотека по работе с ЖК экранами
#include <LiquidCrystal.h>

// Конфигурируем способ подключения экрана ...
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);         // В нашем случае это "LCD Keypad Shield"

// Описываем начертание символа "t-штрих"
byte T1[8] =
 {
   B00001,
   B00001,
   B01000,
   B01000,
   B11100,
   B01000,
   B01110,
   B00000,
 };
// Описываем начертание символа "t-два штриха"
byte T2[8] =
 {
   B00101,
   B00101,
   B01000,
   B01000,
   B11100,
   B01000,
   B01110,
   B00000,
 };

#define DEV_ID 0x90 >> 1                    // сдвиг требуемый wire.h

// Описываем используемые переменные
float cpc = 0;                              // для хранения "COUNT_PER_C" - см. документацию на DS1621
float cr = 0;                               // для хранения "COUNT_REMAIN" - см. документацию на DS1621
float temp = 0;                             // первый (основной) байт показания температуры с термометра
float temp2 = 0;                            // "довесок" - наличие которого добавляет полградуса
float result = 0;                           // результат посчитанный по формуле (более точный)
float result2 = 0;                          // результат считанный непосредственно, с учетом довеска (менее точный)
float tempF = 0;                            // результат посчитанный по формуле, переведенный в фарингейты

float mintemp = 125;                        // инициализация переменной для хранения минимума
float maxtemp = -55;                        // инициализация переменной для хранения максимума

// Инициализация
void setup()
{
// Записываем в ЖКИ новые символы
 lcd.createChar(0, T1);
 lcd.createChar(1, T2);
// Конфигурируем количество строк и символов в строке 
 lcd.begin(16, 2);
 lcd.clear();

// Инициализируем термометр
 Wire.begin();
 Wire.beginTransmission(DEV_ID);           // обращаемся к термометру по его идентификатору на шине I2C
 Wire.send(0xAC);                          // адресуемся для следующего обращения к регистру конфигурации
 Wire.send(0x01);                          // конфигурируем дальнейшее преобразование результата по запросу
// Wire.send(0x02);                          // как вариант - конфигурируем автоматическое преобразование результата
 Wire.beginTransmission(DEV_ID);
 Wire.send(0x22);                          // временно приостановить преобразование данных термометром
// Wire.send(0xEE);                          // для альтернативного варианта - запустить преобразование
 Wire.endTransmission();
}

// Основная часть
void loop()
{
// Запускаем преобразование ... (не требуется в случае, если запустили раньше)  
 Wire.beginTransmission(DEV_ID);
 Wire.send(0xEE);
 Wire.endTransmission();
  
// Даем передышку термометру для преобразования
 delay(750);
 
// Читаем результаты ...
// Сначала значение корректирующего коэффициента COUNT_PER_C
 Wire.beginTransmission(DEV_ID);
 Wire.send(0xA9);
 Wire.endTransmission(); 
 Wire.requestFrom(DEV_ID, 1);
 cpc = Wire.receive();
 
// Теперь значение корректирующего коэффициента COUNT_REMAIN
 Wire.beginTransmission(DEV_ID);
 Wire.send(0xA8);
 Wire.endTransmission(); 
 Wire.requestFrom(DEV_ID, 1);
 cr = Wire.receive();

// Теперь основное значение термометра и "довесок"
 Wire.beginTransmission(DEV_ID);
 Wire.send(0xAA);
 Wire.endTransmission(); 
 Wire.requestFrom(DEV_ID, 2);
 temp = Wire.receive();
 temp2 = Wire.receive();
 
// Приостанавливаем преобразования (в альтернативном варианте - не делаем этого)
 Wire.beginTransmission(DEV_ID);
 Wire.send(0x22);
 Wire.endTransmission();
 
// Считаем результат по формуле:
 result = temp - 0.25 + ((cpc-cr) / cpc);
// Или только учитываем довесок - получаем альтернативный, менее точный, результат (зато без расчетов)
 if (temp2 == 128) result2 = temp + 0.5; else result2 = temp;
 
// Переводим в фарингейты
 tempF = result * 9 / 5 + 32;
 
// Фиксируем возможные минимум и максимум
 if (mintemp>=result) mintemp=result;
 if (maxtemp<=result) maxtemp=result;

// Теперь отрисовваем результат на ЖКИ
 lcd.clear(); 
 lcd.home();
 
// Первая строка отображает температуру в цельсиях:
// * первое показание t' - посчитано по формуле из документации и имеет более точное (хотя и дискретное) значение
// * второе показание t'' - считано непосредственно и имеет дискретное значение с точностью до полградуса цельсия
 lcd.write(0); // Спецсимвол t'
 lcd.print(result);
 lcd.print("C ");
 lcd.write(1); // Спецсимвол t''
 lcd.print(result2);
 lcd.print("C");

 lcd.setCursor(0, 1);
 
// Вариант 1 - Вторая строка отображает расчетные коэффициенты

 lcd.write(0);
 lcd.print(tempF);
 lcd.print("F ");
 lcd.print(temp,0); // "0" - не отображается дробная часть в виду ее отсутствия
 lcd.print(" ");
 lcd.print(cpc,0); // "0" - не отображается дробная часть в виду ее отсутствия
 lcd.print(" ");
 lcd.print(cr,0); // "0" - не отображается дробная часть в виду ее отсутствия

// Вариант 2 - Вторая строка отображает минимальное и максимальное значение
/*
 lcd.setCursor(0, 1);
 lcd.print("l");
 lcd.print(mintemp);
 lcd.print("C h");
 lcd.print(maxtemp);
 lcd.print("C");
*/
}

MiGeRA (ноябрь 2011)



Заглавная » Радиоэлектроника » Arduino - Высокоуровневая платформа устройств на микроконтроллерах » Arduino - Термометр на DS1621