打印

请教香主stm32的32位定时器问题

[复制链接]
11633|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tiger84|  楼主 | 2010-6-23 10:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
因为要实现一个捕获精度约几十个毫秒的高电平或低电平,用16位定时器没有问题,但有时又需要捕获比较长的脉宽,约几秒。鉴于精度与长度的矛盾,16位定时器不够用,于是找出了香主以前提供的32位定时器参考例子。
有如下几个问题,盼香主解答。
(1)程序里有如下定义
     #define TIMxCLK_Freq    72000000000 /*!< In mHz */
    不知道是什么意思?不就是72M吗?怎么多了3个0?
沙发
香水城| | 2010-6-23 10:26 | 只看该作者
什么时候提供的参考例子?请提示一下,哪个帖子?

使用特权

评论回复
板凳
tiger84|  楼主 | 2010-6-23 10:29 | 只看该作者
(2)datasheet里有这么一段用于描述使用一个定时器作为另一个的预分频器的
使用一个定时器作为另一个的预分频器这个例子使用定时器1作为定时器2的预分频器。参考图138的连接,配置如下:
● 配置定时器1为主模式,送出它的更新事件UEV做为触发输出(TIM1_CR2寄存器的MMS=’010’)。然后每次计数器溢出时输出一个周期信号。
● 配置定时器1的周期(TIM1_ARR寄存器)。
● 配置定时器2从定时器1获得输入触发(TIM2_SMCR寄存器的TS=000)
● 配置定时器2使用外部时钟模式(TIM2_SMCR寄存器的SMS=111)
● 置TIM1_CR2寄存器的CEN=1以启动定时器2。
● 置TIM1_CR1寄存器的CEN=1以启动定时器1。

红颜色部分,主机的计数器溢出,从机可以获得一个输入触发,那么下列几种情况,从机会不会也得到一个输入触发?
(1)开启主机对应上升沿或下降沿的中断,主机检测到上升沿或者下降沿中断
(2)直接把主机的计数器清0

使用特权

评论回复
地板
tiger84|  楼主 | 2010-6-23 10:30 | 只看该作者
5
tiger84|  楼主 | 2010-6-23 10:40 | 只看该作者
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define TIMxCLK_Freq    72000000000 /*!< In mHz */

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint32_t MSB = 0, LSB = 1, MSB1 = 0, MSB2 = 0;
__IO uint32_t ExtSignalFreq = 0x00;
__IO uint32_t i = 0;
/**
  * @brief  This function handles TIM3 global interrupt request.
  * @param  None
  * @retval : None
  */
void TIM3_IRQHandler(void)
{
  /* TIM2 CCR1 Register define the MSB of the captured value
     TIM3 CCR1 Register define the LSB of the captured value  */
  if (i == 0)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);

    MSB1 = TIM_GetCapture1(TIM2);
    LSB = TIM_GetCapture1(TIM3);

    i = 1;
  }
  else
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);

    MSB2 = TIM_GetCapture1(TIM2);
    LSB = TIM_GetCapture1(TIM3);

    if (MSB1 > MSB2)
    {
      MSB = 0xFFFF - ((MSB1 - MSB2)) - 1;
    }
    else
    {
      MSB = (MSB2 - MSB1) - 1;
    }
    i = 0;

    /* Calculate the external signal frequency in mHz */
    ExtSignalFreq = (uint32_t)(TIMxCLK_Freq / ((MSB * 65536) + LSB));
  }
}

以上为中断程序的代码。

香主看我的理解是否有问题。

这段代码的timer2是从,timer3是主。timer3发生中断时,只可能捕获到
LSB = TIM_GetCapture1(TIM3);
也就是这句,但是
MSB1 = TIM_GetCapture1(TIM2)或者 MSB2 = TIM_GetCapture1(TIM2)
我觉得MSB1和MSB2只可能是0,原因如下

datasheet里有这么一段
若CC1通道配置为输入: CCR1包含了由上一次输入捕获1事件(IC1)传输的计数器值。

从定时器timer2根本就没有产生捕获事件,它的值只能是0

使用特权

评论回复
6
香水城| | 2010-6-23 10:51 | 只看该作者
确实是多了3个0。

虽然程序中没有解释,但我认为这是因为计数器精度提高到32位,如果不把计算精度也提高,进行整数运算时,可以得到的结果要损失很多精度甚至为0,尤其是结果接近1Hz或小于1Hz时。

程序中是这样使用这个定义的:ExtSignalFreq = (uint32_t)(TIMxCLK_Freq / ((MSB * 65536) + LSB));
因为没有地方用到这个运算结果ExtSignalFreq ,把结果扩大1000倍更容易观察测量数值相对输入信号的变化。

使用特权

评论回复
7
tiger84|  楼主 | 2010-6-23 10:52 | 只看该作者
于是我改成如下
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static uint32_t LSB = 0,MSB = 0;

/**
  * @brief  This function handles TIM3 global interrupt request.
  * @param  None
  * @retval : None
  */
void TIM3_IRQHandler(void)
{
  /* TIM2 CCR1 Register define the MSB of the captured value
     TIM3 CCR1 Register define the LSB of the captured value  */
    if(TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET)  // 检测到上升沿  计算低电平
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC1);
        MSB = TIM_GetCounter(TIM2);
        LSB = TIM_GetCapture1(TIM3);      
        TIM_SetCounter(TIM2,0);
        TIM_SetCounter(TIM3,0);        

        printf("M:%d,L:%d\r\n",MSB,LSB);
        
        
    }
   
    if(TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) // // 检测到下降沿   计算高电平
    {
        TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
        MSB = TIM_GetCounter(TIM2);
        LSB = TIM_GetCapture1(TIM3);
        TIM_SetCounter(TIM2,0);
        TIM_SetCounter(TIM3,0);
        printf("1M:%d,L:%d\r\n",MSB,LSB);        
    }  
   
     
}

程序运行的结果是总是和理论值对应不上,16位的我有试过,所以对定时器计算方法和基本理解上应不会存在问题。
脉宽长一点的,计算还凑合,
短一点的,比如64us,怎么也对应不上,
虽然printf也会花些时间,用的115200,但这个值是基本固定的,可以算出来再减去,但是还是对应不上。

香主和各位兄弟看下,不胜感激涕零

使用特权

评论回复
8
香水城| | 2010-6-23 10:53 | 只看该作者
楼主的其他问题在AN2592中解释了,请你先看看AN2592吧。

使用特权

评论回复
9
tiger84|  楼主 | 2010-6-23 10:55 | 只看该作者
确实是多了3个0。

虽然程序中没有解释,但我认为这是因为计数器精度提高到32位,如果不把计算精度也提高,进行整数运算时,可以得到的结果要损失很多精度甚至为0,尤其是结果接近1Hz或小于1Hz时。

程序中是这样使 ...
香水城 发表于 2010-6-23 10:51


谢谢香主,这个解释不错,不然我老认为我还有哪里理解不对,没法下手了,呵呵。
香主,再帮我看下其他的问题,若是我对定时器理解还不够,我再去看,呵呵

使用特权

评论回复
10
IJK| | 2010-6-23 11:29 | 只看该作者
#define TIMxCLK_Freq    72000000000 /*!< In mHz */
    不知道是什么意思?不就是72M吗?怎么多了3个0?

其实本身注释写得很清楚了,它的单位是 mHz (毫Hz),所以要“多3个0”

使用特权

评论回复
11
tiger84|  楼主 | 2010-6-23 14:03 | 只看该作者
第二个问题在文档里找到答案了,如下:
更新事件(UEV)可以由下列事件产生:
- 计数器上溢或下溢
- 设置UG位
- 通过从模式控制器产生的更新

使用特权

评论回复
12
tiger84|  楼主 | 2010-6-23 14:06 | 只看该作者
本帖最后由 tiger84 于 2010-6-23 14:14 编辑

第3个问题

这段文档
Using this configuration, each time the period to be measured exceeds the 16-bit master
timer Auto-reload register, an update event is generated to clock the slave timer.
When the active edge is detected on the master and slave timer inputs, the two counter
values are copied into the master CCR1 register and the slave CCR1 register, respectively.
Since the slave is clocked by the master update event, the number of master overflow is
recorded by the slave as the MSB part of the 32-bit input capture register, the LSB is read
on the Master CCR1.

红色部分按照我的理解从定时器只是记录了主定时器溢出的次数,但是并不能够产生捕获事件。我的问题就是在这里

使用特权

评论回复
13
tiger84|  楼主 | 2010-6-23 14:24 | 只看该作者
也罢,也罢,还是用软件实现得了

使用特权

评论回复
14
香水城| | 2010-6-23 14:45 | 只看该作者
回12楼:不错,从定时器只是记录了主定时器溢出的次数,但是也会产生捕获事件,你仔细看看AN2592中的这张配置图:

AN2592_Input_Capture.GIF (17.09 KB )

AN2592_Input_Capture.GIF

使用特权

评论回复
15
无冕之王| | 2010-6-23 14:58 | 只看该作者
版主一对一得辅导

使用特权

评论回复
16
无冕之王| | 2010-6-23 14:59 | 只看该作者
大伙也跟着学习了

使用特权

评论回复
17
tiger84|  楼主 | 2010-6-23 16:15 | 只看该作者
本帖最后由 tiger84 于 2010-6-23 16:20 编辑

谢谢香主,我没有仔细看图,看程序时也自以为是,惭愧。
不过这就要求把触发信号同时接到两个定时器上,也就需要两个IO口了,有些浪费。
再次感谢香主。

使用特权

评论回复
18
tiger84|  楼主 | 2010-6-23 16:28 | 只看该作者
把一个触发信号接到2个IO?好像还真能利用起来。
本来我是要测量高电平及低电平的宽度,需要记录好几个值,如果把一个触发信号接到2个IO口上就简单多了。
1个定时器用门控模式得到高电平,1个定时器用1个上升沿及下降沿来得到低电平,软件处理会简单很多。

需要测量高电平及低电平的宽度的应用,还有其他简单的方法没?

使用特权

评论回复
19
香水城| | 2010-6-23 16:49 | 只看该作者
如果要测量高电平及低电平的宽度,只要用不到楼主位的32位定时器级联操作,并不需要把一个触发信号接到2个IO口上,STM32定时器内部有专用通道,可以使用一个I/O口输入信号,在2个通道上分别捕获上升沿和下降沿。请看定时器的结构图:

提示:要学会看框图,前面一个问题也是因为你没有仔细看图,:lol

STM32_TIM_Input_Channels.GIF (15.03 KB )

STM32_TIM_Input_Channels.GIF

使用特权

评论回复
20
tiger84|  楼主 | 2010-6-23 16:56 | 只看该作者
谢谢香主,我开始就是用的你说的这种方式,后来绕来绕去,我都被绕糊涂了,我18楼说的那段话,真是糊涂,呵呵

使用特权

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

本版积分规则

个人签名:专注ARM及linux性能优化

101

主题

862

帖子

0

粉丝