這是之前寫平衡小車時自己用TIM的PWM輸出模式寫了一個步進電機的Stepper庫函數。
1
調用順序
1.1
init函數
1.2
begin函數
1.3
setSpeed函數
2
Stepper類結構
3
TIM結構框圖
Stm32手冊中的結構框圖很重要,只要理解了外設的運行邏輯,按照邏輯一步一步給寄存器設值就可以讓外設按我們的要求運行。
#ifndef __STEPPER_H
#define __STEPPER_H
#include "peripheral.h"
#include "math.h"
#ifdef __cplusplus
extern "C"
{
#endif
enum DIRCTION
{
POS,
INV
};
class Stepper
{
private:
/* data */
uint16_t TIMx_prescaler = 0;
uint32_t TIMx_freq = 0;
TIM_TypeDef *TIMx;
uint32_t Channel;
float speed;
public:
Stepper(TIM_TypeDef *TIMx, uint32_t Channel);
~Stepper();
void init();
void gpio_init();
void begin();
void stop();
void setDirection(DIRCTION dir);
void setFreq(uint16_t freq);
void setSpeed(float speed);
float getSpeed();
};
extern Stepper Stepper_left;
extern Stepper Stepper_right;
#ifdef __cplusplus
}
#endif
#endif
#include "Stepper.h"
Stepper Stepper_left(TIM1, LL_TIM_CHANNEL_CH1);
Stepper Stepper_right(TIM2, LL_TIM_CHANNEL_CH2);
Stepper::Stepper(TIM_TypeDef *TIMx, uint32_t Channel)
{
this- >TIMx = TIMx;
this- >Channel = Channel;
}
Stepper::~Stepper()
{
}
void Stepper::init()
{
//開定時器外設時鐘
if (TIMx == TIM1)
{
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
//設置預分頻器
LL_TIM_SetPrescaler(TIMx, 90);
TIMx_freq = 90000000;
TIMx_prescaler = 90;
}
if (TIMx == TIM2)
{
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
//設置預分頻器
LL_TIM_SetPrescaler(TIMx, 45);
TIMx_freq = 45000000;
TIMx_prescaler = 45;
}
//定時器選擇時鐘源
LL_TIM_SetClockSource(TIMx, LL_TIM_CLOCKSOURCE_INTERNAL);
//設置自動重載寄存器
LL_TIM_SetAutoReload(TIMx, 2000 - 1);
//設置計數方向
LL_TIM_SetCounterMode(TIMx, LL_TIM_COUNTERMODE_CENTER_UP);
//使能自動重載預裝載
LL_TIM_EnableARRPreload(TIMx);
if (Channel == LL_TIM_CHANNEL_CH1 || Channel == LL_TIM_CHANNEL_CH1N)
{
//設置比較值
LL_TIM_OC_SetCompareCH1(TIMx, 1000 - 1);
//設置成PWM模式
LL_TIM_OC_SetMode(TIMx, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
//設置捕獲/比較寄存器值
LL_TIM_OC_EnablePreload(TIMx, LL_TIM_CHANNEL_CH1);
}
if (Channel == LL_TIM_CHANNEL_CH2 || Channel == LL_TIM_CHANNEL_CH2N)
{
//設置比較值
LL_TIM_OC_SetCompareCH2(TIMx, 1000 - 1);
//設置成PWM模式
LL_TIM_OC_SetMode(TIMx, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);
//設置捕獲/比較寄存器值
LL_TIM_OC_EnablePreload(TIMx, LL_TIM_CHANNEL_CH2);
}
//設置輸出極性
LL_TIM_OC_SetPolarity(TIMx, Channel, LL_TIM_OCPOLARITY_HIGH);
//使能輸出
LL_TIM_EnableAllOutputs(TIMx);
LL_TIM_CC_EnableChannel(TIMx, Channel);
//GPIO初始化
gpio_init();
}
void Stepper::gpio_init()
{
if (TIMx == TIM1)
{
//開啟GPIO時鐘
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
//GPIO選為AF
//M1-DIR
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
//M1-STEP
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pin = LL_GPIO_PIN_8;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
if (TIMx == TIM2)
{
//開啟GPIO時鐘
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOC);
//GPIO選為AF
//M2-DIR
LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
//M2-STEP
GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
GPIO_InitStruct.Pin = LL_GPIO_PIN_3;
GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_MEDIUM;
LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
}
void Stepper::begin()
{
LL_TIM_EnableCounter(TIMx);
}
void Stepper::stop()
{
LL_TIM_DisableCounter(TIMx);
}
void Stepper::setDirection(DIRCTION dir)
{
if (dir == INV)
{
if (TIMx == TIM1)
{
LL_GPIO_WriteOutputPort(GPIOB, LL_GPIO_ReadOutputPort(GPIOB) & (~LL_GPIO_PIN_4));
}
if (TIMx == TIM2)
{
LL_GPIO_WriteOutputPort(GPIOB, LL_GPIO_ReadOutputPort(GPIOB) & (~LL_GPIO_PIN_10));
}
}
if (dir == POS)
{
if (TIMx == TIM1)
{
LL_GPIO_WriteOutputPort(GPIOB, LL_GPIO_ReadOutputPort(GPIOB) | (LL_GPIO_PIN_4));
}
if (TIMx == TIM2)
{
LL_GPIO_WriteOutputPort(GPIOB, LL_GPIO_ReadOutputPort(GPIOB) | (LL_GPIO_PIN_10));
}
}
}
void Stepper::setFreq(uint16_t freq)
{
if (freq == 0)
{
LL_TIM_DisableCounter(TIMx);
return;
}
else if (!LL_TIM_IsEnabledCounter(TIMx))
{
LL_TIM_EnableCounter(TIMx);
}
uint32_t ARR_t = TIMx_freq / TIMx_prescaler / freq;
if (ARR_t > 65535) //觸碰上限——頻率過低
{
TIMx_prescaler *= 10; //提高分頻比
}
if (ARR_t < 2) //觸碰下限——頻率過高
{
TIMx_prescaler /= 10; //降低分頻比
}
LL_TIM_SetPrescaler(TIMx, TIMx_prescaler);
ARR_t = TIMx_freq / TIMx_prescaler / freq;
LL_TIM_SetAutoReload(TIMx, ARR_t);
uint16_t CCR_t = ARR_t * 0.5;
if (Channel == LL_TIM_CHANNEL_CH1)
{
LL_TIM_OC_SetCompareCH1(TIMx, CCR_t);
}
if (Channel == LL_TIM_CHANNEL_CH2)
{
LL_TIM_OC_SetCompareCH2(TIMx, CCR_t);
}
}
/**
* @brief 設置轉速
*
* @param speed 轉速-單位(度/秒)
*/
void Stepper::setSpeed(float speed)
{
//判斷速度方向
DIRCTION _dir = POS;
if (speed != abs(speed))
{
_dir = INV;
speed = abs(speed);
}
setDirection(_dir);
//速度限幅
if (speed > 5000)
speed = 5000;
if (speed < 10)
speed = 10;
this- >speed = speed;
//將速度轉化為定時器頻率
uint16_t _freq = speed / 1.8;
setFreq(_freq);
}
float Stepper::getSpeed()
{
return speed;
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
寄存器
+關注
關注
31文章
5355瀏覽量
120516 -
STM32
+關注
關注
2270文章
10904瀏覽量
356342 -
步進電機
+關注
關注
150文章
3112瀏覽量
147548 -
PWM波
+關注
關注
0文章
99瀏覽量
16872 -
預分頻器
+關注
關注
0文章
18瀏覽量
8151
發布評論請先 登錄
相關推薦
Stepper庫函數控制步進電機
問題來源最近自學Arduino,在使用步進電機時開始沒能使步進電機轉起來,轉起來后感覺沒法調速,遂完成此篇筆記供自己后續查閱以及方便遇到相同問題的諸君尋找靈感。對于如何使
發表于 09-07 09:15
TIM—高級定時器輸出PWM
:TIM1->CH1CVR=30; CH1CVR表示通道1,不同通道數字不同,如CH2CVR表示通道23個參數都不能超過16位,最大65535暫停PWM輸出,強制拉高拉低修改
發表于 03-08 11:35
步進電機只抖動不轉是什么問題?
(\"ni\"); stepper.step(-1024); //4步模式下旋轉一周用2048 步。 delay(500);}使用上述代碼 步進
發表于 11-10 08:15
MSP430 Stepper Motor Controller電機控制:步進電機
MSP430 Stepper Motor Controller電機控制:步進電機
發表于 10-12 14:50
?12次下載
PWM輸出實驗詳細示例
(TIMx_CCMR1)的作用PWM輸出極性是什么?PWM配置注意事項占空比怎么設置?庫函數配置步驟第一步:使能GPIO/AFIO/
發表于 12-20 18:58
?2次下載
STM32驅動步進電機梯形算法庫函數版
關于梯形算法的原理查看:AVR446: Linear speed control of stepper motor 里面有原理和代碼(庫函數版F4)廢話不多說直接上鏈接: 梯形算法驅動步進電機
發表于 03-23 10:20
?0次下載
評論