找到原因了,但是没有全部解决。对于我之前提出的问题,原因是:当产生了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引起的中断能够使得本次中断结束后立即被执行。