我正在尝试在由服务器控制的 ESP8266 上制作远程控制的伺服电机控制器。我面临的问题是如何制作一个异步计时器,比如tmr.alarm()
,但以微秒为单位。tmr.delay()
效果不是很好,因为它会停止其他一切并且不太准确。你可以让它在 Arduino 上工作,但是如何在 Lua 中实现它呢?
Lua 中 ESP8266 的亚毫秒计时器
我认为您可能很难通过 ESP8266获得既准确又无阻塞的微秒延迟。
根据NodeMCU 文档:
如果您查看
app/modules/tmr.c
此函数的代码,您将看到它执行了一个低级别的 ets_delay_us(delay)。此函数不是 NodeMCU 代码或 SDK 的一部分;它实际上是xtensa-lx106
引导 ROM 的一部分,是一个简单的定时循环,它轮询内部 CPU 时钟。它在禁用中断的情况下执行此操作,因为如果启用它们,则无法保证延迟将符合要求。
tmr.delay()
真正用于需要对外部硬件 I/O 进行更精确定时控制的地方(例如,将 GPIO 引脚提升 20 微秒)。在几乎所有其他用例中,它都不会实现任何功能目的,因为任何其他基于系统代码的活动都将被阻止执行;在最坏的情况下,它会破坏您的应用程序并产生难以诊断的超时错误。
似乎在这种情况下必须禁用中断,因为如果中断确实发生在中间延迟时间很短(大约几微秒),则中断处理程序将占用比整个延迟更多的时间成为。
假设您想要一个 20 微秒的计时器,并且在大约 10 微秒时发生中断。如果处理程序花费的时间超过 10 μs,则您将已经超过了预期的 20 μs 延迟。
因此,我们可以排除tmr.delay()
您是否确实需要中断工作。
我做了更多的挖掘,显然 ESP8266 确实支持微秒计时器ets_timer_arm_new()
,因为最后一个参数为零。但是,NodeMCU将此值设置为 1,使用毫秒精度。这篇文章似乎支持这个想法:
如果需要获取两次gpio中断的时间间隔,可以使用system api system_get_time()来计算相对时间。并调用 os_timer_arm_us。
如果您愿意尝试编辑和重建固件,可能值得一试。虽然,有一个功能请求,但被拒绝了:
所以我测试了纳秒计时器,并且不能建立小于 1000us 的间隔(使用编译和剥离的代码,在 160MHz CPU 模式下我得到类似 800us 的时间)。这是提供新(大部分不可用)功能的案例吗?
- djphoenix不可行的 ATM -> 关闭。
-马塞尔斯托
我已经设法在启用我们的计时器的情况下重新编译 NodeMCU 固件:
安装 Marcel Stö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 ){
原样,否则你将时可以获得看门狗复位启动- 重新编译固件,刷入你的 ESP8266
当 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 次。