Running two tasks at the same time – Arduino

huangapple go评论97阅读模式
英文:

Running two tasks at same time - Arduino

问题

我想运行void downLinkDataHandle:它里面有一个延迟,用来保持LED的亮度,时间由上行设置(字节0、1和2)。如果我执行void downLinkDataHandle,它里面的延迟会阻止prepareTxFrame(appPort);的执行。

我正在使用Heltec AD-02。

我正在使用的代码不幸的是,我不能添加完整的代码,因为stackoverflow说我只是在发布代码。

我用以下内容替换了static void prepareTxFrame

  1. /* 准备帧的有效载荷 */
  2. static void prepareTxFrame( uint8_t port ) {
  3. float battV = round((getBatteryVoltage() / 10) / 100); // 测量电池电压
  4. appDataSize = 1;
  5. battV = battV * 10; //准备编码
  6. appData[0] = battV; // 电池电压的字节
  7. }

并将void downLinkDataHandle(McpsIndication_t *mcpsIndication)替换为:

  1. void downLinkDataHandle(McpsIndication_t *mcpsIndication) {
  2. int port = mcpsIndication->Port;
  3. if (port ==100) {
  4. int color = 255;
  5. uint32_t delay1=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2]; // LED亮度的延迟
  6. Serial.print("延迟:");
  7. Serial.println(delay1);
  8. uint32_t control = mcpsIndication->Buffer[3];
  9. if (control == 1) {
  10. turnOnRGB(color, delay1);
  11. turnOffRGB();
  12. delay(delay1);
  13. };
  14. };
  15. }
英文:

I want to run void downLinkDataHandle: it has a delay in it to keep a LED on for time set as from the uplink (Byte 0,1 and 2). If I execute void downLinkDataHandle, the delay in it stops prepareTxFrame(appPort); from been executed.

I am using a Heltec AD-02.

Code I am using Unfortunately I can't add the complete code as stackoverflow says I am posting code only.

I replaced static void prepareTxFrame with

  1. /* Prepares the payload of the frame */
  2. static void prepareTxFrame( uint8_t port ) {
  3. float battV = round((getBatteryVoltage() / 10) / 100); // measure battery voltage
  4. appDataSize = 1;
  5. battV = battV * 10; //prep to encode
  6. appData[0] = battV; // Byte for Battery voltage
  7. }

And replaced 'void downLinkDataHandle(McpsIndication_t *mcpsIndication)" with

  1. void downLinkDataHandle(McpsIndication_t *mcpsIndication) {
  2. int port = mcpsIndication-&gt;Port;
  3. if (port ==100) {
  4. int color = 255;
  5. uint32_t delay1=mcpsIndication-&gt;Buffer[0]&lt;&lt;16|mcpsIndication-&gt;Buffer[1]&lt;&lt;8|mcpsIndication-&gt;Buffer[2]; // Delay for LED on
  6. Serial.print(&quot;Delay:&quot;);
  7. Serial.println(delay1);
  8. uint32_t control = mcpsIndication-&gt;Buffer[3];
  9. if (control == 1) {
  10. turnOnRGB(color, delay1);
  11. turnOffRGB();
  12. delay(delay1);
  13. };
  14. };
  15. }

答案1

得分: 2

你需要忘记阻塞delay函数,开始喜欢millis。以下是一个非阻塞LED闪烁函数的示例:

  1. void handleLed(int pin, unsigned timeOn, unsigned timeOff)
  2. {
  3. static int stage;
  4. static unsigned lastMillis = millis();
  5. if (millis() - lastMillis >= (stage ? timeOn : timeOff))
  6. {
  7. digitalWrite(pin, stage);
  8. stage = !stage;
  9. lastMillis = millis();
  10. }
  11. }
  12. void loop(void)
  13. {
  14. handleLed(13, 500, 200);
  15. // 这里可以有其他代码,但也不能使用delay函数
  16. }
英文:

You need to forget blocking delay function and start to love millis.

Here you have an example of non blocking LED blinking function

  1. void handleLed(int pin, unsigned timeOn, unsigned timeOff)
  2. {
  3. static int stage;
  4. static unsigned lastMillis = millis();
  5. if(millis() - lastMillis &gt;= (stage ? timeOn : timeOff))
  6. {
  7. DigitalWrite(pin, stage);
  8. stage = !stage;
  9. lastMillis = millis();
  10. }
  11. }
  12. void loop(void)
  13. {
  14. HandleLed(13, 500, 200);
  15. // he you can have another code - but it also has to do not use delay(functions)
  16. }

答案2

得分: 0

基于@0___________的回答:

如果你想要实际上在一定毫秒数内切换引脚的代码,你可以使用millis() Arduino函数来创建一个由调用者分配的结构体,用于简单的LED/定时器控制。

例如:

  1. typedef struct
  2. {
  3. uint16_t time_on;
  4. uint16_t time_off;
  5. uint16_t count;
  6. uint16_t prev_time;
  7. uint8_t pin;
  8. bool on;
  9. } led_t;
  10. void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
  11. {
  12. led->time_on = time_on;
  13. led->time_off = time_off;
  14. led->count = time_on;
  15. led->prev_time = millis();
  16. led->pin = pin;
  17. led->on = true;
  18. }

这里,led由调用者分配,pin是一个引脚号整数,time_ontime_off表示毫秒数。默认情况下,LED会在指定的time_on时间内点亮。

然后,你可以编写一个函数,根据计时器更新这个结构体:

  1. void led_exec (led_t* led)
  2. {
  3. uint16_t now = millis();
  4. uint16_t diff = now - led->prev_time;
  5. if(diff > led->count) // 防止下溢
  6. {
  7. led->count = 0;
  8. }
  9. else // 倒计时到零
  10. {
  11. led->count -= diff;
  12. }
  13. if(led->count == 0) // 当计数到零时,切换LED和计数器
  14. {
  15. if(led->on)
  16. {
  17. led->count = led->time_off;
  18. }
  19. else
  20. {
  21. led->count = led->time_on;
  22. }
  23. led->on = !led->on;
  24. }
  25. digitalWrite(led->pin, led->on);
  26. }

用法:

  1. static led_t led1, led2;
  2. led_init(&led1, 1, 500, 1000);
  3. led_init(&led2, 2, 1000, 2000);
  4. ...
  5. void loop (void)
  6. {
  7. led_exec(&led1);
  8. led_exec(&led2);
  9. }

这仍然是相当有缺陷和天真的代码,因为计时器周期实际时间取决于程序的繁忙程度。专业程序会使用中断服务例程(ISR),但这段简单的代码可能适用于快速的Arduino项目。我没有测试过它,但它应该能够保持一个LED点亮0.5秒,然后熄灭1秒,同时另一个LED以一半的速度闪烁。

英文:

Based on the answer by @0___________:

If you want something that actually toggles a pin on and off for a stated amount of milliseconds, you could create a caller-allocated struct for your simple LED/timer driver using the crude millis() Arduino function.

For example:

  1. typedef struct
  2. {
  3. uint16_t time_on;
  4. uint16_t time_off;
  5. uint16_t count;
  6. uint16_t prev_time;
  7. uint8_t pin;
  8. bool on;
  9. } led_t;
  10. void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
  11. {
  12. led-&gt;time_on = time_on;
  13. led-&gt;time_off = time_off;
  14. led-&gt;count = time_on;
  15. led-&gt;prev_time = millis();
  16. led-&gt;pin = pin;
  17. led-&gt;on = true;
  18. }

Here led is allocated by the caller, pin is a pin number integer, time_on and time_off are times expressed in milliseconds. By default the LED is on, for the time specified by time_on.

You can then write a function that updates this struct based on the timer:

  1. void led_exec (led_t* led)
  2. {
  3. uint16_t now = millis();
  4. uint16_t diff = now - last_millis;
  5. if(diff &gt; led-&gt;count) // prevent underflow
  6. {
  7. led-&gt;count = 0;
  8. }
  9. else // count down to zero
  10. {
  11. led-&gt;count -= diff;
  12. }
  13. if(count == 0) // when reaching zero, toggle the LED and counters
  14. {
  15. if(led-&gt;on)
  16. {
  17. led-&gt;count = time_off;
  18. }
  19. else
  20. {
  21. led-&gt;count = time_on;
  22. }
  23. led-&gt;on = !led-&gt;on;
  24. }
  25. DigitalWrite(led-&gt;pin, led-&gt;on);
  26. }

Usage:

  1. static led_t led1, led2;
  2. led_init(&amp;led1, 1, 500, 1000);
  3. led_init(&amp;led2, 2, 1000, 2000);
  4. ...
  5. void loop (void)
  6. {
  7. led_exec(&amp;led1);
  8. led_exec(&amp;led2);
  9. }

This is still pretty flawed and naive code since the timer cycle real-time depends on how busy your program is. Professional programs would use an ISR instead but this little code might do for quick & dirty Arduino stuff. I haven't tested it but it should keep one LED lit for 0.5s then off for 1s, while another LED is blinks by half that speed.

huangapple
  • 本文由 发表于 2023年4月11日 04:31:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980490.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定