【滑动平均滤波】

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

映射

映射函数的主要作用是将一个数值从一个范围转换到另一个范围。在您的摇杆项目中,这个函数非常重要,因为它能够将摇杆的原始模拟输入(这些输入可能因设备而异且具有不同的输入范围)标准化到一个统一的数字输出范围内。
映射函数的数学原理:
函数通常表达为:
在这里插入图片描述
其中:

  • x 是原始的输入值。
  • in_min 和 in_max分别是输入值的最小和最大可能值。
  • out_min 和 out_max 分别是输出值的最小和最大范围。
    这个公式的作用是首先计算输入值 𝑥 在其原始范围内的相对位置,然后将这个相对位置转换到目标范围。

边界检查:
为了防止异常值和数据溢出,映射函数中加入了边界检查:

  • 如果x小于in_min,则将x设置为in_min
  • 如果x大于in_max,则将x设置为in_max
// 映射函数
uint16_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
    if (x < in_min) {
        x = in_min;
    }
    if (x > in_max) {
        x = in_max;
    }
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

读取中心点

// 自动读取摇杆中心点
void CalibrateJoystickCenter(void) {
    uint32_t sumX = 0, sumY = 0;
    
    for (int i = 0; i < SAMPLE_COUNT; i++) {
        sumX += HW504_R_X();
        sumY += HW504_R_Y();
        Delay_ms(10);  // 适当延时以获取更稳定的读数
    }
    
    X_CENTER = sumX / SAMPLE_COUNT;
    Y_CENTER = sumY / SAMPLE_COUNT;
}

滑动平均滤波处理

滑动平均滤波是一种常用的数字滤波技术,用于减少数据中的随机变异(噪声),从而获得更加平滑的数据输出。它的工作原理是连续取样本的平均值,每次包括最新的样本并丢弃最早的样本。

滑动平均的计算步骤:
1、将新的输入值加入到一个固定长度的缓冲区(数组)中。
2、缓冲区满后,最旧的数据将被新数据替代。
3、计算缓冲区内所有数据的平均值。
4、返回这个平均值作为滤波后的结果。
代码实现:
在代码中,MovingAverageFilter函数实现了上述逻辑。通过一个循环数组来存储最近的 FILTER_LEN个数据点。索引 filter_index 用于追踪最新数据应该存放的位置。每次调用该函数时,都会计算当前缓冲区内所有值的平均数,并将其作为滤波后的结果返回。

// 滑动平均滤波处理
uint16_t MovingAverageFilter(uint16_t *buffer, int len, uint16_t newValue) {
    buffer[filter_index] = newValue;
    filter_index = (filter_index + 1) % len;
    
    uint32_t sum = 0;
    for (int i = 0; i < len; i++) {
        sum += buffer[i];
    }
    return sum / len;
}

代码

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "HW504.h"

#define DEAD_ZONE 50
#define SAMPLE_COUNT 100  // 用于中心点校准的样本数
#define FILTER_LEN 10     // 滑动平均滤波器长度

uint16_t X_CENTER, Y_CENTER;
uint16_t X, Y;
uint8_t SW;
uint16_t filter_buffer_X[FILTER_LEN] = {0};
uint16_t filter_buffer_Y[FILTER_LEN] = {0};
int filter_index = 0;

// 映射函数
uint16_t map(uint16_t x, uint16_t in_min, uint16_t in_max, uint16_t out_min, uint16_t out_max) {
    if (x < in_min) {
        x = in_min;
    }
    if (x > in_max) {
        x = in_max;
    }
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// 自动读取摇杆中心点
void CalibrateJoystickCenter(void) {
    uint32_t sumX = 0, sumY = 0;
    
    for (int i = 0; i < SAMPLE_COUNT; i++) {
        sumX += HW504_R_X();
        sumY += HW504_R_Y();
        Delay_ms(10);  // 适当延时以获取更稳定的读数
    }
    
    X_CENTER = sumX / SAMPLE_COUNT;
    Y_CENTER = sumY / SAMPLE_COUNT;
}

// 滑动平均滤波处理
uint16_t MovingAverageFilter(uint16_t *buffer, int len, uint16_t newValue) {
    buffer[filter_index] = newValue;
    filter_index = (filter_index + 1) % len;
    
    uint32_t sum = 0;
    for (int i = 0; i < len; i++) {
        sum += buffer[i];
    }
    return sum / len;
}

// 读取并处理摇杆值
void ReadJoystick(void) {
    int rawX = HW504_R_X();
    int rawY = HW504_R_Y();
    SW = HW504_R_SW();
    
    // 对X轴应用死区和映射
    if (abs(rawX - X_CENTER) < DEAD_ZONE) {
        X = 2048;  // 死区内默认值,设置为新范围的中点
    } else {
        X = map(MovingAverageFilter(filter_buffer_X, FILTER_LEN, rawX), 8, 4080, 0, 4095);
    }

    // 对Y轴应用死区和映射
    if (abs(rawY - Y_CENTER) < DEAD_ZONE) {
        Y = 2048;  // 死区内默认值,设置为新范围的中点
    } else {
        Y = map(MovingAverageFilter(filter_buffer_Y, FILTER_LEN, rawY), 8, 4080, 0, 4095);
    }
}

int main(void) {
    OLED_Init();
    HW504_Init();
    CalibrateJoystickCenter();  // 在初始化时自动校准摇杆中心点
    
    OLED_ShowString(1, 1, "X:");
    OLED_ShowString(2, 1, "Y:");
    OLED_ShowString(3, 1, "SW:");
    
    while (1) {
        ReadJoystick();
        
        OLED_ShowNum(1, 3, X, 5);
        OLED_ShowNum(2, 3, Y, 5);
        OLED_ShowNum(3, 5, SW, 1);
        
        Delay_ms(100);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值