打印
[其他ST产品]

为什么用单脉冲模式和RCR寄存器控制定时器发出指定频率和数目的PWM脉冲时,当频率上升...

[复制链接]
175|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
需要产生频率[50, 200k]Hz,数目[1, 2000]的PWM脉冲来驱动步进电机。目前已经尝试了三种方法。
1. 直接使用定时器中断计数和停止脉冲
2. 设置一个门模式从定时器计数和停止脉冲
3. 使用高级定时器的单脉冲和重复计数器(RCR)计数和停止脉冲

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

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



  • #define CLK_FREQ 144000   /* CLK_INT / 1000 */
  • #define DT 1                       /* dt in millisecond */
  • #include "tim.h"
  • #include "gpio.h"
  • #include "math.h"
  • void motorMove(uint8_t xdir,uint16_t xsteps, uint8_t ydir,uint16_t ysteps)
  • {
  •     uint16_t psc = 0;
  •     uint16_t arr = 0;
  •     uint16_t ccr = 0;
  •     xdirOut(xdir);
  •     getFreq(xsteps, DT, &psc, &arr, &ccr);
  •     xpwmOut(psc, arr, ccr, xsteps);
  •     ydirOut(ydir);
  •     getFreq(ysteps, DT, &psc, &arr, &ccr);
  •     ypwmOut(psc, arr, ccr, ysteps);
  • }
  • void xpwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
  • {
  •     htim1.Init.Prescaler = psc;
  •     htim1.Init.Period = arr;
  •     __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, ccr);
  •     htim1.Init.RepetitionCounter = stp - 1;
  •     HAL_TIM_Base_Init(&htim1);
  •     HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
  • }
  • void ypwmOut(uint16_t psc,uint16_t arr,uint16_t ccr,uint16_t stp)
  • {
  •     htim8.Init.Prescaler = psc;
  •     htim8.Init.Period = arr;
  •     __HAL_TIM_SET_COMPARE(&htim8, TIM_CHANNEL_1, ccr);
  •     htim8.Init.RepetitionCounter = stp - 1;
  •     HAL_TIM_Base_Init(&htim8);
  •     HAL_TIM_PWM_Start_IT(&htim8, TIM_CHANNEL_1);
  • }
  • void xdirOut(uint8_t dir)
  • {
  •     if(dir)
  •     {
  •         HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_RESET);
  •     }
  •     else
  •     {
  •     HAL_GPIO_WritePin(X_DIR_GPIO_Port, X_DIR_Pin, GPIO_PIN_SET);
  •     }
  • }
  • void ydirOut(uint8_t dir)
  • {
  •     if(dir)

复制代码


使用特权

评论回复
沙发
jcky001|  楼主 | 2023-1-9 10:20 | 只看该作者
  • void ydirOut(uint8_t dir)
  • {
  •     if(dir)
  •     {
  •         HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_RESET);
  •     }
  •     else
  •     {
  •         HAL_GPIO_WritePin(Y_DIR_GPIO_Port, Y_DIR_Pin, GPIO_PIN_SET);
  •     }
  • }
  • void getFreq(uint16_t steps, const uint16_t dt, uint16_t* psc, uint16_t* arr, uint16_t* ccr)
  • {
  •     double temp;
  •     temp = CLK_FREQ * dt / steps;
  •     temp = sqrt(temp);
  •     *(psc) = ((uint16_t) temp) - 1;
  •     *(arr) = *(psc);
  •     *(ccr) = *(arr) / 2;
  • }

复制代码

上面代码好像没显示全




[color=var(--default-a-next-color)][url=][/url]

使用特权

评论回复
板凳
两只袜子| | 2023-1-11 10:00 | 只看该作者
STM32F303的最高时钟所产生的PWM输出频率到200K时,精度无法保证,也就是会丢失脉冲。如果做连续输出,有可能满足精度,断续需要其它功能,无法保证。

建议选用更高频率的MCU。

使用特权

评论回复
地板
cr315| | 2023-1-11 10:00 | 只看该作者
我不知你是如何确认脉冲个数的,感觉你是通过中断统计个数,会不会这块出了问题。我这边刚才使用第3种方式,计数溢出频率为1MHz,要多少就多少,脉冲个数不多不少的。目前我是通过示波器看的。你再找找原因。

使用特权

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

本版积分规则

1421

主题

3928

帖子

6

粉丝