飞道的博客

STM32编码器的学习笔记

337人阅读  评论(0)

STM32编码器的学习笔记

 

编码器参数:

  • 分辨率:指编码器能够分辨的最小单位。对于增量式编码器,其分辨率表示为编码器转轴旋转一圈所产生的脉冲数,即脉冲数/转 (Pulse Per Revolution 或 PPR)。码盘上透光线槽的数目其实就等于分辨率,也叫多少线,较为常见的有 5-6000 线。对于绝对式编码器,内部码盘所用的位数就是它的分辨率,单位是位 (bit),具体还分单圈分辨率和多圈分辨率。

  • 精度:首先明确一点,精度与分辨率是两个不同的概念。精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。例如有些绝对式编码器参数表里会写 ±20′′,这个就表示编码器输出的读数与转轴实际位置之间存在正负 20 角秒的误差,精度由码盘刻线加工精度、转轴同心度、材料的温度特性、电路的响应时间等各方面因素共同决定。

  • 最大响应频率:指编码器每秒输出的脉冲数,单位是 Hz。计算公式:最大响应频率 = 分辨率 * 轴转速/60。

  • 信号输出形式:对于增量式编码器,每个通道的信号独立输出 上图就是常规信号输出,还有正弦信号输出形式,输出电路形式通常有集电极开路输出、推挽输出、差分输出等。对于绝对式编码器,由于是直接输出几十位的二进制数,为了确保传输速率和信号质量,一般采用串行输出或总线型输出,例如同步串行接口 (SSI)RS485CANopen 或 EtherCAT 等,也有一部分是并行输出,输出电路形式与增量式编码器相同。

 

顺时针旋转就是一个递增的计数器

逆时针旋转就是一个递减的计数器

 

编码器的使用:

  1. 设置从模式寄存器的SMCR(SMS) 工作模式:编码器模式1,编码器模式2,编码器模式3;

  2. 设置输入引脚为TI1,TI2

  3. 设置触发的极性CCER(CC1P,CC2P)

  4. 设置滤波和分频 SCMR(IC1F,IC1PSC   IC2F,IC2PSC)

  5. 使能计数器 CR1(CEN)

  6. 硬件会自动设置CR1(DIR)方向位;

 

不完整代码:


  
  1. #ifndef __BSP_ENCOEDER_H
  2. #define __BSP_ENCOEDER_H
  3. #include "stm32f4xx.h"
  4. /* 定时器选择 */
  5. #define ENCODER_TIM TIM3
  6. #define ENCODER_TIM_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE()
  7. /* 定时器溢出值 */
  8. #define ENCODER_TIM_PERIOD 65535
  9. /* 定时器预分频值 */
  10. #define ENCODER_TIM_PRESCALER 0
  11. /* 定时器中断 */
  12. #define ENCODER_TIM_IRQn TIM3_IRQn
  13. #define ENCODER_TIM_IRQHandler TIM3_IRQHandler
  14. /* 编码器接口引脚 */
  15. #define ENCODER_TIM_CH1_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
  16. #define ENCODER_TIM_CH1_GPIO_PORT GPIOC
  17. #define ENCODER_TIM_CH1_PIN GPIO_PIN_6
  18. #define ENCODER_TIM_CH1_GPIO_AF GPIO_AF2_TIM3
  19. #define ENCODER_TIM_CH2_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
  20. #define ENCODER_TIM_CH2_GPIO_PORT GPIOC
  21. #define ENCODER_TIM_CH2_PIN GPIO_PIN_7
  22. #define ENCODER_TIM_CH2_GPIO_AF GPIO_AF2_TIM3
  23. /* 编码器接口倍频数 */
  24. #define ENCODER_MODE TIM_ENCODERMODE_TI12
  25. /* 编码器接口输入捕获通道相位设置 */
  26. #define ENCODER_IC1_POLARITY TIM_ICPOLARITY_RISING
  27. #define ENCODER_IC2_POLARITY TIM_ICPOLARITY_RISING
  28. /* 编码器物理分辨率 */
  29. #define ENCODER_RESOLUTION 16
  30. /* 经过倍频之后的总分辨率 */
  31. #if (ENCODER_MODE == TIM_ENCODERMODE_TI12)
  32. #define ENCODER_TOTAL_RESOLUTION (ENCODER_RESOLUTION * 4) /* 4倍频后的总分辨率 */
  33. #else
  34. #define ENCODER_TOTAL_RESOLUTION (ENCODER_RESOLUTION * 2) /* 2倍频后的总分辨率 */
  35. #endif
  36. /* 减速电机减速比 */
  37. #define REDUCTION_RATIO 30
  38. extern __IO int16_t Encoder_Overflow_Count;
  39. extern TIM_HandleTypeDef TIM_EncoderHandle;
  40. void Encoder_Init(void);
  41. #endif /* __BSP_ENCODER_H */

 


  
  1. /**
  2. ******************************************************************************
  3. * @file bsp_motor_control.c
  4. * @author fire
  5. * @version V1.0
  6. * @date 2019-xx-xx
  7. * @brief 编码器接口
  8. ******************************************************************************
  9. * @attention
  10. *
  11. * 实验平台:野火 STM32 F407 开发板
  12. * 论坛 :http://www.firebbs.cn
  13. * 淘宝 :http://firestm32.taobao.com
  14. *
  15. ******************************************************************************
  16. */
  17. #include "./Encoder/bsp_encoder.h"
  18. /* 定时器溢出次数 */
  19. __IO int16_t Encoder_Overflow_Count = 0;
  20. TIM_HandleTypeDef TIM_EncoderHandle;
  21. /**
  22. * @brief 编码器接口引脚初始化
  23. * @param 无
  24. * @retval 无
  25. */
  26. static void Encoder_GPIO_Init(void)
  27. {
  28. GPIO_InitTypeDef GPIO_InitStruct = { 0};
  29. /* 定时器通道引脚端口时钟使能 */
  30. ENCODER_TIM_CH1_GPIO_CLK_ENABLE();
  31. ENCODER_TIM_CH2_GPIO_CLK_ENABLE();
  32. /* 设置输入类型 */
  33. GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  34. /* 设置上拉 */
  35. GPIO_InitStruct.Pull = GPIO_PULLUP;
  36. /* 设置引脚速率 */
  37. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  38. /* 选择要控制的GPIO引脚 */
  39. GPIO_InitStruct.Pin = ENCODER_TIM_CH1_PIN;
  40. /* 设置复用 */
  41. GPIO_InitStruct.Alternate = ENCODER_TIM_CH1_GPIO_AF;
  42. /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */
  43. HAL_GPIO_Init(ENCODER_TIM_CH1_GPIO_PORT, &GPIO_InitStruct);
  44. /* 选择要控制的GPIO引脚 */
  45. GPIO_InitStruct.Pin = ENCODER_TIM_CH2_PIN;
  46. /* 设置复用 */
  47. GPIO_InitStruct.Alternate = ENCODER_TIM_CH2_GPIO_AF;
  48. /* 调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO */
  49. HAL_GPIO_Init(ENCODER_TIM_CH2_GPIO_PORT, &GPIO_InitStruct);
  50. }
  51. /**
  52. * @brief 配置TIMx编码器模式
  53. * @param 无
  54. * @retval 无
  55. */
  56. static void TIM_Encoder_Init(void)
  57. {
  58. TIM_Encoder_InitTypeDef Encoder_ConfigStructure;
  59. /* 使能编码器接口时钟 */
  60. ENCODER_TIM_CLK_ENABLE();
  61. /* 定时器初始化设置 */
  62. TIM_EncoderHandle.Instance = ENCODER_TIM;
  63. TIM_EncoderHandle.Init.Prescaler = ENCODER_TIM_PRESCALER;
  64. TIM_EncoderHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
  65. TIM_EncoderHandle.Init.Period = ENCODER_TIM_PERIOD;
  66. TIM_EncoderHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  67. TIM_EncoderHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  68. /* 设置编码器倍频数 */
  69. Encoder_ConfigStructure.EncoderMode = ENCODER_MODE;
  70. /* 编码器接口通道1设置 */
  71. Encoder_ConfigStructure.IC1Polarity = ENCODER_IC1_POLARITY; //上升沿触发 有点不解,不是使用 编码器模式 3 在计数器在 TI1FP1 和 TI2FP2 的边沿计数,
  72. Encoder_ConfigStructure.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  73. Encoder_ConfigStructure.IC1Prescaler = TIM_ICPSC_DIV1;
  74. Encoder_ConfigStructure.IC1Filter = 0;
  75. /* 编码器接口通道2设置 */
  76. Encoder_ConfigStructure.IC2Polarity = ENCODER_IC2_POLARITY;
  77. Encoder_ConfigStructure.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  78. Encoder_ConfigStructure.IC2Prescaler = TIM_ICPSC_DIV1;
  79. Encoder_ConfigStructure.IC2Filter = 0;
  80. /* 初始化编码器接口 */
  81. HAL_TIM_Encoder_Init(&TIM_EncoderHandle, &Encoder_ConfigStructure);
  82. /* 清零计数器 */
  83. __HAL_TIM_SET_COUNTER(&TIM_EncoderHandle, 0);
  84. /* 清零中断标志位 */
  85. __HAL_TIM_CLEAR_IT(&TIM_EncoderHandle,TIM_IT_UPDATE);
  86. /* 使能定时器的更新事件中断 */
  87. __HAL_TIM_ENABLE_IT(&TIM_EncoderHandle,TIM_IT_UPDATE);
  88. /* 设置更新事件请求源为:计数器溢出 这个地方可能会忘记设置 */
  89. __HAL_TIM_URS_ENABLE(&TIM_EncoderHandle);
  90. /* 设置中断优先级 */
  91. HAL_NVIC_SetPriority(ENCODER_TIM_IRQn, 5, 1);
  92. /* 使能定时器中断 */
  93. HAL_NVIC_EnableIRQ(ENCODER_TIM_IRQn);
  94. /* 使能编码器接口 */
  95. HAL_TIM_Encoder_Start(&TIM_EncoderHandle, TIM_CHANNEL_ALL);
  96. }
  97. /**
  98. * @brief 编码器接口初始化
  99. * @param 无
  100. * @retval 无
  101. */
  102. void Encoder_Init(void)
  103. {
  104. Encoder_GPIO_Init(); /* 引脚初始化 */
  105. TIM_Encoder_Init(); /* 配置编码器接口 */
  106. }
  107. /**
  108. * @brief 定时器更新事件回调函数
  109. * @param 无
  110. * @retval 无
  111. */
  112. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  113. {
  114. /* 判断当前计数器计数方向 方向代表电机方向 */
  115. if(__HAL_TIM_IS_TIM_COUNTING_DOWN(&TIM_EncoderHandle))
  116. /* 下溢 */
  117. Encoder_Overflow_Count--;
  118. else
  119. /* 上溢 */
  120. Encoder_Overflow_Count++;
  121. }
  122. /*********************************************END OF FILE**********************/

 

 


转载:https://blog.csdn.net/u010261063/article/details/116209579
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场