Измерение и логгирование температуры с FEZ Panda II

Я долго думал о чем написать следующий пост, debug, потоки (thread), прерывания и т.п для каждого поста как-то мало получится, а одним постом все в куче, тоже не красиво. Да и теории в принципе хватает, это вы и сами сможете почитать, а что непонятно — спросить в моем блоге.
Но тут подвернулась реальная задача измерения температуры нагрева катушки соленоида ЭМ-клапана в длительном промежутке времени. В дальнейшем я решил писать новые топики с практической реализацией и в каждом топике затрагивать немного теоретической части. Т.о. мы будем медленно, но верно продвигаться от более простых, к более сложным проектам.
Итак, имеем популярный цифровой датчик температуры DS18B20 (даташит). Подключил я его по трехпроводной схеме (с внешним питанием). Здесь можно посмотреть схему подключения к Arduino, у нас будет тоже самое подключение, единственное пин данных — D4.
У GHI хорошая техподдержка и сообщество, и для очень многих шилдов, сенсоров, LCD-экранчиков и т.п. уже имеются готовые библиотеки и примеры программ. Естественно, работа плат FEZ с таким популярным датчиком как DS18B20 там тоже освещена. Я не стал изобретать велосипед и воспользовался вот этим рабочим кодом.
Убрав, немного лишнего кода в итоге получилось вот что:

using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;

namespace DS18B20
{
    public class Program
    {
        public static OneWire ow = new OneWire((Cpu.Pin)FEZ_Pin.Digital.Di4);
        public static void Main()
        {
            while (true)
            {
                int temp;
                int sign;
                float tempc = 0;
                byte[] romid = new byte[8];
                byte[] readall = new byte[9];

                ow.Reset();
                ow.WriteByte(0x33);
                ow.Read(romid, 0, 8);
                ow.Reset();
                ow.WriteByte(0x55);
                ow.Write(romid, 0, 8);
                ow.WriteByte(0x44); // Start temperature conversion 
                Thread.Sleep(1000); //wait for conversion to finish 
                ow.Reset();
                ow.WriteByte(0x55);
                ow.Write(romid, 0, 8);
                ow.WriteByte(0xBE); // Read Scratchpad 
                Thread.Sleep(1000); //wait for conversion to finish 
                ow.Read(readall, 0, 9);
                temp = readall[0];    // LSB 
                temp |= (ushort)(readall[1] << 8);   // MSB 
                //determine if the reading is < 0 
                sign = temp & 0x8000;
                if (sign != 0)
                { // value is < 0 
                    temp = (temp ^ 0xFFFF) + 1;
                    tempc = (float)(((temp >> 1) - 0.25 + ((16.00 - readall[6]) / 16.00)) * -1.00); //See datasheet - way to increase resolution 
                }
                else
                {
                    tempc = (float)((temp >> 1) - 0.25 + ((16.00 - readall[6]) / 16.00)); //See datasheet - way to increase resolution 
                }
                Debug.Print("Temp: " + tempc.ToString("F2"));
                Thread.Sleep(3000);
            }
        }
    }
}

Вверху мы видим новую строчку: using GHIElectronics.NETMF.Hardware,
Это необходимо для работы с протоколом OneWire, по которому работает датчик.
Строкой public static OneWire ow = new OneWire((Cpu.Pin)FEZ_Pin.Digital.Di4), мы показываем, что устройство OneWire подключено к 4 выводу Panda II.
Однако, это еще не все. Если сделать новый проект и скопировать туда данный код, то вы увидите следующие ошибки:Ошибки
Дело в том, что данную библиотеку необходимо включить в проект в обозревателе решений (ссылки)
Для этого, нажимаем правой клавишей мыши на ‘Ссылки’ и выбираем ‘Добавить ссылку’
В открывшемся окне «AddReference» вы увидите большой список библиотек. Вам необходимо выбрать библиотеку GHIElectronics.NETMF.Hardware:Подключение библиотеки GHIElectronics.NETMF.Hardware
Теперь ошибок не будет, и код будет компилироваться без ошибок.
В коде есть такая строка: Thread.Sleep(1000), Как можно догадаться, это пауза. Задается в миллисекундах. Т.е. в данном случае происходит пауза при выполнении кода в 1 секунду. В нашем коде находится 3 таких строчки и т.к. код выполняется в постоянном цикле, то каждый цикл будет длиться 1+1+3=5 сек.
Еще одна полезная строчка кода: Debug.Print(«Temp: » + tempc.ToString(«F2»)), которая выводит измеренную температуру в окно отладки.
Debug.Print() очень полезная функция и она незаменима при отладке приложения.
В итоге, после заливки программы в контроллер мы увидим следующие данные в окне вывода:Окно вывода
Теперь немного усложним код. Для того, чтобы видеть, что измерение температуры сделано я решил задействовать встроенный LED. Для этого, я написал небольшую функцию:

public static void BlinkLED(int num)
        {
            int count = 0;
            num = num * 2;
            bool ledState = false;
            while (count < num)
            {
                ledState = !ledState;
                led.Write(ledState);
                count++;
                Thread.Sleep(50);
            }
            led.Write(false);
        }

Данная функция заставляет мигать встроенный на плату светодиод (объект «led») количество раз, равное «num». Пауза 50мс.
Теперь, вызвав данную функцию скажем так: BlinkLED(150), светодиод моргнет 150 раз.
Также, мы немного переделаем наш код, убрав измерение температуры из цикла в отдельную функцию. После модернизации код будет выглядеть так:

using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;

namespace DS18B20
{
    public class Program
    {
        static float temp;     //Температура
        
        public static OneWire ow = new OneWire((Cpu.Pin)FEZ_Pin.Digital.Di4);
        public static OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false); //Инициализация LED
        
        public static void Main()
        {
            while (true)
            {
                temp = GetTemperature();    //Считываем показания температуры с датчика DS18B20
                Debug.Print("Temp: " + temp);   //Вывод данных текущей температуры
                BlinkLED(10);               //Мигаем 10 раз встроенным LED
                Thread.Sleep(3000);         //Пауза 3 сек.
            } 
        }
        public static float GetTemperature()
        {
            int temp2;
            int sign;
            float tempc = 0;
            byte[] romid = new byte[8];
            byte[] readall = new byte[9];

            ow.Reset();
            ow.WriteByte(0x33);
            ow.Read(romid, 0, 8);
            ow.Reset();
            ow.WriteByte(0x55);
            ow.Write(romid, 0, 8);
            ow.WriteByte(0x44); // Start temperature conversion 
            Thread.Sleep(1000); //wait for conversion to finish 
            ow.Reset();
            ow.WriteByte(0x55);
            ow.Write(romid, 0, 8);
            ow.WriteByte(0xBE); // Read Scratchpad 
            Thread.Sleep(1000); //wait for conversion to finish 
            ow.Read(readall, 0, 9);
            temp2 = readall[0];    // LSB 
            temp2 |= (ushort)(readall[1] << 8);   // MSB 
            //determine if the reading is < 0 
            sign = temp2 & 0x8000;
            if (sign != 0)
            { // value is < 0 
                temp2 = (temp2 ^ 0xFFFF) + 1;
                tempc = (float)(((temp2 >> 1) - 0.25 + ((16.00 - readall[6]) / 16.00)) * -1.00); //See datasheet - way to increase resolution 
            }
            else
            {
                tempc = (float)((temp2 >> 1) - 0.25 + ((16.00 - readall[6]) / 16.00)); //See datasheet - way to increase resolution 
            }
            return tempc;
        }
        public static void BlinkLED(int num)
        {
            int count = 0;
            num = num * 2;
            bool ledState = false;
            while (count < num)
            {
                ledState = !ledState;       //Инвертируем предыдущее состояние
                led.Write(ledState);
                count++;
                Thread.Sleep(50);
            }
            led.Write(false);   //Чтобы не оставался включенным
        }
    }
}

В код я добавил комментарии, поэтому думаю все понятно. Как видите, в основном цикле программы теперь всего 4 строчки кода. Последней строкой в цикле стоит пауза 3 сек, но учтите, что в функции GetTemperature() находится еще 2 паузы по 1 сек. Поэтому выполнение данной функции занимает 2 секунды.

Логгирование

На плате FEZ Panda 2 присутствует встроенный слот для MicroSD карт. Его я и решил использовать для сохранение данных о температуре.
Каждые 10 секунд я буду сохранять полученную информацию о температуре с датчика, в файл temp.csv. Помимо температуры, чтобы в дальнейшем построить наглядный график, необходимо сохранять и время. В Panda, есть встроенные часы реального времени RTC. Но, для того, чтобы они сохраняли время после перезагрузки и отключения питания, необходимо подключить внешнюю батарейку. В начале я их и хотел задействовать, но честно говоря немного поэкспериментировав не стал этого делать, да и для моей задачи они не нужны. Тем более в Excel для меня стала проблема построить график, где по X-были данные формата даты (ну не силен я в Excel, мне легче в PHP график сдела

4.5 9 голоса

Оцените статью!

guest
0 Комментарий
Межтекстовые Отзывы
Посмотреть все комментарии