サーバーで制御されるESP8266でリモート制御サーボモーターコントローラーを作成しようとしています。私が直面している問題は、のような非同期タイマーを作成する方法ですtmr.alarm()
が、マイクロ秒単位です。tmr.delay()
他のすべてを停止し、あまり正確ではないため、うまく機能しません。あなたはこれをArduinoで動作させることができますが、これをLuaに実装する方法は?
サーバーで制御されるESP8266でリモート制御サーボモーターコントローラーを作成しようとしています。私が直面している問題は、のような非同期タイマーを作成する方法ですtmr.alarm()
が、マイクロ秒単位です。tmr.delay()
他のすべてを停止し、あまり正確ではないため、うまく機能しません。あなたはこれをArduinoで動作させることができますが、これをLuaに実装する方法は?
回答:
ESP8266 を使用すると、正確かつ非ブロッキングであるマイクロ秒の遅延を得るのに苦労するかもしれません。
NodeMCUのドキュメントによると:
app/modules/tmr.c
この関数のコードを見ると、低レベルのets_delay_us(delay)を実行していることがわかります。この関数は、NodeMCUコードまたはSDKの一部ではありません。これは実際にはxtensa-lx106
ブートROMの一部であり、内部CPUクロックに対してポーリングする単純なタイミングループです。割り込みが無効になっている場合、これが行われます。これは、割り込みが有効になっている場合、要求どおりに遅延が発生するという保証がないためです。
tmr.delay()
実際には、外部ハードウェアI / Oでより正確なタイミング制御が必要な場合に使用することを目的としています(たとえば、GPIOピンを20μSec間ハイに持ち上げる)。他のシステムコードベースのアクティビティは実行がブロックされるため、他のほとんどすべてのユースケースでは機能的な目的は達成されません。最悪の場合、アプリケーションが破損し、診断が難しいタイムアウトエラーが発生します。
この場合、割り込みを無効にする必要があるようですが、割り込みが短い間隔(数マイクロ秒程度)で遅延の途中で発生した場合、割り込みハンドラーは、全体の遅延が想定されていたよりもはるかに長い時間がかかるためです。することが。
20マイクロ秒のタイマーが必要で、約10μsで割り込みが発生したとします。ハンドラーが10μsを超える場合、意図した20μsの遅延をすでに通過しています。
したがって、tmr.delay()
割り込みが機能する必要がある場合は除外できます。
私はもう少し掘り下げました、そして明らかにESP8266はets_timer_arm_new()
最後のパラメーターがゼロであるところまでマイクロ秒タイマーをサポートします。ただし、NodeMCU はこの値を1に設定し、ミリ秒の精度を使用します。この投稿はその考えをサポートしているようです:
2つのgpio割り込みの間隔を取得する必要がある場合は、システムAPIのsystem_get_time()を使用して相対時間を計算します。 os_timer_arm_usを呼び出します。
ファームウェアの編集と再構築を試してみたいと思っているなら、一撃の価値があるかもしれません。ただし、これに対する機能のリクエストがあり、次のように拒否されました。
したがって、ナノ秒タイマーをテストしましたが、1000us未満の間隔を確立することはできません(コンパイルおよびストリップされたコードで、160MHz CPUモードでは800usのようなものが得られました)。これは、新しい(ほとんど使用できない)機能を提供するケースですか?
- djphoenix実現不可能なATM->クローズ。
- marcelstoer
タイマーを有効にしてNodeMCUファームウェアを再コンパイルしました。
MarcelStörのdockerビルド環境をインストールします:https : //hub.docker.com/r/marcelstoer/nodemcu-build/
(例えば、あなたのファームウェアディレクトリにファームウェアファイルを変更./user/nodemcu-firmware
)
./app/user/user_main.c
void user_init(void)
{
ここに次の行を追加します。 system_timer_reinit();
./sdk-overrides/osapi.h
ラインの上に追加 #include_next "osapi.h": #define USE_US_TIMER
./app/modules/tmr.c
-> static int tmr_start(lua_State* L){
変更:os_timer_arm
->os_timer_arm_us
./app/modules/tmr.c
-> static int tmr_interval(lua_State* L){
変更:os_timer_arm
->os_timer_arm_us
./app/modules/tmr.c:
そのままにos_timer_arm
しint luaopen_tmr( lua_State *L ){
ておくと、起動時にウォッチドッグがリセットされます。
CPUが160MHzで動作しているので、8.3kHz(125uSのタイマー遅延)でADCをサンプリングできました。もっと速く行けば、番犬がやってくる。
コード:
local mytimer2 = tmr.create()
local count = 0
local count2 = 0
local adc_read = adc.read
mytimer2:register(125, 1, function (t2)
count = count + 1; count2 = count2 + 1
local adc_v = adc_read(0)
if (count2 == 500) then
count2 = 0
end
if count == 100000 then
mytimer2:stop()
print("Time at end: "..tmr.time())
print("Counter: "..count)
end
end)
print("Time at start: "..tmr.time())
mytimer2:start()
出力:
開始時間:1
終了時間:13
カウンター:100000
12秒で100.000読み取り。