1

最近几天我一直在调试一个不会中断 SMBUS 字符的小程序。我终于找到了一个未实现的中断处理程序。不是我需要处理程序,而是 8051F330 被错误地配置为硬件中断,并且没有中断处理程序来捕获中断。

现在,这对我来说有点令人惊讶。如果没有处理程序,我会期待一个 NOP,但我猜缺少 RETI 会导致 IRQ 锁定?在这种情况下,主循环似乎工作。我知道需要重置中断标志,但是 timer0 IRQ 与我的 SMBUS IRQ 没有任何共同之处。

我是否正确解释了这一点?无意的 IRQ 启用会导致 IRQ 停止工作吗?

4

2 回答 2

0

CPU 供应商假设您永远不会忘记编写处理程序,我想我从未见过一个驱动程序包含所有可能的处理程序。

我只是在重新启用 Timer4 IT 时遇到了使用错误掩码的问题,以便改为启用 Timer5 IT(在我的情况下为 C8051F580)

所以我最终写了一个像下面这样的文件。

正如其他答案中所说,这还不够,因为我没有重置每个处理程序中的特定中断(例如为 Timer5 中断清除 TF5),但它可以让您快速找到问题所在。

宏 SPEC_INT(x) 让我为一行中的每个中断创建一个处理程序。注释行对应于我在应用程序代码中真正使用的中断。每个处理程序调用一个函数 int_general_function( )

注意,8051 不喜欢可重入函数(通常意义上的没有堆栈)。当每个处理程序调用相同的函数时,链接器 (Keil C51/BL51) 会发出L15警告。您必须在 Linker 选项、Overlay 类别中添加以下语句

int_general_function !*

为了防止(潜在的)局部变量和(潜在的)参数不共享它们在内存中的位置。

#define ALLINTERRUPT_C

#include <my_types.h>
#include <my_platform.h> //contains #include "C8051F580.h"

//A global var
u8 global_unexp_int = 0;

void int_general_function(u8 int_nb)
{
    global_unexp_int = int_nb;

    //Do here other useful things 
    //at least place a breakpoint 
    //if you are in debug
}

#define SPEC_INT(x) \
void i##x (void) interrupt x                \
{                                           \
    int_general_function(x);                \
}

//C8051F580
SPEC_INT(INTERRUPT_INT0)
SPEC_INT(INTERRUPT_TIMER0)
SPEC_INT(INTERRUPT_INT1)
SPEC_INT(INTERRUPT_TIMER1)
//SPEC_INT(INTERRUPT_UART0)
SPEC_INT(INTERRUPT_TIMER2)
SPEC_INT(INTERRUPT_SPI0)
SPEC_INT(INTERRUPT_SMBUS0)
SPEC_INT(INTERRUPT_ADC0_WINDOW)
SPEC_INT(INTERRUPT_ADC0_EOC)
//SPEC_INT(INTERRUPT_PCA0)
SPEC_INT(INTERRUPT_COMPARATOR0)
SPEC_INT(INTERRUPT_COMPARATOR1)
SPEC_INT(INTERRUPT_TIMER3)
SPEC_INT(INTERRUPT_LIN0)
SPEC_INT(INTERRUPT_VREG)
//SPEC_INT(INTERRUPT_CAN0)
SPEC_INT(INTERRUPT_PORT_MATCH)
SPEC_INT(INTERRUPT_UART1)
SPEC_INT(INTERRUPT_PCA1)
SPEC_INT(INTERRUPT_COMPARATOR2)
//SPEC_INT(INTERRUPT_TIMER4)
SPEC_INT(INTERRUPT_TIMER5)

希望能帮助到你 ...

于 2015-04-30T14:29:01.330 回答
0

参考C8051F330 数据表,表 15.1。

每个中断源(复位、定时器 0 溢出、SMB0 等)都有一个硬编码的中断向量地址。当中断被断言时,微控制器生成一条LCALL指向该向量地址的指令。SMB0 为 0x003B,例如 Timer 0 溢出为 0x000B。当您编写中断处理程序(interruptKeil 中的关键字,其他示例请参见此问题JMP)时,您的链接器通常会在向量地址处放置某种指令以访问您的处理程序。

如果您忽略为启用的中断编写处理程序,则微控制器仍将矢量到该地址。然后会发生什么取决于链接器在代码空间中的位置。我发现小函数往往会被塞入向量地址之间,特别是如果你没有使用很多中断并且有几个连续的向量地址没有被使用。您可以通过查看反汇编程序中 0x003B(SMB0 向量地址)的代码空间来找出答案。

如果您不小心在正确的时间将某个此类函数置于错误位置的中间,您将获得该函数运行部分的任何副作用,然后RET函数末尾的回到中断前的位置。除了因为你没有通过RETI,中断没有被清除。任何未来相同或更低优先级的中断都将被阻止,因为微认为您仍在为 SMB0 中断提供服务。

您建议 aNOP可能替换未实现的处理程序,但这无法完成,因为您的工具链不知道在编译时启用了哪些中断。如果您不编写处理程序并将其定位在特定的向量地址,则假定该部分代码空间是公平的游戏,并将在其中放置其他内容。

于 2013-10-28T12:45:49.927 回答