用cubemx配置编码器捕获的问题

如题,用了stm32cubemx进行配置编码器模式时遇到了点问题
关于用stm32捕获一个电机的编码器数据
大多是教学帖子都是用两个定时器进行捕获,
一个定时器A开启编码器模式,读取编码器ab相
一个定时器B定时中断,定时读取旋转期间的编码器值并计算速度,例如10ms读取一次

我的问题是是否需要在nvic中开启A定时器的中断?

我看有些帖子说需要配置A和B的中断
有些帖子只配置了B的中断

对这种分歧感到不解,我个人认为不需要开启A的中断,只需要开启B的中断然后定时读取并清零A的计数值就可以了,希望能点拨一下给个明确的答案

是否需要在NVIC中开启A定时器的中断,取决于你的具体需求和代码实现。
1、如果你只需要读取编码器的值并计算速度,可以只配置B定时器的中断,定时读取并清零A的计数值。这样可以减少中断的频率,提高系统的效率。
2、如果你需要在每个编码器脉冲到来时进行一些特定的操作,比如更新某些参数或者进行其他的处理,那么你可能需要配置A定时器的中断。在A定时器的中断中,你可以读取编码器的值,并根据需要进行相应的处理。

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 你可以看下这个问题的回答https://ask.csdn.net/questions/269626
  • 除此之外, 这篇博客: 构建驱动模块6--STM32 缓冲队列中的      缓冲区常常用于临时保存数据,特别是在通讯过程中,先把数据接收下后,后期等待任务空闲在进行处理,这样避免接收数据中处理数据而造成数据丢失。缓冲队列里经常使用为环形缓冲队列,环形队列是一个头尾相接的队列,一般定义当入队操作为缓冲写操作,而出队则定义为缓冲读。当一个数据或者一组消息来到时,进行入队操作;当需要解析消息时才有出队操作。针对该思想编写一个最简单缓冲队列模块。其代码如下: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    缓冲队列实现代码

    typedef struct
    {
    	
    	MsgCell *msgCell;
    	ht_uint32_t wPos;
    	ht_uint32_t rPos;
    	ht_uint32_t Count;
    }cmMsg_t;
    /**********************************************************************************************************
     *
     *  函数名:cmMsgCreate
     *  功 能: 
     *  参  数:
     *  返回值:
     *  版 本: 
     *
     **********************************************************************************************************/
    void* cmMsgCreate(ht_uint32_t wantSize)
    {
    	cmMsg_t *prt=NULL;
      prt=(cmMsg_t *)cmMalloc(sizeof(cmMsg_t)) ;
      prt->msgCell=(MsgCell *)cmMalloc(sizeof(MsgCell)*wantSize) ;
    	prt->rPos=0;
    	prt->wPos=0;
    	prt->Count=wantSize;
    	return (void*)prt;
    	
    }
    /**********************************************************************************************************
     *
     *  函数名:cmMsgWrite
     *  功 能: 
     *  参  数:
     *  返回值:
     *  版 本: 
     *
     **********************************************************************************************************/
     ht_int32_t cmMsgWrite(void * handle,MsgCell msg)
    {
      ht_uint32_t iPos,i;
    	cmMsg_t *prt=(cmMsg_t*)handle;
    	 iPos=(prt->wPos+1)%prt->Count;
    if(( iPos!=prt->rPos)&&(msg.MsgLen<=256))//最大长度不超过256字节
    {
      prt->msgCell[prt->wPos].MsgLen=msg.MsgLen;
      prt->msgCell[prt->wPos].prtMsg=(ht_uint8_t *)cmMalloc(msg.MsgLen) ;
      for(i=0;i<prt->msgCell[prt->wPos].MsgLen;i++)
    	{
    		prt->msgCell[prt->wPos].prtMsg[i]=msg.prtMsg[i];
    	}
       prt->wPos=iPos;
     return 1;
    }
    else
    { 
     return 0;
    }	
    }
    
    /**********************************************************************************************************
     *
     *  函数名:cmMsgRead
     *  功 能: 
     *  参  数:
     *  返回值:
     *  版 本: 
     *
     **********************************************************************************************************/
    
    ht_int32_t cmMsgRead(void * handle,MsgCell *msg )
    {
       ht_uint32_t  i;
    	cmMsg_t *prt=(cmMsg_t*)handle;
     
    	if( prt->wPos!=prt->rPos)
    { 
    	  msg->MsgLen=prt->msgCell[prt->rPos].MsgLen;
    	  for(i=0;i<prt->msgCell[prt->rPos].MsgLen;i++)
    	{
    		msg->prtMsg[i]=prt->msgCell[prt->rPos].prtMsg[i];
    		cmFree(prt->msgCell[prt->rPos].prtMsg);
    	}
         prt->rPos=(prt->rPos+1)%prt->Count;
    	return 1;
    }
    return 0;
    	
    }
  • 以下回答来自chatgpt:

    这个问题涉及到使用STM32CubeMX配置编码器模式,并根据参考资料,你需要使用两个定时器来进行编码器数据的捕获和计算速度。你的问题是关于是否需要在NVIC中开启定时器A的中断。

    根据我的理解和经验,一般情况下只需要开启定时器B的中断即可。在定时器B的中断函数中,你可以读取并清零定时器A的计数值。以下是代码示例:

    首先,在STM32CubeMX中配置定时器A和定时器B: 1. 打开STM32CubeMX并创建一个新的工程。 2. 在"Configuration"选项卡中,选择你的芯片型号。 3. 在"Peripherals"选项卡中,选择"TIM1"和"TIM2"。 4. 针对TIM1进行以下配置: - 在"Mode"选项卡中,选择"Encoder mode"。 - 在"Encoder Interface Mode"选项中,选择"Encoder mode 3"。 - 在"Clock Source"选项中,选择"Internal clock"。 - 在"Interrupt"选项中,选择"Update"中断。 - 在"NVIC Settings"选项中,确保"TIM1 update interrupt"中断已被选中。 5. 针对TIM2进行以下配置: - 在"Mode"选项卡中,选择"Counter mode"。 - 在"Counter Settings"选项中,选择合适的计数方向和计数模式。 - 在"Clock Source"选项中,选择"Internal clock"。 - 在"Prescaler"选项中,选择合适的分频系数。 - 在"Auto-Reload Register (ARR)"选项中,选择合适的计数值。 - 在"Interrupt"选项中,选择"Update"中断。 - 在"NVIC Settings"选项中,确保"TIM2 update interrupt"中断已被选中。

    生成代码并导入到你的工程中。

    然后,在代码中,你需要编写定时器B的中断处理函数,并在其中读取并清零定时器A的计数值。以下是示例代码:

    #include "stm32f4xx_hal.h"
    
    // 定义全局变量用于存储定时器A的计数值
    volatile uint16_t timerA_count = 0;
    
    // 定义定时器B的中断处理函数
    void TIM2_IRQHandler(void)
    {
      if (__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_UPDATE) != RESET)  // 检查是否是更新中断
      {
        if (__HAL_TIM_GET_ITSTATUS(&htim2, TIM_IT_UPDATE) != RESET)  // 检查是否是更新中断标志
        {
          // 读取并清零定时器A的计数值
          timerA_count = __HAL_TIM_GET_COUNTER(&htim1);
          __HAL_TIM_SET_COUNTER(&htim1, 0);
    
          // 执行其他操作,如计算速度或控制电机等
    
          __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE);  // 清除中断标志
        }
      }
    }
    
    // 主函数
    int main(void)
    {
      // 初始化硬件、中断等
    
      // 启动定时器A和定时器B
      HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);
      HAL_TIM_Base_Start_IT(&htim2);
    
      while (1)
      {
        // 执行其他操作
    
        // 读取定时器B的计数器值
        uint16_t timerB_count = __HAL_TIM_GET_COUNTER(&htim2);
      }
    }
    

    以上是一个基本的示例代码,你可以根据你的实际情况进行适当修改。需要注意的是,以上代码仅供参考,具体的配置和实现可能因你的具体硬件和需求而有所不同。在实际使用时,你可能还需要添加其他的配置和代码来满足你的需求。

    希望以上解答对你有所帮助。如果你仍然有疑问或需要进一步的帮助,请随时提问。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^