打印
[应用相关]

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

[复制链接]
357|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
需要产生频率[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)

复制代码



使用特权

评论回复
沙发
flycamelaaa|  楼主 | 2022-11-17 10:23 | 只看该作者
  • 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;
  • }

复制代码

上面代码好像没显示全

使用特权

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

本版积分规则

520

主题

1700

帖子

0

粉丝