0

我使用 Neopixels(64 个 LED),并且我有一个名为 level_up 的函数,它每次都会获得不同的 led_num。一般是水平条;level[1] 将按从 0 到 28 的顺序点亮所有 LED,level[2] 所有 LED 从 29 到 48 等。我附加的功能工作正常,但我需要将延迟更改为 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, 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);

}

4

3 回答 3

1

使用millis()不会像delay(). 因此,我认为您将不得不调整调用您的方法的代码,因为目前看起来您的代码取决于在 for 循环中被阻塞。但通常你会millis()在下面的代码示例中使用 like。您存储开始时间戳,然后在等待期结束后执行某些操作。

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, 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);
于 2019-11-04T07:14:38.597 回答
0

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

millis() 不会休眠或延迟,它只会以毫秒为单位为您提供时间,因为 Arduino 正在运行。

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

uint8_t level[] = {0, 28, 48, 60, 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, strip.Color(0, 0, 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(也许您需要在循环中使用它,以检查它是否“升级”。

于 2019-11-04T08:39:44.043 回答
0

这并不能直接回答您的问题,但是我使用的策略为我提供了任意数量的定时事件,而我的程序不会在 millis() 中阻塞。

在未来设置一个截止日期,并将延迟的操作包含在一个 if 语句中,该语句会轮询millis(),直到达到该截止日期。这并不完美,因为软件计时会因处理而浪费时间,并且由于 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)
    }
于 2019-11-04T06:40:35.370 回答