跳到内容


本手册视频讲解链接指路 👇

【电赛速通教程! 不翻页! 一张图看懂!】

手册说明

对于不翻页速通手册Wiki的说明:

每页图片均有对应的B站视频碎碎念讲解和可复制的伪代码,或许可以帮你更快了解。如有问题欢迎讨论,该系列仍在更新,或许你还有想要补充的内容,欢迎在视频下评论,UP应该会一点一点填坑的 🥺

该系列中的伪代码都不可直接运行,但是你可以发给AI,再告诉他你的环境,可以帮你快速生成可执行的代码并且可以更细致地教会你 😊

祝各位学的开心、代码一编译就能运行~ 🤓

目录如下:

视频版本说明: https://www.bilibili.com/video/BV1Xp3Bz3EH8

功能篇

GPIO

https://www.bilibili.com/video/BV1uU3qzvEAr

json
// 示例伪代码
// 1. 设置GPIO为输出模式
pinMode(GPIO_PIN, OUTPUT);    // 设置为输出 

// 2. 更改输出电平
digitalWrite(GPIO_PIN, HIGH); // 输出高电平
delay(1000); // 延时1000ms
digitalWrite(GPIO_PIN, LOW);  // 输出底电平
go
// 示例伪代码
// 1. 设置GPIO为输入模式,并启用内部上拉电阻
setPinMode(GPIO_PIN, INPUT);       // 设为输入模式
setPullUp(GPIO_PIN);               // 启用上拉电阻
 
// 2. 读取引脚状态(默认HIGH,按下按钮接地变LOW)
if (readDigitalPin(GPIO_PIN) == LOW) {
        print("Valid Press!");     // 触发
    }
}

PWM

https://www.bilibili.com/video/BV1Dy3qzTEvi

java
// 示例伪代码
// 1. 初始化PWM(选择引脚、频率、分辨率)
pwmPin = GPIO_PIN_X;          // 选择支持PWM的引脚(如PA8/PIN9)
pwmFrequency = 1000;          // 设置PWM频率(Hz,如1kHz)
pwmResolution = 8;            // 设置分辨率(比特数,如8位=0~255)

setPinMode(pwmPin, PWM_OUTPUT); // 设置引脚为PWM输出模式 
initPWM(pwmPin, pwmFrequency, pwmResolution); // 初始化PWM硬件
 
// 2. 固定占空比(0%~100%对应0~最大值)
setPWMDutyCycle(pwmPin, 50);  // 设置占空比为50%
  
// 3. 动态占空比
while (1) {
    for (duty = 0; duty <= 100; duty += 10) {
        setPWMDutyCycle(pwmPin, duty);  // 渐变占空比(呼吸灯效果)
        delay(100);
    }
}

ADC

https://www.bilibili.com/video/BV1rP3BzWErg

go
// 示例伪代码
// 1. 配置ADC引脚为模拟输入
adc_configure_pin(PIN_A0);   // 设置A0为模拟输入
 
// 2. 初始化ADC硬件(自动使用默认设置)
adc_init();                  // 启用ADC
 
// 3. 读取一次原始值
raw_value = adc_read(PIN_A0); // 获取0-4095原始值
 
print("ADC值: %d", raw_value); // 直接输出结果

IRQ

https://www.bilibili.com/video/BV14mGEzjEan

javascript
// 示例伪代码
 
// 中断服务函数
void IRQ_Handler() {
    digitalToggle(LED);  // 中断触发时翻转LED
}
 
int main() {
    // 初始化部分
    pinMode(IRQ_PIN, INPUT);          // 设置中断引脚为输入
    setInterrupt(IRQ_PIN, RISING_EDGE, IRQ_Handler);  // 配置上升沿触发
    
    while(1) { /* 其他任务 */ }       // 主循环
}

Timer

https://www.bilibili.com/video/BV16FGJzMEiE

javascript
// 示例伪代码
 
// 中断服务函数
void Timer_IRQHandler() {
    digitalToggle(LED);  // 中断触发时翻转LED
}
 
// 主函数初始化
int main() {
    // 1. 初始化周期定时器(1ms中断)
    Timer_Init(TIM1, PERIODIC, 1000Hz);  // 1ms周期
    NVIC_SetIRQHandler(TIM1_IRQn, Timer_IRQHandler);
    
    // 或者2. 初始化超时定时器(3s单次中断)
    Timer_Init(TIM2, ONESHOT, 3000ms);
    NVIC_SetIRQHandler(TIM2_IRQn, Timer_IRQHandler);
        
    while(1);  // 所有操作由中断完成
}

UART

https://www.bilibili.com/video/BV1itGEzFEVY

javascript
// 示例伪代码
 
// 1.初始化
void UART_Init() {
    // 1. 配置TX/RX引脚(伪代码)
    pinMode(UART_TX_PIN, ALT_FUNC);  // 设为复用功能
    pinMode(UART_RX_PIN, ALT_FUNC);
    
    // 2. 核心参数配置
    uart_setup(port:1, baud:115200, data:8, parity:none, stop:1);
}
  
// 2.主函数,发送或接收UART数据
int main() {
    UART_Init();          // 初始化(含引脚)
    UART_Send("Hello");   // 发送
    char c = UART_Read(); // 接收
}

I2C

https://www.bilibili.com/video/BV1BpGEzYEm6

javascript
// 示例伪代码
void I2C_Init() {
    // 1. 配置I2C引脚(SCL/SDA)
    pinMode(I2C_SCL_PIN, ALT_FUNC_OPEN_DRAIN);  // 开漏输出
    pinMode(I2C_SDA_PIN, ALT_FUNC_OPEN_DRAIN);
    
    // 2. I2C参数配置
    i2c_setup(port:0, speed:400kHz);  // 标准模式(100kHz)或快速模式(400kHz)
}
  
int main() {
    I2C_Init();
    // 1. 向0x27地址的设备发送指令0xFE(示例:LCD清屏)
    I2C_WriteCommand(dev_addr:0x27, cmd:0xFE);
    // 2. 向0x68地址的设备读取6字节(示例:LCD清屏)
        I2C_Read_Reg(dev_addr:0x68, reg:0x3B, buf, len:6);
}

SPI

https://www.bilibili.com/video/BV1bkGEzSEMj

javascript
// 示例伪代码
void SPI_Init() {
    // 1. 配置SPI引脚(SCK/MOSI/MISO)
    pinMode(SPI_SCK_PIN, ALT_FUNC);   // 时钟线
    pinMode(SPI_MOSI_PIN, ALT_FUNC); // 主机输出
    pinMode(SPI_MISO_PIN, ALT_FUNC); // 主机输入
    
    // 2. 配置片选引脚(两个设备)
    pinMode(CS1_PIN, OUTPUT);  // 设备1片选
    pinMode(CS2_PIN, OUTPUT);  // 设备2片选
    digitalWrite(CS1_PIN, HIGH); // 初始不选中
    digitalWrite(CS2_PIN, HIGH);
    
    // 3. SPI参数配置
    spi_setup(port:0, mode:0, speed:1MHz); // 模式0,1MHz时钟
}
// ===== 发送指令 ===== //
void SPI_WriteCommand(uint8_t cs_pin, uint8_tcmd) {
    digitalWrite(cs_pin, LOW);    // 选中设备
    spi_write(cmd);               // 发送指令
    digitalWrite(cs_pin, HIGH);   // 释放设备
}
// ===== 读取数据 ===== //
void SPI_ReadData(uint8_t cs_pin, uint8_t reg, uint8_t *buf, uint8_tlen) {
    digitalWrite(cs_pin, LOW);
    spi_write(reg);              // 先发送寄存器地址
    spi_read(buf, len);          // 连续读取数据
    digitalWrite(cs_pin, HIGH);
}
 
int main() {
    SPI_Init();
    uint8_t data[6];
    
    // 1. 向设备1(CS1)发送指令0xFE
    SPI_WriteCommand(CS1_PIN, 0xFE);
    
    // 2. 从设备2(CS2)的0x3B寄存器读取6字节
    SPI_ReadData(CS2_PIN, 0x3B, data, 6);
}

模块篇

舵机

https://www.bilibili.com/video/BV1qCuMztET5

电机

https://www.bilibili.com/video/BV1jsuuz8EC6

电机编码器

https://www.bilibili.com/video/BV1h9uMzDEXP

javascript
// 示例伪代码
 
// 全局变量
volatile int count = 0;      // 编码器计数
volatile int speed = 0;      // 当前速度

// 中断服务函数:计数器更新
void IRQ_Handler() {
    // 根据A和B的状态进行计数
    if (A_edge == FALLING) {
        if (B == 0) {
            count++;  // B=0,加一
        } elseif (B == 1) {
            count--;  // B=1,减一
        }
    }
    else if (A_edge == RISING) {
        if (B == 1) {
            count++;  // B=1,加一
        } else if (B == 0) {
            count--;  // B=0,减一
        }
    }
    else if (B_edge == RISING) {
        if (A == 0) {
            count++;  // A=0,加一
        } else if (A == 1) {
            count--;  // A=1,减一
        }
    }
    else if (B_edge == FALLING) {
        if (A == 1) {
            count++;  // A=1,加一
        } else if (A == 0) {
            count--;  // A=0,减一
        }
    }
}
// 定时器中断服务函数:更新速度
void Timer_IRQHandler() {
    speed = count;  // 计算当前速度(单位为计数值)
    count = 0;  // 每次定时器中断时清零计数器
}
int main() {
    // 初始化部分
    pinMode(A_PIN, INPUT);      // 设置A引脚为输入
    pinMode(B_PIN, INPUT);      // 设置B引脚为输入
    // 配置A引脚为双沿触发
    setInterrupt(A_PIN, BOTH_EDGES, IRQ_Handler);   
   // 配置B引脚为双沿触发
    setInterrupt(B_PIN, BOTH_EDGES, IRQ_Handler);  
    Timer_Init(TIM1, PERIODIC, 100);  // 100ms周期定时器
    NVIC_SetIRQHandler(TIM1_IRQn, Timer_IRQHandler);  // 配置定时器中断处理函数
    while(1) { 
        // 主循环,处理其他任务    } 
}

TB6612电机驱动

https://www.bilibili.com/video/BV1R2uMzxEQm

L298N电机驱动

https://www.bilibili.com/video/BV1xKuuzkENh

带稳压的TB6612电机驱动

https://www.bilibili.com/video/BV1tFuuz2Ezs

TCRT5000 循迹传感器

https://www.bilibili.com/video/BV1bCuFzxEqK

HC-SR04 超声波测距传感器

https://www.bilibili.com/video/BV1LGucziEsL

SSD1306 OLED屏幕

https://www.bilibili.com/video/BV1PtuMzzEL8

c++
// 示例库函数代码
#include <Wire.h>               // I2C 库
#include <Adafruit_GFX.h>        // GFX 库
#include <Adafruit_SSD1306.h>    // SSD1306 显示器库
 
#define SCREEN_WIDTH 128         // OLED 显示宽度
#define SCREEN_HEIGHT 64         // OLED 显示高度
#define OLED_ADDR      0x3C      // I2C 地址,默认是 0x3C
#define OLED_RESET     -1        // 重置引脚 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);  // 创建 SSD1306 对象,使用 I2C
 
intmain(void) {
    // 初始化硬件
    Wire.begin();  // 初始化 I2C 总线
    display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);  // 初始化 SSD1306
    display.clearDisplay();  // 清空显示器
    display.setTextSize(1);       // 设置文字大小
    display.setTextColor(SSD1306_WHITE); // 设置文字颜色为白色
    delay(1000);  // 延时 1 秒
 
    while (1) {
        display.clearDisplay();  // 清空显示器
        display.setCursor(20, 10);    // 设置显示位置
        display.println("- LEO -");   // 显示文本
        display.display();  // 更新显示
        delay(200);  // 延时 200 毫秒
    }
}

MPU6050 六轴姿态传感器

https://www.bilibili.com/video/BV14WuMzGEh3

javascript
// 示例伪代码
// 1. 初始化部分
voidI2C_Init() {
    // 配置I2C引脚
    pinMode(I2C_SCL_PIN, ALT_FUNC_OPEN_DRAIN);
    pinMode(I2C_SDA_PIN, ALT_FUNC_OPEN_DRAIN);
    
    // I2C参数配置
    i2c_setup(port:0, speed:400kHz);  // 使用快速模式
}
 
// 2. 主程序
intmain() {
    I2C_Init();
    
    // 数据缓冲区
    uint8_traw_data[14];  // 14字节原始数据(6轴+温度)
    int16_t accel[3], gyro[3], temp;
    
    while(1) {
        // 从0x3B寄存器开始读取14字节数据
        I2C_Read_Reg(dev_addr:0x68, reg:0x3B, buf:raw_data, len:14);
        
        // 解析原始数据 (大端格式)
        accel[0] = (raw_data[0]<<8) | raw_data[1];  // X轴加速度
        accel[1] = (raw_data[2]<<8) | raw_data[3];  // Y轴加速度
        accel[2] = (raw_data[4]<<8) | raw_data[5];  // Z轴加速度
        temp     = (raw_data[6]<<8) | raw_data[7];  // 温度
        gyro[0]  = (raw_data[8]<<8) | raw_data[9];  // X轴角速度
        gyro[1]  = (raw_data[10]<<8)| raw_data[11]; // Y轴角速度
        gyro[2]  = (raw_data[12]<<8)| raw_data[13]; // Z轴角速度
        
        // 保存数据 (伪代码)
        save_to_storage(accel, gyro, temp);
        
        delay(10);  // 10ms采样间隔
    }
}

HC-05 蓝牙模块

https://www.bilibili.com/video/BV1byuFzRETX

算法篇

PID

https://www.bilibili.com/video/BV1yGuFz2EFA

java
// 示例伪代码
// 定义PID计算所需变量
float setpoint = 0;     // 目标设定值
float measured_value = 0; // 当前测量值
float error = 0;        // PID输入的误差值 = 目标值 - 测量值
float integral = 0;      // 误差积分项
float last_error = 0;    // 上次误差值
float Compensation = 0;  // PID输出的补偿值
float output = 0;       // 控制器输出
// PID系数(需根据实际系统调整)
float Kp = 1.0;         // 比例系数
float Ki = 0.01;        // 积分系数
float Kd = 0.1;         // 微分系数
// PID计算函数(需周期性调用)
void PID_Compute() {
    // 1. 计算当前误差
    error = setpoint - measured_value;
    // 2. 计算PID三项
    float proportional = Kp * error;         // 比例项:立即响应误差
    integral += Ki * error;                 // 积分项:消除稳态误差
    float derivative = Kd * (error - last_error); // 微分项:抑制超调
    // 3. 合成输出
    output = proportional + integral + derivative;
    // 4. 保存当前误差(用于下次微分计算)
    last_error = error;
    // 5. (可选)输出限幅
    if(output > max_output) output = max_output;
    if(output < min_output) output = min_output;
}
// 主函数
int main() {
    while(1) {
        measured_value = read_sensor();    // 获取传感器数据
        PID_Compute();                     // 计算控制量
        set_actuator(output,Compensation); // 输出控制信号
        delay(20);                         // 20ms控制周期
    }
}

互补滤波

https://www.bilibili.com/video/BV1fHuFz6EQX

java
// 示例伪代码
// 初始化
float angle = 0.0f;         // 初始角度估计值
constfloat alpha = 0.98f;   // 滤波系数
constfloat RAD_TO_DEG = 57.29578f;  // 弧度转角度
 
while(1) {
    // 1. 获取传感器数据(伪函数)
    floataccelY = read_accelY();  // Y轴加速度值
    floataccelZ = read_accelZ();  // Z轴加速度值  
    floatgyroX = read_gyroX();   // X轴角速度值
    float dt = 0.02f;             // 采样周期20ms
 
    // 2. 加速度计计算角度(低频)
    floataccelAngle = atan2f(accelY, accelZ) * RAD_TO_DEG;
 
    // 3. 陀螺仪计算角度变化(高频)
    floatgyroDelta = gyroX * dt;
 
    // 4. 互补滤波融合(核心计算)
    angle = alpha * (angle + gyroDelta) + (1.0f - alpha) * accelAngle;
 
    // 5. 使用最终角度(示例)
    set_actuator(angle);
 
    delay_ms(20);  // 保持固定采样周期
}

平滑滤波

www.bilibili.com/video/BV1nSf8BqESw

c++
// 示例伪代码
// 初始化 
float filteredValue = 0.0f; // 初始滤波值 u(t-1) 
const float alpha = 0.2f; // 滤波系数 α (0~1之间) 

while(1) {

 // 1. 获取当前时刻的原始采样数据(伪函数) 
float currentSample = read_sensor(); // 当前采样值 x(t) 
float dt = 0.02f; // 采样周期20ms 

// 2. EMA滤波核心计算 
// u(t) = α × x(t) + (1 - α) × u(t-1) 
filteredValue = alpha * currentSample + (1.0f - alpha) * filteredValue; 

// 3. 使用滤波后的值(示例) 
process_data(filteredValue); 

// 4. 为下一次迭代准备:u(t) 自动成为下一次的 u(t-1) 
delay_ms(20); 
// 保持固定采样周期
}

滑动窗口

https://www.bilibili.com/video/BV1HSf8BqEUj

c++
// 示例伪代码
// 循环数组定义
#define BUFFER_SIZE 6
int dataBuffer[BUFFER_SIZE];  // 数据缓冲区
int writeIndex = 0;           // 写入位置索引
int count = 0;                // 当前数据数量
 
// 每一次向循环数组存入新数据
void AddDataToBuffer(int newData) {
    // 将新数据存入当前写入位置
    dataBuffer[writeIndex] = newData;
    
    // 更新写入索引(循环)
    writeIndex = (writeIndex + 1) % BUFFER_SIZE;
    
    // 更新数据计数(不超过缓冲区大小)
    if (count < BUFFER_SIZE) {
        count++;
    }
}

状态机

https://www.bilibili.com/video/BV1kSf8BqEAd/

c++
// 示例伪代码
// 状态定义:
// 0=初始化(S0), 1=第一次按下(S1), 2=第一次释放(S2), 3=第二次按下(S3) 
int state = 0; // 事件处理函数 
// 输入参数:eventType - 0表示按下事件,1表示释放事件 。
// 定时中断50ms触发  
void KeyFSM_HandleEvent(int eventType) { 
  switch(state) { 
      case 0: // S0状态 - 初始化 
          if (eventType == 0) { // 按下事件 
              printf("已按下\n"); 
                state = 1; 
          } 
      break; 
      case 1: // S1状态 - 第一次按下 
          if (eventType == 1) { // 释放事件 
              state = 2; // 此时开始记录施放时间 releaseTime
              } 
      break; 
      case 2: // S2状态 - 第一次释放
          if (eventType == 0) { // 按下事件 
              printf("双击\n"); 
              state = 3; 
              } 
          else if (releaseTime >= 500) { // 超过规定间隔500ms
              printf("单击\n"); 
              state = 0; 
              } 
      break; 
      case 3: // S3状态 - 第二次按下 
          if (eventType == 1) { // 释放事件 
              state = 0; 
          } 
      break; 
  }
}