这是之前写平衡小车时自己用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文章
5317浏览量
120003 -
STM32
+关注
关注
2266文章
10871浏览量
354793 -
步进电机
+关注
关注
150文章
3095浏览量
147346 -
PWM波
+关注
关注
0文章
99浏览量
16842 -
预分频器
+关注
关注
0文章
18浏览量
8116
发布评论请先 登录
相关推荐
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次下载
评论