Я увлекаюсь выращиванием растений и хотелось знать уровень освещенности, так как для растений есть рекомендуемые уровни освещенности. На алиэкспрессе был куплен калиброванный датчик BH1750. Также в интернете есть информfция про китайский плеер, позволяющий из него что то собрать, так как есть уже и библиотека для дисплея. И мне захотелось скрестить их: дисплей, ардуину, датчик и конечно все на питании от встроенного в плеер аккумулятора.
Собственно получилось вот что:
Компактный люксметр в корпусе плеера.
Характеристики люксметра определяются датчиком, а он может измерять освещенность от 1 до 65535 люкс.
Как видно на фото на экране кроме цифр ничего нет, даже единиц измерения. Я не стал делать потому что не вижу в этом необходимости, да и экран мелкий. Контроля батареи нет.
Я покупал плеер здесь. Ссылку привожу потому что в данном корпусе есть минимум 2 варианта платы, а контакты привожу для своей.
Есть замечание по плееру: так как я оставил родную схему зарядки, с ней нужно было внимательным: она легко перезаряжает аккумулятор и он вспухает.
Сборка:
1. Плеер аккуратно разобрать, все детали сохранить! Они вам еще пригодятся.
2. Выпаять родной контроллер, разъем 3.5мм (для наушников), разъем для карты памяти, светодиод фонарика. Аккумулятор временно отпаять.
3. Нужна Arduino Pro Mini, у меня была только 5В 16мгц, но она успешно работает и от 3.3В. И разумеется нужен переходник USB-UART на 3.3В.
4. Нужен тонкий провод. У меня МГТФ, диаметр не помню, но толстый для этой задачи, с трудом засунул, берите сразу максимально тонкий.
Так как ни одна имеющаяся библиотека для дисплея меня не устроила, написал свой код, включая управление дисплеем на основе одной из них. Код разбит по файлам, компилировался в Arduino IDE 1.6.12.
#include <avr/pgmspace.h>
#define pgm pgm_read_byte
#include <Wire.h>
#include <BH1750.h>
BH1750 lightMeter;
unsigned int lux;
#define CS 10
#define Data 11
#define Clock 13
#define DC A0
#define LCD_X 128
#define LCD_Y 64
#define LCD_String 8
#define swap(a, b) { int t = a; a = b; b = t; }
#define LCD_D 1
#define LCD_C 0
byte LCD_RAM[LCD_X*LCD_String];
#define BLACK 1
#define WHITE 0
#define LCDWIDTH 128
#define LCDHEIGHT 64
#define CMD_DISPLAY_OFF 0xAE
#define CMD_DISPLAY_ON 0xAF
#define CMD_SET_DISP_START_LINE 0x40
#define CMD_SET_PAGE 0xB0
#define CMD_SET_COLUMN_UPPER 0x10
#define CMD_SET_COLUMN_LOWER 0x00
#define CMD_SET_ADC_NORMAL 0xA0
#define CMD_SET_ADC_REVERSE 0xA1
#define CMD_SET_DISP_NORMAL 0xA6
#define CMD_SET_DISP_REVERSE 0xA7
#define CMD_SET_ALLPTS_NORMAL 0xA4
#define CMD_SET_ALLPTS_ON 0xA5
#define CMD_SET_BIAS_9 0xA2
#define CMD_SET_BIAS_7 0xA3
#define CMD_RMW 0xE0
#define CMD_RMW_CLEAR 0xEE
#define CMD_INTERNAL_RESET 0xE2
#define CMD_SET_COM_NORMAL 0xC0
#define CMD_SET_COM_REVERSE 0xC8
#define CMD_SET_POWER_CONTROL 0x28
#define CMD_SET_RESISTOR_RATIO 0x20
#define CMD_SET_VOLUME_FIRST 0x81
#define CMD_SET_VOLUME_SECOND 0
#define CMD_SET_STATIC_OFF 0xAC
#define CMD_SET_STATIC_ON 0xAD
#define CMD_SET_STATIC_REG 0x0
#define CMD_SET_BOOSTER_FIRST 0xF8
#define CMD_SET_BOOSTER_234 0
#define CMD_SET_BOOSTER_5 1
#define CMD_SET_BOOSTER_6 3
#define CMD_NOP 0xE3
#define CMD_TEST
#include <avr/pgmspace.h>
//цифры размером 16х32 пикселей
static const char mass16x32 [10][64] PROGMEM ={
{ 0xF8, 0xFC, 0xFA, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //0
0x3F, 0x7F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x3F,
0xFE, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE,
0x1F, 0x3F, 0x5F, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F},
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFC, 0xF8, //1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x1F},
{0x00, 0x00, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //2
0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0x7F, 0x3F,
0xFE, 0xFF, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x1F, 0x3F, 0x5F, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x40, 0x00, 0x00},
{0x00, 0x00, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //3
0x00, 0x00, 0x80, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0x7F, 0x3F,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x40, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F},
{0xF8, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFC, 0xF8, //4
0x3F, 0x7F, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0x7F, 0x3F,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x1F},
{0xF8, 0xFC, 0xFA, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x00, 0x00, //5
0x3F, 0x7F, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x40, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F},
{0xF8, 0xFC, 0xFA, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x02, 0x00, 0x00, //6
0x3F, 0x7F, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x80, 0x00, 0x00,
0xFE, 0xFF, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x1F, 0x3F, 0x5F, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F},
{0x00, 0x00, 0x02, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //7
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x7F, 0x3F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x1F},
{0xF8, 0xFC, 0xFA, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //8
0x3F, 0x7F, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0x7F, 0x3F,
0xFE, 0xFF, 0xFE, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x1F, 0x3F, 0x5F, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F},
{0xF8, 0xFC, 0xFA, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0xFA, 0xFC, 0xF8, //9
0x3F, 0x7F, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xBF, 0x7F, 0x3F,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xFE, 0xFF, 0xFE,
0x00, 0x00, 0x40, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0x5F, 0x3F, 0x1F}};
<source lang="arduino">
#include <avr/pgmspace.h>
//======================================================Очистка дисплея
void Clear_LCD() {
for (int index = 0; index < 864 ; index++) {
LCD_RAM[index] = (0x00);
}
}
//=======================================================Управление пинами
void dWrite(byte pin, byte val) {
byte bit = digitalPinToBitMask(pin);
volatile byte *out;
out = portOutputRegister(digitalPinToPort(pin));
(val) ? *out |= bit : *out &= ~bit;
}
#define _BV(bit) (1<<(bit))
//=========================================================Отправка 8 байт
void SendByte(byte mode, byte c) {
dWrite(CS, 0);
(mode) ? dWrite(DC, 1) : dWrite(DC, 0);
for (byte i = 0; i <8; i++) {
dWrite(Clock, 0);
(c & 0x80) ? dWrite(Data, 1) : dWrite(Data, 0);
dWrite(Clock, 1);
c <<= 1;
}
}
//=====================================================Обновить дисплей
void Update() {
for (byte p = 0; p < 8; p++) {
//SendByte(LCD_C, CMD_SET_PAGE | pagemap[p]);
SendByte(LCD_C, CMD_SET_PAGE | p);
byte col = 0;
SendByte(LCD_C, CMD_SET_COLUMN_LOWER | (1 & 0xf));
SendByte(LCD_C, CMD_SET_COLUMN_UPPER | ((1 >> 4) & 0x0F));
SendByte(LCD_C, CMD_RMW);
for (byte col = 0; col < LCD_X; col++) {
SendByte(LCD_D, LCD_RAM[(LCD_X * p) + col]);
}
}
}
//===================================================Нарисовать пиксель
void drawPixel (byte x, byte y, boolean color) {
if ((x < 0) || (x >= LCD_X) || (y < 0) || (y >= LCD_Y)) return;
if (color) LCD_RAM[x + (y / 8)*LCD_X] |= _BV(y % 8);
else LCD_RAM[x + (y / 8)*LCD_X] &= ~_BV(y % 8);
}
//======================================================Вывод картинки
void drawBitmap(byte x, byte y, const char *bitmap, byte w, byte h, boolean color) {
for (int16_t j = 0; j < h; j++) {
for (int16_t i = 0; i < w; i++ ) {
if (pgm(bitmap + i + (j / 8)*w) & _BV(j % 8)) {
drawPixel(x + i, y + j, color);
}
}
}
}
//========================================================================
// Управление дисплеем
//========================================================================
//===================================================Инициализация дисплея
void Inicialize() {
pinMode(CS, OUTPUT);
pinMode(Data, OUTPUT);
pinMode(Clock, OUTPUT);
pinMode(DC, OUTPUT);
// Инициализация дисплея
dWrite(CS, 0);
delay(500);
SendByte(LCD_C, CMD_SET_BIAS_7); // LCD bias select
SendByte(LCD_C, CMD_SET_ADC_NORMAL); // ADC select
SendByte(LCD_C, CMD_SET_COM_REVERSE); // SHL select
SendByte(LCD_C, CMD_SET_DISP_START_LINE); // Initial display line
SendByte(LCD_C, CMD_SET_POWER_CONTROL | 0x4); // turn on voltage converter (VC=1, VR=0, VF=0)
delay(50);
SendByte(LCD_C, CMD_SET_POWER_CONTROL | 0x6); // turn on voltage regulator (VC=1, VR=1, VF=0)
delay(50);
SendByte(LCD_C, CMD_SET_POWER_CONTROL | 0x7); // turn on voltage follower (VC=1, VR=1, VF=1)
delay(10);
SendByte(LCD_C, CMD_SET_RESISTOR_RATIO | 0x6); // set lcd operating voltage (regulator resistor, ref voltage resistor)
SendByte(LCD_C, CMD_DISPLAY_ON);
SendByte(LCD_C, CMD_SET_ALLPTS_NORMAL);
SendByte(LCD_C, CMD_SET_DISP_REVERSE);
SendByte(LCD_C, CMD_SET_VOLUME_FIRST);
SendByte(LCD_C, CMD_SET_VOLUME_SECOND | (0 & 0x3f));
Clear_LCD();
Update();
}
//=========================Вывод символа 16х32 пикселя в координаты XY
void simb16x32(byte x, byte y, boolean color, byte c) {
for (byte k = 0; k < 4; k++) {
for (byte i = 0; i < 16; i++) {
byte line = pgm(&(mass16x32[c][i + k * 16]));
for (byte j = 0; j < 8; j++) {
(line & 0x01) ? drawPixel(x + i, y + j + k * 8, color) : drawPixel(x + i, y + j + k * 8, !color);
line >>= 1;
}
}
}
}
<source lang="arduino">
#include <avr/pgmspace.h>
void setup(){
Inicialize();
lightMeter.begin();
}
+
void loop(){
lux = lightMeter.readLightLevel();
simb16x32(95, 17, 1, lux%10);
lux/=10;
simb16x32(75, 17, 1, lux%10);
lux/=10;
simb16x32(55, 17, 1, lux%10);
lux/=10;
simb16x32(35, 17, 1, lux%10);
lux/=10;
simb16x32(15, 17, 1, lux%10);
Update();
delay(300);
}
<source lang="arduino">
Хочу сразу сказать это скорее индикатор, чем измерительный прибор, но иметь такой индикатор бывает полезно, к тому же на сборку уйдет один вечер при наличии определенного опыта.
Есть также видео, но без звука. Хотел отдельно записать, но оказалось ни один мой микрофон не может это нормально сделать.
Автор: jeka_tm