TI-Nspire & Arduino を利用した温度計 4 of 4、グラフ化する。
最後にグラフ化してみる。Graphs アプリケーションをそのまま使う。
var.store() コマンドで lua から nspire へデータを渡して scatter plot で描画する。
.ino
#include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS 10 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); DeviceAddress thermo0; DeviceAddress thermo1; void setup() { Serial.begin(115200); sensors.begin(); sensors.getAddress(thermo0, 0); sensors.getAddress(thermo1, 1); sensors.setResolution(thermo0, 12); sensors.setResolution(thermo1, 12); } void loop() { if (Serial.read() == 'T') { sensors.requestTemperatures(); Serial.print("0: "); Serial.print(sensors.getTempC(thermo0)); Serial.print(";"); Serial.print("1: "); Serial.print(sensors.getTempC(thermo1)); } }
.lua
-- showing graphically require "asi" require "color" platform.window:setBackgroundColor(color.dodgerblue) PORT = nil rawTime = {} relativeTime = {} INTERVAL = 2 numberOfSensors = 2 DATA = {} for i = 1, numberOfSensors do DATA[i] = {} end gotInitialData = false function on.resize() W, H = platform.window:width(), platform.window:height() fontSize = math.min(H/2, 24) colSpace = W/1.8 end function whenNoData() for i = 1, numberOfSensors do table.insert(DATA[i], 0) end end -------------------------------------------------------------------------- -- シリアルデータの読み取り要求函数(合図として文字 "T" を送信する) -------------------------------------------------------------------------- function requestData() if PORT then PORT:write('T') PORT:read() end end -------------------------------------------------------------------------------- -- ASI ステートリスナーを定義する(ASI の準備が整ったらポートスキャンを開始する) -------------------------------------------------------------------------------- function stateListener(state) if state == asi.ON then asi.startScanning(portScanner) end platform.window:invalidate() end ---------------------------------------------------------------- -- ポートスキャナーを定義する(見つかったポートに接続要求を出す) ---------------------------------------------------------------- function portScanner(port) port:connect(portConnector) end ----------------------------------------------------------------------------------------------------- -- ポートコネクターを定義する --(入出力の準備が整ったらポートスキャンを停止し、読み取りリスナーをセットし、データ読み取り要求を出す) --(接続が外れていたらポートスキャンを開始する) ----------------------------------------------------------------------------------------------------- function portConnector(port, event) PORT = port if event == asi.CONNECTED then asi.stopScanning() port:setReadListener(readListener) if not gotInitialData then gotInitialData = true requestData() -- 初回データを取得してからタイマーをスタートする。 timer.start(INTERVAL) end else whenNoData() platform.window:invalidate() asi.startScanning(portScanner) end end ---------------------------------------------------------------------------------------- -- 読み取りリスナーを定義する(xx.xx 形式のデータを取得する) ---------------------------------------------------------------------------------------- function readListener(port) local data = port:getValue() table.insert(rawTime, timer.getMilliSecCounter()) -- データを取得したときの内部ミリ秒カウンターの値を取得して、 relativeTime[#rawTime] = (rawTime[#rawTime] - rawTime[1])/1000 -- 測定開始時を基準とする秒単位に変換する。 if data then local dataList = string.split(data, ";") -- "0: 温度0;1: 温度1" という形式のデータを {0: 温度0, 1: 温度1, ...} というリストに変換する。 for _, v in ipairs(dataList) do local subList = string.split(v, ":") -- さらに {0, 温度0} {1, 温度1} ... というリストに変換し、 local index = subList[1] local value = tonumber(subList[2]) table.insert(DATA[index + 1] or {{}}, value or nil) -- DATA[1][n] = 温度0、DATA[2][n] = 温度1、... と代入する。 end else whenNoData() end var.store("x", relativeTime) var.store("y0", DATA[1]) var.store("y1", DATA[2]) --[[ print(relativeTime[#relativeTime], DATA[1][#relativeTime], DATA[2][#relativeTime]) --]] platform.window:invalidate() end --------------------------------- -- ASI ステートリスナーを登録する --------------------------------- function on.enterKey() asi.addStateListener(stateListener) end ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- function on.construction() gotInitialData = false end function on.timer() requestData() end function on.paint(gc) gc:setFont("sansserif", "r", fontSize) gc:setColorRGB(color.white) for i, v in ipairs(DATA) do gc:drawString(string.format(" %d: %4.1f °C", (i - 1), v[#v] or 0), (i - 1) * colSpace, 0) end end