OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7043|回复: 3

使用Systick作为基准时钟和TIMER定时器延时后执行相应动作,上电后概率性卡死

[复制链接]

17

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2014-11-21
在线时间
11 小时
发表于 2015-1-21 09:14:02 | 显示全部楼层 |阅读模式
5金钱
原子大哥,各位大虾:
求急救!
我的情况是这样的:
    1、供电是用24V->5V->3.3V(需要24V给外接的负载供电,5V要给蜂鸣器等供电),芯片是STM32F105RBT6。
    2、用Systick作为基准时钟,每1ms产生一个中断更新时钟;用定时器timer6实现延时100ms后产生中断,执行关闭蜂鸣器的动作(在主函数中打开,启动timer6)。

问题描述:1、在24V上电时概率性出错——蜂鸣器一直响,没有关闭。系统按键复位的时候没有问题,屏蔽Systick和采用for循环延时的时候也没有问题,单独不频闭Systick或使用timer6时也会概率性出现。所以初步判断应与软件(主要是Systick和Timer的使用)有关。
    2、在不用24V供电,而采用串口的5V供电时(即略过了24V->5V的芯片),插拔串口接头时也是该概率性问题,而且插在串口1和串口2的概率不同,所以考虑与硬件有关。

现在是用独立看门狗强制复位在,但是很想知道这个问题具体是怎么出现的,以便针对性解决。代码在下面,请大家帮忙看看,感激不尽!

int main(void)
{
// uint32_t i = 0, j = 0;

 RCC_Configuration();

 /*此处配置Systick每1ms产生一个中断(中断函数实现系统运行时间的递增)溢出时清零,若以后增强功能,此函数需要修改*/
 /*----------------Systcik_Configuration------------------*/
 SysTick_Configuration();

 /*外设模块的中断配置放在各自的初始化代码段。
 下面函数完成中断优先级分组和预留(未打开)的系统内部模块的中断配置,可以在需要时根据要求调整*/
 /* NVIC configuration ------------------------------------------------------*/ 
 NVIC_Configuration();
         
 /*此处只定义了控制数字输出量和用于外部中断的部分GPIO口,其余模块的引脚在其初始化时再打开*/
   /* GPIO configuration ------------------------------------------------------*/
   GPIO_Configuration();

 /*CAN 配置*/
 CAN_Config();
   
 /*此处完成用于热电偶温度转换的外接MAX6675和STM32片内ADC1以及DAC的配置,ADC3的配置暂时保留*/
 /*外部ADC MAX6675配置,并选定温度2、3*/
 ExtADC_Configuration();//这两句是配置外接的MAX6675的语句,只涉及引脚的配置问题,与定时无关
 TEMP2_3_Select(TEMP2);  //使温度2、3共用的MX6675接通温度2的传感器   

 /*---------------------USART_Init,TIM_Init------------*/
 USART_Configuration();
 TIM_Configuration();

 /* 内部ADC1 configuration 并启动准换------------------------------------------------------*/ 
 ADC_DMA_Configuration();

 //EXTI_Configuration----
 EXTIX_Configuration();

 /*DAC configuration--------------*/
 DAC_Configuration();
 
 BeepON;
 StartTIM6(BEEP_DELAY_100MS_OFF, 100);
/* for( i = 0 ;i < 72 ;i++)
 {
  for(j = 0; j < 1000; j++)
  {
  }
 }
 BeepOFF;
*/ 
 while(1);
  
}
  


void RCC_Configuration(void)
{
 
 ErrorStatus HSEStartUpStatus;   /* 定义枚举类型变量 HSEStartUpStatus */
 
   RCC_DeInit();       /* 复位系统时钟设置*/
  
   RCC_HSEConfig(RCC_HSE_ON);    /* 开启HSE 外部高速晶振*/
   
   HSEStartUpStatus = RCC_WaitForHSEStartUp();   /* 等待HSE起振并稳定*/
  
   if(HSEStartUpStatus == SUCCESS)   /* 判断HSE起是否振成功,是则进入if()内部 */
   {    
     RCC_HCLKConfig(RCC_SYSCLK_Div1);     /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */ 
   
     RCC_PCLK2Config(RCC_HCLK_Div1);    /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
   
     RCC_PCLK1Config(RCC_HCLK_Div2);       /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
   
     FLASH_SetLatency(FLASH_Latency_2);    /* 设置FLASH延时周期数为2 */
   
     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 使能FLASH预取缓存 */                
     
     RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9); /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
   
     RCC_PLLCmd(ENABLE);     /* 使能PLL */
    
     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 等待PLL输出稳定 */
   
     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);   /* 选择SYSCLK时钟源为PLL */
     
     while(RCC_GetSYSCLKSource() != 0x08);    /* 等待PLL成为SYSCLK时钟源 */
   } 
   
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  /* 打开APB2总线上的GPIOA时钟*/
}

void SysTick_Configuration() 
{
 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择系统时钟  HCLK/8
// fac_us=SystemCoreClock/8000000; //为系统时钟的1/8         
      
 SysTick->LOAD = (SystemCoreClock/8000) - 1; //时间加载,时钟为72MHz时,该值应为9000 - 1     
 SysTick->VAL = 0x00;        //清空计数器

 SysTick->CTRL |=(1<<0 |1<<1);         //开始倒数
   
}

//配置需要用到的定时器
void TIM_Configuration(void)
{
 TIM2_Init();
 TIM3_Init();

 TIM5_Init(); 
 //TIM6用于任务延时完成
 TIM6_Init();

 //TIM7用于定时发送刷新CAN消息  
 TIM7_Init();   
}


//定时器6配置
//用于特定时间的定时,需要手动开启
void TIM6_Init(void)

 NVIC_InitTypeDef NVIC_InitStructure;

 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //使能TIM6时钟,36MHz
 TIM_DeInit(TIM6);
 //初始化定时器6 TIM6 
 TIM6_TimeBaseStructure.TIM_Period = 0; //设定计数器自动重装值
 TIM6_TimeBaseStructure.TIM_Prescaler = 35999;  //预分频器,将72MHz降为2KHz  
 TIM6_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4; //设置时钟分割:TDTS = Tck_tim,对于TIM6、7无效
 TIM6_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
 TIM_TimeBaseInit(TIM6, &TIM6_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
     
 //中断分组初始化
 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;  //TIM6中断
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;  //先占优先级2级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
 NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器    
}

void StartTIM6(TIM6_TASK_FLAG TIM6taskflag, u16 ARR)
{
// printf("------->timer 6<---------");
 enTIM6_TASK_FLAG = TIM6taskflag; 
 TIM6_TimeBaseStructure.TIM_Period = (ARR + ARR - 1); //设定计数器自动重装值 
 TIM_TimeBaseInit(TIM6, &TIM6_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

 TIM_ARRPreloadConfig(TIM6, ENABLE);
 TIM_GenerateEvent(TIM6,TIM_EventSource_Update);    // 产生软件更新事件,立即更新数据
 TIM_ClearFlag(TIM6,TIM_FLAG_Update);              //清除标志位。定时器一打开便产生更新事件,若不清除,将会进入中断
 TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//允许更新中断、在对应的中断函数中失能该中断,以实现单次定时
 
 TIM_Cmd(TIM6,ENABLE );  //使能定时器6 
}

//定时器6中断处理函数
void TIM6_IRQHandler(void)
{
// SYSTEMTIME m_stSYSTEM_TIME;
 //根据StartTIM6设定的定时目的来完成任务
 switch(enTIM6_TASK_FLAG)
 {
  case BEEP_DELAY_100MS_OFF:
    BeepOFF;
    break;
  case BLOWER_DELAY_5S_OFF:    
    StopAirBlower();
    genREFORMINGROOM_HIGH_TEMP_ALARM = OFF;
    break;
 }
  
  TIM_ITConfig(TIM6,TIM_IT_Update,DISABLE);//失能更新中断
 enTIM6_BUSYING_FLAG = OFF;

    TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
}

 


最佳答案

查看完整内容[请看2#楼]

到处放printf,观察程序运行过程,来分析问题.
水好深。。。。。。。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2015-1-21 09:14:03 | 显示全部楼层
到处放printf,观察程序运行过程,来分析问题.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

17

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
134
金钱
134
注册时间
2014-11-21
在线时间
11 小时
 楼主| 发表于 2015-1-22 11:43:53 | 显示全部楼层

 回复【2楼】 正点原子 :
---------------------------------
卡死的时候是没有输出的。。。。。我特地测了一下,由于timer2的优先级高于systick,所以怀疑出现问题的原因是系统未稳定时采用systick容易出错,就改用tim1来定时了,结果又冒出问题了。。。。。。。。
tim1本该设置为1ms的更新中断,可是时间拉的好长,用tim2对比一下,tim2快好多,当tim2的计数值是tim1的200倍时,其响应频率才基本一致。。。。。。。
void TIM1_Init(void)  //实现1ms定时后输出
{
// TIM1_GPIO_Init();  //不接通外部通道,所以不用初始化引脚
 TIM1_TimeBase_Init();
// TIM1_OC_Init();    //不接通外部通道,所以不用初始化输出通道
 TIM1_NVIC_Init();
 TIM1_Start(); 
}
void TIM1_TimeBase_Init(void)
{
 TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

 TIM_DeInit(TIM1);
   /* Time base configuration */  
   TIM_TimeBaseStructure.TIM_Period = 1;       //当定时器从0计数到1,实现1ms的定时
   TIM_TimeBaseStructure.TIM_Prescaler = 35999;     //设置预分频:不预分频,即为72MHz  转为  2KHz
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频系数:不分频
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

   TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
}
void TIM1_NVIC_Init(void)
{
 NVIC_InitTypeDef NVIC_InitStructure;
   //中断分组初始化
 NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;  //TIM1更新中断
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;  //先占优先级6
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
 NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
 TIM_ARRPreloadConfig(TIM1, ENABLE);    // 使能TIM1重载寄存器

 TIM_GenerateEvent(TIM1,TIM_EventSource_Update);    // 产生软件更新事件,立即更新数据
 
 TIM_ClearFlag(TIM1,TIM_FLAG_Update);              //清除标志位。定时器一打开便产生更新事件,若不清除,将会进入中断
  
 TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE);//允许更新中断
}
void TIM1_Start(void)
{
 TIM_Cmd(TIM1, ENABLE);                   //使能定时器1 
}
void TIM1_UP_IRQHandler(void)
{
 printf("-->timer1<-------\r\n");
 TIM_ClearITPendingBit(TIM1, TIM_IT_Update); //清除中断标志位
}
void TIM2_Init(void)  
{
 TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
 
 TIM_DeInit(TIM2);
   /* Time base configuration */  
   TIM_TimeBaseStructure.TIM_Period = 399;//999;       //当定时器从0计数到999,实现0.5s的定时
   TIM_TimeBaseStructure.TIM_Prescaler = 35999;     //设置预分频:不预分频,即为72MHz  转为  2KHz
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分频系数:不分频
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式

   TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

   //中断分组初始化
 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级2级
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //从优先级0级
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
 NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
 TIM_ARRPreloadConfig(TIM2, ENABLE);    // 使能TIM2重载寄存器

 TIM_GenerateEvent(TIM2,TIM_EventSource_Update);    // 产生软件更新事件,立即更新数据
 
 TIM_ClearFlag(TIM2,TIM_FLAG_Update);              //清除标志位。定时器一打开便产生更新事件,若不清除,将会进入中断
  
 TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//允许更新中断

  /* TIM2 enable counter */
 TIM_Cmd(TIM2, ENABLE);                   //使能定时器2 
}


void TIM2_IRQHandler(void)
{
 printf("timer2\r\n");
}
这上面所看到的两个数值配置下,两个定时器的输出频率才基本一致。。。。。。。。。。
RCC配置如下:
void RCC_Configuration(void)
{
 
 ErrorStatus HSEStartUpStatus;   /* 定义枚举类型变量 HSEStartUpStatus */
 
   RCC_DeInit();       /* 复位系统时钟设置*/
  
   RCC_HSEConfig(RCC_HSE_ON);    /* 开启HSE 外部高速晶振*/
   
   HSEStartUpStatus = RCC_WaitForHSEStartUp();   /* 等待HSE起振并稳定*/
  
   if(HSEStartUpStatus == SUCCESS)   /* 判断HSE起是否振成功,是则进入if()内部 */
   {    
     RCC_HCLKConfig(RCC_SYSCLK_Div1);     /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */ 
   
     RCC_PCLK2Config(RCC_HCLK_Div1);    /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
   
     RCC_PCLK1Config(RCC_HCLK_Div2);       /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
   
     FLASH_SetLatency(FLASH_Latency_2);    /* 设置FLASH延时周期数为2 */
   
     FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 使能FLASH预取缓存 */                
     
     RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9); /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
   
     RCC_PLLCmd(ENABLE);     /* 使能PLL */
    
     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 等待PLL输出稳定 */
   
     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);   /* 选择SYSCLK时钟源为PLL */
     
     while(RCC_GetSYSCLKSource() != 0x08);    /* 等待PLL成为SYSCLK时钟源 */
   } 
   
//   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);  /* 打开APB2总线上的GPIOA时钟*/
}
伤感了,不知道是什么原因。。。。。。。。。。

水好深。。。。。。。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2015-1-22 23:18:37 | 显示全部楼层
回复【3楼】woshiyunsk:
---------------------------------
你这个1ms的问题,我在另外一个帖子回复过你了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-26 14:02

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表