Ох, давно хотел уже задокументировать это здесь, да всё времени не было. И вот, спустя полтора года…
Для этого было решено пилить какой-то контроллер 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 коммент.:
Отправить комментарий