Bộ đếm thời gian phụ milisecond cho ESP8266 ở Lua


9

Tôi đang cố gắng tạo một bộ điều khiển động cơ servo được điều khiển từ xa trên ESP8266 do máy chủ điều khiển. Vấn đề tôi gặp phải là làm thế nào để tạo một bộ đếm thời gian không đồng bộ, như tmr.alarm(), nhưng tính bằng micrô giây. tmr.delay()không hoạt động tốt, bởi vì nó dừng mọi thứ khác và không chính xác. Bạn có thể làm điều này để làm việc trên Arduino, nhưng làm thế nào để thực hiện điều này trong Lua?

Câu trả lời:


7

Tôi nghĩ rằng bạn có thể đấu tranh để có được độ trễ micro giây vừa chính xác vừa không chặn với ESP8266.

Theo tài liệu của NodeMCU :

Nếu bạn nhìn vào app/modules/tmr.cmã cho hàm này, thì bạn sẽ thấy rằng nó thực thi một mức thấp ets_delay_us (độ trễ). Hàm này không phải là một phần của mã NodeMCU hoặc SDK; nó thực sự là một phần của xtensa-lx106ROM khởi động và là một vòng lặp thời gian đơn giản, thăm dò đồng hồ CPU bên trong. Nó thực hiện điều này với các ngắt bị vô hiệu hóa, bởi vì nếu chúng được kích hoạt thì không có gì đảm bảo rằng độ trễ sẽ được yêu cầu.

tmr.delay()thực sự được dự định sử dụng khi bạn cần kiểm soát thời gian chính xác hơn trên I / O phần cứng bên ngoài (ví dụ: nâng chân GPIO lên cao trong 20 μSec). Nó sẽ không đạt được mục đích chức năng trong hầu hết các usecase khác, vì mọi hoạt động dựa trên mã hệ thống khác sẽ bị chặn thực thi; tệ nhất là nó sẽ phá vỡ ứng dụng của bạn và tạo ra các lỗi hết thời gian khó chẩn đoán.

Có vẻ như các ngắt phải bị vô hiệu hóa trong trường hợp này đơn giản vì nếu một ngắt xảy ra giữa độ trễ với một khoảng thời gian ngắn (theo thứ tự một vài micro giây), trình xử lý ngắt sẽ mất nhiều thời gian hơn so với toàn bộ độ trễ được cho là được.

Giả sử bạn muốn có một bộ đếm thời gian trong 20 micro giây và một sự cố xảy ra ở khoảng 10 μs. Nếu trình xử lý mất hơn 10, s, bạn đã vượt qua độ trễ 20 giây mà bạn dự định.

Vì vậy, chúng tôi có thể loại trừ tmr.delay()nếu bạn cần ngắt làm việc.

Tôi đã đào sâu hơn một chút và rõ ràng ESP8266 không hỗ trợ bộ định thời micro giây thông qua ets_timer_arm_new()đó tham số cuối cùng bằng không. Tuy nhiên, NodeMCU đặt giá trị này thành 1, sử dụng độ chính xác đến mili giây . Bài đăng này dường như ủng hộ ý tưởng đó:

Nếu bạn cần lấy khoảng thời gian giữa hai gpio ngắt, hãy sử dụng hệ thống api system_get_time () để tính thời gian tương đối. (Chúng tôi) Nếu bạn muốn sử dụng một api os_timer để sắp xếp một sự kiện hẹn giờ cho chúng tôi, hãy sử dụng system_timer_Vinit vào đầu user_init và gọi os_timer_arm_us.

Nếu bạn sẵn sàng thử chỉnh sửa và xây dựng lại phần sụn, nó có thể đáng để thử. Mặc dù, có một yêu cầu tính năng cho việc này , đã bị từ chối là:

Vì vậy, tôi đã thử nghiệm bộ định thời nano giây và không thể thiết lập các khoảng nhỏ hơn 1000us (với mã được biên dịch và tước và ở chế độ CPU 160 MHz, tôi có khoảng 800us). Đây có phải là một trường hợp để cung cấp chức năng mới (chủ yếu là không sử dụng)?
- djphoenix

ATM không khả thi -> đóng cửa.
- marcelstoer


5

Tôi đã quản lý để biên dịch lại chương trình cơ sở NodeMCU với tính năng hẹn giờ của chúng tôi:

  • Cài đặt môi trường xây dựng docker của Marcel Stör: https://hub.docker.com/r/marcelstoer/nodemcu-build/

  • thay đổi tập tin phần sụn trong thư mục phần sụn của bạn (ví dụ ./user/nodemcu-firmware)

    1. ./app/user/user_main.c

      void user_init(void)
      {

thêm ngay vào đây dòng: system_timer_reinit();

  1. ./sdk-overrides/osapi.h thêm phía trên dòng #include_next "osapi.h": #define USE_US_TIMER

  2. ./app/modules/tmr.c-> static int tmr_start(lua_State* L){ thay đổi: os_timer_arm->os_timer_arm_us

  3. ./app/modules/tmr.c-> static int tmr_interval(lua_State* L){ thay đổi: os_timer_arm->os_timer_arm_us

  4. ./app/modules/tmr.c:rời os_timer_armtrong int luaopen_tmr( lua_State *L ){như là, nếu không bạn sẽ nhận được một cơ quan giám sát thiết lập lại sau khi khởi động

    • biên dịch lại firmware và flash ESP8266 của bạn

Với CPU chạy ở tốc độ 160 MHz, tôi đã quản lý để lấy mẫu ADC với 8.3kHz (độ trễ hẹn giờ là 125uS). Nếu tôi đi nhanh hơn, cơ quan giám sát sẽ đá vào.

Mã số:

    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()

Đầu ra:

Thời gian bắt đầu: 1

Thời gian kết thúc: 13

Số lượt truy cập: 100000

100.000 lượt đọc trong 12 giây.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.