OpenEdv-开源电子网

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

关于通用定时器,用过的请协助

[复制链接]

35

主题

152

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
312
金钱
312
注册时间
2013-6-26
在线时间
0 小时
发表于 2013-7-26 15:11:52 | 显示全部楼层 |阅读模式
编个程序自己玩玩,构思好了,编写出来,发现软件仿真的结果与自己预期的的不太一样,有图
构想:以0.5S的速度翻转,看到led灯闪烁;如果某一刻按下按键 PA8 则改变频率 1S翻转一次,然后就没有然后了。
先放上定时器配置:
void GP_Timer_Configuration(void)//通用定时器配置
{
 
 TIM_TimeBaseStructure.TIM_Period =4999;//定时500毫秒
 TIM_TimeBaseStructure.TIM_Prescaler = 7199;//分频数=7200=7199+1
 TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;//时钟分频因子在这里没有用,选为缺省值即可
 TIM_TimeBaseStructure.TIM_CounterMode =TIM_CounterMode_Up;//向上计数模式
 //TIM_TimeBaseStructure.TIM_RepetitionCounter=? 这个参数是高级定时器需要的,不配置也可以
 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
 TIM_ARRPreloadConfig(TIM3, ENABLE);  //也不知道这句到底有没有意义
 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE );  
}

外部中断处理程序
void EXTI9_5_IRQHandler(void)

 if(EXTI_GetITStatus(EXTI_Line8)!= RESET)//确认是来自EXIT_8的中断  SW5被按下
 {
  //TIM_UpdateDisableConfig(TIM3, DISABLE); 
  TIM_TimeBaseStructure.TIM_Period =9999;//定时1000毫秒
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
 // TIM_UpdateDisableConfig(TIM3, ENABLE);
  EXTI_ClearITPendingBit(EXTI_Line8);  
 } 
}
然后上图:


从软件的仿真来看,效果似乎实现了,但是问题的关键是从0.5s翻转变到1s翻转的那一小段。
我设置的定时器向上计数,中断是更新中断,在其中断处理程序中翻转LED状态。逻辑分析仪的显示仿佛在说按下按键时,发生了两件事:
1、进入了外部中断 修改了ARR的值
2、进入了定时器中断,翻转的led
问题是,有可能进入定时器中断吗?有事件更新发生吗?
上文档图:


如果按照文档的时序图,我预期按下按键时,ARR被载入新值,等到以0.5秒为间隔的更新事件发生,再载入到影子寄存器,然后再以1s为间隔发生更新事件。
仿真与预期不符,是我预期错了,还是仿真(软件)错了。望指教。
PS,要不拿示波器看看?

STM32_GP定时器_向上计数.rar

2.42 MB, 下载次数: 81

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

35

主题

152

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
312
金钱
312
注册时间
2013-6-26
在线时间
0 小时
 楼主| 发表于 2013-7-26 15:21:23 | 显示全部楼层
楼主我可能说的太多、太乱了。不好意思,简单地说,就是仿真中,grid是0.5s分界的,我定时由0.5s切换到1s,那么IO的翻转应该刚好落在grid界线上,为什么没有出现这个“应该”呢?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-7-26 16:02:21 | 显示全部楼层
应该是你更新ARR的时候,进入了更新中断.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

35

主题

152

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
312
金钱
312
注册时间
2013-6-26
在线时间
0 小时
 楼主| 发表于 2013-7-26 16:05:09 | 显示全部楼层
回复【3楼】正点原子:
---------------------------------
原子哥,我也是这么想的,问题是为什么会进入更新中断才是核心疑问。。。我上传了附件,MDK工程,如果有空,你可以试试吗?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-7-26 18:14:19 | 显示全部楼层
问题应该出在这里:

void EXTI9_5_IRQHandler(void)
{  
if(EXTI_GetITStatus(EXTI_Line8)!= RESET)//确认是来自EXIT_8的中断  SW5被按下
{
//TIM_UpdateDisableConfig(TIM3, DISABLE);
TIM_TimeBaseStructure.TIM_Period =9999;//定时1000毫秒 
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// TIM_UpdateDisableConfig(TIM3, ENABLE);
EXTI_ClearITPendingBit(EXTI_Line8);
}
}

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
这句话,是关键.
你这句话是回去配置整个定时器的所有参数的,而不是单纯改了ARR值.
连同CNT,PSC什么的都改了....
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

35

主题

152

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
312
金钱
312
注册时间
2013-6-26
在线时间
0 小时
 楼主| 发表于 2013-7-29 13:57:36 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
原子哥说的在理,我细看了一下这个TIM_TimeBaseInit函数代码:
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  uint16_t tmpcr1 = 0;

  /* Check the parameters */
  assert_param(IS_TIM_ALL_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));

  tmpcr1 = TIMx->CR1;  

  if((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM2) || (TIMx == TIM3)||
     (TIMx == TIM4) || (TIMx == TIM5)) 
  {
    /* Select the Counter Mode */
    tmpcr1 &= (uint16_t)(~((uint16_t)(TIM_CR1_DIR | TIM_CR1_CMS)));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_CounterMode;
  }
 
  if((TIMx != TIM6) && (TIMx != TIM7))
  {
    /* Set the clock division */
    tmpcr1 &= (uint16_t)(~((uint16_t)TIM_CR1_CKD));
    tmpcr1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision;
  }

  TIMx->CR1 = tmpcr1;

  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;
 
  /* Set the rescaler value */
  TIMx->SC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if ((TIMx == TIM1) || (TIMx == TIM8)|| (TIMx == TIM15)|| (TIMx == TIM16) || (TIMx == TIM17))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the rescaler and the Repetition counter
     values immediately */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;           
}
造成ARR更新的是由于最后一句:TIMx->EGR = TIM_PSCReloadMode_Immediate;
//#define TIM_PSCReloadMode_Immediate        ((uint16_t)0x0001) 
这里将EGR寄存器的UG位置1,相当于产生了一个更新事件

经过改动之后,至少向下计数模式下,软件仿真所发生的事和我预期的一样,但是向上计数模式我就不敢说了,在0.5s变1s还好说,1s变0.5s似乎有问题,我再试试。感谢原子哥
回复 支持 反对

使用道具 举报

35

主题

152

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
312
金钱
312
注册时间
2013-6-26
在线时间
0 小时
 楼主| 发表于 2013-7-29 15:00:36 | 显示全部楼层
不得不说,向下计数,我不知道通过什么现象来看出文档中的影子、预装载寄存器的存在。而在向上计数模式中,我感觉所谓的影子、预装载寄存器是骗人的,使用TIM_SetAutoreload()函数后,新的ARR值马上就发挥作用了。也不知道是不是我配置错了什么,明明有:
TIM_ARRPreloadConfig(TIM3, ENABLE);
却好像一点作用都没有一样
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-7-29 17:01:24 | 显示全部楼层
回复【7楼】烂泥桑:
---------------------------------
你可以仿真看下结果.
仿真把定时器的频率设低,输出PWM频率尽量低,方便观测.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-7-16 04:35

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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