当前位置: 首页 > news >正文

TIM输出比较之PWM驱动直流电机应用案例

文章目录

  • 前言
  • 一、应用案例演示
  • 二、电路接线图
  • 三、应用案例代码
  • 四、应用案例分析
    • 4.1 初始化PWM模块
      • 4.1.1 RCC开启时钟
      • 4.1.2 配置时基单元
      • 4.1.3 配置输出比较单元
      • 4.1.4 配置GPIO
      • 4.1.5 运行控制
    • 4.2 PWM输出模块
    • 4.3 电机模块
      • 4.3.1 Motor初始化模块
      • 4.3.2 电机调速模块
    • 4.4 主程序


前言

提示:本文主要用作在学习江科大自化协STM32入门教程后做的归纳总结笔记,旨在学习记录,如有侵权请联系作者
本案例实现了一个利用输出占空比可调的PWM信号来驱动直流电机的功能。每按一次按键电机按照增量或减量的速度正反转动,比如按一下,OLED上显示当前的速度值为+20,再按一下,+40,以此类推。其中正转显示为+,反转显示为-。


一、应用案例演示

TIM输出比较之PWM驱动直流电机

二、电路接线图

这里红色的模块是TB6612电机驱动模块,它的第一个引脚VM为电机电源,同样的我们可以把它接到STLINK的5V引脚上。第二个VCC逻辑电源,接面包板3.3V正极。第三个GND电源负极,接面包板的负极。之后AO1、AO2电机输出端,接电机的两根线。STBY待机控制脚,不需要待机,直接接逻辑电源3.3V正极。剩下的三个是控制引脚,AIN1和AIN2是方向控制,任意接两个GPIO就行了,这里我接的是PA4和PA5两个引脚。PWMA是速度控制,需要接PWM的输出脚,这里我接的是PA2这个引脚。最后在PB1接了一个按键用于控制电机。
在这里插入图片描述
在这里插入图片描述

三、应用案例代码

PWM.h文件:

#ifndef __PWM_H
#define __PWM_Hvoid PWM_Init(void);
void PWM_SetCompare3(uint16_t Compare);#endif

PWM.c实现文件:

#include "stm32f10x.h"                  // Device headervoid PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARRTIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;		//PSCTIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCStructInit(&TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;		//CCRTIM_OC3Init(TIM2, &TIM_OCInitStructure);TIM_Cmd(TIM2, ENABLE);
}void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2, Compare);
}

电机头文件Motor.h:

#ifndef __MOTOR_H
#define __MOTOR_Hvoid Motor_Init(void);
void Motor_SetSpeed(int8_t Speed);#endif

电机实现文件Motor.c:

#include "stm32f10x.h"                  // Device header
#include "PWM.h"void Motor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);PWM_Init();
}void Motor_SetSpeed(int8_t Speed)
{if (Speed >= 0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(-Speed);}
}

主程序main.c:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"uint8_t KeyNum;
int8_t Speed;int main(void)
{OLED_Init();Motor_Init();Key_Init();OLED_ShowString(1, 1, "Speed:");while (1){KeyNum = Key_GetNum();if (KeyNum == 1){Speed += 20;if (Speed > 100){Speed = -100;}}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1, 7, Speed, 3);}
}

完整工程:TIM输出比较之PWM驱动直流电机应用案例

四、应用案例分析

整体思路与LED呼吸灯那一章节基本是一致的,在那一章里已经讲得非常详细了,这里就不再累述了,不懂的可以回过头去看一看。

文章传送门在此:TIM输出比较之PWM驱动LED呼吸灯应用案例

在这里插入图片描述

这里需要注意的是,本案例换了一个GPIO口,所以对应的定时器的通道也要更换。如下表所示,可以看到PA2对应的是TIM2的CH3通道。

在这里插入图片描述

4.1 初始化PWM模块

4.1.1 RCC开启时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

4.1.2 配置时基单元

TIM_InternalClockConfig(TIM2);TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;		//PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

TIM_InternalClockConfig(TIM2);//选择时基单元的时钟源,选择内部时钟。若不调用这个函数,系统上电后默认也是内部时钟。

计算公式如下:
PWM频率:Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比:Duty = CCR / (ARR + 1)
PWM分辨率:Reso = 1 / (ARR + 1)
换算公式:1 MHz = 1,000 KHz = 1,000,000 Hz

假设我要输出一个频率为1KHz,占空比为50%,分辨率为1%的PWM波形,时钟源选择内部时钟,也就是说CK_PSC=72MHz。

代入公式计算可得:
Freq =1000 = 72000000 / 720 / 100
那么可以推算出PSC为719,ARR为99
同样的道理,Duty = 50% = CCR / 100,推算出CCR为50。
同样也可以推算出周期 T = 1 / 1000 = 0.001秒,也就是1毫秒。(频率是周期的倒数 f = 1 / T)

输出频率为1KHz,占空比为50%(CCR设置为50),分辨率为1%(受占空比变化影响)的PWM波形代码如下:

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720- 1;		//PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

那如果我们设置频率为1KHz的话就会出现一个问题,就是这个电机会发出蜂鸣器的响声,在堵转的时候很明显。因为电机里面也是线圈和磁铁,所以在PWM的驱动下会发出蜂鸣器的声音,这是正常现象。那有什么办法可以避免呢?研究表明,人耳能听到的范围是20Hz到20KHz,那这样的话我们可以把频率调到人耳能接受的范围就可以了。

加大频率我们可以通过减小预分频器来完成,这样不会影响占空比。所以我们给这个预分频器去掉一个0,那就是10KHz了。再减半为36,那就是20KHz了。

那么输出频率为20KHz的PWM波形代码如下:

TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 100 - 1;		//ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 36 - 1;		//PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);

4.1.3 配置输出比较单元

TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;		//CCR
TIM_OC3Init(TIM2, &TIM_OCInitStructure);

4.1.4 配置GPIO

GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);

4.1.5 运行控制

TIM_Cmd(TIM2, ENABLE);

4.2 PWM输出模块

void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2, Compare);
}

4.3 电机模块

4.3.1 Motor初始化模块

void Motor_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);PWM_Init();
}

电机模块的初始化包括两个部分,分别是控制电机正反转的两个GPIO(PA4和PA5)以及PWM模块。

4.3.2 电机调速模块

void Motor_SetSpeed(int8_t Speed)
{if (Speed >= 0){GPIO_SetBits(GPIOA, GPIO_Pin_4);GPIO_ResetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(Speed);}else{GPIO_ResetBits(GPIOA, GPIO_Pin_4);GPIO_SetBits(GPIOA, GPIO_Pin_5);PWM_SetCompare3(-Speed);}
}

GPIO_SetBits()和GPIO_ResetBits()用于设置电机正反转,PWM_SetCompare3函数用于设置电机速度。

在这里插入图片描述

4.4 主程序

主程序在while(1)主循环里通过获取按键按下的状态对电机进行调速,当速度超过100的时候反方向运行。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Motor.h"
#include "Key.h"uint8_t KeyNum;
int8_t Speed;int main(void)
{OLED_Init();Motor_Init();Key_Init();OLED_ShowString(1, 1, "Speed:");while (1){KeyNum = Key_GetNum();if (KeyNum == 1){Speed += 20;if (Speed > 100){Speed = -100;}}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1, 7, Speed, 3);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • UEFI启动流程
  • 《黑神话:悟空》到底是用什么语言开发的
  • 从0到1构建视频汇聚生态:EasyCVR视频汇聚平台流媒体协议支持的前瞻性布局
  • 依靠 VPN 生存——探索 VPN 后利用技术
  • 【Python】列表和元组
  • 两个独立的SpringBoot项目如何互相引用?
  • 20240824给飞凌OK3588-C的核心板刷Ubuntu22.04后适配SONY索尼的HDMI OUT的机芯8530
  • 【通俗易懂】限流、降级、熔断有什么区别?
  • C语言刷题日记(附详解)(2)
  • 防患未然:构建AIGC时代下开发团队应对突发技术故障与危机的全面策略
  • 代码随想录算法训练营day30 | 贪心算法 | 452.用最少数量的箭引爆气球、435.无重叠区间、763.划分字母区间
  • PostgreSQL SELECT 语句:深入解析与实例应用
  • vscode修改选中文字颜色及当前tab颜色
  • web前端之选项卡集合、动态添加类名、动态移除类名、动态添加样式、激活、间距、节流、tabBar
  • VS实用调试技巧
  • #Java异常处理
  • “大数据应用场景”之隔壁老王(连载四)
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • Android Studio:GIT提交项目到远程仓库
  • CentOS从零开始部署Nodejs项目
  • es6要点
  • git 常用命令
  • input实现文字超出省略号功能
  • java中具有继承关系的类及其对象初始化顺序
  • Laravel核心解读--Facades
  • Mybatis初体验
  • opencv python Meanshift 和 Camshift
  • Rancher-k8s加速安装文档
  • SpringBoot 实战 (三) | 配置文件详解
  • 日剧·日综资源集合(建议收藏)
  • 如何设计一个比特币钱包服务
  • 网络应用优化——时延与带宽
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 源码安装memcached和php memcache扩展
  • 正则表达式
  • 移动端高清、多屏适配方案
  • ​软考-高级-系统架构设计师教程(清华第2版)【第20章 系统架构设计师论文写作要点(P717~728)-思维导图】​
  • ​总结MySQL 的一些知识点:MySQL 选择数据库​
  • (1)无线电失控保护(二)
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (编译到47%失败)to be deleted
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (篇九)MySQL常用内置函数
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一) springboot详细介绍
  • (一)SpringBoot3---尚硅谷总结
  • .NET:自动将请求参数绑定到ASPX、ASHX和MVC(菜鸟必看)
  • .NET+WPF 桌面快速启动工具 GeekDesk
  • .Net各种迷惑命名解释
  • .NET开源、简单、实用的数据库文档生成工具
  • .net流程开发平台的一些难点(1)