在嵌入式C中,我正在尝试创建一种通用的方法来安全地将值从我的ISR(前景)传递到我的主循环(背景)。 “通用”我的意思是我不想暂停中断(因为这是编译器/ CPU特定的,可能有副作用),只想用繁忙的标志等来做。对于这个特殊的机制,我不需要一个队列,我只想检索ISR报告的最新值。
所以我使用的模式是一个结构和一些在结构上运行的函数。问题当然是“写”功能是基于ISR的,并且可以随时中断“读取”功能,我想消除数据损坏的可能性。这种方法是一个双插槽系统,还有几个忙标志。
会起作用吗?和/或有更简单的方法吗? (记住这是嵌入式C,我试图通用/便携。)谢谢!
typedef struct
{
uint8_t busy;
int32_t valueA;
int32_t valueB;
uint8_t reading_from_A;
uint8_t last_wrote_to_B;
} sSafeI32_Fore2Back;
void SafeI32_InitFore2Back(sSafeI32_Fore2Back * si)
{
si->busy = 0;
si->valueA = 0;
si->valueB = 0;
si->reading_from_A = 0;
si->last_wrote_to_B = 1;
}
int32_t SafeI32_ReadFromBack(sSafeI32_Fore2Back * si)
{
int32_t rtn;
si->busy = 1;
if (si->last_wrote_to_B)
{
rtn = si->valueB;
}
else
{
si->reading_from_A = 1;
rtn = si->valueA;
si->reading_from_A = 0;
}
si->busy = 0;
return rtn;
}
void SafeI32_WriteFromFore(sSafeI32_Fore2Back * si, int32_t v)
{
if (si->busy == 0)
{
si->valueA = v;
si->last_wrote_to_B = 0;
}
else
{
if (si->reading_from_A)
{
si->valueB = v;
si->last_wrote_to_B = 1;
}
else
{
si->valueA = v;
si->last_wrote_to_B = 0;
}
}
}
答案 0 :(得分:0)
这样做的一种简单,常见的方法是使读取功能确保在读取期间不被抢占。 ISR每次执行时都会更新一个计数器,并且读取功能可确保计数器在访问期间不会发生变化。如果计数器确实发生了变化,则再次执行读取。
typedef struct
{
int32_t value;
uint32_t counter;
} sSafeI32_Fore2Back;
void SafeI32_InitFore2Back(volatile sSafeI32_Fore2Back * si)
{
si->value = 0;
si->counter = 0;
}
int32_t SafeI32_ReadFromBack(volatile sSafeI32_Fore2Back * si)
{
int32_t rtn;
uint32_t ctr;
do {
ctr = si->counter;
rtn = si->value;
} while(ctr != si->counter);
return rtn;
}
void SafeI32_WriteFromFore(sSafeI32_Fore2Back * si, int32_t v)
{
si->value = v;
si->counter++;
}
答案 1 :(得分:0)
既然你知道中断不能轮流中断(除非你有一些特殊的异国情况),这很简单:
static volatile bool changed = false;
static uint32_t value;
void isr (void) // it is an interrupt; it can't be interrupted by the caller
{
changed = true;
value = something;
}
void caller (void)
{
...
changed = false;
uint32_t val = value;
if(changed)
{
// handle error, discard val
}
}
changed
变量甚至不需要原子访问。
但是请注意,ISR和调用者之间共享的所有变量必须是volatile
,否则可能会出现各种奇怪且非常微妙的优化错误。