打印

在TIMx的PWM_Output例子中,ARR的值如何传送到它的影子寄存器?

[复制链接]
4570|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
bhsdlmj|  楼主 | 2009-5-14 14:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
在STM32的通用定时器的PWM_Output例子中,TIMx_ARR的值是如何传送到它对应的影子寄存器中的?????? 


我用的是最新的库V3.0.0,手册也是看的最新版本的。 

--------------------------------- 

TIMx_ARR的值是传送到它对应的影子寄存器中,可以这样做:当TIMx_CR1的位APRE=0时,立即将TIMx_ARR的值传送到它对应的影子寄存器中。当TIMx_CR1的位APRE=1时,则当发生更新事件时,将TIMx_ARR的值传送到它对应的影子寄存器中。 

------------------------------ 

而在PWM_Output例子中,TIMx_CR1的位APRE=1,并且禁止更新事件, 那么TIMx_ARR的值是如何传送到它对应的影子寄存器中的呢? 

  

原来以为是例子中设置了EGR寄存器的UG位致使更新了影子寄存器(因为手册中说UG=1时,Re-initialize the counter and generates an update of the registers.),后来发现不是UG位的设置的原因。 

  

那么到底TIMx_ARR的值是如何传送到它对应的影子寄存器中的? 

指点一下!! 
沙发
bhsdlmj|  楼主 | 2009-5-14 15:47 | 只看该作者

哪位有时间 帮忙解释一下?!!!

使用特权

评论回复
板凳
渤海三叠浪| | 2009-5-14 17:34 | 只看该作者

我 现在没空给你解释 以后再说

使用特权

评论回复
地板
bhsdlmj|  楼主 | 2009-5-15 09:18 | 只看该作者

奇怪!

这个问题为什么没人回答呢 很奇怪啊!!!

使用特权

评论回复
5
lut1lut| | 2009-5-15 10:44 | 只看该作者

我没看到啊

哪里有“禁止更新事件”了? 

使用特权

评论回复
6
barboon| | 2009-5-15 10:58 | 只看该作者

影子寄存器的作用就是指定了你对ARR寄存器写入新值的生效

影子寄存器的作用就是指定了你对ARR寄存器写入新值的生效时间:
TIMx_CR1的位APRE=0时,ARR写入值是即使生效的:
比如ARR原来等于10,你在写入新值5时,计数器是3,那么当计数器计数到5,就会发生更新事件

TIMx_CR1的位APRE=1时,ARR写入值是到下一次更新事件以后才生效:
比如ARR原来等于10,你在写入新值5时,计数器是3,这次计数器计数到10,才会发生更新事件,但是从下一个计数周期时,计数到5就会发生更新事件

如果把EGR寄存器的UG位置1,表示强制发生一个更新事件

使用特权

评论回复
7
lut1lut| | 2009-5-15 11:18 | 只看该作者

而且,这个例子中除了第一次对ARR寄存器赋值

,其他地方没有再更新这个ARR了。所以APRE=0/1都无所谓。

使用特权

评论回复
8
bhsdlmj|  楼主 | 2009-5-15 12:16 | 只看该作者

多谢各位


回5楼:在stm32f10x_tim.c里面 我用红色标出来了

void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  /* Check the parameters */
  assert_param(IS_TIM_123458_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));
  /* Select the Counter Mode and set the clock division */
  TIMx->CR1 &= CR1_CKD_Mask & CR1_CounterMode_Mask;//回复5楼
  TIMx->CR1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision |
                TIM_TimeBaseInitStruct->TIM_CounterMode;
  
  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;

  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if (((*(uint32_t*)&TIMx) == TIM1_BASE) || ((*(uint32_t*)&TIMx) == TIM8_BASE))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler value immediatly */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;   
       
}
 
//================================
回6楼 ,你说的 和 我在1楼说的是一样的啊!!!! 解释不了ARR的值如何传送到它的影子寄存器?
 
我在一楼说了ARR的值传送到对应的影子寄存器的值的两种方法:TIMx_ARR的值是传送到它对应的影子寄存器中,可以这样做:当TIMx_CR1的位APRE=0时,立即将TIMx_ARR的值传送到它对应的影子寄存器中。当TIMx_CR1的位APRE=1时,则当发生更新事件时,将TIMx_ARR的值传送到它对应的影子寄存器中。 
可是 现在情况是禁止更新事件,并且APRE=1.所以这两种方法都行不通。
所以按道理说只能通过设置EGR的UG为1了,因为手册中说UG=1时,Re-initialize the counter and generates an update of the registers.),
但是TIMx->EGR = TIM_PSCReloadMode_Immediate;    上面的注释是 /* Generate an update event to reload the Prescaler value immediatly */就是说设置UG=1仅仅为了立即重装PSC的值。
并且即便把TIMx->EGR = TIM_PSCReloadMode_Immediate;    删除,ARR的值仍会传送到它的影子寄存器中。
真不知道是如何传送的?

使用特权

评论回复
9
lut1lut| | 2009-5-15 13:56 | 只看该作者

没有问题啊

TIMx->CR1 &= CR1_CKD_Mask & CR1_CounterMode_Mask
注意这里是个 &,人家TIM->CR1以前是0,与上1还是0咯。

你自己单步调试,在寄存器窗口就可以清楚看到,执行完这个函数,
UDIS=0 --〉update enable的

使用特权

评论回复
10
bhsdlmj|  楼主 | 2009-5-15 15:24 | 只看该作者

多谢lut1lut

呵呵 我确实是看错了!!!TIM->CR1以前是确实是0

不过还是有问题啊!!!
若在TIMx->CR1 &= CR1_CKD_Mask & CR1_CounterMode_Mask;之前加一句
TIMx->CR1 =  (uint16_t)0x0002;//令UDIS=1,即禁止更新事件
ARR的值还是可以传送到影子寄存器啊,????

你说“单步调试,在寄存器窗口就可以清楚看到,执行完这个函数,
UDIS=0 --〉update enable的”,请问用的是什么编译器??



使用特权

评论回复
11
lut1lut| | 2009-5-15 15:41 | 只看该作者

ARR的值还是可以传送到影子寄存器

你怎么判断已经传到了,看到仍然有PWM输出?而且这些PWM的频率和占空比正确?

什么编译其都一样,本来是0,与上1还是1。
我用的是IAR

使用特权

评论回复
12
bhsdlmj|  楼主 | 2009-5-15 16:01 | 只看该作者

回lut1lut

我用MDK看的 ,MDK可以仿真出PWM波形 都正确

你试验出来不正确么??

使用特权

评论回复
13
lut1lut| | 2009-5-15 16:39 | 只看该作者

我没有拉波形看

手册中讲ARR自装载寄存器时,是这样说的:
=================================================================
 The update event is sent when the counter 
reaches the overflow (or underflow when downcounting) and if the UDIS bit equals 0 in the 
TIMx_CR1 register. It can also be generated by software. 
=================================================================
更新事件是这样产生的:
计数器溢出 and UDIS=0
也可以通过软件产生(就是设置UG)

似乎,UG设置产生更新事件,不受UDIS的限制。

我不确定~~~

使用特权

评论回复
14
bhsdlmj|  楼主 | 2009-5-15 17:01 | 只看该作者

似乎有点眉目了!!!

将int main(void)函数里面的TIM_ARRPreloadConfig(TIM3, ENABLE);挪到下面的位置,似乎就不能装进影子寄存器了!!!
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
{
  /* Check the parameters */
  assert_param(IS_TIM_123458_PERIPH(TIMx)); 
  assert_param(IS_TIM_COUNTER_MODE(TIM_TimeBaseInitStruct->TIM_CounterMode));
  assert_param(IS_TIM_CKD_DIV(TIM_TimeBaseInitStruct->TIM_ClockDivision));
  /* Select the Counter Mode and set the clock division */
  TIMx->CR1 =  (uint16_t)0x0002;
  TIM_ARRPreloadConfig(TIM3, ENABLE);    
  TIMx->CR1 &= CR1_CKD_Mask & CR1_CounterMode_Mask;
  TIMx->CR1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision |
                TIM_TimeBaseInitStruct->TIM_CounterMode;
  
  /* Set the Autoreload value */
  TIMx->ARR = TIM_TimeBaseInitStruct->TIM_Period ;

  /* Set the Prescaler value */
  TIMx->PSC = TIM_TimeBaseInitStruct->TIM_Prescaler;
    
  if (((*(uint32_t*)&TIMx) == TIM1_BASE) || ((*(uint32_t*)&TIMx) == TIM8_BASE))  
  {
    /* Set the Repetition Counter value */
    TIMx->RCR = TIM_TimeBaseInitStruct->TIM_RepetitionCounter;
  }

  /* Generate an update event to reload the Prescaler value immediatly */
  TIMx->EGR = TIM_PSCReloadMode_Immediate;
}

以前的程序是数据先装进影子寄存器再令 APRE=1的,这样APRE的值根本没起作用。现在把那条语句挪位置先让APRE=1,这样就装不进影子寄存器了!!!!




可惜没示波器啊,MDK软件仿真不可信的!!

还有 我估计很有可能影子寄存器的初始值是65535

我就有个万利板子 根据灯的亮度做如上判断的!

使用特权

评论回复
15
lut1lut| | 2009-5-15 17:42 | 只看该作者

我用示波器拉着看了看

正如LZ的代码,在TIM_TimeBaseInit()中,
  /* Select the Counter Mode and set the clock division */
  TIMx->CR1 =  (uint16_t)0x0002;
  TIM_ARRPreloadConfig(TIM3, ENABLE);    
  TIMx->CR1 &= CR1_CKD_Mask & CR1_CounterMode_Mask;
  TIMx->CR1 |= (uint32_t)TIM_TimeBaseInitStruct->TIM_ClockDivision |
                TIM_TimeBaseInitStruct->TIM_CounterMode;
。。。。。。
  /* Generate an update event to reload the Prescaler value immediatly */
  TIMx->EGR = TIM_PSCReloadMode_Immediate; 

只加上粗体第一句,波形正常
又加上粗体第二局,波形不正常,是一个PWM很小,周期很长的PWM

在以上两句粗体情况下,把设置UG注释掉,一样的异常波形。

另外,我把第一句粗体注释掉,即禁止update event,但是把最后一句软件设置UG注释掉,波形一样正常。

似乎,
1。软件设置UG不影响ARR
2。没有第二句粗体时,即ARR不预装载,firmware设置ARR,就立马生效了。
   ARR如果预装载了,则firmware设置ARR不能里马生效,需要等到update event

使用特权

评论回复
16
渤海三叠浪| | 2009-5-15 21:20 | 只看该作者

回楼上

楼上说“又加上粗体第二局,波形不正常,是一个PWM很小,周期很长的PWM”

PWM很小  应该是你的CCRx_Val设置的小了点   周期的长度我估计是与65535有关

加上粗体第二句,则我猜有可能占空比是CCRx_Val/65535

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

55

主题

351

帖子

0

粉丝