你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

为什么用单脉冲模式和RCR寄存器控制定时器发出指定频率和数目的PWM脉冲时,当频率上升,输出的脉冲数目总是小于设定值?

[复制链接]
Eryxmachus 提问时间:2022-11-13 18:25 / 未解决
需要产生频率[50, 200k]Hz,数目[1, 2000]的PWM脉冲来驱动步进电机。目前已经尝试了三种方法。
1. 直接使用定时器中断计数和停止脉冲
2. 设置一个门模式从定时器计数和停止脉冲
3. 使用高级定时器的单脉冲和重复计数器(RCR)计数和停止脉冲

个人认为第三种方法最简单、最可靠。毕竟所有的控制都是硬件完成的。但是当频率上升到200kHz时,三种方法均无法产生数目准确的PWM脉冲。并且脉冲数目总是小于预期值。

下面是我计时器的设置和代码。

TIM1SETTING.PNG
CHIP.PNG
  1. #define CLK_FREQ 144000   /* CLK_INT / 1000 */
  2. #define DT 1                       /* dt in millisecond */

  3. #include "tim.h"
  4. #include "gpio.h"
  5. #include "math.h"

  6. void motorMove(uint8_t xdir,uint16_t xsteps, uint8_t ydir,uint16_t ysteps)
  7. {
  8.     uint16_t psc = 0;
  9.     uint16_t arr = 0;
  10.     uint16_t ccr = 0;
  11.        
  12.     xdirOut(xdir);
  13.     getFreq(xsteps, DT, &psc, &arr, &ccr);
  14.     xpwmOut(psc, arr, ccr, xsteps);

  15.     ydirOut(ydir);
  16.     getFreq(ysteps, DT, &psc, &arr, &ccr);
  17.     ypwmOut(psc, arr, ccr, ysteps);
  18. }



  19. void xpwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
  20. {
  21.     htim1.Init.Prescaler = psc;
  22.     htim1.Init.Period = arr;
  23.     __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, ccr);
  24.     htim1.Init.RepetitionCounter = stp - 1;
  25.     HAL_TIM_Base_Init(&htim1);
  26.     HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
  27. }

  28. void ypwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
  29. {
  30.     htim8.Init.Prescaler = psc;
  31.     htim8.Init.Period = arr;
  32.     __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1, ccr);
  33.     htim8.Init.RepetitionCounter = stp - 1;
  34.     HAL_TIM_Base_Init(&htim8);
  35.     HAL_TIM_PWM_Start_IT(&htim8, TIM_CHANNEL_1);
  36. }

  37. void xdirOut(uint8_t dir)
  38. {
  39.     if(dir)
  40.     {
  41.         HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_RESET);
  42.     }
  43.     else
  44.     {
  45.     HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_SET);
  46.     }
  47. }

  48. void ydirOut(uint8_t dir)
  49. {
  50.     if(dir)
复制代码


收藏 评论5 发布时间:2022-11-13 18:25

举报

5个回答
Eryxmachus 回答时间:2022-11-13 18:28:14
  1. void ydirOut(uint8_t dir)
  2. {
  3.     if(dir)
  4.     {
  5.         HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_RESET);
  6.     }
  7.     else
  8.     {
  9.         HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_SET);
  10.     }       
  11. }

  12. void getFreq(uint16_t steps, const uint16_t dt, uint16_t* psc, uint16_t* arr, uint16_t* ccr)
  13. {
  14.     double temp;
  15.     temp = CLK_FREQ * dt / steps;
  16.     temp = sqrt(temp);
  17.     *(psc) = ((uint16_t) temp) - 1;
  18.     *(arr) = *(psc);
  19.     *(ccr) = *(arr) / 2;
  20. }
复制代码
上面代码好像没显示全
xmshao 回答时间:2022-11-14 11:09:25
我不知你是如何确认脉冲个数的,感觉你是通过中断统计个数,会不会这块出了问题。我这边刚才使用第3种方式,计数溢出频率为1MHz,要多少就多少,脉冲个数不多不少的。目前我是通过示波器看的。你再找找原因。
Eryxmachus 回答时间:2022-11-14 13:10:20
xmshao 发表于 2022-11-14 11:09
我不知你是如何确认脉冲个数的,感觉你是通过中断统计个数,会不会这块出了问题。我这边刚才使用第3种方式 ...

我发现如果只产生一次脉冲的话频率到1MHz确实也没问题。问题在于我需要反复调用motorMove函数产生脉冲。我发现debug模式下,即使我反复调用motorMove,脉冲数也没有问题。而debug模式和正常启动唯一的区别在于断点之间相当于产生了人工的延迟。所以我加了一个一毫秒的延时,然后就搞定了。 break.PNG
Glenxu 回答时间:2022-12-25 19:12:17
STM32F303的最高时钟所产生的PWM输出频率到200K时,精度无法保证,也就是会丢失脉冲。如果做连续输出,有可能满足精度,断续需要其它功能,无法保证。

建议选用更高频率的MCU。

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版