一、简介

上一节课主要学习了输出比较和PWM的基本原理和结构,本节课就主要以实践为主通过STM32最小系统板和驱动器控制舵机和直流电机。

上一节课的坐标 初学者STM32—输出比较与PWM-CSDN博客

二、舵机

舵机是一种根据输入PWM信号占空比来控制输出角度的装置

输入PWM信号要求:周期为20ms,对应50Hz,高电平宽度为0.5ms~2.5ms

根据上图所示,舵机内部是由直流电机驱动的,还有一个控制电路版,PWM输入某个信号,它就会以某种角度转动。根据最右边的图可知,我们这个舵机是180度的舵机,当给予的PWM脉冲信号不同宽度的时候就会以不同的角度进行旋转。舵机在很多领域都会用上,比如遥控车的转弯、机械臂的关节等等。

上图是舵机的电路结构,主要由三根线组成,电源、地线和PWM信号线

不同颜色的舵机接线:

第一种        黑色:GND        红色:+5V        黄色:信号线

第二种        棕色 :GND       红色:+5V        橙色:信号线

三、直流电机驱动

直流电机是一种将电能转换为机械能的装置,有两个电极,当电极正接时,电机正转,当电极反接时,电机反转

直流电机属于大功率器件,GPIO口无法直接驱动,需要配合电机驱动电路来操作

TB6612是一款双路H桥型的直流电机驱动芯片,可以驱动两个直流电机并且控制其转速和方向

我们通过看原理图:电机接O1和O2,当左上和右下形成两路推挽电路就会导通驱动电机旋转,当右上和左下两路导通的时候电机就以另一个方向旋转。 

 

上图为电机的驱动芯片和引脚定义图。我们可以通过引脚定义图知道如何输入信号控制电机。

根据定义图所示:PWM给与的信号按照一定频率的高低运行就能实现电机的运行而且还能根据电平的时间实现速读的变化。

注意:VM必须要和驱动电压一致        H:高电平        L:低电平

四、PWM控制舵机

时钟源连接着时基单元,我们通过配置好时基单元后计数器就会根据已经配置好的模式进行输出控制,前面讲过用输出控制寄存器配置,通过配置好的参考电平,使能时候就可以控制GPIO口输出相应的PWM了。

但是GPIO控制PWM的时候必须要配置成复用推挽输出,我们参考下图复用功能,当我们配置了复用推挽输出,输出数据寄存器就会断开,片上外设就能够连接上输出控制然后才能够输出PWM波形。

代码部分

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,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_7;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);	TIM_InternalClockConfig(TIM3);

首先第一步就是打开总线APB1和APB2,TIM3是在APB1中,GPIO在APB2中

配置GPIO,注意这里输出配置为复用推挽,上面说出了原因

开启GPIO_Pin_7(TIM3在PA7引脚)(后面要考)

开启TIM3的时基单元时钟

	TIM_TimeBaseInitTypeDef TIM_TimeBAseInitStructure;TIM_TimeBAseInitStructure.TIM_ClockDivision =TIM_CKD_DIV1;		//分频模式TIM_TimeBAseInitStructure.TIM_CounterMode =TIM_CounterMode_Up;		//计数模式向上计数TIM_TimeBAseInitStructure.TIM_Period =20000 - 1;		//重装器的值ARRTIM_TimeBAseInitStructure.TIM_Prescaler =72 - 1;		//预分频器的值PSCTIM_TimeBAseInitStructure.TIM_RepetitionCounter = 0;		//重复计数器的值TIM_TimeBaseInit(TIM3,&TIM_TimeBAseInitStructure);

然后配置时基单元 

这个配置按照平常配置,但是ARR和PSC必须要满足舵机运行的频率

PWM频率:  Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 50Hz

PWM占空比:  Duty = CCR / (ARR + 1)

PWM分辨率:  Reso = 1 / (ARR + 1)

这里设置的是20000的ARR 和 72的PSC,而后面的CCR的值是可变的,我设置为500到2500,这样占空比就能在0.005~0.025(对应高电平宽度0.5ms~2.5ms)满足舵机0~180度

	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_OC2Init(TIM3,&TIM_OCInitStructure);TIM_Cmd(TIM3,ENABLE);

然后配置输出比较的参数,同样也是用结构体配置的 

TIM_OCPolarity :极性选择为 高 ,当输出REF为高电平时就是高电平,反之

然后输出使能:TIM_OutputState_Enable

CCR:0(后面通过函数自己配置)

最后填入OC2Init中

由于我选择的是TIM3的通道2(CH2),所以配置的是OC2Init

 上图是通用定时器的部分结构,OC2Init中的OC2就是CH2通道,当然也可以选择其他通道,这里只是举个例子。因为每个通用定时器都能输出四路PWM。

void PWM_SetCompare2(uint16_t Compare)
{TIM_SetCompare2(TIM3,Compare);
}void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

TIM_SetCompare2这个函数也是因为用了OC2通道所以是TIM_SetCompare 而不是1或者其他

最后我们通过这个函数来填写CCR的值,其中Compare是一个变量,在500~2500之间,实现了舵机从0~180度的控制。

五、直流电机的控制

由于直流电机的控制和舵机控制相似,就省略讲解,但是也会重点讲解时基单元的配置和方向控制

时基单元的配置

	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);

PWM频率:  Freq = CK_PSC / (PSC + 1) / (ARR + 1) = 20KHz 

为什么要这个频率呢?因为频率太低当我们捂住电机的时候会发现有呜呜声,这样就会产生噪音。我们将频率提高到20KHz超出了让人耳能听到的频率就不会听到这个噪音。 

#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);	}
}

GPIO_SetBits置1        GPIO_ResetBits置0

他们分别连接TB6612的AO1和AO2,当参数speed大于0就是正转,小于0就是反转

六、完整代码(按键控制舵机)

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Servo.h"
#include "Key.h"uint8_t KeyNum;
float Angle;
int main(void)
{Key_Init();OLED_Init();Servo_Init();OLED_ShowString(1,1,"Angle:");while(1){KeyNum=Key_GetNum();if(KeyNum == 2){Angle+=30;if(Angle > 180){Angle = 0;}}Servo_SetAngle(Angle);OLED_ShowNum(1,7,Angle,3);}}

Servo.c

#include "stm32f10x.h"                  // Device header
#include "PWM.h"void Servo_Init(void)
{PWM_Init();
}
void Servo_SetAngle(float Angle)
{PWM_SetCompare2(Angle / 180 * 2000 + 500);
}

 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;		//CCR的值TIM_OC3Init(TIM2,&TIM_OCInitStructure);TIM_Cmd(TIM2,ENABLE);
}
void PWM_SetCompare3(uint16_t Compare)
{TIM_SetCompare3(TIM2,Compare);
}

PWM.h 

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

Servo.c 

#ifndef __SERVO_H
#define __SERVO_Hvoid Servo_Init(void);
void Servo_SetAngle(float Angle);#endif

Key.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
void Key_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;GPIO_Init(GPIOB,&GPIO_InitStructure);
}
uint8_t Key_GetNum(void)
{uint8_t KeyNum=0; if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)Delay_ms(20);KeyNum=1;}return KeyNum;
}

Key.h 

#ifndef __KEY_H
#define __KEY_Hvoid Key_Init(void);
uint8_t Key_GetNum(void);#endif

这段完整代码实现的效果:当按键按下的时候 舵机运动30度,加满180度的时候就会重新归位0度

七、完整代码(按键控制电机速度)

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)
{Key_Init();OLED_Init();Motor_init();OLED_ShowString(1,1,"Speed:");while(1){KeyNum=Key_GetNum();if(KeyNum == 1){Speed+=20;if(Speed>100)Speed=0;}Motor_SetSpeed(Speed);OLED_ShowSignedNum(1,7,Speed,3);}
}

  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);	}
}

 Motor.h

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

Key.c与Key.h和上面(按键控制舵机)的Key函数一样

最后实现的效果:按键每按一次,电机就会以百分之20的比例进行增速最后增到100,再次按下就会归零。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/89695.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/89695.shtml
英文地址,请注明出处:http://en.pswp.cn/web/89695.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中的异常处理机制:try-catch

一、基本概念 异常(Exception):程序执行过程中发生的非正常情况,比如除以零、访问越界、内存不足等。 异常处理(Exception Handling):对异常情况进行捕获、分析,并采取补救措施&…

如何从 Windows 11 或 10 远程访问 Ubuntu 24.04 或 22.04 桌面

了解如何使用 RDP(远程桌面协议)从 Windows 11 或 10 远程连接 Ubuntu 24.04 Noble 或 22.04 LTS Jammy JellyFish 桌面的步骤。 Windows 提供了一个便捷的功能,称为远程桌面连接,它使用 RDP 协议来远程连接 PC。当从 Windows 系统建立远程桌面连接时,使用起来非常简单,…

Linux 服务器中,Tab 键自动补全功能失效

在 Linux 服务器中,Tab 键自动补全功能失效通常与 bash-completion 组件缺失或配置异常有关。以下是解决问题的两个关键 YUM 指令及操作步骤:1. 安装 bash-completion 组件 sudo yum install -y bash-completion说明: bash-completion 是提供…

SpringBoot服装推荐系统实战

Spring Boot 服装推荐系统实例 以下是基于Spring Boot实现的服装推荐系统的30个实例代码示例,涵盖核心功能和实现方法。 用户注册与登录功能 @RestController @RequestMapping("/api/auth") public class AuthController {@Autowiredprivate UserService userSer…

WIN10系统优化篇(一)

你是否疑惑为什么别人家的电脑运行速度飞快,而自己的却卡顿难用?其实,很多时候 Windows 系统可以通过简单的优化措施来提升使用体验。本文根据项目实战多年对 Win10 优化经验,将帮你找出系统卡顿的原因,并给出针对性的…

Flutter状态管理篇之ChangeNotifier基础篇(一)

目录 前言 一、什么是ChangeNotifier 二、ChangeNotifier 的基本用法 三、结合Flutter UI 使用 四、结合 Provider 的高级用法 五、ChangeNotifier 的优势与注意事项 5.1 优势 5.2 注意事项 六、与 ValueNotifier 的比较 七、实际应用场景 八、总结 前言 在 Flutter…

react17更新哪些新特性

React 17 是一个“无新特性”的发布版本,它的主要目标是为未来的 React 版本打好基础,同时改善与旧版本共存和升级的体验。虽然没有引入新的开发者 API,但它在内部做了很多重要的改进。以下是 React 17 的核心更新内容和特性:&…

Unity 常见数据结构分析与实战展示 C#

Unity 常见数据结构分析与实战展示 提示:内容纯个人编写,欢迎评论点赞,来指正我。 文章目录Unity 常见数据结构分析与实战展示1. 引言2. Unity 数据结构概述3. 常见数据结构1. 数组(Array)2. 列表(List&…

【Linux网络编程】应用层协议 - HTTP

目录 初识HTTP协议 认识URL HTTP协议的宏观格式 Socket封装 TcpServer HttpServer 整体设计 接收请求 web根目录与默认首页 发送应答 完善页面 HTTP常见Header HTTP状态码 HTTP请求方法 cookie与session Connection 抓包 初识HTTP协议 应用层协议一定是基于…

技术演进中的开发沉思-36 MFC系列: 对话框

MFC这个章节里,不能忽视的是对话框的开发。如果把 MFC 程序比作一栋办公楼,那对话框就是「会客室」—— 它是程序与用户面对面交流的地方:用户在这里输入数据,程序在这里展示信息,彼此的互动都从这个空间开始。今天围绕…

(李宏毅)deep learning(五)--learning rate

一,关于learning rate的讨论:(1)在梯度下降的过程中,当我们发现loss的值很小的时候,这时我们可能以为gradident已经到了local min0(低谷),但是很多时候,loss很小并不是因…

pytorch:tensorboard和transforms学习

tensorboard:可视化数据 在anaconda安装: pip install tensorboard2.12.0最好使用这个版本 不然后面调用会报错 因为版本过高的原因 然后还碰到了安装的时候 安装到C盘去了 但是我用的虚拟环境是在E盘:此时去C盘把那些新安装的复制过来就好了 附录我C盘的…

常用的100个opencv函数

以下是OpenCV中最常用的100个函数及其作用与注意事项的全面整理,按功能模块分类,结合官方文档与工业实践优化排序。各函数均标注Python(cv2)和C(cv::)命名,重点参数以加粗突出: &…

【C++】红黑树,详解其规则与插入操作

各位大佬好,我是落羽!一个坚持不断学习进步的大学生。 如果您觉得我的文章有所帮助,欢迎多多互三分享交流,一起学习进步! 也欢迎关注我的blog主页: 落羽的落羽 一、红黑树的概念与规则 红黑树是一种更加特殊的平衡二…

Camera相机人脸识别系列专题分析之十七:人脸特征检测FFD算法之libhci_face_camera_api.so 296点位人脸识别检测流程详解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: Camera相机人脸识别系列专题分析之十七:人脸特征检测FFD算法之libhci_face_camera_api.so 296点位人脸识别检测流程详解 目录 一、背景 二、:FFD算法libhci_face_camera_api.s…

PostgreSQL 16 Administration Cookbook 读书笔记:第7章 Database Administration

编写一个要么完全成功要么完全失败的脚本 事务(transaction)可以实现all or nothing。不过这里指的是psql的-和--single-transaction选项。可以实现transaction wrapper: 此选项只能与一个或多个 -c 和/或 -f 选项组合使用。它会导致 psql 在…

DeepSeekMath:突破开源语言模型在数学推理中的极限

温馨提示: 本篇文章已同步至"AI专题精讲" DeepSeekMath:突破开源语言模型在数学推理中的极限 摘要 数学推理由于其复杂且结构化的特性,对语言模型构成了重大挑战。本文介绍了 DeepSeekMath 7B,该模型在 DeepSeek-Code…

实体类序列化报错:Caused by: java.lang.NoSuchMethodException: com.xx.PoJo$Item.<init>()

原实体类代码EqualsAndHashCode(callSuper true) Data public class Pojo extends BaseBean {private static final long serialVersionUID -4291335073882689552L;ApiModelProperty("")private Integer id;......private List<Item> list;AllArgsConstructo…

基于单片机病床呼叫系统/床位呼叫系统

传送门 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目速选一览表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品题目功能速览 概述 该系统是以单片机STM32F103为核心的基于无线网络的医院病房呼叫系统&#xff0c;分为从机和主机两…

[黑马头条]-登录实现思路

需求分析在黑马头条项目中&#xff0c;登录有两种方式&#xff1a;一种是用户输入账号密码后登录&#xff0c;这种方式登陆后的权限很大&#xff0c;可以查看&#xff0c;也可以进行其他操作&#xff1b;另一种方式就是用户点击不登录&#xff0c;以游客的身份进入系统&#xf…