0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

用TIM的PWM輸出模式寫一個(gè)步進(jìn)電機(jī)的Stepper庫(kù)函數(shù)

冬至子 ? 來(lái)源:Vulcan Matrix ? 作者:Vulcan ? 2023-07-24 14:36 ? 次閱讀

這是之前寫平衡小車時(shí)自己用TIM的PWM輸出模式寫了一個(gè)步進(jìn)電機(jī)的Stepper庫(kù)函數(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手冊(cè)中的結(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í)器外設(shè)時(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;
    }


    //定時(shí)器選擇時(shí)鐘源
    LL_TIM_SetClockSource(TIMx, LL_TIM_CLOCKSOURCE_INTERNAL);


    //設(shè)置自動(dòng)重載寄存器
    LL_TIM_SetAutoReload(TIMx, 2000 - 1);
    //設(shè)置計(jì)數(shù)方向
    LL_TIM_SetCounterMode(TIMx, LL_TIM_COUNTERMODE_CENTER_UP);
    //使能自動(dòng)重載預(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時(shí)鐘
        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時(shí)鐘
        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) //觸碰上限——頻率過(guò)低
    {
        TIMx_prescaler *= 10; //提高分頻比
    }


    if (ARR_t < 2) //觸碰下限——頻率過(guò)高
    {
        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)化為定時(shí)器頻率
    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)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5275

    瀏覽量

    119693
  • STM32
    +關(guān)注

    關(guān)注

    2263

    文章

    10849

    瀏覽量

    353914
  • 步進(jìn)電機(jī)
    +關(guān)注

    關(guān)注

    150

    文章

    3085

    瀏覽量

    147208
  • PWM波
    +關(guān)注

    關(guān)注

    0

    文章

    99

    瀏覽量

    16820
  • 預(yù)分頻器
    +關(guān)注

    關(guān)注

    0

    文章

    18

    瀏覽量

    8106
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    stm32的官方庫(kù)函數(shù)步進(jìn)電機(jī)的那個(gè)脈沖函數(shù)嗎?

    stm32的官方庫(kù)函數(shù)步進(jìn)電機(jī)的那個(gè)脈沖函數(shù)嗎,還是說(shuō)要自己編寫
    發(fā)表于 07-23 06:37

    stm32比較輸出模式及用于步進(jìn)電機(jī)控制

    驅(qū)動(dòng)器,PWM輸出模式只適用于電機(jī)直轉(zhuǎn),不適合精準(zhǔn)控制脈沖個(gè)數(shù)和精準(zhǔn)角度以及做步進(jìn)
    發(fā)表于 10-26 07:00

    Stepper電機(jī)驅(qū)動(dòng)庫(kù)有哪些問(wèn)題?

    Stepper庫(kù),但是,結(jié)果是電機(jī)未轉(zhuǎn)動(dòng),以至于我認(rèn)為購(gòu)買的電機(jī)出了問(wèn)題,自己還測(cè)試了下,最后發(fā)現(xiàn)電機(jī)是正確的,是
    發(fā)表于 07-08 08:01

    Stepper庫(kù)函數(shù)控制步進(jìn)電機(jī)

    問(wèn)題來(lái)源最近自學(xué)Arduino,在使用步進(jìn)電機(jī)時(shí)開始沒能使步進(jìn)電機(jī)轉(zhuǎn)起來(lái),轉(zhuǎn)起來(lái)后感覺沒法調(diào)速,遂完成此篇筆記供自己后續(xù)查閱以及方便遇到相同問(wèn)題的諸君尋找靈感。對(duì)于如何使
    發(fā)表于 09-07 09:15

    STM32F429如何使用TIM4和TIM14 的PWM波驅(qū)動(dòng)步進(jìn)電機(jī)

    STM32F429如何使用TIM4和TIM14 的PWM波驅(qū)動(dòng)步進(jìn)電機(jī)?
    發(fā)表于 12-21 07:24

    PWM的兩個(gè)比較模式是什么

    (TIMx_CCMR1)的作用PWM輸出極性是什么?PWM配置注意事項(xiàng)占空比怎么設(shè)置?庫(kù)函數(shù)配置步驟第步:使能GPIO/AFIO/
    發(fā)表于 02-16 07:14

    STM8的PWM輸出模式PWM1和PWM2的區(qū)別是什么

    STM8自學(xué)筆記:TIMPWM輸出模式中關(guān)于PWM1 和 PWM2的區(qū)別STM8的
    發(fā)表于 03-02 06:07

    TIM—高級(jí)定時(shí)器輸出PWM

    :TIM1->CH1CVR=30; CH1CVR表示通道1,不同通道數(shù)字不同,如CH2CVR表示通道23個(gè)參數(shù)都不能超過(guò)16位,最大65535暫停PWM輸出,強(qiáng)制拉高拉低修改
    發(fā)表于 03-08 11:35

    步進(jìn)電機(jī)只抖動(dòng)不轉(zhuǎn)是什么問(wèn)題?

    (\"ni\"); stepper.step(-1024); //4步模式下旋轉(zhuǎn)2048 步。 delay(500);}使用上述代碼 步進(jìn)
    發(fā)表于 11-10 08:15

    個(gè)開關(guān)手動(dòng)控制步進(jìn)電機(jī)的實(shí)現(xiàn)方法

    介紹了個(gè)開關(guān)代替單片機(jī)對(duì)步進(jìn)電機(jī)進(jìn)行手動(dòng)控制的原理電路,給出了步進(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次下載
    MSP430 <b class='flag-5'>Stepper</b> Motor Controller<b class='flag-5'>電機(jī)</b>控制:<b class='flag-5'>步進(jìn)</b><b class='flag-5'>電機(jī)</b>

    STM8TIM1配置

    基于STM8-TIM1的單通道PWM輸出,互補(bǔ)PWM輸出謹(jǐn)以本文記錄最近使用STM8進(jìn)行電機(jī)驅(qū)動(dòng)
    發(fā)表于 12-03 13:51 ?6次下載
    STM8<b class='flag-5'>TIM</b>1配置

    PWM輸出實(shí)驗(yàn)詳細(xì)示例

    (TIMx_CCMR1)的作用PWM輸出極性是什么?PWM配置注意事項(xiàng)占空比怎么設(shè)置?庫(kù)函數(shù)配置步驟第步:使能GPIO/AFIO/
    發(fā)表于 12-20 18:58 ?2次下載
    <b class='flag-5'>PWM</b><b class='flag-5'>輸出</b>實(shí)驗(yàn)詳細(xì)示例

    STM32驅(qū)動(dòng)步進(jìn)電機(jī)梯形算法庫(kù)函數(shù)

    關(guān)于梯形算法的原理查看:AVR446: Linear speed control of stepper motor 里面有原理和代碼(庫(kù)函數(shù)版F4)廢話不多說(shuō)直接上鏈接: 梯形算法驅(qū)動(dòng)步進(jìn)電機(jī)
    發(fā)表于 03-23 10:20 ?0次下載
    STM32驅(qū)動(dòng)<b class='flag-5'>步進(jìn)</b><b class='flag-5'>電機(jī)</b>梯形算法<b class='flag-5'>庫(kù)函數(shù)</b>版

    PWM輸出控制電機(jī)

    PWM 輸出控制電機(jī)電機(jī)系列 、PWM 輸出控制電機(jī)
    發(fā)表于 05-06 11:03 ?5次下載
    <b class='flag-5'>PWM</b><b class='flag-5'>輸出</b>控制<b class='flag-5'>電機(jī)</b>