需要产生频率[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)
复制代码
|
我发现如果只产生一次脉冲的话频率到1MHz确实也没问题。问题在于我需要反复调用motorMove函数产生脉冲。我发现debug模式下,即使我反复调用motorMove,脉冲数也没有问题。而debug模式和正常启动唯一的区别在于断点之间相当于产生了人工的延迟。所以我加了一个一毫秒的延时,然后就搞定了。
建议选用更高频率的MCU。