嵌入式系统 - 轮询
Embedded System - Polling
我有大约 6 个传感器(GPS、IMU 等)需要不断从中收集数据。出于我的目的,我需要从每个(在很短的时间范围内)读取一个完整的数据包。现在我正在使用中断,但这会导致来自某些传感器的数据多于其他传感器,并且如前所述,我需要匹配数据。
转移到基于轮询的系统是否会更好,在该系统中我可以按设定顺序轮询每个传感器?这样我就可以每隔 'cycle' 从每个传感器获取数据。
但是,我担心轮询的速度,因为这个系统需要接近实时地运行。
投票结合 "master timer interrupt" 可能是你的朋友。假设您的 "slowest" 传感器可以提供 20 毫秒间隔的数据,并且可以更快地读取其他传感器。那是 每秒 50 次更新。如果这足够接近实时(可能接近 IMU),也许你可以这样进行:
- 设置一个 20 毫秒的定时器。
当计时器关闭时,在中断服务程序中设置一个标志:
volatile uint8_t timerFlag = 0;
ISR(TIMER_ISR_whatever)
{
timerFlag = 1; // nothing but a semaphore for later...
}
然后,在您的主循环中,当 timerFlag
说是时候了:
while(1)
{
if(timerFlag == 1)
{
<read first device>
<read second device>
<you get the idea ;) >
timerflag = 0;
}
}
通过这种方式,您可以读取每个设备并保持它们的读数同步。这是嵌入式space中解决这个问题的典型方法。现在,如果您需要比 20 毫秒更快的数据,那么您可以缩短计时器等。在这种情况下,最大的问题是 "how fast can you poll" 与 "how fast do you need to poll." 只有实验和了解特性你的各种设备的时间可以告诉你。但是我提出的是一个通用的解决方案,当所有时间 "fit."
编辑,不同的方法
一个更基于中断的例子:
volatile uint8_t device1Read = 0;
volatile uint8_t device2Read = 0;
etc...
ISR(device 1)
{
<read device>
device1Read = 1;
}
ISR(device 2)
{
<read device>
device2Read = 1;
}
etc...
// main loop
while(1)
{
if(device1Read == 1 && device2Read == 1 && etc...)
{
//< do something with your "packet" of data>
device1Read = 0;
device2Read = 0;
etc...
}
}
在此示例中,您的所有设备都可以由中断驱动,但主循环处理仍由最慢中断的节奏控制和调整。可以使用每个设备的最新完整读取,无论速度或延迟如何。这种模式是否更接近您的想法?
如果您的传感器可以几乎立即(与您所需的输出频率相比)提供数据,轮询是一个非常好的且易于实施的想法。当您的数据源需要大量(甚至可变)时间来提供读数或需要异步 "initiate/collect" 周期时,它确实会陷入噩梦。您必须对轮询周期进行排序以适应 "slowest" 数据源。
如果您知道每个来源的平均值 "data conversion rate",可能的解决方案是设置多个计时器(每个数据源),在 poll time - data conversion rate
触发并启动在这些定时器 ISR 的测量中。然后有一个在 poll timer + some safety margin
触发的最后一个计时器收集所有转换结果。
另一方面,"having too many measurements" 来自 "fast" 数据源的明显问题不会让我太困扰,只要你没有任何合理的方法来处理这些浪费的问题CPU/sensor加载。
如果您有一些周期要浪费,最后一个更简单的方法是:只需将数据源从 "slowest" 排序到 "fastest" 并按该顺序启动测量,然后等待结果相同的顺序和轮询。
我有大约 6 个传感器(GPS、IMU 等)需要不断从中收集数据。出于我的目的,我需要从每个(在很短的时间范围内)读取一个完整的数据包。现在我正在使用中断,但这会导致来自某些传感器的数据多于其他传感器,并且如前所述,我需要匹配数据。
转移到基于轮询的系统是否会更好,在该系统中我可以按设定顺序轮询每个传感器?这样我就可以每隔 'cycle' 从每个传感器获取数据。
但是,我担心轮询的速度,因为这个系统需要接近实时地运行。
投票结合 "master timer interrupt" 可能是你的朋友。假设您的 "slowest" 传感器可以提供 20 毫秒间隔的数据,并且可以更快地读取其他传感器。那是 每秒 50 次更新。如果这足够接近实时(可能接近 IMU),也许你可以这样进行:
- 设置一个 20 毫秒的定时器。
当计时器关闭时,在中断服务程序中设置一个标志:
volatile uint8_t timerFlag = 0; ISR(TIMER_ISR_whatever) { timerFlag = 1; // nothing but a semaphore for later... }
然后,在您的主循环中,当
timerFlag
说是时候了:while(1) { if(timerFlag == 1) { <read first device> <read second device> <you get the idea ;) > timerflag = 0; } }
通过这种方式,您可以读取每个设备并保持它们的读数同步。这是嵌入式space中解决这个问题的典型方法。现在,如果您需要比 20 毫秒更快的数据,那么您可以缩短计时器等。在这种情况下,最大的问题是 "how fast can you poll" 与 "how fast do you need to poll." 只有实验和了解特性你的各种设备的时间可以告诉你。但是我提出的是一个通用的解决方案,当所有时间 "fit."
编辑,不同的方法
一个更基于中断的例子:
volatile uint8_t device1Read = 0;
volatile uint8_t device2Read = 0;
etc...
ISR(device 1)
{
<read device>
device1Read = 1;
}
ISR(device 2)
{
<read device>
device2Read = 1;
}
etc...
// main loop
while(1)
{
if(device1Read == 1 && device2Read == 1 && etc...)
{
//< do something with your "packet" of data>
device1Read = 0;
device2Read = 0;
etc...
}
}
在此示例中,您的所有设备都可以由中断驱动,但主循环处理仍由最慢中断的节奏控制和调整。可以使用每个设备的最新完整读取,无论速度或延迟如何。这种模式是否更接近您的想法?
如果您的传感器可以几乎立即(与您所需的输出频率相比)提供数据,轮询是一个非常好的且易于实施的想法。当您的数据源需要大量(甚至可变)时间来提供读数或需要异步 "initiate/collect" 周期时,它确实会陷入噩梦。您必须对轮询周期进行排序以适应 "slowest" 数据源。
如果您知道每个来源的平均值 "data conversion rate",可能的解决方案是设置多个计时器(每个数据源),在 poll time - data conversion rate
触发并启动在这些定时器 ISR 的测量中。然后有一个在 poll timer + some safety margin
触发的最后一个计时器收集所有转换结果。
另一方面,"having too many measurements" 来自 "fast" 数据源的明显问题不会让我太困扰,只要你没有任何合理的方法来处理这些浪费的问题CPU/sensor加载。
如果您有一些周期要浪费,最后一个更简单的方法是:只需将数据源从 "slowest" 排序到 "fastest" 并按该顺序启动测量,然后等待结果相同的顺序和轮询。