STM32代码优化后的问题

lcllcl20031   2010-12-7 11:00 楼主
刚接触STM32,还只看了时钟系统、中断、GPIO和通用定时器的普通定时功能。
编译器MDK4.0,借固件库写个了用TIM2控制灯闪的程序。不优化时正常,优化后(优化等级1~3都试过)闪烁频率翻倍了!本来一秒一次,现在一秒两次。
使用RCC_GetClocksFreq(&RCC_clock_value)函数读出来的时钟值如下:f[SYSCLK]=8MHz,f[HCLK]=8MHz,f[PCLK1]=8MHz,f[PCLK2]=8MHz,f[ADCCLK]=4MHz。读出的TIM2->PSC值为99(即TIM2分频系数为100)
这个问题找得我头大了。各位帮忙看看。下面是相关部分程序:

void RCC_config(void)
{
     RCC_HSEConfig(RCC_HSE_ON);      //HES开启;
     if(SUCCESS==RCC_WaitForHSEStartUp());  //等待时钟准备好;
     {
//  while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);   
     RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);   //使用HSE时钟;
     while(RCC_GetSYSCLKSource()!= 0x04); //检查时钟源是否已是HSE;
     RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB时钟分频系数为1;
     RCC_PCLK2Config(RCC_HCLK_Div1);  //APB2时钟分频系数为1;
     RCC_PCLK1Config(RCC_HCLK_Div1);  //APB1时钟分频系数为1;
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //开启GPIOB时钟;
     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);   //开启TIM2时钟;
    }  
}
  
void TIM2_config(void)
{
     TIM_InternalClockConfig(TIM2); //TIM2使用内部时钟;
     TIM_SetAutoreload(TIM2,4000);  //设置自动重装载寄存器,定时50ms;
     TIM_CounterModeConfig(TIM2,TIM_CounterMode_Up); //TIM2向上计数,
即从0到TIM2_ARR;
     TIM_PrescalerConfig(TIM2,99,TIM_PSCReloadMode_Immediate);  //f[TIM2]=
f[CLK_APB1]/(99+1),即100分频,并立即产生更新;
     TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //此次更新不产生中断;
     TIM_Cmd(TIM2,ENABLE);  //开启计数器;
     TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);  //开启TIM2的更新中断;
}  

//中断配置;
void NVIC_Configuration(void)
{
     NVIC_InitTypeDef NVIC_InitStructure;
     //开TIM2全局中断;
     NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //选择TIM2通道;
     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级;  
     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //响应优先级;
     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
     NVIC_Init(&NVIC_InitStructure);
}
  
void device_init(void)
{
    RCC_config();
    GPIO_config();
    TIM2_config();
    NVIC_Configuration();
}
  
//TIM2 50ms中断函数;
void TIM2_IRQHandler(void)
{
    static vu8 t500ms_for_PCB_shine=0;
    if(++t500ms_for_PCB_shine>=10)
    {
         LED1_SHINE();
         t500ms_for_PCB_shine=0;
    }
    TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //清除中断标志;
}      
  
int main(void)
{
device_init();
while(1);
}

回复评论 (10)

                                 大家都没遇到过这问题呀?一天又过去了,我还没找出来,急晕了。
点赞  2010-12-7 13:56
                                 顶
点赞  2010-12-7 17:26
                                 顶
点赞  2010-12-7 18:23
看时钟以及中断没有什么问题的,我建议device_init()函数走完后看下timer寄存器是否和预期一样,如果一样说明定时器没问题。
LED1_SHINE()函数怎么实现的呢,里面没有delay之类的吧?
再不行,就调用DBGMCU_Config(DBGMCU_TIM2_STOP, ENABLE);把定时器设置成调试运行,实际的跟踪下
点赞  2010-12-7 20:52
TO 5楼:
谢谢你的建议。TIM2的所有寄存器我都对比过,哪怕是没有用到的那些捕捉、输出类的。优化等级不同寄存器读出的结果是一样的。包括RCC的所有寄存器。
LED1_SHINE()是一个预定义:
#define LED1_ON()   GPIO_ResetBits(GPIOB,GPIO_Pin_12) //GPIOB->BRR=GPIO_Pin_12
#define LED1_OFF()  GPIO_SetBits(GPIOB,GPIO_Pin_12)  //GPIOB->BSRR=GPIO_Pin_12
#define LED1_SHINE()  GPIOB->ODR ^=GPIO_Pin_12
今天上午才发现DATASHEET里面有讲APB1分频系数为1的话,f[TIM2]=f[APB1],
否则f[TIM2]=2f[APB1],因此找到了一线暑光,但后来试了,不管怎样调APB1的分频系数,优化级别调高后频率就变了。。。
点赞  2010-12-7 21:31
还有一个怪问题:
还是1楼所述代码,优化等级为0,将TIM2中断程序中的清除中断标志
“TIM_ClearITPendingBit(TIM2,TIM_IT_Update)”去掉,改成如下:
先定义一个函数:
void test_fanc(void)
{
     TIM2->SR &= 0xfffe;
}
TIM2中断程序最后调用test_fanc();测试结果正常。
再改一种方式:不定义上述函数,直接在TIM2中断程序最后写“TIM2->SR &= 0xfffe;”灯的闪烁频率翻倍了,经测试正好是前面频率的两倍!注意这里的优化等级还是0!
RCC和TIM2相关的寄存器、读频率函数读出的频率两种方式下完全一样!
看了汇编,调用test_fanc()的多了一句
0x080001AE F000F82D  BL.W     test_func (0x0800020C)
然后再有不同的地方就是main()开始之前的一些。本人汇编水平太烂,根据全篇汇篇来找出受影响的地方太困难。~~~~
另外,device_init()函数中RCC_config()、GPIO_config()、TIM2_config()这三个函数我任意调换一下位置灯都不会亮的,只有这个排列顺序灯才会正常闪烁。
点赞  2010-12-8 15:39
7楼这个问题是因为总线的延迟,造成外设的状态变化与CPU不同步所导致。

解决的办法是,如果清中断标志的操作是中断处理程序中的最后一条语句时,需要在这条语句之后加以个小的延迟,一般为2~3个NOP。
点赞  2010-12-8 16:02
香帅呀,你咋不早出现呢?这个下午真高兴!
优化的问题也解决了!以后进中断就清标志了。
不过有一点没弄明白,为什么频率正好是正常的2倍呢?如果说是因为没有清除又引发了一次中断,那么灯闪烁的占空比不会正好是1:1吧(经过测试发现不管怎样调占空比能保持1:1)。
可能这一块的处理机制我还是没了解。
点赞  2010-12-8 16:29
                                 哈哈,我这个人比较懒,不愿意看程序(很久没看,也不大看得懂),
点赞  2010-12-8 16:36
                                 顶香帅,原来是这样,怪不得中断处理中,都是一进入中断函数就清标志呢
点赞  2010-12-8 21:53
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复