代码功能解释
这段代码是一个基于Arduino平台的控制程序,主要功能包括:
- 初始化:设置引脚模式、初始化编码器、舵机和EEPROM。
- 按键检测:处理按钮的单击、双击和长按事件,并根据事件执行相应操作。
- 编码器更新:检测旋转编码器的状态,调整变量值并控制LED闪烁。
- 舵机控制:根据设定的角度和速度移动舵机。
- LED控制:根据条件交替闪烁两个LED。
详细解释
-
初始化:
- 设置引脚模式为输入或输出。
- 初始化编码器、舵机和EEPROM。
-
主循环:
- 持续检测按键状态。
- 更新编码器状态。
- 控制舵机运动。
- 控制LED闪烁。
-
按键检测:
- 检查每个按钮的状态。
- 根据按键事件(长按、双击、单击)执行不同操作。
-
编码器更新:
- 检测编码器旋转方向。
- 根据旋转方向增加或减少变量值。
- 切换LED状态。
-
舵机控制:
- 根据设定的角度和速度移动舵机。
- 正向和反向移动舵机。
-
LED控制:
- 控制两个LED交替闪烁。
#include "Arduino.h"
#include <Bounce2.h>
#include <Servo.h>
#include <EEPROM.h>
// 定义引脚
#define EC11_A PB_2 // 编码器A
#define EC11_B PA_7 // 编码器B
#define BUTTON_1 PA_4 // 按钮1
#define BUTTON_2 PA_6 // 按钮2
#define PWM_1 PB_0 // PWM控制
#define LED_0 PA_0 // LED0
#define LED_1 PA_1 // LED1
// 定义常量
const unsigned long debounceTime = 50;
const unsigned long longPressTime = 1000;
const unsigned long doubleClickTime = 300;
const long led_interval = 300;
const int DEFAULT_START_ANGLE = 90;
const int DEFAULT_STEPS = 100;
// 定义变量
uint8_t fast_num = 1; // 运动速度
uint8_t fast_delta = 90; // 运动距离
uint8_t Count_step = 1; // 运动速度调节步进
bool Duoji_run_Flag = false;
bool CounterChanged = false;
int pos = 0;
int variableA = 0;
int variableB = 0;
bool isVariableA = true;
// 定义LED状态
bool led0State = LOW;
bool led1State = LOW;
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
bool led0Blinked = false;
bool led1Blinked = false;
// 定义按键状态结构体
struct ButtonState
{
int pin;
int lastState;
int currentState;
unsigned long lastDebounceTime;
unsigned long lastClickTime;
bool isLongPress;
bool isSingleClickHandled;
};
// 初始化按键状态
ButtonState button1 = {BUTTON_1, HIGH, HIGH, 0, 0, false, false};
ButtonState button2 = {BUTTON_2, HIGH, HIGH, 0, 0, false, false};
// 初始化Bounce对象
Bounce encoderPinAButton = Bounce();
Bounce encoderPinBButton = Bounce();
// 初始化Servo对象
Servo myservo;
// 宏定义调试输出
#define _DRV_TAG_ " line"
#define serial_dbg(fmt, args...) \
do \
{ \
if (1) \
{ \
Serial.printf("" _DRV_TAG_ "%d [%s] " fmt " \n", __LINE__, __FUNCTION__, ##args); \
} \
} while (0)
// 初始化函数
void setup()
{
Serial.begin(115200);
serial_dbg("Hello, Air001. \n");
// 设置LED引脚为输出模式
pinMode(LED_0, OUTPUT);
pinMode(LED_1, OUTPUT);
// 初始化LED状态为灭
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, LOW);
// 设置按键引脚为输入模式
pinMode(BUTTON_1, INPUT);
pinMode(BUTTON_2, INPUT);
// 初始化编码器
sys_RotaryInit();
// 初始化PWM频率和分辨率
pinMode(PWM_1, OUTPUT);
myservo.attach(PWM_1, 500, 2500); // 修正脉冲宽度
read_eeprom();//读数据
}
// 主循环函数
void loop()
{
checkButton(); // 检测按键
encoder_update(); // 更新编码器状态
duoji(); // 控制舵机
led_blink_once(); // 控制LED闪烁
}
void blinkLEDsAlternatingTwice() {
// 保存当前LED状态
bool savedLed0State = led0State;
bool savedLed1State = led1State;
// 交替闪烁两次
for (int i = 0; i < 2; i++) {
digitalWrite(LED_0, HIGH);
digitalWrite(LED_1, LOW);
delay(led_interval);
digitalWrite(LED_0, LOW);
digitalWrite(LED_1, HIGH);
delay(led_interval);
}
// 恢复LED状态
digitalWrite(LED_0, savedLed0State);
digitalWrite(LED_1, savedLed1State);
}
void write_eeprom() {
// 写入EEPROM
EEPROM.write(0, fast_num);
EEPROM.write(1, fast_delta);
// 写完EEPROM后两颗LED交替闪烁两次
blinkLEDsAlternatingTwice();
}
void read_eeprom() {
// 读取EEPROM
fast_num = EEPROM.read(0);
fast_delta = EEPROM.read(1);
if (fast_num == 0 || fast_delta == 0) {
fast_num = DEFAULT_START_ANGLE;
fast_delta = DEFAULT_STEPS;
write_eeprom();
}
serial_dbg("fast_num: %d, fast_delta: %d", fast_num, fast_delta);
}
// 初始化编码器
void sys_RotaryInit()
{
pinMode(EC11_A, INPUT);
pinMode(EC11_B, INPUT);
pinMode(BUTTON_1, INPUT_PULLUP);
encoderPinAButton.attach(EC11_A);
encoderPinAButton.interval(5);
encoderPinBButton.attach(EC11_B);
encoderPinBButton.interval(5);
}
// 检测按键状态
void checkButton()
{
checkButtonState(button1);
checkButtonState(button2);
}
// 处理按键状态
void checkButtonState(ButtonState &button)
{
int reading = digitalRead(button.pin); // 读取按钮状态
// 去抖动处理
if (reading != button.lastState)
{
button.lastDebounceTime = millis();
}
if ((millis() - button.lastDebounceTime) > debounceTime)
{
if (reading != button.currentState)
{
button.currentState = reading;
if (button.currentState == LOW)
{
button.lastClickTime = millis();
button.isLongPress = false;
button.isSingleClickHandled = false; // 新增标志位
}
else
{
unsigned long pressDuration = millis() - button.lastClickTime;
if (pressDuration > longPressTime)
{
button.isLongPress = true;
handleLongPress(button.pin);
}
else if (!button.isLongPress)
{
// 检查是否为双击
if ((millis() - button.lastClickTime) < doubleClickTime && !button.isSingleClickHandled)
{
if (digitalRead(button.pin) == HIGH)
{
handleDoubleClick(button.pin);
button.isSingleClickHandled = true; // 标记双击已处理
}
}
else if (!button.isSingleClickHandled)
{
// 如果不是双击,则处理单击事件
handleSingleClick(button.pin);
button.isSingleClickHandled = true;
}
}
}
}
}
button.lastState = reading;
}
// 处理长按事件
void handleLongPress(int pin)
{
switch (pin)
{
case BUTTON_1:
serial_dbg("Button 1 Long Press");
isVariableA = !isVariableA;
if (isVariableA)
{
digitalWrite(LED_1, LOW);
led1State = LOW;
serial_dbg("Switching to Variable A");
}
else
{
digitalWrite(LED_1, HIGH);
led1State = HIGH;
serial_dbg("Switching to Variable B");
}
break;
case BUTTON_2:
serial_dbg("Button 2 Long Press");
Duoji_run_Flag = true;
break;
default:
break;
}
}
// 处理双击事件
void handleDoubleClick(int pin)
{
switch (pin)
{
case BUTTON_1:
serial_dbg("Button 1 Double Click");
Duoji_run_Flag = true;
break;
case BUTTON_2:
serial_dbg("Button 2 Double Click");
break;
default:
break;
}
}
// 处理单击事件
void handleSingleClick(int pin)
{
switch (pin)
{
case BUTTON_1:
write_eeprom();
serial_dbg("Button 1 Single Click");
break;
case BUTTON_2:
serial_dbg("Button 2 Single Click");
Duoji_run_Flag = true;
break;
default:
break;
}
}
// 更新编码器状态
void encoder_update()
{
encoderPinAButton.update();
encoderPinBButton.update();
// 检测编码器旋转
if (encoderPinAButton.fell())
{
if (encoderPinBButton.read() == HIGH)
{
if (isVariableA)
{
variableA=fast_num;
variableA += Count_step; // 顺时针旋转
fast_num = variableA;
}
else
{
variableB = fast_delta;
variableB += Count_step; // 顺时针旋转
fast_delta = variableB;
}
}
else
{
if (isVariableA)
{
variableA=fast_num;
variableA -= Count_step; // 逆时针旋转
fast_num = variableA;
}
else
{
variableB = fast_delta;
variableB -= Count_step; // 逆时针旋转
fast_delta = variableB;
}
}
CounterChanged = true;
if (isVariableA)
{
serial_dbg("Variable A= %d ", variableA);
}
else
{
serial_dbg("Variable B= %d ", variableB);
}
led0Blinked = false;
led_blink_once();
}
}
// 控制舵机
void duoji()
{
if (Duoji_run_Flag)
{
int DEFAULT_END_ANGLE = fast_delta + DEFAULT_START_ANGLE;
Duoji_run_Flag = false;
unsigned long startTime = millis();
int totalTime = fast_num * 200;
// 正向移动
moveServo(DEFAULT_START_ANGLE, DEFAULT_END_ANGLE, DEFAULT_STEPS, startTime, totalTime);
startTime = millis();
// 反向移动
moveServo(DEFAULT_END_ANGLE, DEFAULT_START_ANGLE, DEFAULT_STEPS, startTime, totalTime);
}
}
// 移动舵机的辅助函数
void moveServo(int startAngle, int endAngle, int steps, unsigned long startTime, int totalTime)
{
unsigned long stepDuration = totalTime / steps;
float deltaAngle = (endAngle - startAngle) * 0.5;
for (int i = 0; i <= steps; i++)
{
float t = (float)i / steps;
int angle = startAngle + deltaAngle * (1 - cos(t * PI));
myservo.write(angle);
delay(totalTime / steps);
// 非阻塞延时
while (millis() - startTime < (i + 1) * stepDuration)
{
checkButton();
yield(); // 或者其他适合的多任务处理方法
}
}
}
// 控制LED闪烁
void led_blink_once()
{
unsigned long currentMillis = millis();
// 控制LED1闪烁一次
blinkLEDOnce(LED_0, led0State, previousMillis1, currentMillis, led_interval, led0Blinked);
// 控制LED2闪烁一次
blinkLEDOnce(LED_1, led1State, previousMillis2, currentMillis, led_interval, led1Blinked);
}
// 闪烁LED一次
void blinkLEDOnce(int pin, bool &state, unsigned long &previousMillis, unsigned long currentMillis, long led_interval, bool &blinked)
{
if (!blinked)
{
if (currentMillis - previousMillis >= led_interval)
{
previousMillis = currentMillis;
state = !state; // 切换LED状态
digitalWrite(pin, state);
if (state == LOW)
{
blinked = true; // 标记LED已经闪烁
}
}
}
}