stm32 PWM移相

步进电机简介

玩过步进电机应该都知道,让步进电机转起来的要满足严格的时序,下面就以最常见的步进电机24byj48说起。24byj48有四相,就是四个极(ABCD),用于通电,联想下电池两极。所以它又有好几种控制方法,最常见的是单四拍(A-B-C-D)、双四拍(AB-BC-CD-DA)、八拍(A-AB-B-BC-C-CD-D-DA),A就是A通电,AB就是A,B都通电。

目的

目的就是要让电机转起来,这里以八拍的方式转。八拍好过于四拍的是更顺畅,角度可以更精细。在网上看了很多控制方法,基本全是用单片机的I/O实现的,这做法确实让电机转起来了。但是想下,在一个项目中若要在干其他工作时电机还要依旧保持转动,比如空调上下调风的摆动,用这种方法就不能达到同步进行了,会被其他任务打断。所以目的又变成让电机和其他任务并行工作,这就要通过STM32的PWM来进行控制。分析了下这个相序图,得出来的波形如下面所示,四个波形每个相位相差45°,占空比是2/8.

方法

定时器是向上计数,每次都是从0~65535.让每个通道开始计数的起点不一样就能实现相位的偏移。再计算好相应数值填入通道比较寄存器以触发通道中断,在通道中断中再次修改比较寄存器的数值,以此类推就可实现任意移相。

实现代码

硬件平台:STM32F103
编译器 :MDK5
SYSCLK : 72Mhz

//motor.c
void Motor1_Init(Motor MotorChValue)
{  GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;TIM_OCInitTypeDef  TIM_OCInitStructure;NVIC_InitTypeDef NVIC_InitStructure;/*设置中断*/   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure); /*时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);    RCC_APB2PeriphClockCmd( MOTOR1_CLK | RCC_APB2Periph_AFIO, ENABLE);/*通道引脚*/  GPIO_InitStructure.GPIO_Pin = MOTOR1_A1_PIN | MOTOR1_B1_PIN | MOTOR1_A2_PIN | MOTOR1_B2_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(MOTOR1_A1_PORT, &GPIO_InitStructure);//初始化GPIOGPIO_InitStructure.GPIO_Pin = MOTOR1_A2_PIN | MOTOR1_B2_PIN; GPIO_Init(MOTOR1_A2_PORT, &GPIO_InitStructure);//初始化TIM3TIM_TimeBaseStructure.TIM_Period = 65535; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值TIM_TimeBaseStructure.TIM_Prescaler =72-1; //72分频,TIM3 = 1MhzTIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //1分频TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化TIM3 Channel2 PWM模式   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStructure.TIM_Pulse = MotorChValue.Ch1Value;TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC1TIM_OCInitStructure.TIM_Pulse = MotorChValue.Ch2Value;TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC2TIM_OCInitStructure.TIM_Pulse = MotorChValue.Ch3Value;TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC3TIM_OCInitStructure.TIM_Pulse = MotorChValue.Ch4Value;TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM4 OC4TIM_ITConfig(TIM3, TIM_IT_CC1|TIM_IT_CC2|TIM_IT_CC3|TIM_IT_CC4,ENABLE);TIM_SetCounter(TIM3,0);
//  TIM_Cmd(TIM3, DISABLE);  }void Motor1_Stop(void)
{TIM_DeInit(TIM3);      //关闭电机,电机1定时器4
}void Motor1_Cw(void)   //电机1正转
{   Motor Motor1Cw; /* 设置第一次触发捕获通道的值,错开指定相位 */Motor1Cw.Ch1Value = ((PERIOD_COUNT_VALUE*2)/8);Motor1Cw.Ch2Value = ((PERIOD_COUNT_VALUE*4)/8);Motor1Cw.Ch3Value = ((PERIOD_COUNT_VALUE*6)/8);Motor1Cw.Ch4Value = ((PERIOD_COUNT_VALUE*8)/8);TIM_Cmd(TIM3, ENABLE);}void TIM3_IRQHandler(void)   //TIM3中断
{static u8 Count1=0,Count2=0,Count3=0,Count4=0;if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {if(RESET == Count1){TIM3->CCR1 =(TIM3->CCR1 +ADD1);}else {TIM3->CCR1 =(TIM3->CCR1 +ADD2);}Count1 = !Count1;TIM_ClearITPendingBit(TIM3, TIM_IT_CC1  );  //清除TIMx的中断待处理位:TIM 中断源 }else if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {if(RESET == Count2){TIM3->CCR2 =(TIM3->CCR2 +ADD1);      }else {TIM3->CCR2 =(TIM3->CCR2 +ADD2);}Count2 = !Count2;TIM_ClearITPendingBit(TIM3, TIM_IT_CC2  );  //清除TIMx的中断待处理位:TIM 中断源 }else if (TIM_GetITStatus(TIM3, TIM_IT_CC3) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {if(RESET == Count3){TIM3->CCR3 =(TIM3->CCR3 +ADD1);}else {TIM3->CCR3 =(TIM3->CCR3 +ADD2);}Count3 = !Count3;TIM_ClearITPendingBit(TIM3, TIM_IT_CC3  );  //清除TIMx的中断待处理位:TIM 中断源 }else if (TIM_GetITStatus(TIM3, TIM_IT_CC4) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 {if(RESET == Count4){TIM3->CCR4 =(TIM3->CCR4 +ADD1);}else {TIM3->CCR4 =(TIM3->CCR4 +ADD2);}Count4 = !Count4;TIM_ClearITPendingBit(TIM3, TIM_IT_CC4  );  //清除TIMx的中断待处理位:TIM 中断源 }}
//motor.h
#define PERIOD 100                                  //频率100hz
#define PERIOD_COUNT_VALUE  (1000000/PERIOD)        //频率所对应的计数值(period of timer4、timer3 is 1M)#define ADD1      ((PERIOD_COUNT_VALUE*3)/8)
#define ADD2        ((PERIOD_COUNT_VALUE*5)/8)#define MOTOR1_CLK        RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB
#define MOTOR1_A1_PORT  GPIOA
#define MOTOR1_A1_PIN   GPIO_Pin_6
#define MOTOR1_B1_PORT  GPIOA
#define MOTOR1_B1_PIN   GPIO_Pin_7
#define MOTOR1_A2_PORT  GPIOB
#define MOTOR1_A2_PIN   GPIO_Pin_0
#define MOTOR1_B2_PORT  GPIOB
#define MOTOR1_B2_PIN   GPIO_Pin_1typedef struct
{u16 Ch1Value;u16 Ch2Value;u16 Ch3Value;u16 Ch4Value;}Motor;

在main里调用void Motor1_Cw(void)即可。

以上个人拙见,欢迎与您一起讨论。

STM32实现PWM移相任意角度相关推荐

  1. STM32通用定时器输出带死区互补PWM/任意移相PWM

    项目上遇到了多个通道的带死区的互补功能,单纯靠H7的TIM1/TIM8/TIM15/TIM16/TIM17几个硬件自带的死区互补还不够,本文就使用通用定时器TIM2/TIM3/TIM4/TIM5来实现 ...

  2. 基于STM32高级定时器的全桥移相PWM发波方案

    关注.星标公众号,不错过精彩内容 来源:STM32单片机 用于移相控制的全桥PWM变换器是中大功率DC-DC变换电路中最常用的电路之一,由于其可以实现开关管的软开关特性,在数字电源的设计中被广泛采用, ...

  3. STM32F103移相全桥PWM寄存器实现

    STM32F103移相全桥PWM寄存器实现 由于项目需求需要使用单片做一个移相全桥的DCDC电源.采用STM32F103芯片,采用直接控制寄存器实现PWM移相控制 基本原理 两桥臂分别使用定时器TIM ...

  4. 第十八章 AT32F403A基于V2库 定时器输出移相pwm

    目录 概述 硬件 TMR互联同步 软件 初始化 初始化代码 测试 概述 本文主要是使用AT32F403A开发板,基于V2库使用tmr的同步功能来实现定时器输出移相pwm的功能. 串口工具使用的Atli ...

  5. STM32实现任意角度移相全桥PWM

    MCU:STM32F334C8T6 最近因某些原因,需要用到任意角度移相的PWM波形来驱动全桥电路,本文记录实现过程. 类似于全桥整流器,将四个二极管换成开关器件,就是全桥逆变器,两个桥臂,需要用四路 ...

  6. STM32实战六 PWM加移相正交

    这一章编写PWM程序,使用TIM3以两个通道,完全映射到PC6和PC7,除普通PWM输出外,增加移相正交PWM功能,为后面的编码器计数模式提供信号源. PWM.h #ifndef __PWM__ #d ...

  7. 三电平半桥LLC谐振变换器电路仿真 采用频率控制方式 引入一定的移相角度

    三电平半桥LLC谐振变换器电路仿真 采用频率控制方式 引入一定的移相角度(比较小) 驱动信号采用CMPA CMPB方式产生 增计数模式(参照DSP PWM生成) 相比普通半桥LLC开关管电压应力小 输 ...

  8. 基于STM32的单片2KW+全数控移相全桥开关电源研发记录

    STM32系列,带来了用单片低成本32位芯片,开发单片数控移相全桥开关电源的可能. 核心驱动:采用2路带互补.死区控制的定时器,产生2相移相100KHz驱动信号,输出驱动.多通道ADC.移相控制等全硬 ...

  9. STM32移相全桥电源方案

    STM32移相全桥电源方案,源代码,原理图,pcb都有 id=656505358189&

最新文章

  1. 2021年大数据HBase(四):HBase的相关操作-客户端命令式!【建议收藏】
  2. 【166期推荐】医院中电脑耗材采购该不该归信息科负责?
  3. Spring OXM- 漫谈XML解析技术
  4. eclipse启动tomcat不能正常访问问题
  5. 前端学习(1666):前端系列实战课程之仿造qq发送消息思路
  6. 关于性能优化的一些实践
  7. sqlserver临时表操作
  8. linux中vi后如何退出命令,linux用VI编辑后保存退出命令是什么啊?
  9. 汇编语言伪指令详解(附实例)
  10. Magisk中文文档
  11. SQLAlchemy session 使用问题
  12. python docx文档_【IT专家】python操作docx文档
  13. Bootstrap基础三 排版
  14. 我从冯·诺依曼计算机体系,追溯到了JVM,原来一切如此
  15. 央行930新政启动房贷证券化 将撬动10万亿进楼市
  16. ppt播放动画花屏-问题解决
  17. 达内java培优训练营 2106班
  18. 【正点原子MP157连载】 第六章 TF-A 使用-摘自【正点原子】【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7
  19. C语言:将身高的英尺英寸化成米
  20. 手把手教你快速搭建个人博客 Hexo + Github

热门文章

  1. JS文件中的敏感信息+swagger接口测试
  2. 《python 黑帽子》 示例 :UDP客户端
  3. ubuntu pip安装mpi4py报错mpi.h no such file
  4. 百度文库下载系统源码开发原理
  5. Python向列表中插入元素(列表)
  6. ColorUI使用帮助
  7. excel打开txt格式文件
  8. 浅析诊断数据库—ODX
  9. 如何建设好智能工厂?
  10. ubuntu 輸入法设置