понеділок, 13 квітня 2020 р.

ПІДКЛЮЧЕННЯ СЕНСОРІВ З ІНТЕРФЕЙСОМ

1-Wire - протокол передачі даних в обидві сторони по одній лінії. Даний протокол розроблений корпорацією Dallas Semiconductor (зараз Maxim Integrated) в далеких 90-х, але активно використовується і зараз.
На 1-Wire сьогодні працює більшість "пігулок" - домофонних чіпів (DS1990A), карток доступу, а також через 1-Wire спілкуються популярні сенсори температури (DS18S20 і DS18B20), транзисторні ключі (DS2405, DS2406), програмовані порти введення-виведення (DS2408), АЦП і ЦАП, годинник реального часу (DS2417) і багато іншого.
Режим зв'язку в цьому протоколі - асинхронний і напівдуплексний, а при надсиланні мультибайтних цілих передача йде від молодшого байта до старшого. При цьому у нас завжди є ведучий - один пристрій на шині, який відсилає команди, і ведені - пристрої, які ці команди приймають і відповідають на них, якщо необхідно; кожний з ведених пристроїв підключається безпосередньо до загальної шині.
Ще раз підкреслимо - на шині може бути лише один ведучий - інакше виникнуть конфлікти, коли обидва ведучих «тягнутимуть ковдру на себе».
Протокол 1-Wire хороший тим, що не складний в реалізації і вимагає для зв'язку всього два-три дроти (шина даних, земля і, при необхідності, живлення); однак при цьому він не позбавлений і недоліків - цей протокол досить чутливий до часу і до завад. Також 1-Wire не призначений для передачі великих обсягів інформації та для швидкісного обміну даними - максимальна швидкість 15,4 Кбіт/с.
Відстань передачі досягає 300 м, якщо дотримуватися певних умов:
  • - застосування кабеля типу "вита пара";
  • - використання спеціального драйвера мережі (активне підтягування з врахуванням струму в лінії);
  • - використання технології «спільна шина» з єдиним стовбуром (не вільна топологія);

Фізично для організації інтерфейсу необхідні як мінімум лінія для даних і "земля"; досить часто також для підключення пристроїв необхідна також лінія живлення, проте деякі ведені пристрої можуть живитися і паразитно - отримувати "підживлення" через шину даних. Згідно інструкції з використання, шина даних повинна бути підтягнута до живлення резистором 4.7 кОм, однак даний номінал використовується при відносно коротких лініях; якщо ж відстань між пристроями досить велика, то опір резистора можна зменшити.
Обмін інформацією ведеться так званими тимчасовими, або тайм-слотами (60 мкс): один тайм-слот служить для обміну одним бітом інформації. Дані передаються біт за бітом, починаючи з молодшого біта молодшого байта - це, до речі, досить часто призводить до помилок у новачків - здається, що потрібно передавати дані зліва направо, так, як вони зберігаються в пам'яті - але при передачі по 1-Wire, наприклад, двобайтового числа порядок передачі буде таким:
Маємо число 1023410, яке в двійковому вигляді виглядає так: 00100111 11111010.
Передача по 1-Wire буде виглядати так:
0 → 1 → 0 → 1 → 1 → 1 → 1 → 1 → 1 → 1 → 1 → 0 → 0 → 1 → 0 → 0
При обміні інформацією ведучий ініціює кожний зв'язок на бітному рівні. Це означає, що передача кожного біта, незалежно від напрямку (передача чи прийом), повинна бути ініційована ведучим. Шина даних за замовчуванням підтягується до "одиниці", тому для початку як прийому, так і для передачі ведучий опускає лінію на деякий час в "нуль".
Увага: ні ведучий, ні ведені не виставляють на шині "одиницю" - це може призвести до короткого замиканням: якщо один пристрій виставить на шині "1", а інший - "0"; тому як ведучий, так і ведений можуть використовувати тільки два стани: "на вихід в нуль" і "z-стан" (на вхід без підтягування). Підтягування до живлення здійснюється резистором.
Розглянемо 5 основних команд для зв'язку по шині 1-Wire: "Запис 1", "Запис 0", "Читання", "Скидання" і "Присутність".
На малюнках червоним виділено управління лінією від ведучого, синім - управління лінією від веденого, чорним - звільнена лінія (за допомогою підтягування шина автоматично переходить в "одиницю").
Сигнал "Запис 1". Ведучий встановлює низький рівень протягом 1 ... 15 мкс. Після цього, протягом решти тимчасового слота він звільняє шину
Сигнал "Запис 0". Ведучий формує низький рівень протягом не менше 60 мкс, але не довше 120 мкс:
Сигнал "Читання". Ведучий встановлює низький рівень протягом 1 ... 15 мкс. Після цього ведений, якщо хоче передати 0, утримує шину в низькому стані до 60 мкс; якщо ж ведений хоче передати 1, то він просто звільняє лінію. Ведучий зазвичай сканує стан шини після закінчення 15 мкс після встановлення низького рівня на шині:
Так, ведений утримує лінію до землі, якщо хоче передати "0", і просто відпускає лінію, якщо хоче передати "1".
Таким чином при читанні отримуємо наступні діаграми:
Сигнал "Читання при отриманні 1":
Сигнал "Читання при отриманні 0":
Основні проблеми, які виникають при реалізації читання-запису - це проблеми з часом, тобто "невитримування", або навпаки, "перевитримування" тимчасових затримок при читанні лінії. Виникають ці проблеми через те, що часто не роблять поправку на затримку виконання команд мов програмування високого рівня. Особливо це стосується різних "додаткових" функцій.
Сигнал "скидання/присутність". Тут тимчасові інтервали імпульсів відрізняються. Ведучий встановлює низький рівень протягом 8 тимчасових слотів (480 мкс), а потім звільняє шину. Даний тривалий період низького стану називається сигналом "скидання".
Якщо на шині присутній ведений, то він повинен протягом 60 мкс після звільнення вкдучим шини встановити низький рівень тривалістю не менше 60 мкс. Даний відгук носить назву "присутність". Якщо такий сигнал не виявляється, то ведучий повинен думати, що немає підключених пристроїв до шини і подальший зв'язок неможливий.
Дана послідовність сигналів завжди починає будь-який обмін інформацією між пристроями.
Крім цього, потрібно враховувати, що будь-який ведений пристрій після підключення живлення відразу ж видає сигнал присутності.
Сигнал "скидання" дозволяє ведучому достроково завершити обмін інформацією - наприклад, якщо сенсор температури передає нам всю свою пам'ять, а нам потрібні тільки перші два байта, які містять значення температури, то після отримання цих двох байт мікросхема просто може опустити лінію в нуль на потрібну тривалість часу - сенсор зрозуміє, що більше нічого пересилати не треба.
При реалізації зазвичай необхідно запрограмувати мікроконтролер чи мікрокомп’ютер як ведучий пристрій, тому мікрокомп’ютеру варто генерувати сигнали тривалості трохи більшої необхідного мінімуму, а відповіді від ведених пристроїв чекати за найгіршими прогнозами - тоді взаємодія по протоколу буде оптимальною.
При цьому ведучому треба не забувати періодично перевіряти стан лінії даних - те, що вона повертається в підтягнутий стан з плином часу - а то може виникнути ситуація, наприклад, що який-небудь ведений зламався і закорочує, наприклад, лінію в нуль – і, в принципі, протокол не перевіряє дану проблему сам, хоча помилка може і не виникнути.
Розглянемо "вищий" рівень протоколу 1-Wire - послідовність дій при взаємодії ведучого і веденого, а також основні команди на прикладі використання температурних сенсорів.
Використання температурних сенсорів з Raspberry Pi
Raspberry Pi не має виводів АЦП (аналого-цифрового перетворювача) в GPIO, і тому зможемо використати лише цифровий сенсор температури.
Сенсор, який найчастіше вибирають, це Dallas DS18B20 - сенсор температури з інтерфейсом 1-Wire (однопровідний). Він відносно дешевий, його легко знайти, простий у використанні і показує температуру з точністю до +/-0,5 градуса у всьому діапазоні від -10 до +85 градусів Цельсія.
Для того, щоб він взаємодіяв з Raspberry Pi, нам потрібний лише один резистор - на 4,7 К, який діє як «підтягуючий» резистор, - і підключити все, як показано нижче:
Спочатку не забудьте дозволити інтерфейс 1-Wire в меню Налаштування -> Інтерфейси, щоб Raspberry Pi зміг приймати дані від сенсора.
Далі, увійдіть на Raspberry Pi і в командному рядку виконайте такі команди:

sudo modprobe w1-gpio
sudo modprobe w1_therm


щоб завантажити модулі ядра однопровідних пристроїв зв'язку, необхідні для використання сенсора температури.
(Щоб уникнути необхідності ручного введення цих команд щоразу, коли повторно завантажуєте Pi, відредагуйте з використанням nano або подібного редактора файл "/etc/modules" додаванням рядків w1-gpio і w1_therm у кінець файлу.)
Тепер в командному рядку введіть:

ls -l /sys/bus/w1/devices/

щоб побачити список пристроїв, підключених в даний момент до вашого Raspberry Pi.
Ваш сенсор температури з'явиться з адресою у форматі 28-00000xxxxxx. Нижче можете побачити, що адреса нашого сенсора температури була 28-00000283c6cd. Кожен сенсор температури DS18B20 має унікальну жорстко задану адресу, так що ви при необхідності можете підключити кілька сенсорів температури і, як і раніше, читати їх окремо.
Знайдіть свій сенсор температури і введіть наступну команду в терміналі, щоб відкрити файл сенсора і переглянути показання температури:

cat /sys/bus/w1/devices/28-00000283c6cd/w1_slave

(переконавшись, звичайно, що підставили адресу свого власного сенсора температури)

Вище ми бачимо, що на виході цієї команди є два рядки даних. Наприкінці другого рядку після "t=" є числове значення. Це значення є помножена на 1000 температура сенсора в градусах Цельсія. Тому, в нашому прикладі, ми бачимо показання t=24812 і температура буде 24812/1000 = 24,812 градусів за Цельсієм.
Читати температуру за допомогою командного рядка, як тут, не дуже зручно. Загалом ми хочемо вимірювати температуру через регулярні проміжки часу і або відображати десь, або зберігати в файлі для подальшого аналізу. Для цього ми повинні написати сценарій. Наш простий сценарій на Python для вимірювання та відображення температури один раз в секунду може бути таким:
Цей сценарій один раз на секунду читає файл сенсора температури, отримує другий рядок, розбиває його на розділені пробілами елементи, отримує десятий з цих елементів (деномінованих '9', бо '0' є першим елементом), пропускає перші два символи ("t=") цього елемента і перетворює те, що залишається (24812 в нашому прикладі), з рядка в числове значення, яке потім ділиться на 1000, щоб показати нам температуру, яка виводиться на екран.
Скріншот вище показує запуск сценарію поки сенсор температури проходить нагрівання.

Сценарій Python для читання даних з сенсора
Створимо новий сценарій Python у вікні терміналу (наприклад, з nano temperature.py) або з IDLE (Interactive Development Environment).
Нашим першим кроком є імпорт необхідних модулів: os дозволяє нам включити драйвери 1-Wire та інтерфейс з нашим сенсором, а time дозволяє Raspberry Pi визначити час та використовувати часові періоди в нашому коді.
Введемо наступний код:

# Імпорт бібліотек
import os
import time

# Ініціалізація виводів GPIO
os.system('modprobe w1-gpio') # Вмикання модуля GPIO
os.system('modprobe w1-therm') # Вмикання модуля Temperature

# Отримання device file (w1_slave file), який зберігає дані температури
temp_sensor = ‘sys/bus/w1/devices/28-000005e2fdc3/w1_slave

# Функція, яка читає дані з сенсора
def temp_raw():
   f = open(temp_sensor, 'r') # Відкриття значення температури в device file
   lines = f.readlines() # Повернення тексту
   f.close()
   return lines

# Перетворення значення сенсора в температуру
def read_temp():
   lines = temp_raw() # Читання температури 'device file'

   # Якщо перший рядок не має 'YES', чекати 0.2 с
   # і потім прочитати device file знову.
   while lines[0].strip()[-3:] != 'YES':
      time.sleep(0.2)
   lines = temp_raw()

   # Знаходження позиції '=' в другому рядку
   # device file.
   temp_output = lines[1].find('t=')

   # Якщо '=' знайдено, то перетворення решти рядка після
   # '=' в градуси Цельсія, а потім в градуси Фаренгейта
   if temp_output != -1:
      temp_string = lines[1][temp_output +2:]
      temp_c = float(temp_string) / 1000.0
      temp_f = temp_c * 9.0 / 5.0 + 32.0
      return temp_c, temp_f

# Виведення температури, поки не зупинимо програму.
while True:
   print(read_temp())
   time.sleep(1)
Щоб запустити код, необхідно визвати його з правами Super User:
sudo python temperature.py

Швидке відображення температури в командному рядку – Bash
Замість того, щоб писати сценарій Python для читання температури з сенсора, можна написати один рядок команди, яка буде читати сенсора, витягувати температуру з частини повернутих даних і обробляти результат за допомогою Bash в командному рядку Raspberry Pi.
Є багато способів для досягнення цієї мети, але от один приклад з використанням sed і awk:

cat /sys/bus/w1/devices/28-00000283c6cd/w1_slave | sed -n 's/^.*\(t=[^ ]*\).*/\1/p' | sed 's/t=//' | awk '{x=$1}END{print(x/1000)}'

Символ труби "|" використовується для передачі виводу однієї команди до наступної команди. Цей скрипт спочатку читає температуру з сенсора, перш ніж повернути два рядки даних, остання частина другого рядка, яка є t=XXXXX, де XXXXX - температура в мілліградусах Цельсія. Потім ми використовуємо sed, щоб знайти «слово», яке починається з 't=' в даних, далі пересилаємо його до другої команди sed, яка видаляє 't='. Нарешті, чисельний результат пересилається до команди awk, яка ділить цей результат на 1000 і відображає температуру в градусах Цельсія.
Очевидно, що ви не хотіли б набирати цей довгий рядок щоразу, коли перевіряєте температуру свого сенсора, тому можете створити псевдонім:
alias checktemp="cat /sys/bus/w1/devi......x/1000)}"

Тепер при введенні команди checktemp в командному рядку, будуть запущені всі збережені команди.

Альтернативно, можете зберегти команди як сценарій оболонки. Для цього відкрийте текстовий редактор за допомогою команди:

sudo nano checktemp

який створить порожній файл з ім'ям checktemp. Введіть:

#!/bin/bash

в першому рядку, а потім введіть команди cat /sys/bus... і т.д. в другому рядку. Натисніть Ctrl-X, щоб вийти і зберегти файл. Щоб зробити даний файл виконуваним для можливості його запуску, введіть:

chmod +x checktemp

і, нарешті, перемістимо його в каталог /usr/bin, де зберігається більшість виконуваних файлів:

mv checktemp /usr/bin/

Тепер, коли набираєте checktemp в командному рядку, то буде запускатися ваш сценарій і буде відображатися прочитана з сенсора температура.

Підключення декількох сенсорів температури до Raspberry Pi
Тепер ми розглянемо, як можна під’єднати кілька сенсорів температури до Raspberry Pi, що особливо корисне для деяких додатків вимірювання різниці температур, де потрібні два або більше сенсорів температури.
Вище показано, як схематично підключити три температурних сенсори DS18B20 до GPIO виводів Raspberry Pi. Відзначимо, що хоча ми використовуємо декілька температурних сенсорів для читання, ми маємо три з'єднання з Raspberry Pi: 3,3 В і 0 В підключення живлення сенсорів, і один провід даних, який повертає прочитану температуру від всіх сенсорів.
Прочитати показання температури з декількох сенсорів через один провід можна тому, що кожен сенсор DS18B20 має унікальний серійний номер, закодований в нього при виготовленні, який Raspberry Pi може використати для його ідентифікації.
При використанні декількох сенсорів, перше, що треба зробити, це отримати серійний номер для кожного сенсора і фізично маркувати їх, щоб знати, де який сенсор, коли будете встановлювати їх у різних місцях всієї системи.
Дотримуйтесь інструкцій, наведених вище, про підключення одного сенсора, щоб встановити кожен з них на своєму Raspberry Pi і скористайтеся командою:

ls -l sys/bus/w1/devices

щоб знайти серійний номер для першого сенсора.
Потім додайте другий сенсор і визначте його, повторно перевіривши підключені пристрої та відзначте його серійний номер. Повторіть цей процес, поки не підключите і не визначите всі сенсори.
Щоб підтвердити, що все працює як треба, отримайте температуру з кожного сенсора один за одним за допомогою команди:

cat /sys/bus/w1/devices/28-00000xxxxxxx/w1_slave

... замінивши XXXXXXX правильним серійним номером для кожного сенсора.
Тепер ви готові використовувати сенсори температури у своєму проекті на Raspberry Pi. Подібним чином можна використовувати з Raspberry Pi й інші цифрові сенсори з інтерфейсом 1-Wire.

Використання WebIOPi для роботи з сенсорами
WebIOPi також може обробляти отримані дані з різних пристроїв, у тому числі з сенсорів. Ви можете використовувати цю функціональність, щоб перетворити свій RPi в веб-термометр, підключивши сенсор температури до нього і створивши простий додаток WebIOPi для читання даних сенсора. Ми використаємо сенсор температури DS18S20 і резистор 4.7K.
Почніть з підключенням обох компонентів, як було показано на схемі вище (вивід "землі" 1 - до виводу Ground, вивід даних 2 -.до виводу 7 GPIO, а вивід живлення 3 - до 3,3 В)
Після підключення DS18B20 подайте живлення на RPi, зайдіть в систему, далі введіть в терміналі:
sudo nano /boot/config.txt.
Додайте внизу текста, який відкрився, рядок:
dtoverlay=w1–gpio
Збережіть зміни, вийдіть з nano і перезавантажте RPi
sudo reboot
Далі, ви повинні включити сенсор в конфігурації WebIOPi. Щоб зробити це, запустіть команду:
sudo nano /etc/webiopi/config
Розкоментуйте рядок
#temp2 = DS18B20
(тобто, видаліть символ #) у розділі DEVICES. Потім перезавантажте WebIOPi допомогою команди:
sudo /etc/init.d/webiopi restart
Якщо ви вже завантажили в терміналі необхідні модулі ядра w1-gpio і w1-therm, як описано вище, і знайшли серійний номер сенсора температури, то можемо відкрити браузер.
Введіть в браузері адресу
http://raspberrypi:8000/app/devices-monitor
 і ви повинні побачити поточне показання температури. Звичайно, сторінка за замовчуванням для моніторингу сенсорів та пристроїв є недостатньою і не особливо функціональною, тому, можливо, захочете створити свій власний веб-додаток для читання і відображення даних сенсора. Але чудово, що вам не доведеться починати з нуля: На офіційному форумі WebIOPi, ви можете знайти розумний веб-додаток, який зчитує температуру і відображає її за допомогою віджета Google gauge як показано на рис. нижче:
Код, щоб вивчити і налаштувати показ температури з Google Gauge, такий:
<html>
         <head>
         <script type="text/javascript"
src="//www.google.com/jsapi"></script>
         <script type="text/javascript" src="/webiopi.js"></script>
         <script type="text/javascript">
         webiopi().ready(function() {
         tmp = new Temperature("temp2");{
         setInterval(updateUI,1000);
         }
                 function updateUI() {
                         tmp.getCelsius(temperatureCallback);
                 }
                 function temperatureCallback(tmp, data) {
                         gaugeData.setValue(0, 0, data);
                         gauge.draw(gaugeData, gaugeOptions);
                 }
         });
         </script>
         <script type="text/javascript">
         google.load('visualization', '1', {packages: ['gauge']});
         google.setOnLoadCallback(drawGauge);
         var gaugeOptions = {min: 0, max: 110, yellowFrom: 50, yellowTo: 70,
         redFrom: 70, redTo: 110, minorTicks: 5};
         var gauge;
         function drawGauge() {
                 gaugeData = new google.visualization.DataTable();
                 gaugeData.addColumn('number', 'Temp');
                 gaugeData.addRows(1);
                 gaugeData.setCell(0, 0, 0);
                 gauge = new google.visualization.Gauge(document.getElementById('gauge_div'));{
                 gauge.draw(gaugeData, gaugeOptions);
                 }
         }
         </script>
</head>
<body>
<div id="gauge_div" style="width:560px; height: 280px;"></div>
</body>
</html>
Нам потрібно переналаштувати WebIOPi, щоб він використовував каталог /home/pi/project/html, як свій кореневий каталог документів. Створіть відповідні каталоги і в каталозі html збережіть показаний вище код.
Тепер внесіть зміни у файл конфігурації:
sudo nano /etc/webiopi/config
Команда відкриє конфігураційний файл у текстовому редакторі nano. Додайте рядок doc-root = /home/pi/project/html в секції [HTTP]. Збережіть зміни і перезавантажте WebIOPi за допомогою:
sudo /etc/init.d/webiopi restart
В браузері за посиланням http://raspberrypi:8000 ви повинні побачити відображення температури з Google Gauge, звичайно, замінивши raspberrypi на ІР-адресу свого мікрокомп’ютера.

Немає коментарів:

Дописати коментар