RSS блога
Подписка
Arduino Keypad Shield или Знакосинтезирующий ЖКИ
- Цена: $3.99
- Перейти в магазин
Добрый день (опционально вечер/ночь).
Сегодня расскажу Вам о китайском ЖКИ. Брался в качестве баловства, возможно создания какого-либо проекта, получения навыков работы с ЖКИ, прошу под кат:
ПРЕДИСЛОВИЕ
Данный шилд лежит уже очень давно, все баловался с ним, подключал разную аппаратуру, датчики, писал меню и списки, порядка 1.5 лет прошло, как он участвует в моих разнообразных тестах и проектах.
ОПИСАНИЕ
Размер дисплея: 80 мм х 58 мм;
Рабочее напряжение: 4.5-5В;
Дисплей: 16х2;
Совместимость HD44780;
Подсветка: синий фон, белые символы;
Имеется переменный резистор, для регулировки яркости;
Русского языка нет.
Вообще исходя из цены, дисплей стоит там крайне бюджетный, такие в целом продаются за 80-100р. на али.
Фотографии специально делались на ардуине, что бы можно было оценить, то как дисплей устанавливается в разъемы. (попадались шилды, которые из-за совсем кривой пайки вставали с перекосом).
Пайка у дисплея нормальная (не плохая и не отличная, конкретно — нормальная, сойдет).
Подсветка дисплея осуществляется одним светодиодом с рефлектором, установленным с торца матрицы.
ТЕСТИРОВАНИЕ
В качестве тестирования был взят старый скетч:
Каков был функционал, такой и получил. Все работает исправно, кнопки все нажимаются, регулировка яркости работает в полном объеме:
Минимальная:
Средняя:
Максимальная:
Видео тест шилда с запущенной игрой:
ВЫВОДЫ
Учитывая его стоимость, а так же то что он проработал у меня под разными издевательствами уже 1.5 года, недостатков нет.
За скетчем сюда:
Сегодня расскажу Вам о китайском ЖКИ. Брался в качестве баловства, возможно создания какого-либо проекта, получения навыков работы с ЖКИ, прошу под кат:
ПРЕДИСЛОВИЕ
Данный шилд лежит уже очень давно, все баловался с ним, подключал разную аппаратуру, датчики, писал меню и списки, порядка 1.5 лет прошло, как он участвует в моих разнообразных тестах и проектах.
ОПИСАНИЕ
Размер дисплея: 80 мм х 58 мм;
Рабочее напряжение: 4.5-5В;
Дисплей: 16х2;
Совместимость HD44780;
Подсветка: синий фон, белые символы;
Имеется переменный резистор, для регулировки яркости;
Русского языка нет.
Вообще исходя из цены, дисплей стоит там крайне бюджетный, такие в целом продаются за 80-100р. на али.
Фотографии специально делались на ардуине, что бы можно было оценить, то как дисплей устанавливается в разъемы. (попадались шилды, которые из-за совсем кривой пайки вставали с перекосом).
Пайка у дисплея нормальная (не плохая и не отличная, конкретно — нормальная, сойдет).
Подсветка дисплея осуществляется одним светодиодом с рефлектором, установленным с торца матрицы.
ТЕСТИРОВАНИЕ
В качестве тестирования был взят старый скетч:
Каков был функционал, такой и получил. Все работает исправно, кнопки все нажимаются, регулировка яркости работает в полном объеме:
Минимальная:
Средняя:
Максимальная:
Видео тест шилда с запущенной игрой:
ВЫВОДЫ
Учитывая его стоимость, а так же то что он проработал у меня под разными издевательствами уже 1.5 года, недостатков нет.
За скетчем сюда:
Скетчик
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );
const int FIELD_WIDTH = 16;
const float BAR_PROBABILITY = 1;
int button;
const int BUTTON_NONE = 0;
const int BUTTON_RIGHT = 1;
const int BUTTON_UP = 2;
const int BUTTON_DOWN = 3;
const int BUTTON_LEFT = 4;
const int BUTTON_SELECT = 5;
int gameStatus;
const int MAIN_MENU = 0;
const int IN_GAME = 1;
const int PAUSE = 2;
const int ENDING = 3;
char gameFields[32];
const char SPACE = ' ';
const char BAR = '*';
const char PLAYER = '>';
int gameSpeed;
int SPEED_HIGH = 70;
int SPEED_NORMAL = 300;
int changeSpeed = 5000;
long startGameTime;
long lastMovementTime;
long lastChangeSpeedTime;
long endGameTime;
long bestGameTime;
int topQueue = true;
int getPressedButton()
{
int buttonValue = analogRead(0);
if (buttonValue < 100) {
return BUTTON_RIGHT;
}
else if (buttonValue < 200) {
return BUTTON_UP;
}
else if (buttonValue < 400){
return BUTTON_DOWN;
}
else if (buttonValue < 600){
return BUTTON_LEFT;
}
else if (buttonValue < 800){
return BUTTON_SELECT;
}
return BUTTON_NONE;
}
void startGame()
{
SPEED_NORMAL = 250;
startGameTime = millis();
lastMovementTime = millis();
lastChangeSpeedTime = millis();
endGameTime = 0;
// Очищаем игровое поле
for (int i = 0; i < 2*FIELD_WIDTH; i++)
{
gameFields[i] = SPACE;
}
gameFields[0] = PLAYER;
gameStatus = IN_GAME;
printGameField();
}
void moveGameField()
{
if (gameFields[0] == PLAYER && gameFields[1] == BAR ||
gameFields[FIELD_WIDTH] == PLAYER && gameFields[FIELD_WIDTH+1] == BAR)
{
gameOver();
return;
}
int playerPos = 0;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
playerPos = FIELD_WIDTH;
}
for (int i = 0; i < FIELD_WIDTH*2; i++)
{
if (i != FIELD_WIDTH-1)
{
gameFields[i] = gameFields[i+1];
}
}
gameFields[playerPos] = PLAYER;
int topBarsCount = 0;
int bottomBarsCount = 0;
for (int i = 0; i < FIELD_WIDTH; i++)
{
if (gameFields[i] == BAR)
{
topBarsCount++;
}
}
for (int i = FIELD_WIDTH; i < FIELD_WIDTH*2; i++)
{
if (gameFields[i] == BAR)
{
bottomBarsCount++;
}
}
if (topQueue)
{
if (gameFields[FIELD_WIDTH-1] != BAR &&
gameFields[FIELD_WIDTH-2] != BAR &&
gameFields[FIELD_WIDTH-3] != BAR &&
bottomBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[2*FIELD_WIDTH-1] = BAR;
} else
{
gameFields[2*FIELD_WIDTH-1] = SPACE;
}
if (gameFields[2*FIELD_WIDTH-1] != BAR &&
gameFields[2*FIELD_WIDTH-2] != BAR &&
gameFields[2*FIELD_WIDTH-3] != BAR &&
topBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[FIELD_WIDTH-1] = BAR;
} else
{
gameFields[FIELD_WIDTH-1] = SPACE;
}
topQueue = false;
} else
{
if (gameFields[2*FIELD_WIDTH-1] != BAR &&
gameFields[2*FIELD_WIDTH-2] != BAR &&
gameFields[2*FIELD_WIDTH-3] != BAR &&
topBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[FIELD_WIDTH-1] = BAR;
} else
{
gameFields[FIELD_WIDTH-1] = SPACE;
}
if (gameFields[FIELD_WIDTH-1] != BAR &&
gameFields[FIELD_WIDTH-2] != BAR &&
gameFields[FIELD_WIDTH-3] != BAR &&
bottomBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[2*FIELD_WIDTH-1] = BAR;
} else
{
gameFields[2*FIELD_WIDTH-1] = SPACE;
}
topQueue = true;
}
}
void gameOver()
{
gameStatus = ENDING;
endGameTime += (millis() — startGameTime);
if (endGameTime > bestGameTime)
{
bestGameTime = endGameTime;
}
int playerPos = 0;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
playerPos = FIELD_WIDTH;
}
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(«Last time:»);
lcd.print(endGameTime/1000);
lcd.print(" sec");
lcd.setCursor(0, 1);
lcd.print(«Best time:»);
lcd.print(bestGameTime/1000);
lcd.print(" sec");
}
void printGameField()
{
for (int i = 0; i < FIELD_WIDTH*2; i++)
{
lcd.setCursor(i%FIELD_WIDTH, i/FIELD_WIDTH);
lcd.print(gameFields[i]);
}
}
void pause()
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(«Paused»);
lcd.setCursor(0, 1);
lcd.print(" PRESS — SELECT");
gameStatus = PAUSE;
endGameTime += (millis()-startGameTime);
}
void setup()
{
gameStatus = MAIN_MENU;
button = BUTTON_NONE;
bestGameTime = 0;
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" PRESS — SELECT");
lcd.setCursor(0, 1);
lcd.print(" START GAME ");
}
void loop()
{
button = getPressedButton();
switch (gameStatus)
{
case MAIN_MENU:
if (button == BUTTON_SELECT)
{
startGame();
}
break;
case IN_GAME:
gameSpeed = SPEED_NORMAL;
switch (button)
{
case BUTTON_RIGHT:
gameSpeed = SPEED_HIGH;
break;
case BUTTON_LEFT:
pause();
break;
case BUTTON_UP:
if (gameFields[0] == BAR)
{
gameOver();
} else
{
gameFields[0] = PLAYER;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
gameFields[FIELD_WIDTH] = SPACE;
}
}
break;
case BUTTON_DOWN:
if (gameFields[FIELD_WIDTH] == BAR)
{
gameOver();
} else
{
gameFields[FIELD_WIDTH] = PLAYER;
if (gameFields[0] == PLAYER)
{
gameFields[0] = SPACE;
}
}
break;
}
if (millis() — lastMovementTime > gameSpeed)
{
lastMovementTime = millis();
moveGameField();
}
if (millis() — lastChangeSpeedTime > changeSpeed)
{
lastChangeSpeedTime = millis();
SPEED_NORMAL -= 40;
// Предельная скорость
if (SPEED_NORMAL < 50)
{
SPEED_NORMAL = 50;
SPEED_HIGH = 50;
}
}
if (gameStatus == IN_GAME)
printGameField();
break;
case PAUSE:
if (button == BUTTON_SELECT)
{
gameStatus = IN_GAME;
startGameTime = millis();
}
break;
case ENDING:
if (button != BUTTON_NONE)
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(" PRESS — SELECT");
lcd.setCursor(0, 1);
lcd.print(" START GAME ");
gameStatus = MAIN_MENU;
}
break;
}
}
LiquidCrystal lcd(8, 9, 4, 5, 6, 7 );
const int FIELD_WIDTH = 16;
const float BAR_PROBABILITY = 1;
int button;
const int BUTTON_NONE = 0;
const int BUTTON_RIGHT = 1;
const int BUTTON_UP = 2;
const int BUTTON_DOWN = 3;
const int BUTTON_LEFT = 4;
const int BUTTON_SELECT = 5;
int gameStatus;
const int MAIN_MENU = 0;
const int IN_GAME = 1;
const int PAUSE = 2;
const int ENDING = 3;
char gameFields[32];
const char SPACE = ' ';
const char BAR = '*';
const char PLAYER = '>';
int gameSpeed;
int SPEED_HIGH = 70;
int SPEED_NORMAL = 300;
int changeSpeed = 5000;
long startGameTime;
long lastMovementTime;
long lastChangeSpeedTime;
long endGameTime;
long bestGameTime;
int topQueue = true;
int getPressedButton()
{
int buttonValue = analogRead(0);
if (buttonValue < 100) {
return BUTTON_RIGHT;
}
else if (buttonValue < 200) {
return BUTTON_UP;
}
else if (buttonValue < 400){
return BUTTON_DOWN;
}
else if (buttonValue < 600){
return BUTTON_LEFT;
}
else if (buttonValue < 800){
return BUTTON_SELECT;
}
return BUTTON_NONE;
}
void startGame()
{
SPEED_NORMAL = 250;
startGameTime = millis();
lastMovementTime = millis();
lastChangeSpeedTime = millis();
endGameTime = 0;
// Очищаем игровое поле
for (int i = 0; i < 2*FIELD_WIDTH; i++)
{
gameFields[i] = SPACE;
}
gameFields[0] = PLAYER;
gameStatus = IN_GAME;
printGameField();
}
void moveGameField()
{
if (gameFields[0] == PLAYER && gameFields[1] == BAR ||
gameFields[FIELD_WIDTH] == PLAYER && gameFields[FIELD_WIDTH+1] == BAR)
{
gameOver();
return;
}
int playerPos = 0;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
playerPos = FIELD_WIDTH;
}
for (int i = 0; i < FIELD_WIDTH*2; i++)
{
if (i != FIELD_WIDTH-1)
{
gameFields[i] = gameFields[i+1];
}
}
gameFields[playerPos] = PLAYER;
int topBarsCount = 0;
int bottomBarsCount = 0;
for (int i = 0; i < FIELD_WIDTH; i++)
{
if (gameFields[i] == BAR)
{
topBarsCount++;
}
}
for (int i = FIELD_WIDTH; i < FIELD_WIDTH*2; i++)
{
if (gameFields[i] == BAR)
{
bottomBarsCount++;
}
}
if (topQueue)
{
if (gameFields[FIELD_WIDTH-1] != BAR &&
gameFields[FIELD_WIDTH-2] != BAR &&
gameFields[FIELD_WIDTH-3] != BAR &&
bottomBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[2*FIELD_WIDTH-1] = BAR;
} else
{
gameFields[2*FIELD_WIDTH-1] = SPACE;
}
if (gameFields[2*FIELD_WIDTH-1] != BAR &&
gameFields[2*FIELD_WIDTH-2] != BAR &&
gameFields[2*FIELD_WIDTH-3] != BAR &&
topBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[FIELD_WIDTH-1] = BAR;
} else
{
gameFields[FIELD_WIDTH-1] = SPACE;
}
topQueue = false;
} else
{
if (gameFields[2*FIELD_WIDTH-1] != BAR &&
gameFields[2*FIELD_WIDTH-2] != BAR &&
gameFields[2*FIELD_WIDTH-3] != BAR &&
topBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[FIELD_WIDTH-1] = BAR;
} else
{
gameFields[FIELD_WIDTH-1] = SPACE;
}
if (gameFields[FIELD_WIDTH-1] != BAR &&
gameFields[FIELD_WIDTH-2] != BAR &&
gameFields[FIELD_WIDTH-3] != BAR &&
bottomBarsCount < FIELD_WIDTH/2 &&
random(9) < BAR_PROBABILITY)
{
gameFields[2*FIELD_WIDTH-1] = BAR;
} else
{
gameFields[2*FIELD_WIDTH-1] = SPACE;
}
topQueue = true;
}
}
void gameOver()
{
gameStatus = ENDING;
endGameTime += (millis() — startGameTime);
if (endGameTime > bestGameTime)
{
bestGameTime = endGameTime;
}
int playerPos = 0;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
playerPos = FIELD_WIDTH;
}
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('x');
delay(300);
lcd.setCursor(playerPos%FIELD_WIDTH, playerPos/FIELD_WIDTH);
lcd.print('X');
delay(300);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(«Last time:»);
lcd.print(endGameTime/1000);
lcd.print(" sec");
lcd.setCursor(0, 1);
lcd.print(«Best time:»);
lcd.print(bestGameTime/1000);
lcd.print(" sec");
}
void printGameField()
{
for (int i = 0; i < FIELD_WIDTH*2; i++)
{
lcd.setCursor(i%FIELD_WIDTH, i/FIELD_WIDTH);
lcd.print(gameFields[i]);
}
}
void pause()
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(«Paused»);
lcd.setCursor(0, 1);
lcd.print(" PRESS — SELECT");
gameStatus = PAUSE;
endGameTime += (millis()-startGameTime);
}
void setup()
{
gameStatus = MAIN_MENU;
button = BUTTON_NONE;
bestGameTime = 0;
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.begin(16, 2);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
lcd.setCursor(0, 1);
lcd.print(" RACE GAME ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" SPACE INVADERS ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
delay(600);
lcd.setCursor(0, 0);
lcd.print(" PRESS — SELECT");
lcd.setCursor(0, 1);
lcd.print(" START GAME ");
}
void loop()
{
button = getPressedButton();
switch (gameStatus)
{
case MAIN_MENU:
if (button == BUTTON_SELECT)
{
startGame();
}
break;
case IN_GAME:
gameSpeed = SPEED_NORMAL;
switch (button)
{
case BUTTON_RIGHT:
gameSpeed = SPEED_HIGH;
break;
case BUTTON_LEFT:
pause();
break;
case BUTTON_UP:
if (gameFields[0] == BAR)
{
gameOver();
} else
{
gameFields[0] = PLAYER;
if (gameFields[FIELD_WIDTH] == PLAYER)
{
gameFields[FIELD_WIDTH] = SPACE;
}
}
break;
case BUTTON_DOWN:
if (gameFields[FIELD_WIDTH] == BAR)
{
gameOver();
} else
{
gameFields[FIELD_WIDTH] = PLAYER;
if (gameFields[0] == PLAYER)
{
gameFields[0] = SPACE;
}
}
break;
}
if (millis() — lastMovementTime > gameSpeed)
{
lastMovementTime = millis();
moveGameField();
}
if (millis() — lastChangeSpeedTime > changeSpeed)
{
lastChangeSpeedTime = millis();
SPEED_NORMAL -= 40;
// Предельная скорость
if (SPEED_NORMAL < 50)
{
SPEED_NORMAL = 50;
SPEED_HIGH = 50;
}
}
if (gameStatus == IN_GAME)
printGameField();
break;
case PAUSE:
if (button == BUTTON_SELECT)
{
gameStatus = IN_GAME;
startGameTime = millis();
}
break;
case ENDING:
if (button != BUTTON_NONE)
{
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(" PRESS — SELECT");
lcd.setCursor(0, 1);
lcd.print(" START GAME ");
gameStatus = MAIN_MENU;
}
break;
}
}
Самые обсуждаемые обзоры
+91 |
3201
202
|
+27 |
1005
42
|
+31 |
1009
28
|
Но уже задумался о метеостанции(температура, влажность и давление) + термометром вынесенным на улицу.
Как идея это вести логи на СД карту и куда-то их потом выплёвывать и обрабатывать ))) Но а по факту ещё сам не знаю что с ним делать ))) И со всем тем что прикупил ))))
Поделитесь идеями что можно придумать эдакого :)
Пока что нарыл вот это: www.youtube.com/watch?v=EzOMIqlDnWo
Меня больше в данном моём проекте интересует вариант хранение данных, и анализ с прогнозами и графиками на небольшом сайте ( в идеале на базе ардуино или esp8266 )
Есть вариант сделать электронную проходную или систему прихода и ухода сотрудников по пропускам, но опять же пока что это только идеи для которых у меня в голове не сложился кубик-рубик )))
Только не знаю как он развивается.
Данные пробного периода.
Обсуждение проекта здесь
Собрал 10 беспроводных термометров — гидрометров. В каждом:
1. Arduino pro mini 3.3v
2. DHT11 — влажность
3. DS18B20 — температура
4. NRF24L01 — экономичный радиопередатчик на 2.4ГГц
5. Liion батарейка на 300mah
6. Платка зарядки Liion батарейки.
Всё это живёт в боксе под 4AAA батарейки и от 1 зарядки работает около 1 года
Все датчики разбросаны по дому и раз в 5 минут передают свои показания + заряд батарейки на хаб.
Хаб это:
1. NRF24L01 с выносной антенной
2. ESP8266
3. Блок питания 220v-3.3v
Хаб принимает значения термометров и отправляет их по WiFi серверу, на котором крутится majordomo*.
C любого планшета можно открыть вебстраничку majordomo. посмотреть как дела в комнатах и установить желаемую температуру.
Majordomo по радио управляет работой газового котла.*
Также осуществляется контроль поливом и проветриванием теплицы.*
*Ещё не реализовано.
Я понимаю, что всё это можно купить и работать оно будет лучше чем у меня, но это просто увлечение такое.
А вот NRF24L01 я так и не смог завести на расстоянии больше 2-х метров: неустойчивая связь, потери сообщений.
Модули вроде брал нормальные, конденсаторы на питание напаивал, с параметрами номера канала, скорости передачи и мощности сигнала игрался…
Сдался и ушел на модули 433 МГц.
С NRF я тоже долго обнимался? подбирал оптимальный электролит. Остановился на тантале 10мкф + обычный 0,1мкф. Ещё куча геморроя была с библиотеками. RF24 в интернете несколько штук ходит и не все работают адекватно.
С 433 я начинал, не понравилась дальность и потребляемая мощность. но там просче конечно. поделки можно очень быстро собирать и недалеко они хорошо работают.
Если хочется минимум проблем с библиотеками и нужна простая сетка сенсоров на nrf/rfm — советую глянуть MySensors. Там буквально несколькими строчками кода решается любой вопрос. Есть десятки готовых примеров кода, на пальцах объяснено куда и что подключать, есть их же сайт с готовыми железными разработками — www.openhardware.io/explore
P.S. с 5-вольтовыми версиями BME280 советую быть внимательнее, люди жалуются, что находящийся в паре миллиметров от сенсора линейный стабилизатор греется и влияет на показания сенсора.
Мне теперь нужно как то majordomo освоить т.к. ESP8266 умеет передавать всё полученное от nrf24 или в majordomo или MQTT брокеру или на narodmon.ru. на narodmon.ru передалось всё просто — графики строятся и всё ок, но это не то, что я хотел. мне нужен свой локальный сервак, строящий графики, и поддерживающий с помощью котла температуру. ну и потом чего нить ещё к нему добавлю.
У меня что-то похоже на Raspberry Pi работает. Туда подключен гейтвей MySensors, который принимает данные от сенсоров, скрипт на перле складывает их в MQTT. Ну и несколько других скриптов отправляют из MQTT в Zabbix для рисования графиков, туда же (MQTT) подключается телеграм-бот, чтобы с телефона информацию смотреть. Котёл, кстати, тоже мониторится, но не регулируется.
Типа такой реализации.
— покрытие на ЖК глянцевое. Проходим мимо. :)
Документация:
И на более новую версию
А модулёк полезен, если надо по быстрому проверить какой новый датчик перед подключением в схему.
Подскажите, кто знает, пожалуйста.
В аналогичном. От RobotDyn косяк в плате. Зачем-то на AFREF подают напряжение. В результате, если вы надумаете работать с температурой корпуса процессора
// ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
то получите цены на дрова.
Лечится просто. Скусить по самые… эээ-корень. Ножку AREF на этом шилде.
Я старался, менял библиотеки, менял версии IDE…