我使用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, 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);
}
答案 0 :(得分:1)
使用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, 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);
答案 1 :(得分:0)
这不能直接回答您的问题,但是我使用的策略为我提供了许多定时事件,而我的程序没有在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)
}
答案 2 :(得分: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(也许您需要在循环中检查它是否“升级”。)