掌握驱动之道:L298N模块多方式驱动电机的优劣分析

news2024/9/22 13:39:06

L298N模块是一种常用的直流电机驱动模块,它可以通过控制输入端口来实现对电机的速度和方向的控制。L298N模块有3个输入端口:IN1、IN2和EN。

方法一:使用高级定时器输出通道和互补输出通道控制电机 将模块的IN1和IN2分别连接到STM32高级定时器输出通道引脚和互补输出通道引脚,通过配置定时器的输出通道和互补输出通道的PWM大小来控制电机的速度和方向。将一个普通的GPIO引脚连接到模块的EN端口来控制电机的制动和启动。

下面是使用STM32的HAL库来配置定时器和GPIO引脚的代码示例:

#include "stm32f4xx_hal.h"

// 定义L298N模块的引脚
#define IN1_Pin GPIO_PIN_0
#define IN1_GPIO_Port GPIOA
#define IN2_Pin GPIO_PIN_1
#define IN2_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_2
#define EN_GPIO_Port GPIOA

// 定义定时器和互补输出通道
#define TIM_PWM TIM_CHANNEL_1
#define TIM_COMPLEMENTARY PWM_CHANNEL_2

// 配置定时器和GPIO引脚
void MX_TIM_Config(void)
{
  // 定时器初始化
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Init.Prescaler = 0;
  htim.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim.Init.Period = 1000;
  htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim.Init.RepetitionCounter = 0;
  htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  HAL_TIM_PWM_Init(&htim);

  // GPIO引脚初始化
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin = IN1_Pin | IN2_Pin | EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 控制电机的速度和方向
void motorControl(uint16_t speed)
{
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Channel = TIM_PWM;

  // 设置PWM输出通道的比例,控制电机的速度
  HAL_TIM_PWM_Start(&htim, TIM_PWM);
  HAL_TIM_PWM_SetValue(&htim, TIM_PWM, speed);

  // 设置互补输出通道,控制电机的方向
  HAL_TIMEx_PWMN_Start(&htim, TIM_COMPLEMENTARY);
  HAL_TIMEx_PWMN_SetValue(&htim, TIM_COMPLEMENTARY, 100 - speed);
}

// 控制电机的启动和停止
void motorStartStop(uint8_t enable)
{
  GPIO_PinState state = enable ? GPIO_PIN_SET : GPIO_PIN_RESET;
  HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, state);
}


该方法的优点是可以精确控制电机的速度和方向,缺点是需要使用高级定时器和互补输出通道,占用了宝贵的硬件资源。适用于需要精确控制电机的应用场景。

方法二:使用通用定时器控制电机 将模块的IN1和IN2分别连接到STM32通用定时器的两个输出通道引脚,通过配置定时器的这两个输出通道的PWM大小来控制电机的速度和方向。同样,将一个普通的GPIO引脚连接到模块的EN端口来控制电机的制动和启动。

#include "stm32f4xx_hal.h"

// 定义L298N模块的引脚
#define IN1_Pin GPIO_PIN_0
#define IN1_GPIO_Port GPIOA
#define IN2_Pin GPIO_PIN_1
#define IN2_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_2
#define EN_GPIO_Port GPIOA

// 定义定时器和输出通道
#define TIM_PWM TIM_CHANNEL_1

// 配置定时器和GPIO引脚
void MX_TIM_Config(void)
{
  // 定时器初始化
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Init.Prescaler = 0;
  htim.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim.Init.Period = 1000;
  htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim.Init.RepetitionCounter = 0;
  htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  HAL_TIM_PWM_Init(&htim);

  // GPIO引脚初始化
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin = IN1_Pin | IN2_Pin | EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 控制电机的速度
void motorSpeedControl(uint16_t speed)
{
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Channel = TIM_PWM;

  // 设置PWM输出通道的比例,控制电机的速度
  HAL_TIM_PWM_Start(&htim, TIM_PWM);
  HAL_TIM_PWM_SetValue(&htim, TIM_PWM, speed);
}

// 控制电机的方向
void motorDirectionControl(uint8_t direction)
{
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;

  // 停止对应的PWM信号,控制电机的方向
  if (direction == 0) {
    HAL_TIM_PWM_Stop(&htim, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1);
  } else {
    HAL_TIM_PWM_Stop(&htim, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_2);
  }
}

// 控制电机的启动和停止
void motorStartStop(uint8_t enable)
{
  GPIO_PinState state = enable ? GPIO_PIN_SET : GPIO_PIN_RESET;
  HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, state);
}


方法二可以通过停止对应的PWM信号来控制电机的方向,通过调用motorDirectionControl()函数,
传入0表示正向运动,1表示反向运动。同时,使用motorSpeedControl()函数来控制电机的速度,通过改变PWM的占空比来调节电机的转速。最后,使用motorStartStop()函数来启动或停止电机,传入1表示启动电机,传入0表示停止电机。

这种方法的优点是使用通用定时器控制电机,灵活性较高,可以同时控制电机的速度和方向。适用于需要精确控制电机运动的应用场景。

方法三:将模块的IN1和IN2分辨链接到STM32的普通GPIO引脚来控制电机的运转方向和启动、停止,将模块的EN端口连接到定时器的PWM端口来控制电机的速度,该控制方法的编程代码解析如下:

下面是使用STM32的HAL库来配置GPIO引脚的代码示例:

#include "stm32f4xx_hal.h"

// 定义L298N模块的引脚
#define IN1_Pin GPIO_PIN_0
#define IN1_GPIO_Port GPIOA
#define IN2_Pin GPIO_PIN_1
#define IN2_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_2
#define EN_GPIO_Port GPIOA

// 定义定时器和PWM通道
#define TIM_PWM TIM_CHANNEL_1

// 配置GPIO引脚
void MX_GPIO_Config(void)
{
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin = IN1_Pin | IN2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 控制电机的速度
void motorSpeedControl(uint16_t speed)
{
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Channel = TIM_PWM;

  // 设置PWM输出通道的比例,控制电机的速度
  HAL_TIM_PWM_Start(&htim, TIM_PWM);
  HAL_TIM_PWM_SetValue(&htim, TIM_PWM, speed);
}

// 控制电机的方向和启动停止
void motorDirectionControl(uint8_t direction, uint8_t enable)
{
  GPIO_PinState state1 = direction ? GPIO_PIN_SET : GPIO_PIN_RESET;
  GPIO_PinState state2 = enable ? GPIO_PIN_SET : GPIO_PIN_RESET;

  HAL_GPIO_WritePin(IN1_GPIO_Port, IN1_Pin, state1);
  HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, state2);
}

该方法的优点是简单易实现,缺点是无法精确控制电机的速度和方向。适用于简单的电机控制应用场景。

方法四:就是将IN1链接到定时器的PWM通道引脚上,将IN2链接到一个普通的GPIO端口上,控制IN2端口的电平就可以控制电机方向,控制IN1上的PWM信号就可以控制电机的速度,控制EN端口的电平就可以控制到电机的启动、停止,只是电机控制控制在两个方向上的PWM的表达不一致,在IN2为低电平的正方向上PWM大速度就高,而在IN2为低电平的反方向运转则是PWM小速度高,
方法四中,将IN1连接到定时器的PWM通道引脚上,通过改变PWM的占空比来控制电机的速度。将IN2连接到一个普通的GPIO端口上,通过改变IN2引脚的电平来控制电机的方向。同时,使用EN引脚来控制电机的启动和停止。

#include "stm32f4xx_hal.h"

// 定义L298N模块的引脚
#define IN1_Pin GPIO_PIN_0
#define IN1_GPIO_Port GPIOA
#define IN2_Pin GPIO_PIN_1
#define IN2_GPIO_Port GPIOA
#define EN_Pin GPIO_PIN_2
#define EN_GPIO_Port GPIOA

// 定义定时器和PWM通道
#define TIM_PWM TIM_CHANNEL_1

// 配置定时器和GPIO引脚
void MX_TIM_Config(void)
{
  // 定时器初始化
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Init.Prescaler = 0;
  htim.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim.Init.Period = 1000;
  htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim.Init.RepetitionCounter = 0;
  htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  HAL_TIM_PWM_Init(&htim);

  // GPIO引脚初始化
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin = IN1_Pin | EN_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = IN2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}

// 控制电机的速度
void motorSpeedControl(uint16_t speed , uint8_t direction)
{
  TIM_HandleTypeDef htim;

  htim.Instance = TIM1;
  htim.Channel = TIM_PWM;

  // 设置PWM输出通道的比例,控制电机的速度
  HAL_TIM_PWM_Start(&htim, TIM_PWM);
  uint16_t speed_ = direction ? speed :100 - speed ; 
  HAL_TIM_PWM_SetValue(&htim, TIM_PWM, speed);
}

// 控制电机的方向
void motorDirectionControl(uint8_t direction)
{
  GPIO_PinState state = direction ? GPIO_PIN_SET : GPIO_PIN_RESET;
  HAL_GPIO_WritePin(IN2_GPIO_Port, IN2_Pin, state);
}

// 控制电机的启动和停止
void motorStartStop(uint8_t enable)
{
  GPIO_PinState state = enable ? GPIO_PIN_SET : GPIO_PIN_RESET;
  HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, state);
}

该方法的优点是可以通过一个普通的GPIO引脚来控制电机的方向,同时使用定时器的PWM通道来控制电机的速度。相对于方法二而言,方法四减少了一个PWM通道的使用,并且方向控制更加直观和灵活。缺点是需要对PWM信号与方向的控制进行特殊的映射,需要根据具体需求来调整PWM占空比和方向控制的规则。

适用场景分析: 方法四适用于需要控制电机方向和速度的应用场景,且对PWM通道的资源需求较高的情况下,例如需要控制多个电机的时候。同时,方法四也适用于对控制精度要求不高的场景,例如一些简单的机械运动控制。

综上所述,不同的链接方式和驱动方法适用于不同的应用场景。方法一可以精确控制电机的速度和方向,适用于需要精细控制的应用场景;方法二适用于需要精确控制电机运动的应用场景。方法三简单易实现,适用于简单的电机控制应用场景。根据具体需求选择合适的方法来驱动电机。方法四也适用于对控制精度要求不高的场景,例如一些简单的机械运动控制。
 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python GUI编程利器:Tkinker中的事件处理(11)

​ 小朋友们好,大朋友们好! 我是猫妹,一名爱上Python编程的小学生。 和猫妹学Python,一起趣味学编程。 今日目标 学习下事件处理的相关知识点: 事件处理四要素 事件序列 事件绑定 今天要实现如下效果&#xff1…

Java在Excel中进行数据分析

摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前一段时间淘宝出了一个“淘宝人生”的模块,可以看从注册淘宝账号至今的消…

k8s实战3-使用Helm在AKS上发布应用

AKS(Azure Kubenetes Service)是微软云azure上的K8s服务。 主要分为三步 1 连接到AKS 2 用kubectl发布应用 3 用Helm发布应用 1 登录 az login 2 连接dp-npr-dsm-aks(Dsm项目的AKS) az account set --subscription {{subID}} az aks get-credent…

指针的进阶(一)

目录 1. 字符指针 方法一 方法二 字符指针面试题 2. 指针数组 3. 数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 4. 数组传参和指针传参 4.1 一维数组传参 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 5. 函数指针 代码一 代…

Windows用户怎么取消访问共享文件夹的密码

许多Windows系统用户在访问共享文件夹的时候却提示需要输入密码才可访问。这一步给很多人造成了困扰,其实我们可以取消访问共享文件夹密码。请看下面的两个方法。 方法一: 搜索 网络和共享中心。点击 更改高级共享设置。在最底下密码保护的共享那项&…

用C#写汉诺塔问题

假设要将n个圆盘从A->C,中间可以借助B,那么递归思路是这样的,我们先将除最大的一个圆盘外的其它n-1个圆盘从A->B,借助C,然后将最大的一个圆盘搬到C,最后将刚才的n-1个盘子,从B->C借助A&#xff0c…

Qt完成闹钟提示

未启动: 启动: .cpp #include "widget.h" #include "ui_widget.h"void Widget::btn1_slots() {//点击启动开始定时event_timer this->startTimer(1000);btn1->setEnabled(false);btn2->setEnabled(true);edit2->setEnabled(false…

一个月学通Python(十三):高级Python必须掌握的进阶知识点

专栏介绍 结合自身经验和内部资料总结的Python教程,每天3章,1个月就能全方位的完成Python的学习并进行实战开发。加油吧!卷起来! 全部文章请访问专栏:《Python全栈教程(0基础》 文章目录 专栏介绍Python语言进阶1. 数据结构和算法2. 函数的使用方式3. 面向对象相关知识…

Todo-List案例版本五

安装库npm i pubsub-js 消息的订阅与发布 src/App.vue <template><div class"app"><h1>{{ msg }}</h1><School/><Student/></div> </template><script> import Student from ./components/Student import …

微信小程序常用组件的简单使用 view,scroll-view,swiper,swiper-item,text,rich-text,button,image

微信小程序常用组件的简单使用 1. view组件2. scroll-view 组件3. swiper 和 swiper-item 组件3.1. swiper组件中的常用属性 4. text 和 rich-text组件4.1. text组件4.2. rich-text 组件 5. button 组件6. image组件6.1. image的mode属性 1. view组件 view组件就类似于html中的…

问题总结(持续更新,欢迎补充)

文章目录 前言webshell流量特征内存马蜜罐应急响应Windows 事件ID如何是误报还是攻击&#xff08;如何判断是否攻击成功&#xff09;研判的思路渗透测试思路内网渗透相关溯源反制反序列化&#xff08;Shiro、Weblogic、Log4j&#xff09;CDNMySQL5.5版本以上和以下读写权限的区…

linux 系统errno 对应参考及代码

结论 linux下系统errno都有对应的说明描述&#xff0c;发生错误时获取errno即可知道具体问题描述 如下图 代码如下 golang版 package main import ("syscall""strings""fmt" ) func main() {for i : 0; i < 200; i {if !strings.HasPrefi…

【开源项目】自动化运维平台spug

Spug 基本介绍 Spug是面向中小型企业设计的轻量级无Agent的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、应用发布部署、在线任务计划、配置中心、监控、报警等一系列功能。 批量执行: 主机命令在线批量执行在线终端: 主机支持浏览器在线终端登录…

为什么技术牛逼的人,不能直接提为项目经理?

早上好&#xff0c;我是老原。 很多来私信我职业规划的小友&#xff0c;有很大一部分都是从事了大几年&#xff0c;10年的技术开发大佬…… 到这个层级的大佬&#xff0c;他们最大的困惑是&#xff1a;到我这个年纪/级别还有必要转管理吗&#xff1f; 是否有必要&#xff0c…

X6 基于VUE流程编辑器开发

先看效果图 主要插件X6 x6-vue-shape antv/x6-plugin-dnd 代码太多没有整理出来

个人云服务器搭建MQTT服务器

个人云服务器搭建MQTT服务器 文章目录 个人云服务器搭建MQTT服务器1️⃣ 前言2️⃣ EMQX部署 1️⃣ 前言 MQTT &#x1f449;MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;即消息队列遥测传输协议 • 是一个轻量的发布订阅模式消息传输协议&#xff0c;专门…

leetcode140. 单词拆分 II 记忆化DFS

https://leetcode.cn/problems/word-break-ii 给定一个字符串 s 和一个字符串字典 wordDict &#xff0c;在字符串 s 中增加空格来构建一个句子&#xff0c;使得句子中所有的单词都在词典中。以任意顺序 返回所有这些可能的句子。 注意&#xff1a;词典中的同一个单词可能在分…

趣谈拜占庭将军问题

拜占庭将军问题&#xff08;The Byzantine Generals Problem&#xff09;&#xff0c;它其实是借拜占庭将军的故事展现了分布式共识问题&#xff0c;还探讨和论证了解决的办法。而大多数人觉得它难理解&#xff0c;除了因为分布式共识问题比较复杂之外&#xff0c;还与莱斯利兰…

【C++ OJ练习】6.验证回文串

1.题目链接 力扣 2.解题思路 字母全部要变成小写 并且不能管空格和标点 这样从前和后分别遍历并进行比较 如果遇到不是相同 字符的话 说明不是回文串 就这样一直往下走 直到最后两下标相遇 那么就是回文串 注意双循环条件 3.代码 class Solution { public://除去标点和空…

【如何在深度学习的道路上越走越远?——《深度学习模式与实践》】

作为近几年人工智能领域的主要研究方向之一&#xff0c;深度学习主要通过构建深度卷积神经网络和采用大量样本数据作为输入&#xff0c;最终得到一个具有强大分析能力和识别能力的模型。深度学习可以是有监督的、半监督的或无监督的。深度学习架构(例如深度神经网络、深度信念网…