我有两个中断服务程序(ISR),基本上完全相同 事物,但每个处理来自不同设备的中断(虽然相同类型的设备)。因此,逻辑是相同的,但它们访问不同的CPU寄存器和存储器位置。
作为一个简单的例子,请考虑以下代码:
extern volatile unsigned int dev1_rx_buffer;
extern volatile unsigned int dev2_rx_buffer;
volatile unsigned char data;
void __attribute__((__interrupt__)) _dev1_interrupt(void)
{
/* Clear interrupt flag */
dev1.IF = 0;
if (dev1.IS_FULL) {
/* Read data from device */
data = dev1_rx_buffer;
} else {
/* do something else using registers of device 1 */
}
/* More stuff using registers of device 1 */
}
void __attribute__((__interrupt__)) _dev2_interrupt(void)
{
/* Clear interrupt flag */
dev2.IF = 0;
if (dev2.IS_FULL) {
/* Read data from device */
data = dev2_rx_buffer;
} else {
/* do something else using registers of device 2 */
}
/* More stuff using registers of device 2 */
}
如何避免代码重复与适用于ISR的限制 (即我不能将参数传递给ISR,应该避免函数调用 因为他们的开销。)
我曾考虑编写一个模板,使用更高级别的脚本语言从中生成两个ISR,但我更喜欢只使用C或C预处理器宏的解决方案。
答案 0 :(得分:6)
在这种情况下,我通常让ISR(向量入口点)的前端设置指向设备特定块的指针,然后使用指向该块的指针调用公共代码。
粗略(不用担心ISR语法等)。
void __attribute__((__interrupt__)) Isr1(void)
{
CommonISR(&dev1info);
}
void __attribute__((__interrupt__)) Isr2(void)
{
CommonISR(&dev2info);
}
void CommonISR(Foo *devptr)
{
devptr->count = 0;
devptr->reset();
etc...
}
dev1info和dev2info在启动时配置/初始化;他们可能有指向HW寄存器等的指针......
答案 1 :(得分:2)
如果他们正在处理相同类型的设备,那么只有一个中断处理程序处理多个中断是非常合理的。您可以检查顶部设置了哪个标志并从那里继续。但是,如果两个中断处理程序用于不同类型的设备并且具有相同的逻辑流程,我不建议这样做。
答案 2 :(得分:2)
为什么不使用内联辅助函数来获取指向设备和缓冲区的指针?
我会检查生成的程序集,以确保编译器完成我期望的工作。
你也可以使用一个宏,但恕我直言,这对于长期的功能来说这样做并不好。
答案 3 :(得分:1)
你确定你的编译器不会优化函数调用吗? 你绝对可以使用宏来自动生成这个代码,但它会有点难看:
#define __CONCAT(a,b) a ## b
#define ISR_DECLARE(name) \
\
void __attribute__((__interrupt__)) _CONCAT(name,_interrupt)(void) \
{ \
/* Clear interrupt flag */ \
name.IF = 0; \
\
if (name.IS_FULL) \
{ \
/* Read data from device */ \
data = _CONCAT(name, _rx_buffer); \
} \
else \
{ \
/* do something else using registers of device 1 */ \
}\
/* More stuff using registers of device 1 */ \
}
然后:
ISR_DECLARE(dev_1)
ISR_DECLARE(dev_2)
但我强烈建议首先检查一下你的编译器是否会使用内联优化代码,如之前的帖子所示。