這是之前寫平衡小車時自己用TIM的PWM輸出模式寫了一個步進(jìn)電機(jī)的Stepper庫函數(shù)。
1
調(diào)用順序
1.1
init函數(shù)
1.2
begin函數(shù)
1.3
setSpeed函數(shù)
2
Stepper類結(jié)構(gòu)
3
TIM結(jié)構(gòu)框圖
Stm32手冊中的結(jié)構(gòu)框圖很重要,只要理解了外設(shè)的運(yùn)行邏輯,按照邏輯一步一步給寄存器設(shè)值就可以讓外設(shè)按我們的要求運(yùn)行。
#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()
{
//開定時器外設(shè)時鐘
if (TIMx == TIM1)
{
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_TIM1);
//設(shè)置預(yù)分頻器
LL_TIM_SetPrescaler(TIMx, 90);
TIMx_freq = 90000000;
TIMx_prescaler = 90;
}
if (TIMx == TIM2)
{
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
//設(shè)置預(yù)分頻器
LL_TIM_SetPrescaler(TIMx, 45);
TIMx_freq = 45000000;
TIMx_prescaler = 45;
}
//定時器選擇時鐘源
LL_TIM_SetClockSource(TIMx, LL_TIM_CLOCKSOURCE_INTERNAL);
//設(shè)置自動重載寄存器
LL_TIM_SetAutoReload(TIMx, 2000 - 1);
//設(shè)置計(jì)數(shù)方向
LL_TIM_SetCounterMode(TIMx, LL_TIM_COUNTERMODE_CENTER_UP);
//使能自動重載預(yù)裝載
LL_TIM_EnableARRPreload(TIMx);
if (Channel == LL_TIM_CHANNEL_CH1 || Channel == LL_TIM_CHANNEL_CH1N)
{
//設(shè)置比較值
LL_TIM_OC_SetCompareCH1(TIMx, 1000 - 1);
//設(shè)置成PWM模式
LL_TIM_OC_SetMode(TIMx, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_PWM1);
//設(shè)置捕獲/比較寄存器值
LL_TIM_OC_EnablePreload(TIMx, LL_TIM_CHANNEL_CH1);
}
if (Channel == LL_TIM_CHANNEL_CH2 || Channel == LL_TIM_CHANNEL_CH2N)
{
//設(shè)置比較值
LL_TIM_OC_SetCompareCH2(TIMx, 1000 - 1);
//設(shè)置成PWM模式
LL_TIM_OC_SetMode(TIMx, LL_TIM_CHANNEL_CH2, LL_TIM_OCMODE_PWM1);
//設(shè)置捕獲/比較寄存器值
LL_TIM_OC_EnablePreload(TIMx, LL_TIM_CHANNEL_CH2);
}
//設(shè)置輸出極性
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 設(shè)置轉(zhuǎn)速
*
* @param speed 轉(zhuǎn)速-單位(度/秒)
*/
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;
//將速度轉(zhuǎn)化為定時器頻率
uint16_t _freq = speed / 1.8;
setFreq(_freq);
}
float Stepper::getSpeed()
{
return speed;
}
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報(bào)投訴
-
寄存器
+關(guān)注
關(guān)注
31文章
5301瀏覽量
119862 -
STM32
+關(guān)注
關(guān)注
2264文章
10858瀏覽量
354391 -
步進(jìn)電機(jī)
+關(guān)注
關(guān)注
150文章
3090瀏覽量
147279 -
PWM波
+關(guān)注
關(guān)注
0文章
99瀏覽量
16830 -
預(yù)分頻器
+關(guān)注
關(guān)注
0文章
18瀏覽量
8110
發(fā)布評論請先 登錄
相關(guān)推薦
stm32的官方庫函數(shù)有步進(jìn)電機(jī)的那個脈沖函數(shù)嗎?
stm32的官方庫函數(shù)有步進(jìn)電機(jī)的那個脈沖函數(shù)嗎,還是說要自己編寫
發(fā)表于 07-23 06:37
stm32比較輸出模式及用于步進(jìn)電機(jī)控制
驅(qū)動器,PWM輸出模式只適用于電機(jī)一直轉(zhuǎn),不適合精準(zhǔn)控制脈沖個數(shù)和精準(zhǔn)角度以及做步進(jìn)
發(fā)表于 10-26 07:00
Stepper電機(jī)驅(qū)動庫有哪些問題?
的Stepper庫,但是,結(jié)果是電機(jī)未轉(zhuǎn)動,以至于我認(rèn)為購買的電機(jī)出了問題,自己還測試了一下,最后發(fā)現(xiàn)電機(jī)是正確的,是
發(fā)表于 07-08 08:01
Stepper庫函數(shù)控制步進(jìn)電機(jī)
問題來源最近自學(xué)Arduino,在使用步進(jìn)電機(jī)時開始沒能使步進(jìn)電機(jī)轉(zhuǎn)起來,轉(zhuǎn)起來后感覺沒法調(diào)速,遂完成此篇筆記供自己后續(xù)查閱以及方便遇到相同問題的諸君尋找靈感。對于如何使
發(fā)表于 09-07 09:15
STM32F429如何使用TIM4和TIM14 的PWM波驅(qū)動步進(jìn)電機(jī)?
STM32F429如何使用TIM4和TIM14 的PWM波驅(qū)動步進(jìn)電機(jī)?
發(fā)表于 12-21 07:24
PWM的兩個比較模式是什么
(TIMx_CCMR1)的作用PWM輸出極性是什么?PWM配置注意事項(xiàng)占空比怎么設(shè)置?庫函數(shù)配置步驟第一步:使能GPIO/AFIO/
發(fā)表于 02-16 07:14
STM8的PWM輸出模式中PWM1和PWM2的區(qū)別是什么
STM8自學(xué)筆記:TIM的PWM輸出模式中關(guān)于PWM1 和 PWM2的區(qū)別STM8的
發(fā)表于 03-02 06:07
TIM—高級定時器輸出PWM
:TIM1->CH1CVR=30; CH1CVR表示通道1,不同通道數(shù)字不同,如CH2CVR表示通道23個參數(shù)都不能超過16位,最大65535暫停PWM輸出,強(qiáng)制拉高拉低修改
發(fā)表于 03-08 11:35
步進(jìn)電機(jī)只抖動不轉(zhuǎn)是什么問題?
(\"ni\"); stepper.step(-1024); //4步模式下旋轉(zhuǎn)一周用2048 步。 delay(500);}使用上述代碼 步進(jìn)
發(fā)表于 11-10 08:15
用一個開關(guān)手動控制步進(jìn)電機(jī)的實(shí)現(xiàn)方法
介紹了用一個開關(guān)代替單片機(jī)對步進(jìn)電機(jī)進(jìn)行手動控制的原理電路,給出了步進(jìn)
發(fā)表于 04-29 13:52
?23次下載
MSP430 Stepper Motor Controller電機(jī)控制:步進(jìn)電機(jī)
MSP430 Stepper Motor Controller電機(jī)控制:步進(jìn)電機(jī)
發(fā)表于 10-12 14:50
?12次下載
STM8TIM1配置
基于STM8-TIM1的單通道PWM輸出,互補(bǔ)PWM輸出謹(jǐn)以本文記錄最近使用STM8進(jìn)行電機(jī)驅(qū)動
發(fā)表于 12-03 13:51
?6次下載
PWM輸出實(shí)驗(yàn)詳細(xì)示例
(TIMx_CCMR1)的作用PWM輸出極性是什么?PWM配置注意事項(xiàng)占空比怎么設(shè)置?庫函數(shù)配置步驟第一步:使能GPIO/AFIO/
發(fā)表于 12-20 18:58
?2次下載
STM32驅(qū)動步進(jìn)電機(jī)梯形算法庫函數(shù)版
關(guān)于梯形算法的原理查看:AVR446: Linear speed control of stepper motor 里面有原理和代碼(庫函數(shù)版F4)廢話不多說直接上鏈接: 梯形算法驅(qū)動步進(jìn)電機(jī)
發(fā)表于 03-23 10:20
?0次下載
評論