• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

MAX44009 освещённость

Serg2see

New member
Здравствуйте!
Имеется ESP-07. К нему подключаю BME280, MAX44009, SSD1306, BS18B20, датчик движения и кнопка.
Соответственно по I2C подключаю BME280, MAX44009 и SSD1306.
Идея достаточно простая - все измеряемые параметры должны передаваться по WiFi на сервер, планируется, что это будет малина с экранчиком и контроллеров, подключаемых к малине будет несколько. Но до этого ещё пока далеко.
Реализацию делаю по шагам: подключил BME280 и BS18B20, затем SSD1306, на который вывожу две температуры. На каждый датчик делаю отдельный файл lua. Работает, в ESPlorer выводятся две температуры, давление и влажность. Далее подключил MAX44009 и тут запутался, не хватает знаний, я только начинаю осваивать тему с esp.
Какие-то показания идут в ESPlorer, но некорректные. Собственно запутался в написании скетча Display_Init.lua.
Прошу не пинать строго, подскажите, как сделать правильно.
Код main.lua (здесь всё работает):
Код:
print("Start main.lua")


-- Init Wifi
dofile ("WIFIdata.lua")

-- Global Variables
g_data = {P=0, Ti=0, To=0, H=0}

-- IIC init
sda = 2
scl = 1
--local sla = 0x3c
i2c.setup(0, sda, scl, i2c.SLOW)

-- MAX44009 Init
i2c.write(0,0x02, 0x40)

-- BME280 init
dofile("BME280_Init.lua")
dofile("BME280_Read.lua")

-- Init Display SSD1306 128x32
-- font_10x20r,font_8x13r,font_9x15r,font_chikita
--if cfg.display==1 then
  dofile('Display_Init.lua')
  dofile('Display_Show.lua')
--end

-- Start timer
tmr.register(1, 5000, tmr.ALARM_AUTO, function()
  dofile("DS18B20_Read.lua")
  dofile("BME280_Read.lua")
  dofile("Light_Read.lua")
  print ("  to = "..g_data.To.."   ti = "..g_data.Ti.."   P = "..g_data.P.."   H = "..g_data.H.." %") -- TEST
  print(adc.read(0)) -- TEST
  print(luminance) -- TEST
  --if cfg.display==1 then
    dofile('Display_Show.lua')
  --end
end)
tmr.start(1)

--Start HTTP 'server'
dofile ("Server.lua")
А вот код Display_Init.lua, который дописать корректно не получается:
Код:
local lux_addr = 0x4A
local id = 0
-- initialize i2c, set pin1 as sda, set pin2 as scl
-- i2c.setup(id, sda, scl, i2c.SLOW)

--i2c.start(id)
--i2c.address(id, lux_addr ,i2c.TRANSMITTER)
--i2c.write(id,0x02, 0x40)

--i2c.stop(id)
--tmr.delay(500000)

-- defined function: read from reg_addr content of dev_addr
function read_reg(dev_addr, reg_addr)
    local c = {a=0, b=0}
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.a = i2c.read(0, 1)
    i2c.start(0)
    c.b = i2c.read(0, 1)
    i2c.stop(0)
    return c
end

-- get content of register 0x03 of device lux_addr
local reg = read_reg(lux_addr, 0x03)
--print(string.byte(reg))
--luminance = string.byte(reg)
--luminance = reg.a

--Convert the data to lux

luminance = string.byte(reg.a) .. ", " .. string.byte(reg.b)
По этому коду выводятся цифры (luminance =) "92, 255", если немного затемнить датчик MAX44009, то цифра 92 уменьшается.

На "языке Arduino" это бы выглядело так (да простит меня первоисточник, но откуда взял уже не помню):
Код:
#include<Wire.h>

// MAX44009 I2C address is 0x4A(74)
#define Addr 0x4A

void setup()
{
  // Initialise I2C communication as MASTER
  Wire.begin();
  // Initialise serial communication, set baud rate = 9600
  Serial.begin(9600);

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select configuration register
  Wire.write(0x02);
  // Continuous mode, Integration time = 800 ms
  Wire.write(0x40);
  // Stop I2C transmission
  Wire.endTransmission();
  delay(300);
}

void loop()
{
  unsigned int data[2];

  // Start I2C Transmission
  Wire.beginTransmission(Addr);
  // Select data register
  Wire.write(0x03);
  // Stop I2C transmission
  Wire.endTransmission();

  // Request 2 bytes of data
  Wire.requestFrom(Addr, 2);

  // Read 2 bytes of data
  // luminance msb, luminance lsb
  if (Wire.available() == 2)
  {
    data[0] = Wire.read();
    data[1] = Wire.read();
  }

  // Convert the data to lux
  int exponent = (data[0] & 0xF0) >> 4;
  int mantissa = ((data[0] & 0x0F) << 4) | (data[1] & 0x0F);
  float luminance = pow(2, exponent) * mantissa * 0.045;

  // Output data to serial monitor
  Serial.print("Ambient Light luminance :");
  Serial.print(luminance);
  Serial.println(" lux");
  delay(300);
}
Но у меня на Lua всё должно быть.
Прошу помочь, знаний не хватает, учусь.
Для подробностей прилагаю даташит на MAX44009 и схему подключения.
Сергей
 

Вложения

Serg2see

New member
Некоторое уточнение.
Похоже, что данные считываются, только непонятно почему вторая часть всегда 255. Соответственно не пойму корректно ли, но сначала нужно сделать вычисление.
В даташите :
Bits in Lux High-Byte register 0x03 give the 4 bits of exponent E3:E0 and 4 most significant bits of the mantissa byte M7:M4, and represent the lux reading of ambient light. The remaining 4 bits of the mantissa byte M3:M0 are in the Lux Low-Byte register 0x04 and enhance resolution of the lux reading from the IC.
Exponent (E[3:0]): Exponent bits of the lux reading (0000 to 1110). Note: A reading of 1111 represents an overrange condition.
Mantissa (M[7:4]): Four most significant bits of mantissa byte of the lux reading (0000 to 1111).
Lux = 2(exponent) x mantissa x 0.72
Exponent = 8xE3 + 4xE2 + 2xE1 + E0
Mantissa = 8xM7 + 4xM6 + 2xM5 + M4
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
Update of the contents of this register is internally disabled during I2C read operations to ensure proper data transfer between internal ADC and I2C registers. Update of I2C registers is resumed when the master sends a STOP command.
If user wants to read both the Lux High-Byte register 0x03 and Lux Low-Byte register 0x04, then the master should not send a STOP command between the reads of the two registers. Instead a Repeated START command should be used.
This ensures accurate data is obtained from the I2C registers (by disabling internal updates during the read process).
Непонятно почему в даташите 0.72, а во всех найденных примерах 0.045?
Как можно реализовать вычисление, указанное в даташите - следующую часть кода в Lua?
Код:
        // Convert the data to lux
        int exponent = (data[0] & 0xF0) >> 4;
        int mantissa = ((data[0] & 0x0F) << 4) | (data[1] & 0x0F);
        float luminance = pow(2, exponent) * mantissa * 0.045;
Сдвиги "<<" и ">>" Lua в моей версии не понимает: Lua 5.1.4 on SDK 1.5.4.1
 

nikolz

Well-known member
Некоторое уточнение.
Похоже, что данные считываются, только непонятно почему вторая часть всегда 255. Соответственно не пойму корректно ли, но сначала нужно сделать вычисление.

Сдвиги "<<" и ">>" Lua в моей версии не понимает: Lua 5.1.4 on SDK 1.5.4.1
а это смотрели:
Простейший люксметр на ESP8266 и датчике MAX44009
yanbe/max44009-esp-idf-i2c
преобразования надо делать библиотекой bit
nodemcu/nodemcu-firmware
 

Serg2see

New member
Вот, изучаю, спасибо!
Сейчас пробую написать, получилось что-то вроде:
Код:
exponent = bit.rshift(string.byte(reg.a) + 0xF0, 4)
mantissa = bit.lshift(string.byte(reg.a) + 0x0F, 4) or (string.byte(reg.b) + 0x0F)
luminance = ((2 ^ exponent) * mantissa) * 0.045
Но выводит странное число... (luminance = 2077690429.44) что не так делаю?
 
Последнее редактирование:

nikolz

Well-known member
Вот, изучаю.
Сейчас пробую написать что-то вроде:
Код:
exponent = bit.rshift(string.byte(reg.a) + 0xF0, 4)
mantissa = bit.lshift(string.byte(reg.a) + 0x0F, 4) or (string.byte(reg.b) + 0x0F)
luminance = ((2 ^ exponent) * mantissa) * 0.045
Но выводит странное число... (luminance = 2077690429.44) что не так делаю?
смотрите библиотеку bit - а не string
###bit module

 

Serg2see

New member
смотрите библиотеку bit - а не string
###bit module

Вот, что получилось... как-то громоздко.
Код:
exponent = bit.rshift(bit.band(string.byte(reg.a), 0xF0), 4)
mantissa = bit.bor(bit.lshift(bit.band(string.byte(reg.a), 0x0F), 4), (bit.band(string.byte(reg.a), 0x0F)))
luminance = ((2 ^ exponent) * mantissa) * 0.045
Пожалуйста подскажите как распечатать (вывести в ESPlorer) число в двоичном формате (тип 1110 1111). Хочу сравнить с данными даташита, где сказано:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
Или есть другой способ проверки?
 

nikolz

Well-known member
Вот, что получилось... как-то громоздко.
Код:
exponent = bit.rshift(bit.band(string.byte(reg.a), 0xF0), 4)
mantissa = bit.bor(bit.lshift(bit.band(string.byte(reg.a), 0x0F), 4), (bit.band(string.byte(reg.a), 0x0F)))
luminance = ((2 ^ exponent) * mantissa) * 0.045
Пожалуйста подскажите как распечатать (вывести в ESPlorer) число в двоичном формате (тип 1110 1111). Хочу сравнить с данными даташита, где сказано:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
Или есть другой способ проверки?
это Вам надо сделать преобразование самому или найти в инете пример.
Перевод десятичных чилел в двоичные, и обратно, в lua
 

Serg2see

New member
это Вам надо сделать преобразование самому или найти в инете пример.
Перевод десятичных чилел в двоичные, и обратно, в lua
Спасибо!
Правда что-то не так... второй регистр (c.b в функции чтения или reg.b в расчёте) всегда равен 255.
Где ошибка найти не могу.
 

nikolz

Well-known member
Спасибо!
Правда что-то не так... второй регистр (c.b в функции чтения или reg.b в расчёте) всегда равен 255.
Где ошибка найти не могу.
надо читать документацию.
------------------------------------
Bits in Lux High-Byte register 0x03 give the 4 bits of exponent E3:E0 and 4 most significant bits of the mantissa byte
M7:M4, and represent the lux reading of ambient light. The remaining 4 bits of the mantissa byte M3:M0 are in the Lux
Low-Byte register 0x04 and enhance resolution of the lux reading from the IC.
Exponent (E[3:0]): Exponent bits of the lux reading (0000 to 1110). Note: A reading of 1111 represents an overrange condition.
Mantissa (M[7:4]): Four most significant bits of mantissa byte of the lux reading (0000 to 1111).
Lux = 2(exponent) x mantissa x 0.72
Exponent = 8xE3 + 4xE2 + 2xE1 + E0
Mantissa = 8xM7 + 4xM6 + 2xM5 + M4
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
Update of the contents of this register is internally disabled during I2C read operations to ensure proper data transfer between internal ADC and I2C registers. Update of I2C registers is resumed when the master sends a STOP command.
If user wants to read both the Lux High-Byte register 0x03 and Lux Low-Byte register 0x04, then the master should not send a STOP command between the reads of the two registers. Instead a Repeated START command should be used.
This ensures accurate data is obtained from the I2C registers (by disabling internal updates during the read process).

------------------------------------
Вот перевод из нее:
Если пользователь хочет прочитать как высокая байт Люкс регистра 0x03 и низкий байт Люкс регистра 0х04, то мастер не должен отправьте команду STOP между считываниями двух регистров. Вместо этого следует использовать повторную команду запуска.
Это гарантирует получение точных данных из регистров I2C (путем отключения внутренних обновлений в процессе чтения).
 

Serg2see

New member
Так я вроде так и делаю:
Код:
function read_reg(dev_addr, reg_addr)
    local c = {a=0, b=0}
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.a = i2c.read(0, 1)
    i2c.start(0)
    c.b = i2c.read(0, 1)
    i2c.stop(0)
    return c
end
Два раза через start считываю - read. Но c.b всегда даёт одно число - 255.
Или я что-то не так понимаю?
 
Последнее редактирование:

Serg2see

New member
Посмотрел более тщательно
Действительно в этом примере сказано, что проблема считывания последовательно двух таймингов в таймаутах. поэтому не читая второй сразу за первым, читаю один, затем второй через стоп. Это понижает немного точность, но другого способа пока не нашел. Получившийся код функции чтения:
Код:
function read_reg(dev_addr, reg_addr1, reg_addr2)
    local c = {a=0,b=0}
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr1)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.a = i2c.read(0, 1)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr2)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.b = i2c.read(0, 1)
    i2c.stop(0)
    return c
end

local reg = read_reg(0x4A, 0x03, 0x04)
Оба регистра меняются. При полной темноте даёт 0, под лампой 8939.52.

Теперь думаю как проверить.
Есть в даташите исходные условия для проверки:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.

Есть идеи?
 
Последнее редактирование:

nikolz

Well-known member
Посмотрел более тщательно

Действительно в этом примере сказано, что проблема считывания последовательно двух таймингов в таймаутах. поэтому не читая второй сразу за первым, читаю один, затем второй через стоп. Это понижает немного точность, но другого способа пока не нашел. Получившийся код функции чтения:
Код:
function read_reg(dev_addr, reg_addr1, reg_addr2)
    local c = {a=0,b=0}
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr1)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.a = i2c.read(0, 1)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.TRANSMITTER)
    i2c.write(0, reg_addr2)
    i2c.stop(0)
    i2c.start(0)
    i2c.address(0, dev_addr, i2c.RECEIVER)
    c.b = i2c.read(0, 1)
    i2c.stop(0)
    return c
end

local reg = read_reg(0x4A, 0x03, 0x04)
Оба регистра меняются. При полной темноте даёт 0, под лампой 8939.52.

Теперь думаю как проверить.
Есть в даташите исходные условия для проверки:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.

Есть идеи?
поставьте не стоп а задержку.
 

Serg2see

New member
Попробовал много значений задержки... при любых от 10 до 1000 даёт 255.
Думаю как проверить значения, полученные в результате расчёта по примерам даташита.
 

nikolz

Well-known member
Попробовал много значений задержки... при любых от 10 до 1000 даёт 255.
Думаю как проверить значения, полученные в результате расчёта по примерам даташита.
что-то у Вас не так в консерватории. Но у меня этого датчика нет.
Проверьте внимательнее код программы. У других же работает верно.
 

Serg2see

New member
Код работает, но алгоритму, указанному ранее:
Этот алгоритм не совсем соответствует даташиту в части "не посылки команды СТОП".
В общем код выдаёт освещённость, на мой взгляд похожую на правду, но меня беспокоит корректность этих данных, поэтому ищу способ проверки.
Пока такая идея:
1. Полученные результаты c.a и c.b конвертировать в двоичный код (пока не знаю как);
2. Сделать таблицу в соответствий двоичного кода и освещённости в соответствии с данными даташита:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
(надо подумать как это сделать, например в Excel)
3. Просто визуально сравнить.

Понимаю, что это будет проверка только расчётной части, но пока других идей просто нет.
 

nikolz

Well-known member
Код работает, но алгоритму, указанному ранее:

Этот алгоритм не совсем соответствует даташиту в части "не посылки команды СТОП".
В общем код выдаёт освещённость, на мой взгляд похожую на правду, но меня беспокоит корректность этих данных, поэтому ищу способ проверки.
Пока такая идея:
1. Полученные результаты c.a и c.b конвертировать в двоичный код (пока не знаю как);
2. Сделать таблицу в соответствий двоичного кода и освещённости в соответствии с данными даташита:
A code of 0000 0001 calculates to be 0.72 lux.
A code of 1110 1111 calculates to be 176,947 lux.
A code of 1110 1110 calculates to be 165,151 lux.
(надо подумать как это сделать, например в Excel)
3. Просто визуально сравнить.

Понимаю, что это будет проверка только расчётной части, но пока других идей просто нет.
Посмотрите в документации стр 17 там подробно нарисован алгоритм чтения двух байт
Figure 8. Reading Two Registers Consecutively Without a STOP Condition in Between Reads
 
Сверху Снизу