Ох, давно хотел уже задокументировать это здесь, да всё времени не было. И вот, спустя полтора года…
Для этого было решено пилить какой-то контроллер Atmega с каким-то ethernet-свистком, чтобы он через оптопары замыкал кнопки включения. А заодно сообщал об успехе или неуспехе затеи.
Немного покопавшись я решил закупить основанную на enc28j60 приблуду для ардуины, а заодно и саму ардуину. Изучив особенности программирования enc28j60 руками (без высокоуровневых IDE и готовых библиотек) и бегло осмотрев errata, который, надо отметить, чуть ли не больше даташита, стало ясно, что на низком уровне рулить “этим” сущий ад и боль. Поэтому, будем собирать всё на базе добротного китайского клона Arduino nano или функционального аналога (лучше просто взять arduino, правда).
В итоге система будет состоять из основного модуля в виде связки Arduino+enc28j60 и выносного блока с оптопарами и резисторами.
В целом выглядеть и подключаться всё будет так:
https://github.com/developersu/NoWOL
Необходимые библиотеки в eagle_files/lib/ .
Для выносного модуля понадобится:
Какую проблему решаем?
Стоит задача включать и выключать ПК нажимая на кнопки включения\выключения и сброса не руками, а через интернет (ну или через тоннель в интранет). В идеале спросонья через виджет в телефоне а-ля узнал погоду за бортом, включил ПК и можно идти ставить кофе.Для этого было решено пилить какой-то контроллер Atmega с каким-то ethernet-свистком, чтобы он через оптопары замыкал кнопки включения. А заодно сообщал об успехе или неуспехе затеи.
Немного покопавшись я решил закупить основанную на enc28j60 приблуду для ардуины, а заодно и саму ардуину. Изучив особенности программирования enc28j60 руками (без высокоуровневых IDE и готовых библиотек) и бегло осмотрев errata, который, надо отметить, чуть ли не больше даташита, стало ясно, что на низком уровне рулить “этим” сущий ад и боль. Поэтому, будем собирать всё на базе добротного китайского клона Arduino nano или функционального аналога (лучше просто взять arduino, правда).
В итоге система будет состоять из основного модуля в виде связки Arduino+enc28j60 и выносного блока с оптопарами и резисторами.
В целом выглядеть и подключаться всё будет так:
Но перед тем, как начать…
Поставим себе пару пакетов:1. dev-embedded/arduino 2. sci-electronics/eagle (ветка 7.x.x и лучше из нестабильной ветки)Все необходимые файлы лежат в проекте на GitHub:
https://github.com/developersu/NoWOL
Про выносной модуль
Файлы для Eagle CAD находятся в директории eagle_files/m2Board/ .Необходимые библиотеки в eagle_files/lib/ .
Для выносного модуля понадобится:
Part | Value | Device | Package | Library | Sheet |
---|---|---|---|---|---|
IC2 | КР293КП4А | DIL08 | ic-package | 1 | |
IC3 | КР293КП4А | DIL08 | ic-package | 1 | |
IN | PINHD-1X6 | 1X06 | pinhead | 1 | |
OUT | PINHD-1X6 | 1X06 | pinhead | 1 | |
R1 | 450Ω или 470Ω | R-EU_0204/5 | 0204/5 | resistor | 1 |
R2 | 450Ω или 470Ω | R-EU_0204/5 | 0204/5 | resistor | 1 |
R3 | 330Ω | R-EU_0204/5 | 0204/5 | resistor | 1 |
TO_MCU | PINHD-1X5 | 1X05 | pinhead | 1 |
По-поводу R1 и R2 резисторов, я собрал две пары, чтобы получилось 450 Ом в каждой. Думаю, что если взять просто пару штук на 470 Ом всё тоже будет работать. Но всё же обещать не буду.
Его принципиальная схема выглядит весьма просто:
Разводка выполняется на односторонней плате:
* 'cuz soviet works better
Если присмотреться, разводка слегка отличается от той, что приведена на первом рисунке. Тут я убрал перемычку. Как вы уже поняли, в качестве оптопар используется отечественная схема КР293КП4А в корпусе DIP8. Внутри каждой микросхемы находится 2 оптопары. Одна из схем замыкает и размыкает кнопки (питание и сброс), а вторая говорит микроконтроллеру включена ли система, определяя это по светодиоду-индикатору питания. Если первую микросхему замыкает МК, то вторую — ПК. Через отдельный пин микроконтроллер зажигает индикатор питания сам, когда понимает, что и система (ПК) тоже его зажгла. Уж не знаю.. может это несколько избыточно и можно было сделать проще. Впрочем, получилось как получилось.
Примечание: наверное надо было навесить на вторую оптопару какие-то резисторы.. но блин, datasheet по ним такой немногословный. В общем как-то работает уже больше года, так что, пока всё не сгорело,имеет право на жизнь.
Если всё спаять и приправить должным количеством пыли, получится примерно следующее:
Про программирование Arduino
Теперь перейдём к программированию Arduino. Как говорилось ранее, предполагается использование Arduino Nano.Я уже не помню что куда нажимать и подключать, чтобы это дело прошить но у меня есть скетч!
Для этого скетча понадобится библиотека ehtercard. И скетч и библиотека находятся в директории arduino_sketchbook/.
А вот и сам код:
#include <EtherCard.h> #define PWR_PIN 6 #define RST_PIN 7 #define PWR_LED_IN 8 #define PWR_LED_OUT 5 int i; // Зададим MAC адрес устройства static byte mymac[] = { 0xDE,0xAD,0xBE,0xEE,0xEE,0xEF }; // Чем больше данных отображается на странице, тем больше требуется буфер для них byte Ethernet::buffer[900]; BufferFiller bfill; //Массив задействованных контактов для управления оптопарами int LedPins[] = {PWR_PIN,RST_PIN}; //Массив для фиксации изменений boolean PinUpdate = 0; //100-reset 200-power 5050-powerOFF 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" "<html>" "<head><title>" "noWOL" "</title><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"><style>" "body { font-family: monospace;\n" "background-color: #000000;\n" "font-size: 30px;\n" "font-weight: bold;\n" "color: #b2b2b2;}\n" "a:link, a:visited { display: inline-block;\n" "color: #b2b2b2;\n" "font-weight: 700;\n" "text-decoration: none;\n" "padding: .3em 2em;\n" "outline: none;\n" "border: 2px solid;\n" "border-radius: 15px;\n" "transition: 0.2s;}\n" "a:hover {color: #fefefe;}\n" "</style></head>" "<body><center>" ; 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" "401 Unauthorized"; void homePage() { bfill.emit_p(PSTR("$F" " " "$F<p>" "<a href='?RESET=on'> RESET </a><p>" //D6 "<a href='?POWER0=on'> POWER </a><p>" //D7 short "<a href='?POWER1=on'>POWER 5sec</a><br />"), //D7 long //"PWR LED out D5 : $F <br /></body></html>"), http_OK, (digitalRead(PWR_LED_IN) == HIGH)?PSTR("<span style=\"color: #AA0000\"> ▄▄▄▄▄▄</span>"):PSTR("<span style=\"color: #00c600\"> ▄▄▄▄▄▄</span>")),//⬤ // (bitRead(PORTD,PWR_LED_OUT) == HIGH)?PSTR("HIGH"):PSTR("LOW")), "</center></body>" "</html>" ; } void pick_pin(int pin, int del) { digitalWrite(pin,HIGH); delay(del); digitalWrite(pin,LOW); PinUpdate = 0; } void setup() { // SET UART // Serial.begin(9600); //Change default ethercard CS - pin 8 to 10 //if (ether.begin(sizeof Ethernet::buffer, mymac, 10) == 0) // Serial.println( "Access to Ethernet controller failed"); ether.begin(sizeof Ethernet::buffer, mymac, 10); ether.dhcpSetup(); // if (!ether.dhcpSetup()) // Serial.println("DHCP routine failed"); //Print over UART configuration recieved: // ether.printIp("IP: ", ether.myip); // ether.printIp("GW: ", ether.gwip); // ether.printIp("DNS: ", ether.dnsip); for(i = 0; i < 2; i++) { pinMode(LedPins[i],OUTPUT); } pinMode(PWR_LED_OUT,OUTPUT); pinMode(PWR_LED_IN,INPUT_PULLUP); // LED-питания как вход } void loop() { delay(1); if (digitalRead(PWR_LED_IN) == HIGH) { // если мать выключена if (bitRead(PORTD,PWR_LED_OUT) == HIGH) digitalWrite(PWR_LED_OUT,LOW); } else if (bitRead(PORTD,PWR_LED_OUT) == LOW) { digitalWrite(PWR_LED_OUT,HIGH); } switch (PinUpdate) { case 0: break; case 1: pick_pin(RST_PIN, 200); break; case 2: pick_pin(PWR_PIN, 200); break; case 3: pick_pin(PWR_PIN, 5050); break; } word len = ether.packetReceive(); //Проверить ethernet пакеты word pos = ether.packetLoop(len); //Проверить TCP пакеты if (pos) { 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(); //Если обнаружено изменения на станице, то запускаем функцию } //"10" = количество символов "?RESET=on ". else if (strncmp("?RESET=on ", data, 10) == 0) { bfill.emit_p(http_Found); PinUpdate = 1; } else if (strncmp("?POWER0=on ", data, 11) == 0) { bfill.emit_p(http_Found); PinUpdate = 2; } else if (strncmp("?POWER1=on ", data, 11) == 0) { bfill.emit_p(http_Found); PinUpdate = 3; } else { //Страница не найдена bfill.emit_p(http_Unauthorized); } } ether.httpServerReply(bfill.position()); } }Теперь, когда всё что надо прошито, соединяем как указано на рисунке в начале публикации и подключаем это дело к сети. На машрутизаторе должен быть настроен DHCP сервер.
Мак-адрес нового устройства, как ясно из исходного кода, будет de:ad:be:ee:ee:ef. Лучше сразу назначить постоянную аренду. В OpenWRT с LuCI идём в:
«Сеть» → «DHCP и DNS» → вкладка «Основные настройки» → «Постоянные аренды» → «Добавить».
Пишем там как показано на рисунке:
Когда всё настроено и подключено, заходим на адрес http://192.168.1.100 и видим следующее:
Только вот квадратик будет красным, а не зеленым. Это и есть индикатор питания.
Назначение кнопок пояснять нет смысла. Последняя симулирует долгое нажатие, что приводит к принудительному отключению.
То, что всё это находится в интрасети и не отсвечивает в мир меня вполне устраивает, ведь при подключении по VPN доступ появляется и в Android-приложении и через WEB-интерфейс. Ах да! Для всего этого дела есть ещё и Android-приложение :) Но о нём во второй части.
Вредные советы
Как бы не использовать Arduino?
Лучше таки его использовать.Но можно и спаять свою ардуину
Сразу оговорюсь, я наделал кучу ошибок и паял отдельные костыли чтобы всё сошлось.. потом переделал схему, потом ещё пару раз, и уже не помню на сколько там правильная разводка. Так что лучше внимательно изучить и прислать мне фидбек в виде линки на исправленную версию. Или апробировать, если всё правильно =)
Используется двусторонний текстолит. Перемычки тут не помогут.
Находится всё в директории eagle_files/atmegaBoard/ .
Список компонентов:
Part | Value | Device | Package | Library | Sheet |
---|---|---|---|---|---|
C1 | 22pF | C-EUC0603 | C0603 | resistor | 1 |
C2 | 22pF | C-EUC0603 | C0603 | resistor | 1 |
C3 | 10uF | CC0603 | C0603 | eagle-ltspice | 1 |
C4 | 22uF | CC0603 | C0603 | eagle-ltspice | 1 |
IC1 | atmega328p | atmega328p | TQFP32-08 | avr-6 | 1 |
IC3 | LM1117IMPX-3.3 | LM1117IMPX-3.3 | SOT223 | lm1117 | 1 |
JP1 | PINHD-2X5 | 2X05 | pinhead | 1 | |
JP3 | PINHD-1X2 | 1X02 | pinhead | 1 | |
Q1 | 16MHz | XTAL/S | QS | special | 1 |
SV1 | MA05-1 | MA05-1 | con-lstb | 1 | |
U1 | USB"" | USB-MICRO-SMD | MicroUSB | 1 |
Схема принципиальная:
Сама разводка:
Что тут добавить.. земля на гребёнке справа. JP3 нужен для прошивки схемы. Прошивается она через Arduino IDE.. Кажется с помощью самой ардуины. Ну или через USBasp программатор. В общем, главное ничего не перепутать. А настройки должны быть вроде таких:
1)
2)
В следующей части будет обзор Android-приложения. APK файл находится в папке Android_APK.
Итого
У меня вся эта разработка шла не очень гладко, но получилось вполне сносно. Вот конечный результат в корпусе из спичек. Для антуража покрашено йодом.Что касается дальнейшего развития этой инициативы, то я планирую добавить сюда ещё один выносной модуль для ещё одного ПК.
--
Особая благодарность Unyuu за неоценимый вклад. Во многом благодаря его советам этот проект стал возможен.
Текстовый материал распространяется по лицензии Creative Commons С указанием авторства-Некоммерческая-С сохранением условий 4.0 Всемирная.
Обратите внимание: это ограничение не касается графических изображений и исходного кода. Если на самом изображении не указано иного, они доступны по лицензии Creative Commons С указанием авторства 4.0 Всемирная.
0 коммент.:
Отправить комментарий