Arduino UNO R3 使用L298N模块控制双路电机

效果:

https://weixin.qq.com/sph/AAt2I3ZAP

硬件接线参考:

L298N模块两边连接两个电机,输入12V与GND,5V输出不用连接

Arduino 5V 接JoyStick5V

Arduino GND 接L298N的GND及JoyStick的GND

Arduino VIN 接 电池输入12V 

A0,A1分别接JoyStick的JRX,JRY

Arduino 的4,5,6,7 分别接L298N 的IN4,IN3,IN2,IN1

Arduino 的9,10分别接L298N的ENA,ENB

公共点接入电源的正负极,橙色12V,黑色GND

Arduino USB连接电脑,用于写入控制程序

电池准备3个18650  3.7V的

通电写入程序后,JoyStick可控制电机前进,后退,左右转,停止

UNO_L298N_JOYSTICK.ino

/*
 * Arduino UNO + L298N + Joystick 控制双直流电机
 * 引脚配置(更新版):
 * 电机A:ENA=D9, IN1=D4, IN2=D5
 * 电机B:ENB=D10, IN3=D6, IN4=D7
 * 摇杆:VRx=A0, VRy=A1
 */

// ============= L298N引脚定义(更新) =============
// 电机A(左侧电机)
const int ENA = 9;     // PWM速度控制 - D9
const int IN1 = 4;     // 方向1 - D4
const int IN2 = 5;     // 方向2 - D5

// 电机B(右侧电机)  
const int ENB = 10;    // PWM速度控制 - D10
const int IN3 = 6;     // 方向1 - D6
const int IN4 = 7;     // 方向2 - D7

// ============= 摇杆引脚定义 =============
const int JOYSTICK_X = A0;  // X轴 - 左右转向
const int JOYSTICK_Y = A1;  // Y轴 - 前后移动
const int JOYSTICK_BUTTON = 2; // 摇杆按钮(可选)

// ============= 全局变量 =============
int xValue = 0;      // 摇杆X轴值 (0-1023)
int yValue = 0;      // 摇杆Y轴值 (0-1023)
int xMapped = 0;     // 映射后的X值 (-255到255)
int yMapped = 0;     // 映射后的Y值 (-255到255)

int deadZone = 15;   // 死区范围,防止摇杆微小漂移
int maxSpeed = 200;  // 最大速度(PWM值),锂电池11V建议不超过200

// ============= 初始化设置 =============
void setup() {
  Serial.begin(115200);
  
  // 设置L298N引脚为输出
  pinMode(ENA, OUTPUT);
  pinMode(ENB, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
  
  // 特别注意:D10需要设置PWM频率,防止电机啸叫
  // 调整PWM频率为31.25kHz(可选,如电机有噪音可启用)
  // setPWMFrequency10();
  
  // 设置摇杆按钮(如果使用)
  pinMode(JOYSTICK_BUTTON, INPUT_PULLUP);
  
  // 初始停止电机
  stopMotors();
  
  Serial.println("=== L298N + Joystick 控制系统 ===");
  Serial.println("引脚配置:");
  Serial.println("  电机A: ENA=9, IN1=4, IN2=5");
  Serial.println("  电机B: ENB=10, IN3=6, IN4=7");
  Serial.println("  摇杆: X=A0, Y=A1");
  Serial.println("摇杆控制说明:");
  Serial.println("  ↑ 向前推:前进");
  Serial.println("  ↓ 向后拉:后退");
  Serial.println("  ← 向左推:左转");
  Serial.println("  → 向右推:右转");
  Serial.println("  ○ 松开:停止");
  Serial.println("================================");
}

// ============= 主循环 =============
void loop() {
  // 1. 读取摇杆值
  readJoystick();
  
  // 2. 处理控制逻辑
  processJoystickControl();
  
  // 3. 检查摇杆按钮(紧急停止)
  checkJoystickButton();
  
  // 4. 显示调试信息(每秒显示一次)
  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 1000) {
    debugOutput();
    lastPrint = millis();
  }
  
  // 5. 小延迟稳定读取
  delay(15);
}

// ============= 摇杆读取函数 =============
void readJoystick() {
  // 读取原始值(多次采样取平均,减少噪声)
  int xSum = 0, ySum = 0;
  for (int i = 0; i < 3; i++) {
    xSum += analogRead(JOYSTICK_X);
    ySum += analogRead(JOYSTICK_Y);
    delay(2);
  }
  
  xValue = xSum / 3;
  yValue = ySum / 3;
  
  // 映射到-255到255范围
  // 注意:摇杆原始值中间位置通常是512,但不同摇杆可能不同
  xMapped = map(xValue, 0, 1023, 255, -255);  // 注意:有的摇杆需要反转
  yMapped = map(yValue, 0, 1023, -255, 255);  // Y轴:向前推是负值,向后拉是正值
  
  // 应用死区,防止微小漂移
  if (abs(xMapped) < deadZone) xMapped = 0;
  if (abs(yMapped) < deadZone) yMapped = 0;
}

// ============= 摇杆控制逻辑 =============
void processJoystickControl() {
  // 情况1:摇杆在中心位置 - 停止
  if (xMapped == 0 && yMapped == 0) {
    stopMotors();
    return;
  }
  
  // 计算速度和转向的合成
  int forwardSpeed = yMapped;  // Y轴控制前后
  int turnSpeed = xMapped;     // X轴控制转向
  
  // 差速转向计算
  int leftSpeed = forwardSpeed + turnSpeed;
  int rightSpeed = forwardSpeed - turnSpeed;
  
  // 限制最大速度
  int maxOutput = maxSpeed;
  leftSpeed = constrain(leftSpeed, -maxOutput, maxOutput);
  rightSpeed = constrain(rightSpeed, -maxOutput, maxOutput);
  
  // 控制电机
  controlMotorA(leftSpeed);
  controlMotorB(rightSpeed);
}

// ============= 电机控制函数 =============

// 控制电机A(左侧)
void controlMotorA(int speed) {
  speed = constrain(speed, -maxSpeed, maxSpeed);
  
  if (speed > 0) {
    // 正转
    digitalWrite(IN1, HIGH);
    digitalWrite(IN2, LOW);
    analogWrite(ENA, speed);
  } else if (speed < 0) {
    // 反转
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, HIGH);
    analogWrite(ENA, -speed);
  } else {
    // 停止
    digitalWrite(IN1, LOW);
    digitalWrite(IN2, LOW);
    analogWrite(ENA, 0);
  }
}

// 控制电机B(右侧)
void controlMotorB(int speed) {
  speed = constrain(speed, -maxSpeed, maxSpeed);
  
  if (speed > 0) {
    // 正转
    digitalWrite(IN3, HIGH);
    digitalWrite(IN4, LOW);
    analogWrite(ENB, speed);
  } else if (speed < 0) {
    // 反转
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, HIGH);
    analogWrite(ENB, -speed);
  } else {
    // 停止
    digitalWrite(IN3, LOW);
    digitalWrite(IN4, LOW);
    analogWrite(ENB, 0);
  }
}

// 简化控制函数(兼容旧代码)
void forward(int speedVal) {
  speedVal = constrain(speedVal, 0, maxSpeed);
  controlMotorA(speedVal);
  controlMotorB(speedVal);
}

void backward(int speedVal) {
  speedVal = constrain(speedVal, 0, maxSpeed);
  controlMotorA(-speedVal);
  controlMotorB(-speedVal);
}

void turnLeft(int speedVal) {
  speedVal = constrain(speedVal, 0, maxSpeed);
  controlMotorA(-speedVal);  // 左轮后退
  controlMotorB(speedVal);   // 右轮前进
}

void turnRight(int speedVal) {
  speedVal = constrain(speedVal, 0, maxSpeed);
  controlMotorA(speedVal);   // 左轮前进
  controlMotorB(-speedVal);  // 右轮后退
}

// 停止所有电机
void stopMotors() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
}

// 紧急刹车
void brakeMotors() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
  analogWrite(ENA, 255);  // 快速放电
  analogWrite(ENB, 255);
  delay(50);
  analogWrite(ENA, 0);
  analogWrite(ENB, 0);
}

// ============= 辅助函数 =============

// 检查摇杆按钮(紧急停止)
void checkJoystickButton() {
  if (digitalRead(JOYSTICK_BUTTON) == LOW) {
    Serial.println("[紧急停止] 摇杆按钮被按下!");
    brakeMotors();
    delay(1000);  // 锁定1秒防止误触
  }
}

// 调试信息输出
void debugOutput() {
  Serial.print("摇杆: X=");
  Serial.print(xValue);
  Serial.print("(");
  Serial.print(xMapped);
  Serial.print(")  Y=");
  Serial.print(yValue);
  Serial.print("(");
  Serial.print(yMapped);
  Serial.println(")");
  
  // 读取电机使能引脚状态(调试用)
  int enaState = digitalRead(ENA) ? 255 : 0;
  int enbState = digitalRead(ENB) ? 255 : 0;
  Serial.print("ENA:");
  Serial.print(enaState);
  Serial.print(" ENB:");
  Serial.println(enbState);
}

// 调整D10的PWM频率(减少电机噪音)
void setPWMFrequency10() {
  // 设置Timer1的PWM频率为31.25kHz(用于D9,D10)
  // 注意:这会影响millis()和delay()的精度
  TCCR1A = 0b00000001;  // 8位相位修正PWM
  TCCR1B = 0b00000001;  // 无预分频
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宏权实验室

有你的鼓励,我会更加努力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值