英文:
Running two tasks at same time - Arduino
问题
我想运行void downLinkDataHandle
:它里面有一个延迟,用来保持LED的亮度,时间由上行设置(字节0、1和2)。如果我执行void downLinkDataHandle
,它里面的延迟会阻止prepareTxFrame(appPort);
的执行。
我正在使用Heltec AD-02。
我正在使用的代码不幸的是,我不能添加完整的代码,因为stackoverflow说我只是在发布代码。
我用以下内容替换了static void prepareTxFrame
:
/* 准备帧的有效载荷 */
static void prepareTxFrame( uint8_t port ) {
float battV = round((getBatteryVoltage() / 10) / 100); // 测量电池电压
appDataSize = 1;
battV = battV * 10; //准备编码
appData[0] = battV; // 电池电压的字节
}
并将void downLinkDataHandle(McpsIndication_t *mcpsIndication)
替换为:
void downLinkDataHandle(McpsIndication_t *mcpsIndication) {
int port = mcpsIndication->Port;
if (port ==100) {
int color = 255;
uint32_t delay1=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2]; // LED亮度的延迟
Serial.print("延迟:");
Serial.println(delay1);
uint32_t control = mcpsIndication->Buffer[3];
if (control == 1) {
turnOnRGB(color, delay1);
turnOffRGB();
delay(delay1);
};
};
}
英文:
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
/* Prepares the payload of the frame */
static void prepareTxFrame( uint8_t port ) {
float battV = round((getBatteryVoltage() / 10) / 100); // measure battery voltage
appDataSize = 1;
battV = battV * 10; //prep to encode
appData[0] = battV; // Byte for Battery voltage
}
And replaced 'void downLinkDataHandle(McpsIndication_t *mcpsIndication)" with
void downLinkDataHandle(McpsIndication_t *mcpsIndication) {
int port = mcpsIndication->Port;
if (port ==100) {
int color = 255;
uint32_t delay1=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2]; // Delay for LED on
Serial.print("Delay:");
Serial.println(delay1);
uint32_t control = mcpsIndication->Buffer[3];
if (control == 1) {
turnOnRGB(color, delay1);
turnOffRGB();
delay(delay1);
};
};
}
答案1
得分: 2
你需要忘记阻塞delay
函数,开始喜欢millis
。以下是一个非阻塞LED闪烁函数的示例:
void handleLed(int pin, unsigned timeOn, unsigned timeOff)
{
static int stage;
static unsigned lastMillis = millis();
if (millis() - lastMillis >= (stage ? timeOn : timeOff))
{
digitalWrite(pin, stage);
stage = !stage;
lastMillis = millis();
}
}
void loop(void)
{
handleLed(13, 500, 200);
// 这里可以有其他代码,但也不能使用delay函数
}
英文:
You need to forget blocking delay
function and start to love millis
.
Here you have an example of non blocking LED blinking function
void handleLed(int pin, unsigned timeOn, unsigned timeOff)
{
static int stage;
static unsigned lastMillis = millis();
if(millis() - lastMillis >= (stage ? timeOn : timeOff))
{
DigitalWrite(pin, stage);
stage = !stage;
lastMillis = millis();
}
}
void loop(void)
{
HandleLed(13, 500, 200);
// he you can have another code - but it also has to do not use delay(functions)
}
答案2
得分: 0
基于@0___________的回答:
如果你想要实际上在一定毫秒数内切换引脚的代码,你可以使用millis()
Arduino函数来创建一个由调用者分配的结构体,用于简单的LED/定时器控制。
例如:
typedef struct
{
uint16_t time_on;
uint16_t time_off;
uint16_t count;
uint16_t prev_time;
uint8_t pin;
bool on;
} led_t;
void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
{
led->time_on = time_on;
led->time_off = time_off;
led->count = time_on;
led->prev_time = millis();
led->pin = pin;
led->on = true;
}
这里,led
由调用者分配,pin
是一个引脚号整数,time_on
和time_off
表示毫秒数。默认情况下,LED会在指定的time_on
时间内点亮。
然后,你可以编写一个函数,根据计时器更新这个结构体:
void led_exec (led_t* led)
{
uint16_t now = millis();
uint16_t diff = now - led->prev_time;
if(diff > led->count) // 防止下溢
{
led->count = 0;
}
else // 倒计时到零
{
led->count -= diff;
}
if(led->count == 0) // 当计数到零时,切换LED和计数器
{
if(led->on)
{
led->count = led->time_off;
}
else
{
led->count = led->time_on;
}
led->on = !led->on;
}
digitalWrite(led->pin, led->on);
}
用法:
static led_t led1, led2;
led_init(&led1, 1, 500, 1000);
led_init(&led2, 2, 1000, 2000);
...
void loop (void)
{
led_exec(&led1);
led_exec(&led2);
}
这仍然是相当有缺陷和天真的代码,因为计时器周期实际时间取决于程序的繁忙程度。专业程序会使用中断服务例程(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:
typedef struct
{
uint16_t time_on;
uint16_t time_off;
uint16_t count;
uint16_t prev_time;
uint8_t pin;
bool on;
} led_t;
void led_init (led_t* led, uint8_t pin, uint16_t time_on, uint16_t time_off)
{
led->time_on = time_on;
led->time_off = time_off;
led->count = time_on;
led->prev_time = millis();
led->pin = pin;
led->on = true;
}
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:
void led_exec (led_t* led)
{
uint16_t now = millis();
uint16_t diff = now - last_millis;
if(diff > led->count) // prevent underflow
{
led->count = 0;
}
else // count down to zero
{
led->count -= diff;
}
if(count == 0) // when reaching zero, toggle the LED and counters
{
if(led->on)
{
led->count = time_off;
}
else
{
led->count = time_on;
}
led->on = !led->on;
}
DigitalWrite(led->pin, led->on);
}
Usage:
static led_t led1, led2;
led_init(&led1, 1, 500, 1000);
led_init(&led2, 2, 1000, 2000);
...
void loop (void)
{
led_exec(&led1);
led_exec(&led2);
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论