找到原因了,但是没有全部解决。对于我之前提出的问题,原因是:当产生了CC2中断,且正要进入程序段2时,此时发生了CC1中断。由于CC2IF是1,则TIM1_CC的中断悬停位不会被置一,此情况如下图所示:

5.png

(23.38 KB, 下载次数: 152)

2014-4-11 15:36 上传

然而当程序段2执行后,CC2IF标志被清除,则此时来了CC1中断后,TIM1_CC的中断悬停位会被再次置一。这也是为什么从来不会进入test=5的断点。参见我的程序:

```c

void TIM1_CC_IRQHandler(void)

{

vu8 test=1;

//程序段1

if (TIM1_CC1IF)

{

TIM1_CC1IF = 0;

CCR_Mask_x += CCR_Acc_x;

TIM1->CCR1 = CCR_Mask_x;

}

//程序段2:

if (TIM1_CC2IF)

{

TIM1_CC2IF = 0;

CCR_Mask_y += CCR_Acc_y;

TIM1->CCR2 = CCR_Mask_y;

}

//程序段3:

if (1==TIM1_CC1IF)//6clk

{

if (NVIC_GetPendingIRQ(TIM1_CC_IRQn))

{

test = 2; //说明发生了CC1中断,且硬件自动置1了Pending位。这个断点有40%的机会进入//3clk

}

if (!NVIC_GetPendingIRQ(TIM1_CC_IRQn))//22clk

{

test = 3; //说明发生了CC1中断,但是硬件没有置一Pending位。这个断点也有40%的机会进入

}

}

//程序段4:

if (test==1 && &&&& TIM1_CC1IF==1)

{

if (NVIC_GetPendingIRQ(TIM1_CC_IRQn))

{

test = 4; //说明发生了CC1中断,且硬件置1了Pending位。这个断点有20%的机会进入

}

if (!NVIC_GetPendingIRQ(TIM1_CC_IRQn))

{

test = 5; //★令人同样奇怪的是,这个断点不会进入★

}

}

}

```

根据提供的内容,需要在进入中断之前,先读取TIM1的SR寄存器到内存变量,然后清零SR,最后根据内存变量来判断。为了保护这个过程,可以采用流水线指令隔离ISB和互斥访问LDREX/STREX。但是在这个过程中,遇到了一个问题:即使在LDREX和STREX之间手动添加一个测试语句TIM1->SR = 1;,STREX的执行总是成功的。这可能是因为在这个问题中,使用LDREX和STREX的方式有误。

以下是重构后的代码:

```c

void TIM1_CC_ISR(void)

{

u8 test = 0;

u32 TIM1_SR_mask;

__TRY_:

TIM1_SR_mask = __LDREXH(&(TIM1->SR));

__asm("isb");

TIM1->SR = 1;

if (__STREXH(0, &(TIM1->SR)))

{

goto __TRY_;

}

```

在这段代码中,首先将TIM1的SR寄存器读取到内存变量TIM1_SR_mask中,然后对硬件进行禁处理。接下来将TIM1的SR寄存器设置为1,表示允许中断。最后,使用STREX指令将修改后的值写回TIM1的SR寄存器。如果写回成功,则继续执行;否则,回到__TRY_标签处重新尝试。

在实际使用中,当CCR2触发中断并在TIM1_CC_ISR中断处理程序中再次触发CCR1匹配中断时,硬件有时会自动设置TIM1_CC的中断悬停位,有时则不会。这可能导致程序错过一次CCR1匹配中断,从而在实际使用中成为一个严重的问题。

要解决这个问题,可以尝试在TIM1_CC_ISR中断处理程序中显式地设置TIM1_CC的中断悬停位。具体操作如下:

1. 在TIM1_CC_ISR中断处理程序中,首先清除TIM1的中断标志位(TIM_IT_CC)。

2. 然后设置TIM1的中断悬停位(TIM_IT_CC),以确保下次中断立即执行。

以下是修改后的TIM1_CC_ISR中断处理程序示例代码:

```c

void TIM1_CC_ISR(void)

{

// 清除TIM1的中断标志位

TIM_ClearITPendingBit(TIM1, TIM_IT_CC);

// 设置TIM1的中断悬停位

TIM_SetITPendingBit(TIM1, TIM_IT_CC);

// 其他中断处理代码...

}

```

通过这种方式,可以确保在情况1下,硬件总是设置TIM1_CC的中断悬停位,从而保证CCR1引起的中断能够使得本次中断结束后立即被执行。