Сообщество - Arduino & Pi

Arduino & Pi

1 493 поста 20 825 подписчиков

Популярные теги в сообществе:

2728

Как я делал удаленное управление теплом в гараже.

Для обогрева своего гаража, я использую 2 "конвектора". Один конвектор включен постоянно на +5 градусов, для поддержания плюсовой температуры, второй "конвектор" включается по необходимости.


Раньше приходилось бегать, включать его, уходить домой, ждать час-два пока температура поднимется до комфортных +20, но это быстро надоело, одолела лень и я решил применить максимально бюджетный вариант удаленного включения на Arduino.


Что необходимо было купить:

Arduino nano: https://ru.aliexpress.com/item/Freeshipping-1PCS-Nano-3-0-co...

146 руб

Модуль ENC28J60: https://ru.aliexpress.com/item/2PCS-ENC28J60-Ethernet-LAN-Ne...

165 руб

Датчик температуры DHT22: https://ru.aliexpress.com/item/1pcs-DHT22-digital-temperatur...

151руб

Реле: https://ru.aliexpress.com/item/5PCS-LOY-1-Channel-5V-Relay-M...

40руб

Коротко о подключении всего этого барахла.


Модуль ENC28J60:

VCC к 5V

GND к GND

SCK к Pin 13

SO к Pin 12

ST к Pin 11

CS к Pin 10


Реле:

S к Pin 2

Vcc к 5V

GND к GND


Датчик температуры DHT22:

Vcc к 3.3V

GND к GND

DATA к Pin4

Здесь все понятно без схем, если не понятно, в интернете есть масса материала о том, как подключать эти модули. А вот готового скетча, я не нашел, да и искать было лень… Проще было найти скетч управления реле и скетч вывода данных с датчика, скрестить их и набросать страницу, чтоб ей было удобно управлять с телефона и обычного ПК.


Что из этого вышло:


#include "DHT.h"

#include <EEPROM.h>

#define DHTPIN 4

#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

#include <EtherCard.h>

static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 }; // MAC Address должен быть уникальным в локальной сети

static byte myip[] = { 192,168,1,222 }; // Постоянный IP адресс нашей страницы

byte Ethernet::buffer[1000];

BufferFiller bfill;

// Начальные данные

int LedPins[] = {

2,3,5,6,7,8,9};

int t=0;

int h=0;

boolean PinStatus[7];

const char http_OK[] PROGMEM =

"HTTP/1.0 200 OK\r\n"

"Content-Type: text/html\r\n"

"Pragma: no-cache\r\n\r\n"

"\r\n"

"<meta charset='UTF-8'>"

"<meta name='viewport' content='width=device-width, initial-scale=1.0'>"

"<meta http-equiv='refresh' content='10'/>";

const char http_Found[] PROGMEM =

"HTTP/1.0 302 Found\r\n"

"Location: /\r\n\r\n";

const char http_Unauthorized[] PROGMEM =

"HTTP/1.0 401 Unauthorized\r\n"

"Content-Type: text/html\r\n\r\n"

"<h1>401 Unauthorized</h1>";

// Подключаем Ethernet порт HR911105A и датчик DHT22

void setup () {

if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0)

Serial.println( "Failed to access Ethernet controller");

ether.staticSetup(myip);

for(int i = 0; i <= 7; i++)

{

pinMode(LedPins[i],OUTPUT);

PinStatus[i]=EEPROM.read(i);

digitalWrite(LedPins[i],PinStatus[i]);

}

dht.begin();

}

// Получаем данные от DHT22

static void ReadDHT22()

{

h = dht.readHumidity();

t = dht.readTemperature();

}

// Оформление Web страницы

static word homePage() {

bfill = ether.tcpOffset();

bfill.emit_p(PSTR("$F"

"<title>Гараж</title>"

"<p style=\"text-align: center;\"><br />Конвектор: <br> <span style=\"font-size: 4em;\"><a href=\"?ArduinoPIN2=$F\">$F</a></span>"),

http_OK,

PinStatus[0]?PSTR("off"):PSTR("on"),

PinStatus[0]?PSTR("<font color=\"green\"><b>ON</b></font>"):PSTR("<font color=\"red\">OFF</font>"));

bfill.emit_p(PSTR(

"<br><br>Температура: <br> <span style=\"font-size: 4em;\">$D C</span> <br /><br />Влажность:<br> <span style=\"font-size: 4em;\"> $D %</span></p>"),t, h);

return bfill.position();

}

void loop () {

delay(1); // Задержка

word len = ether.packetReceive();

word pos = ether.packetLoop(len);

if (pos) // check if valid tcp data is received

{

ReadDHT22();

bfill = ether.tcpOffset();

char *data = (char *) Ethernet::buffer + pos;

if (strncmp("GET /", data, 5) != 0) {

bfill.emit_p(http_Unauthorized);

}

else {

data += 5;

if (data[0] == ' ') {

homePage();

}

else if (strncmp("?ArduinoPIN2=on ", data, 16) == 0) {

PinStatus[0] = true;

digitalWrite(LedPins[0],PinStatus[0]);

EEPROM.write(0,PinStatus[0]); // записываем в ячейку EEPROM №0, текущее состояние LedPins[0].

bfill.emit_p(http_Found);

}

else if (strncmp("?ArduinoPIN2=off ", data, 17) == 0) {

PinStatus[0] = false;

digitalWrite(LedPins[0],PinStatus[0]);

EEPROM.write(0,PinStatus[0]);

bfill.emit_p(http_Found);

}

else {

// Page not found

bfill.emit_p(http_Unauthorized);

}

}

ether.httpServerReply(bfill.position()); // send http response

}

}


Коротко о данном скетче:

В память ардуины (EEPROM) сохраняется информация о последнем положении кнопки реле, перебои со светом нам не страшны, положение кнопки всегда отражает реальное состояние реле, не будет такого, что на странице выводится OFF а на самом деле ON.


Далее подключаю сборку к локалке, для питания использую старую зарядку от мобильного телефона.


Вызываю страницу по IP адресу, который мы задали в начале скетча: http://192.168.1.222


Получаю страницу с данными:

Всё открывается, данные с датчика верные, реле на нажатие кнопки реагирует, положение запоминает.


Далее нужен корпус. Можно заколхозить из какого-нибудь пластикового контейнера, или заказать на али типовой пластиковый корпус для подобного барахла, или купить распределительную коробку в электротоварах, но мне лень выходить из дома, поэтому, я по-быстрому накидал в солиде уродца и распечатал его на 3D принтере.

Собрал все в корпус, закрепил модули термоклеем.

Установил крышку, держится и без шурупов, можно было и не предусматривать отверстия под них.

Когда моделировал корпус, особо головой не думал, по этому реле почему-то сделал по середине… Лучше было его разместить с краю. Ну да ладно, и так сойдет…

Притащил все в гараж, подключил, проверил. Вывел двойную розетку т.к. одинарной под руками не было.

Вывел датчик DHT22 примерно на среднюю высоту стены, т.к. конвекторы сильно греют потолок, а пол помещения долго остается прохладным.


Датчик кстати оснащен и гигрометром, это очень хорошо, т.к. в мастерской я работаю с деревом, знать о текущей влажности воздуха очень полезно.

Провел интернет в гараж. Купил недорогую направленную Wi-Fi антенну, поставил её на карниз пока вот так, летом если дойдут руки и не будет лень сделаю нормальный кронштейн.

В гараже установил обычную точку доступа и настроил её как адаптер. Поймал сигнал от направленной антенны, которая без труда пробила стену гаража, поставил небольшой коммутатор и подключил к нему нашу систему.


Теперь гараж с домом у нас в одной сети и самое время настроить виртуальный сервер на домашнем роутере.


Прописываем порт который мы открываем например 7777, прописываем IP нашей системы 192.168.1.222, прописываем порт по которому будет доступна наша страница, для доступа из браузера порт 80.

При наличии статического IP адреса от провайдера, наша система теперь доступна откуда угодно по адресу http://нашip:порт


Если провайдер не предоставляет статический IP, можно сделать и другими способами, но для этого потребуется всегда включенный ПК в доме.


У меня есть статика и зарегистрированный домен, к поддомену которого, я привязал свою систему и мне нет необходимости помнить свой IP для доступа к управлению.

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

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


Спасибо за внимание. Если есть вопросы, готов ответить )

Показать полностью 18
156

Прошивка ESP8266 по WIFI и присвоение статического IP

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

Прошивка ESP8266 по WIFI и присвоение статического IP

И всего-то нужно в скетч добавить пару строк и ВСЁ, теперь оно доступно для прошивки по сети!

Хотя что я рассказываю, всё объясняю в видео, смотрим:

Показать полностью 1 1
205

Контроль уровня CO2 (Углекислого газа) на Arduino

И вот очередная идея, доведенная до готового устройства. На этот раз это устройство, контролирующее уровень углекислого газа (CO2) в помещении, и при превышении этого уровня, устройство переключает реле, которое в свою очередь запускает вентиляцию.

Собрано устройство на основе Arduino Pro mini и инфракрасного измерителя CO2 MH-Z19. LCD дисплей 1602 отображает данные с датчика температуры и влажности, уровень CO2 в ppm(промилле) и пороговый уровень срабатывания реле. Порог срабатывания устанавливается с помощью энкодера KY-040, это оказалось удобнее, чем использовать просто кнопки. Для питания устройства от сети 220В, использовал преобразователь AC-DC 220 - 5.

Схема устройства в таком вот виде:

Видео по этой статье:

Скетч Arduino IDE и библиотеки качаем тут: https://yadi.sk/d/CtE6i18336LguQ

Показать полностью 2 1
164

#8 Функции и их применение. Основы Arduino для начинающих

Привет начинающим ардуинщикам! :)


После небольшого перерыва, наконец-то готова 8-я видео-статья из цикла «Основы Arduino для начинающих» и сегодня мы поговорим о таком важном инструменте в арсенале программиста, как функции. Научимся с ними работать и использовать их в своем коде.


Предыдущие выпуски вы найдете здесь: 0,1,2,3,4,5,6,7


Видеоверсия поста:

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


Если мы пойдем по пути написания программы, как мы это делали раньше, то у нас получится очень длинная вереница строк кода, где будет трудно найти начало кода для обработки полученной информации, с какого-либо нужного нам датчика.

Гораздо удобнее будет разбить нашу систему и её код на отдельные выполняемые ими функции. Например, датчику освещенности сопоставить функцию измерения освещенности, датчику температуры – измерение температуры и так далее. В результате мы получим некоторый список функций, с которыми уже будет гораздо проще работать и осуществлять различные манипуляции.

Удобство функций также заключается в том, что мы можем передавать и получать от них какую-либо информацию. К примеру, у нас есть функция вывода информации на дисплей, которую мы можем настроить на прием каких-либо символов. Тогда в основном коде вам останется только указать имя функции и необходимый текст, который вы желаете вывести на экран, а дальше уже не отвлекаться на не нужную часть кода по выводу этого текста на дисплей.

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

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


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


Для начала возьмем очень простую задачу. Допустим, что в вашей программе часто (а говоря часто, я имею в виду 2 и более раза), приходится использовать один и тот же фрагмент кода - например, зажигать несколько светодиодов и подавать сигнал в зависимости от состояния какого-либо пина. Можно пойти по сложному пути и всякий раз писать лишние строки в те места кода, где это понадобится, а можно всего один раз написать функцию и затем вызывать ее в нужных местах – что мы сейчас и сделаем.

Простейшая функция выглядит следующим образом:

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


Итак, заготовка простейшей функции готова и в ней уже написан необходимый нам код.

Давайте посмотрим, как же вызывать эту функцию в основном цикле программы. На самом деле, все так же просто – вам нужно указать имя этой функции и обязательно не забыть про круглые скобки и точку с запятой. Так как функция ничего не принимает, то мы так же оставляем скобки пустыми.

Теперь, если представить что мы программа, то алгоритм работы будет такой: сначала, как и обычно, происходит запуск микроконтроллера и его настройка в функции setup, затем мы переходим в функцию loop и затем, попадая на строчку вызова нашей функции, переходим в эту функцию. В ней так же строка за строкой выполняется каждая команда и, по окончанию функции, осуществляется выход из нее обратно на то место, откуда был осуществлен вызов.


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

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


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


Что бы использовать эту возможность, теперь в пустых скобках мы должны указать тип и имя переменной, которая будет отвечать за номер пина. Назовем её, например, numberPin и дадим ей тип byte, который может нести в себе число от 0 до 255.

Теперь, обращаясь к функции, мы так же обязаны указать в круглых скобках число от 0 до 255 и если этого не сделать, то компилятор выдаст вам ошибку, так как функция теперь обязана принимать какое-либо значение. В нашем случае мы будем указывать номер пина, с которым хотим работать, поставим, например, цифру 4.


Чтобы код, написанный внутри нашей функции, стал таким же универсальным, на том месте, где до этого мы писали конкретный номер пина для считывания, теперь необходимо указать переменную nomberPin, которая подставит сюда такое число, какое мы передали при обращении к функции – в нашем случае это цифра 4, то есть 4-й пин.


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


Если мы хотим передать нашей функции не одно, а несколько значений, то мы просто указываем тип и имя переменной через запятую, и затем уже используем эти переменные в коде. При вызове функции нам так же необходимо указывать значения через запятую, так как теперь функция будет ждать от нас столько значений, сколько указано в её круглых скобках. Мы можем передавать в нее всё, что угодно, будь то показания с датчиков или текстовые сообщения, которые необходимо вывести на дисплей. Все зависит от кода, который вы укажете в теле функции.

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


Итак, мы научились сообщать функции какие-либо данные для работы. Давайте посмотрим, каким образом осуществляется возврат результата вычисления функцией.


При определении функции мы указали, что возвращаемый ею тип является void, то есть она ничего не возвращает. Изменим void, например, на тип byte и теперь в функции мы обязаны указать возврат какого-либо результата ее вычисления. Для того, что бы функция вернула какое-то значение, существует оператор return, и запись, например, return 5 означает, что наша программа, дойдя до этого момента, сделает выход из функции, при этом запомнив результат равный 5.

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

Тогда программа, дойдя до этого момента, будет поступать так – она переходит в указанную нами функцию, выполняется там, доходит до оператора return и запоминает значение, которое мы указали. Это значение она записывает по адресу переменной result. Теперь result равен тому числу, которое возвращает наша функция.

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

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

Обязательно поделитесь своими успехами или вопросами в комментариях, ну а на этом про функции все, спасибо за то, что дочитали до конца и до встречи в 9-м выпуске! ;)

Показать полностью 14
96

Проигрыватель на базе Raspberry Pi 3 модель B

Проигрыватель на базе Raspberry Pi 3 модель B


Хочу поделиться с вами, уважаемые читатели опытом по созданию проигрывателя на основе Raspberry Pi.

Я хотел использовать ОС Linux и поэтому я выбрал именно Raspberry Pi, т.к. в ней используется ГП (GPU) VideoCore IV и поэтому нет проблем воспроизведением графики.

В качестве операционной системы был выбран OSMC.

Для управления я использую инфракрасный ПДУ IRF Media W-01RN, а для удалённого управления по HTTP расширение AWXi.


На сегодняшний день прототип собран на фанере размером 300×400×6 (мм):

На нём установлены:

- Блок питания MeanWell RS-75-5 (5 В, 12 А);

- Для питания Raspberry Pi используется кабель Micro USB 0.35 м, 20AWG (LG);

- Raspberry Pi 3 модель B, установлена карта памяти TF (Micro SD) SanDisk 48 МБ/с. 32 Гб SDHC SDXC UHS-I Class10;

- Для охлаждения Raspberry Pi 3 используется вентилятор на 12 В/0.13 А, 30х30х10 мм, подключённый через повышающий преобразователь на LM2577(XL6009);

- Часы реального времени на DS3231;

- Внешний жёсткий диск 2.5” USB 3.0 Toshiba Canvio Basics 500 Гб. (HDTB305EK3AA).


Для распределения питания используется самодельный блок из 7 розеток USB 2.0:

Релейный включатель/выключатель питания, вот схема:

Для подключения дополнительных устройств используется хаб USB2.0 ORICO H4013-U2.


В ближайшее время планирую установить внешний DVD USB 2.0 и преобразователь HDMI в VGA а также сделать крепление для внешнего жёсткого диска.


Большинство комплектующих заказано на AliExpress, радиодетали были куплены в магазине радиодеталей Радиоремонт.

Крепёж приобретался в магазинах КрепМастер12.

Подробная техническая информация доступна на этой странице.

Показать полностью 3
83

Дорогие друзья, с Новым, 2017 Годом вас!

От лица администратора сообщества "Arduino&Pi" хочу поздравить всех ардуинщиков, программистов, а так же других пикабушников с наступающими праздниками! Пусть в новом году исполнятся все ваши самые заветные желания, проекты удачно компилируются, а интересные идеи никогда не покидают вашу голову :)

С праздником, друзья!

P.S.: В комментариях к этому посту, как и обычно, можно задавать свои вопросы и помогать другим

Дорогие друзья, с Новым, 2017 Годом вас!
Отличная работа, все прочитано!