如何在此函数中使用millis()而非for循环

我使用Neopixels(64个LED),并且我有一个名为level_up的函数,每次都会获得不同的led_num。通常,它是一个水平栏; level [1]将按从0到28的顺序点亮所有LED,level [2]将按29到48的顺序点亮所有LED,依此类推。 我附加的函数工作正常,但是我需要将延迟更改为millis(),但不确定如何。有什么想法吗?

uint8_t level[] = {0,28,48,60,64};  //levels 0 to 4


void level_up(uint8_t wait,uint8_t led_num) {
    uint8_t start_point;
    if (led_num == level[1]) start_point = 0;   //up from level 0 to 1
    if (led_num == level[2]) start_point = 28;  //up from level 1 to 2
    if (led_num == level[3]) start_point = 48;  //up from level 2 to 3
    if (led_num == level[4]) start_point = 60;  //...

    for (uint8_t i = start_point; i < led_num; i++) {
        strip.setPixelColor(i,strip.Color(0,255));
        strip.show();
        delay(wait);  //TODO: change it to timer
    }
}

void loop() {
    if (plus_btn.pressed()) {
        score++;
        if (score >= 4) {
            score = 4;
        }
    }
    if (minus_btn.pressed()) {
        score--;
        if (score <= 0) {
            score = 0;
        }
    }

switch (score) {
    case 0:
        if (last_score == 1) level_down(50,level[0]);
        last_score = 0;
        break;
    case 1:
        // if last_score was 0 make the blue effect because level is up
        if (last_score == 0) level_up(50,level[1]);
        // if last_score was 2 make the red effect because level is down
        if (last_score == 2) level_down(50,level[1]);
        last_score = 1;
        break;
    case 2:
        if (last_score == 1) level_up(50,level[2]);
        if (last_score == 3) level_down(50,level[2]);
        last_score = 2;
        break;
    case 3:
        if (last_score == 2) level_up(50,level[3]);
        if (last_score == 4) level_down(50,level[3]);
        last_score = 3;
        break;
    case 4:
        winning_timer.start();
        winning();
        digitalWrite(WINNING_SENSOR_PIN,HIGH);
        break;
}

Serial.println(score);

}

nidi_3 回答:如何在此函数中使用millis()而非for循环

使用millis()不会像delay()那样阻塞for循环。 因此,我认为您将不得不修改正在调用您的方法的代码,因为目前看来您的代码依赖于在for循环中被阻塞。 但是通常,您将像下面的代码示例一样使用millis()。您存储开始时间戳记,然后在等待期结束后执行一些操作。

uint8_t level[] = {0,28,48,60,64};  //levels 0 to 4

uint8_t counter;
uint8_t end_point;
bool show_level;

void level_up(uint8_t wait,uint8_t led_num) {
    if (led_num == level[1]) counter = 0;   //up from level 0 to 1
    if (led_num == level[2]) counter = 28;  //up from level 1 to 2
    if (led_num == level[3]) counter = 48;  //up from level 2 to 3
    if (led_num == level[4]) counter = 60;  //...
    show_level =true;
    end_point = led_num;
}

bool set_pixel_color(uint8_t wait) 
{
    if(timestamp - millis() == wait)
    {
        strip.setPixelColor(counter,strip.Color(0,255));
        strip.show();
        timestamp = millis();
        return true; // incremented 
    }    
    return false;
}

void show_level_led_strip()
{
    if(show_level)
    {
        if(counter > end_point) // escape when the counter gets bigger then the current led_num
        {
            show_level = false;
        }
        else
        {
            if(set_pixel_color(50))
            {
                counter++;
            }
        }
    }
}

void loop() {
    if (plus_btn.pressed()) {
        score++;
        if (score >= 4) {
            score = 4;
        }
    }
    if (minus_btn.pressed()) {
        score--;
        if (score <= 0) {
            score = 0;
        }
    }

    switch (score) {
        case 0:
            if (last_score == 1) level_down(level[0]);
            last_score = 0;
            break;
        case 1:
            // if last_score was 0 make the blue effect because level is up
            if (last_score == 0) level_up(level[1]);
            // if last_score was 2 make the red effect because level is down
            if (last_score == 2) level_down(level[1]);
            last_score = 1;
            break;
        case 2:
            if (last_score == 1) level_up(level[2]);
            if (last_score == 3) level_down(level[2]);
            last_score = 2;
            break;
        case 3:
            if (last_score == 2) level_up(level[3]);
            if (last_score == 4) level_down(level[3]);
            last_score = 3;
            break;
        case 4:
            winning_timer.start();
            winning();
            digitalWrite(WINNING_SENSOR_PIN,HIGH);
            break;
    }

    show_level_led_strip();
}

Serial.println(score);
,

这不能直接回答您的问题,但是我使用的策略为我提供了许多定时事件,而我的程序没有在millis()中阻塞。

设置将来的截止日期,并将延迟的操作包含在轮询millis()的if语句中,直到达到该截止日期为止。这不是很完美,因为软件计时由于处理而浪费时间,并且由于millis()溢出和环绕问题(请在arduino.cc上查找)。

/* Global variables (constexpr creates a compile time only constant) */
constexpr uint32_t WAIT_INTERVAL = 10;  // interval is 10ms
uint32_t deadline = 0;  // when to run next

// inside loop()
    uint32_t now = millis();  // capture the current millis() value
    if(now >= deadline)
    {
        deadline = now + WAIT_INTERVAL;  // push the next deadline into the future
        // perform timed periodic operations here (call function or whatever)
    }
,

阅读您的帖子和所有评论后,我想我知道您想要什么。您只想让循环继续,而在延迟期间不停留在此功能中吗?

millis()不会睡眠或延迟,它仅以毫秒为单位给您时间,因为Arduino正在运行。

因此,您只需将其添加到代码中即可使用:

uint8_t level[] = {0,64};  //levels 0 to 4
unsigned long lastTime = 0;  // << add this
uint8_t start_point = 0; // << move here

void update_leds(uint16_t wait,uint8_t led_num) {
    if(start_point >= led_num) return;
    if(millis() - lastTime > wait) {  // << add this
        //uint8_t start_point;
        lastTime = millis(); // << add this

        //for (uint8_t i = start_point; i < led_num; i++) {
            strip.setPixelColor(start_point,255));
            strip.show();
            //delay(wait);  // << remove this
        //}
        start_point++;
    }
}

void level_up(uint8_t led_num) {
    if (led_num == level[1]) start_point = 0;   //up from level 0 to 1
    if (led_num == level[2]) start_point = 28;  //up from level 1 to 2
    if (led_num == level[3]) start_point = 48;  //up from level 2 to 3
    if (led_num == level[4]) start_point = 60;  //...
}

将等待时间从uint8_t更改为uint16_t,因为255可能太少了。

现在,您可以多次调用此函数,但是仅在超时结束时更新LED。

只有一个问题:如果循环中还有其他延迟,也许LED的更新时间比预期的要晚几毫秒...如果您理解我的意思。

编辑:有时,如果LED灯已更新,您还希望得到通知。因此,您可以返回布尔值来说明该函数是否更新了led(也许您需要在循环中检查它是否“升级”。)

本文链接:https://www.f2er.com/3168724.html

大家都在问