2.做個迷你氣象站·二

模塊化

在繼續(xù)推進我們這個迷你氣象站之前,我們需要了解一下lua的模塊與包。具體的概念這里不贅述。

引入模塊和包的一個主要原因是,后面我們要涉及的功能模塊比較多。按照模塊化編程的思想是,讓不同的功能代碼分散在不同的文件中,以減少代碼的耦合性。

先來看一個簡單的例子

module = { }

module.value = 1

function  module.func()
  print(module.value)
end

return module

首先,定義一個module的table。然后往這個table寫入一堆東西。最后返回這個module。實現(xiàn)一個模塊就是這么簡單。

而引用這個模塊也是相當?shù)暮唵?,在另外一個文件里面使用require "module"即可。引號里是module的名字。一般來說把模塊名與文件名保持一致即可。

第一個模塊

既然是第一個lua模塊,那就要拿最最最簡單的功能模塊來練手了。我想最簡單的非gpio莫屬了。

不知道你忘記沒有,nodemcu上面有2個IO外設(shè)。沒錯,一個flash按鍵和一個藍色的led。我們先把這兩個外設(shè)封裝起來成為我們第一個模塊,命名為myIO。模塊包含了以下幾個功能:

  • IO初始化
  • 寫IO
  • 讀IO

讓我們一點一點來實現(xiàn),

--1
myIO = { }

local key, led = 3, 0
local keymode, ledmode = gpio.INPUT, gpio.OUTPUT
local keyCnt = 0

這里我們先定義一個myIO的table,和一些局部變量。局部變量只可以被模塊內(nèi)部訪問。另外,local key, led = 3, 0是lua里面一個有趣的語法,和下面的寫法是等效的。

local key = 3
local led = 0

接下來是初始化IO

--3
function myIO.gpioInit()
    gpio.mode(key, keymode)
    gpio.mode(led, ledmode)
    return true
end

這是模塊的一個函數(shù),初始化key和led,是可以被模塊外的其他函數(shù)調(diào)用的。下面這個函數(shù)是用來控制led狀態(tài)的,我想不需要我多說了。

--4
function myIO.setLED(s) 
    if s == true then
        gpio.write(led, gpio.LOW)
    else
        gpio.write(led, gpio.HIGH)
    end
end

弄完led的,接著來寫一個按鍵的。

--2
local function keyScan()
    local v = gpio.read(key)

    if v == 0 then 
        keyCnt = keyCnt + 1
        if keyCnt > 50 then 
            v = 2 
            keyCnt = 0
        end
    else
        if keyCnt > 5 then 
            v = 1 
            keyCnt = 0
        else 
            v = 0 
            keyCnt = 0
        end
    end

    return v
end

你可能發(fā)現(xiàn)了,這個函數(shù)和前面不一樣。恩,沒錯。這個多了個local,少了個myIO。這其實是個局部函數(shù),或者說模塊內(nèi)部函數(shù)。

這個用來做按鍵掃描,可以判斷按鍵是長按還是短按(短按在松手后判斷)。為啥這個函數(shù)要做出local的呢?后面在說明原因。

接著來看最后一個函數(shù)

--5
function myIO.setKey(short, long)
    local s = 0

    if myIO.ktimer == nil then
        myIO.ktimer = tmr.create()
    end
    
    tmr.stop(myIO.ktimer)

    --20ms
    tmr.register(myIO.ktimer, 20, tmr.ALARM_AUTO, function()
        
        local k = keyScan()
        --調(diào)整掃描頻率
        if s == 1 then 
            tmr.interval(myIO.ktimer, 20)
            s = 0
        end

        if k == 1 then
            short()
        elseif k == 2 then
            long()
            tmr.interval(myIO.ktimer, 500)
            s = 1
        end
    end)

    tmr.start(myIO.ktimer)

end

函數(shù)有點長。不過,你應該看出來了。這里面其實就是創(chuàng)建了一個定時器,并注冊了回調(diào)事件來處理鍵盤。

不知道你有沒有注意到這里,

    if myIO.ktimer == nil then
        myIO.ktimer = tmr.create()
    end

是的,這個定義了一個模塊變量。以為著你可以在其他模塊里面使用myIO.ktimer來操作鍵盤掃描這個定時器。

也許,你還留意到了short, long。這兩個參數(shù)在函數(shù)內(nèi)部被當做函數(shù)使用了。

這種做的好處是,我們在模塊內(nèi)部對按鍵的行為做好封裝,外部代碼不用知道鍵盤的具體邏輯,這需要把長按和短按的兩個函數(shù)傳進來即可,類似于回調(diào)。這樣更符合模塊化編程。

這也是為什么keyScan()是一個局部函數(shù)。因為外面的世界不需要知道里面的世界是什么樣子的!

最后,別忘記了

--6
return myIO

測試模塊

模塊寫好了,能不能用還要測試才知道。建議先按--1 ~ --6拷貝代碼到文件,并命名為myIO.lua。然后使用我們平時用的那個軟件的upload功能把文件上傳到nodemcu上。

重新寫個測試文件test.lua。代碼如下。

local myIO = require "myIO"
myIO.gpioInit()

function a()
    print("short")
end

function b()
    print("long")
end

myIO.setKey(a, b)

使用local myIO = require "myIO"來引入包,并給這個包重新起個名字,方便后面使用。

初始化IO,并定義2個函數(shù),在設(shè)置按鍵事件回調(diào)。

最后,按一下nodemcu上面的flash來看效果吧。長按和短按是不一樣的!

效果出來了!

關(guān)于模塊化,暫且先到這。后面我們都會講用的的功能封裝成一個一個模塊!

點完贊再走??!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容