Senin, 07 November 2016

Tutorial NodeMCU: Interfacing ESP8266 dengan DS3231 hardware RTC (WeMos, Lua)

Pada contoh tulisan ini membutuhkan module i2c dan sntp pada firmware NodeMCU, jika tidak maka dapat menghasilkan error "not enough memory" maupun "attempt to index global 'sntp' (a nil value)"

Anda dapat meng-kustomisasi firmware NodeMCU dengan memasukan module RTC kedalamnya, tetapi permasalahan pada firmware ini adalah anda perlu melakukan sinkronisasi  waktu ke time server melalui network time protocol (NTP) dengan module sntp setelah koneksi ke wifi berhasil dilakukan karena software RTC tidak mengupdate waktu ketika board WeMos dalam keadaan OFF.
sntp.sync("1.id.pool.ntp.org",

 function(sec,usec,server)
   print('setting time to:', sec, usec, "from: " .. server)
   rtctime.set(sec, usec)
   utc = rtctime.epoch2cal(rtctime.get())
   print("Waktu adalah UTC:" .. string.format("%04d/%02d/%02d %02d:%02d:%02d", utc["year"], utc["mon"], utc["day"], utc["hour"], utc["min"], utc["sec"]))
   wib = rtctime.epoch2cal(rtctime.get()+7*60*60) -- tambah 7
   print("Waktu adalah WIB:" .. string.format("%04d/%02d/%02d %02d:%02d:%02d", wib["year"], wib["mon"], wib["day"], wib["hour"], wib["min"], wib["sec"]))     
 end,

 function()
   print('failed!')
 end
)
Hardware RTC seperti DS3231 memiliki baterai internal untuk menjaga RTC tetap berdetak walaupun board WeMos dalam keadaan OFF, sehingga dapat digunakan pada lingkungan intranet dimana wifi tersedia tetapi koneksi ke internet dibatasi, ataupun koneksi ke internet tidak tersedia setiap saat.
Gambar 1. Hardware RTC module DS3231

Pemakaian DS3231 adalah menghubungkan pin VCC ke 3V3 pada board WeMos, dan GND ke GND pada board, sedangkan SCL ke pin D1, dan SDA ke pin D2, yang memang disediakan khusus untuk serial Clock (SCL) dan serial data (SDA).
Gambar 2. Pin D1 untuk SCL dan pin D2 untuk SDA

Komunikasi antara DS3231 dengan board WeMos adalah melalui inter-integrated-circuit (I2C), sehingga untuk itu perlu dipastikan bahwa firmware yang terinstalasi adalah tersedia module I2C. Kebetulan firmware yang saya gunakan telah saya kustomisasi melalui https://nodemcu-build.com/ dengan pilihan module sebagai berikut:

 Gambar 3. Kustomisasi firmware

Sehingga ketika booting mendapatkan pesan:
NodeMCU custom build by frightanic.com
    branch: master
    commit: 7b83bbb2ea134cd85ac9d63108603cc02c4e20f7
    SSL: false
    modules: file,gpio,i2c,net,node,rtctime,sntp,tmr,uart,wifi
 build     built on: 2016-11-06 12:52
 powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)
Berikut ini adalah module ds3231.lua yang berisi fungsi-fungsi untuk setter dan getter melalui hardware RTC DS3231 melalui kemunikasi I2C.

credentials.lua
Source code silakan mengacu pada artikel sebelumnya
init.lua

Source code silakan mengacu pada artikel sebelumnya

ds3231.lua
--------------------------------------------------------------------------------
-- DS3231 I2C module for NODEMCU
-- NODEMCU TEAM
-- LICENCE: http://opensource.org/licenses/MIT
-- Tobie Booth <tbooth@hindbra.in>
--------------------------------------------------------------------------------

local moduleName = ...
local M = {}
_G[moduleName] = M

-- Default value for i2c communication
local id = 0

--device address
local dev_addr = 0x68

local function decToBcd(val)
  return((((val/10) - ((val/10)%1)) *16) + (val%10))
end

local function bcdToDec(val)
  return((((val/16) - ((val/16)%1)) *10) + (val%16))
end

-- initialize i2c
--parameters:
--d: sda
--l: scl
function M.init(d, l)
  if (d ~= nil) and (l ~= nil) and (d >= 0) and (d <= 11) and (l >= 0) and ( l <= 11) and (d ~= l) then
    sda = d
    scl = l
  else
    print("iic config failed!") return nil
  end
    print("init done")
    i2c.setup(id, sda, scl, i2c.SLOW)
end

--get time from DS3231
function M.getTime()
  i2c.start(id)
  i2c.address(id, dev_addr, i2c.TRANSMITTER)
  i2c.write(id, 0x00)
  i2c.stop(id)
  i2c.start(id)
  i2c.address(id, dev_addr, i2c.RECEIVER)
  local c=i2c.read(id, 7)
  i2c.stop(id)
  return bcdToDec(tonumber(string.byte(c, 1))),
  bcdToDec(tonumber(string.byte(c, 2))),
  bcdToDec(tonumber(string.byte(c, 3))),
  bcdToDec(tonumber(string.byte(c, 4))),
  bcdToDec(tonumber(string.byte(c, 5))),
  bcdToDec(tonumber(string.byte(c, 6))),
  bcdToDec(tonumber(string.byte(c, 7)))
end

--set time for DS3231
function M.setTime(second, minute, hour, weekday, date, month, year)
  i2c.start(id)
  i2c.address(id, dev_addr, i2c.TRANSMITTER)
  i2c.write(id, 0x00)
  i2c.write(id, decToBcd(second))
  i2c.write(id, decToBcd(minute))
  i2c.write(id, decToBcd(hour))
  i2c.write(id, decToBcd(weekday))
  i2c.write(id, decToBcd(date))
  i2c.write(id, decToBcd(month))
  i2c.write(id, decToBcd(year))
  i2c.stop(id)
end

return M
app.lua
require("ds3231")

-- ESP-8266 pin D1=scl, pin D2=sda
pinSCL, pinSDA = 1,2

ds3231.init(pinSDA, pinSCL)

sntp.sync("1.id.pool.ntp.org",

 function(sec,usec,server)
   print('setting time to:', sec, usec, "from: " .. server)
   rtctime.set(sec, usec)  
   utc = rtctime.epoch2cal(rtctime.get())
   ds3231.setTime(utc["sec"], utc["min"], utc["hour"], 0, utc["day"], utc["mon"], 16)  

   print("Waktu adalah UTC:" .. string.format("%04d/%02d/%02d %02d:%02d:%02d", utc["year"], utc["mon"], utc["day"], utc["hour"], utc["min"], utc["sec"]))

   second, minute, hour, day, date, month, year = ds3231.getTime();
   print("Waktu ds3231:" .. string.format("Time & Date: %s:%s:%s %s/%s/%s", hour, minute, second, date, month, year))
 end,

 function()
   print('failed!')
 end
)

-- Don't forget to release it after use
ds3231 = nil
package.loaded["ds3231"]=nil

Hasil eksekusi adalah:
setting time to:    1478529932    824760    from: 202.65.114.202
Waktu adalah UTC:2016/11/07 14:45:32
Waktu ds3231:Time & Date: 14:45:32 7/11/16
Catatan:
tahun pada hardware RTC DS3231 adalah dua digit, misalnya 2016 adalah ditulis sebagai 16.

Bagaimana kalau koding diatas dijalankan pada firmware yang tidak tersedia module I2C?

System anda akan memberikan pesan "not enough memori" pada baris yang menjalanlan require("ds3231")

Tidak ada komentar:

Posting Komentar