概述:
本篇文章主要讲述在第一篇中代码程序的详细解释,包含各段代码的功能及作用,以方便大家能够更好的了解并分析代码的用途。
一.总代码程序
// 定义左右轮脉冲计数器和时间标记
int leftCounter = 0, rightCounter = 0;
unsigned long time = 0, old_time = 0; // 时间标记,用于计算速度
unsigned long time1 = 0; // 时间标记,用于其他计时功能
float lv, rv; // 左、右轮速度
// 定义运动控制命令
#define STOP 0
#define FORWARD 1
#define BACKWARD 2
#define TURNLEFT 3
#define TURNRIGHT 4
#define CHANGESPEED 5
// 定义电机引脚
int leftMotor1 = 2;
int leftMotor2 = 3;
int rightMotor1 = 4;
int rightMotor2 = 5;
bool speedLevel = 0; // 速度档位,0表示低速,1表示高速
// 定义PWM引脚
int leftPWM = 9;
int rightPWM = 10;
void setup() {
// 初始化串口通信,波特率为9600
Serial.begin(9600);
// 设置外部中断0,当引脚0电平从高到低变化时触发RightCount_CallBack函数
attachInterrupt(0, RightCount_CallBack, FALLING);
// 设置外部中断1,当引脚1电平从高到低变化时触发LeftCount_CallBack函数
attachInterrupt(1, LeftCount_CallBack, FALLING);
// 设置电机引脚为输出模式
pinMode(leftMotor1, OUTPUT);
pinMode(leftMotor2, OUTPUT);
pinMode(rightMotor1, OUTPUT);
pinMode(rightMotor2, OUTPUT);
// 设置PWM引脚为输出模式
pinMode(leftPWM, OUTPUT);
pinMode(rightPWM, OUTPUT);
}
void loop() {
// 调用速度检测函数
SpeedDetection();
// 如果串口有数据可读
if (Serial.available() > 0) {
// 读取蓝牙模块发送到串口的数据
int cmd = Serial.read();
// 如果接收到的数据不是换行符,则进行控制
if (cmd != 10) {
// 打印接收到的命令
Serial.print(cmd - 48);
// 根据命令控制小车运动
motorRun(cmd - 48);
}
// 如果当前是高速档位
if (speedLevel) {
// 设置左右轮PWM值为120,对应较低速度
analogWrite(leftPWM, 120);
analogWrite(rightPWM, 120);
} else {
// 设置左右轮PWM值为250,对应较高速度
analogWrite(leftPWM, 250);
analogWrite(rightPWM, 250);
}
}
}
// 速度计算函数
bool SpeedDetection() {
// 获取当前时间(毫秒)
time = millis();
// 如果计时时间达到1秒
if (abs(time - old_time) >= 1000) {
// 关闭外部中断0和1
detachInterrupt(0);
detachInterrupt(1);
// 计算左右轮转速(转/分钟),并打印到串口
lv = (float)leftCounter * 60 / 20;
rv = (float)rightCounter * 60 / 20;
Serial.print("left:");
Serial.print(lv);
Serial.print(" right:");
Serial.println(rv);
// 重置左右轮脉冲计数器,记录当前时间,重新开启外部中断0和1
leftCounter = 0;
rightCounter = 0;
old_time = millis();
attachInterrupt(0, RightCount_CallBack, FALLING);
attachInterrupt(1, LeftCount_CallBack, FALLING);
return 1;
} else {
return 0;
}
}
// 右轮编码器中断服务函数,当引脚0电平从高到低变化时触发,增加右轮脉冲计数器
void RightCount_CallBack() {
rightCounter++;
}
// 左轮编码器中断服务函数,当引脚1电平从高到低变化时触发,增加左轮脉冲计数器
void LeftCount_CallBack() {
leftCounter++;
}
// 小车运动控制函数,根据命令控制小车运动状态
void motorRun(int cmd) {
switch (cmd) {
case FORWARD:
Serial.println("FORWARD");
// 设置电机引脚电平,使小车前进
digitalWrite(leftMotor1, HIGH);
digitalWrite(leftMotor2, LOW);
digitalWrite(rightMotor1, HIGH);
digitalWrite(rightMotor2, LOW);
break;
case BACKWARD:
Serial.println("BACKWARD");
// 设置电机引脚电平,使小车后退
digitalWrite(leftMotor1, LOW);
digitalWrite(leftMotor2, HIGH);
digitalWrite(rightMotor1, LOW);
digitalWrite(rightMotor2, HIGH);
break;
case TURNLEFT:
Serial.println("TURN LEFT");
// 设置电机引脚电平,使小车左转
digitalWrite(leftMotor1, HIGH);
digitalWrite(leftMotor2, LOW);
digitalWrite(rightMotor1, LOW);
digitalWrite(rightMotor2, HIGH);
break;
case TURNRIGHT:
Serial.println("TURN RIGHT");
// 设置电机引脚电平,使小车右转
digitalWrite(leftMotor1, LOW);
digitalWrite(leftMotor2, HIGH);
digitalWrite(rightMotor1, HIGH);
digitalWrite(rightMotor2, LOW);
break;
case CHANGESPEED:
Serial.println("CHANGE SPEED");
// 切换速度档位
if (speedLevel)
speedLevel = 0;
else
speedLevel = 1;
break;
default:
Serial.println("STOP");
// 停止所有电机
digitalWrite(leftMotor1, LOW);
digitalWrite(leftMotor2, LOW);
digitalWrite(rightMotor1, LOW);
digitalWrite(rightMotor2, LOW);
}
}
二.代码分段解释
1.第一段
// 定义左右轮脉冲计数器和时间标记
int leftCounter = 0, rightCounter = 0;
unsigned long time = 0