这个问题让我疯了。它消耗的时间太多了,我可以帮忙,请! 基本上,我使用Get()从我的服务器下载天气数据。这很好用。我想做的就是在16x2 i2c lcd屏幕上显示它,但是我受到“内存不足”问题的困扰。 我已经尝试了社区提供的几个模块,所有人似乎都遇到了同样的问题,所以我确信这个问题与我的代码/调用约定有关。 我目前正在使用模块lcd.lua,这是Vladimir Dronnikov提供的略有变化。并在规定的庄园中称呼它
<pre>
i2c.setup(0, 3, 4, i2c.SLOW)
lcd = dofile("lcd.lua")()
</pre>
调用lua脚本充满了印刷语句:
<pre>
lcd.put(lcd:locate(0, 0),"Mast Temp: ")
</pre>
我的文件结构如下所示
<pre>
Init.lua -- opportunity to prevent script execution. Calls wifiConnect
wifiConnect.lua -- connects to wifi and calls dofile(DetServerData())
GetServerData.lua -- Fetches data and displays on lcd module.
</pre>
当wifiConnect针对GetServerData调用dofile时,通常会覆盖“内存不足”,有时脚本会在遇到“内存不足”错误之前运行2到3次。 然而,我有它跑了8000-9000次,然后跌倒。 (只有一两次。) 如果我允许wifiConnect运行GetFileData,它将停止
<pre>
PANIC: unprotected error in call to Lua API (not enough memory)
</pre>
加载GetServerData似乎在堆上消耗13816个字节..离开18800.肯定足以运行。 我尝试过require(getServerData),数字略有不同,结果相同。
GetServerData如下
-- 0 DS18B20_temp_C -- 1 WindSpeed_kmph -- 2 WindBearing; -- 3 WindDir -- 4 BMP_temp -- 5 BMP_pressure -- BMP_altitude --------------REMOVED -- 6 DHT22_temperature -- 7 DHT22_humidity -- DH22_dewPoint--------------REMOVED -- DHT22_heatIndex--------------REMOVED local WDPin = 1 local LCDscreenPin = 2 local LCDmaxScreen = 4 local cycleCount=0 local WDogLED = false local dataTable={} ; i=1 local connClosed = true local LCDpageID = 1 function GetData() if connClosed == true then local conn=net.createConnection(net.TCP, 0) print("Open connection...") WatchDog() if conn == nil then print("Connection error") else conn:connect(80,'31.220.16.114') connClosed = false tmr.alarm(4,3000,0,ResetConn) conn:send("GET /test.txt? HTTP/1.1\r\n") conn:send("Host: theoldschool.esy.es\r\n") conn:send("Accept: */*\r\n") conn:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n") conn:send("\r\n") conn:on("disconnection", function(conn) connClosed = true WatchDog() print("Disconnected...") end) -- on:"disconection" conn:on("receive",function(conn,payload) cleanData = extractWeatherData(payload) DbugGarbageCollect() fillDataTable(cleanData,'\r\n') for k,v in pairs(dataTable) do print(k,v) end cycleCount = cycleCount +1 print(cycleCount) end)-- on recieve end-- if conn == nil end -- if connClosed end--GetData function ResetConn() print("Stuck") connClosed = true end -- ResetConn function fillDataTable(inputstr, sep) local i=0 for str in string.gmatch(inputstr, "([^"..sep.."]+)") do dataTable[i] = str i = i + 1 end--for end--splitCmd function stripMarkers(str, chrs) local s = str:gsub("["..chrs:gsub("%W","%%%1").."]", '') return s end function extractWeatherData (payload) local startChar = string.find(payload, '%') local s = string.sub(payload, startChar,endChar) s = stripMarkers(s, "") return s end -- extractWeatherData function WatchDog() if WDogLED == false then WDogLED = true gpio.write(WDPin, gpio.HIGH) else WDogLED = false gpio.write(WDPin, gpio.LOW) end --if end--WatchDog function DbugGarbageCollect() local before = collectgarbage("count") collectgarbage() print(before - collectgarbage("count")) print(node.heap()) end --DbugGarbageCollect function LCDdisplay() lcd.clear() if LCDpageID == 1 then lcd.put(lcd:locate(0, 0),"Mast Temp: ") lcd.put(lcd:locate(1, 0),"Shade Tmp: ") elseif LCDpageID == 2 then lcd.put(lcd:locate(0, 0),"Wind Dir: ") lcd.put(lcd:locate(1,0),"Wind Knts: ") elseif LCDpageID == 3 then lcd.put(lcd:locate(0, 0),"Pressure: ") lcd.put(lcd:locate(1, 0),"BMP Temp: ") elseif LCDpageID == 4 then lcd.put(lcd:locate(0, 0),"DHT Temp: ") lcd.put(lcd:locate(1, 0),"Humidity: ") else lcd.put(lcd:locate(0, 0),"SCREEN ERROR 1") end --if --updateLCDDisplay() collectgarbage() end --LCDdisplay function updateLCDDisplay() if LCDpageID == 1 then lcd.put(lcd:locate(0, 11),dataTable[0]) -- LCDScreenOP.lcdprint(dataTable[0],1,11) -- LCDScreenOP.lcdprint(dataTable[7],2,11) elseif LCDpageID == 2 then --LCDScreenOP.lcdprint(dataTable[2],1,10) -- LCDScreenOP.lcdprint(dataTable[3],1,14) -- LCDScreenOP.lcdprint(dataTable[1],2,11) elseif LCDpageID == 3 then -- LCDScreenOP.lcdprint(dataTable[5],1,10) -- LCDScreenOP.lcdprint(dataTable[4],2,10) elseif LCDpageID == 4 then --LCDScreenOP.lcdprint(dataTable[6],1,10) -- LCDScreenOP.lcdprint(dataTable[7],2,10) else -- LCDScreenOP.cls() -- LCDScreenOP.cursor(0) -- LCDScreenOP.lcdprint("U/D ERROR",1,0) end --if -- package.loaded.LCDScreenOP = nil DbugGarbageCollect() end -- updateDisplay function LCDScreenChange(level) LCDpageID = LCDpageID + 1 if LCDpageID == LCDmaxScreen + 1 then LCDpageID = 1 end LCDdisplay() end-- buttonpress --============================ CODE ============================== i2c.setup(0, 3, 4, i2c.SLOW) lcd = dofile("lcd.lua")() print ("here") gpio.mode(WDPin, gpio.OUTPUT) gpio.write(WDPin, gpio.HIGH) gpio.mode(LCDscreenPin, gpio.INPUT, gpio.PULLUP) DbugGarbageCollect() gpio.trig(LCDscreenPin, "down",LCDScreenChange) tmr.alarm(2,1500,1,GetData)
在加载GetServerData并允许它运行时,esplorer窗口的屏幕抓取如下所示
<pre>
abort = true
startup aborted
=node.heap()
>**32616**
file.remove("GetServerData.lua");
file.open("GetServerData.lua","w+");
w = file.writeline
-- Above code in here !!
file.close();
dofile("GetServerData.lua");
>not enough memory
dofile('GetServerData.lua')
not enough memory
=node.heap()
>**18800**
dofile('GetServerData.lua')
>not enough memory
</pre>
我们将非常感激地收到任何帮助,并且可以提供任何其他可能有用的信息
非常感谢 菲利普
答案 0 :(得分:1)
这需要很多代码来梳理。如果您提供了Minimal, Complete, and Verifiable example来重现问题(&gt; Minimal ),那会更有帮助。
快速浏览一下就发现了2.5个问题,但可能会有更多问题。
关闭价值
conn:on("receive",function(conn,payload)
泄漏,因为回调参数不应该是conn
而是其他内容。请参阅https://github.com/nodemcu/nodemcu-firmware/issues/194#issuecomment-184817667或https://stackoverflow.com/a/37379426/131929
发送是异步的
conn:send
不应该快速连续调用,因为每个调用都是异步的,因此无法保证调用顺序。有关详细信息和一个很好的示例,请参阅net.socket:send
文档。
考虑http模块
使用http.get
可以帮助您降低代码的复杂性。