逐飞 K60 电感测量 AD 值方法

发布时间 2023-03-28 15:12:31作者: 滑稽果

2019 年我参加的一个智能车小项目里的代码,今天共享出来以便于我后期回顾。

程序使用逐飞库

智能小车通过电感测量地面电磁线,得出 AD 值,通常会再将 AD 值交给 PID 进行运算,从而控制舵机的转向运行,闭环控制在本文这里暂时不谈。

本项目使用了四个电感,安装位置分别为小车左侧水平放置、左侧垂直放置、右侧水平放置、右侧垂直放置。如下俯视图(请忽略我糟糕的绘图技能/doge)

img

首先需要初始化相关变量以及电感:

#define ADCNUM 3      // 测量的电感值的数量
#define INDUCTNUM 4   // 电感的数量

uint16 adcVal[4];     // 通过电感测量得到的 AD 值
uint32 adcSumVal[4];  // 通过电感测量得到的 AD 值的总和
uint32 adcAverVal[4][ADCNUM];  // 通过电感测量得到的 AD 值的平均
uint16 adcFirst[5], adcSecond[5];  // 通过计算,最终得出的可用的水平的两个电感 AD 值
uint16 adcThird[5], adcFourth[5];  // 通过计算,最终得出的可用的垂直的两个电感 AD 值,用于 90°弯
uint16 adc[4];        // 通过计算,最终得出的可用的 AD 值

// AD 初始化
void AdcInit(void) {

    adc_init(ADC0_SE8);     // B0
    adc_init(ADC0_SE9);     // B1
    adc_init(ADC0_SE12);    // B2
    adc_init(ADC0_SE13);    // B3

}

初始化完成后,电感开始测量 AD 值,所以我们需要将 AD 值读取出来。由于环境的不可控性,导致采集的某些 AD 值可能会有较多的突变,所以为了防止程序产生误判,在 AD 值采集出来后需要立即进行滤波:

// 读取电感测出的 AD 的值
void AdcRead(void) {

    int16 i = 0, j = 0, k = 0, _exc = 0;
    uint16 _adcVal[4][5];   // 读取电感的 AD 值(局部变量)
    uint32 _adcSumVal[4];   // 电感 AD 值的总和(局部变量)
    uint32 _adcAverVal[4];  // 电感 AD 值的平均(局部变量)

    for(i = 0; i < 5; i++) {

        _adcVal[0][i] = adc_once(ADC0_SE8, ADC_16bit);      // ADC0 通道,水平左电感
        _adcVal[1][i] = adc_once(ADC0_SE9, ADC_16bit);      // ADC0 通道,水平右电感
        _adcVal[2][i] = adc_once(ADC0_SE12, ADC_16bit);     // ADC0 通道,垂直左电感
        _adcVal[3][i] = adc_once(ADC0_SE13, ADC_16bit);     // ADC0 通道,垂直右电感
    }

    // 冒泡排序,使值按照从小到大进行排序
    for(i = 0; i < INDUCTNUM; i++) {
        for(j = 0; j < 4; j++) {
            for(k = 0; k < 4-j; k++) {

                // 如果当前的值比下一个值大,则这两个值进行交换
                if(_adcVal[i][k] > _adcVal[i][k+1]) {
                    _exc = _adcVal[i][k+1];
                    _adcVal[i][k+1] = _adcVal[i][k];
                    _adcVal[i][k] = _exc;
                }
            }
        }
    }

    // 删除五个值中的最大值和最小值,取中间三项值求出总和以及平均值
    for(i = 0; i < INDUCTNUM; i++) {
        _adcSumVal[i] = _adcVal[i][1] + _adcVal[i][2] + _adcVal[i][3];
        _adcAverVal[i] = _adcSumVal[i] / 3;
    }

    // 将计算出来的平均值赋值给全局变量,以利于后面使用
    for(i = 0; i < INDUCTNUM; i++) {
        adcAverVal[i][ADCNUM-1] = _adcAverVal[i];
    }

    // 滑动平均滤波,过滤浮动较大的 AD 值
    for(i = 0; i < ADCNUM-1; i++) {
        adcAverVal[0][i] = adcAverVal[0][i + 1];
        adcAverVal[1][i] = adcAverVal[1][i + 1];
        adcAverVal[2][i] = adcAverVal[2][i + 1];
        adcAverVal[3][i] = adcAverVal[3][i + 1];
    }

    // 计算四个电感的 AD 总和
    for(i = 0; i < ADCNUM; i++) {

        adcSumVal[0] += adcAverVal[0][i];
        adcSumVal[1] += adcAverVal[1][i];
        adcSumVal[2] += adcAverVal[2][i];
        adcSumVal[3] += adcAverVal[3][i];
    }

    // 通过 AD 总和值求出平均值
    for(i = 0; i < INDUCTNUM; i++) {

        adcVal[i] = adcSumVal[i] / ADCNUM;
        adcSumVal[i] = 0;
    }
}

AD 值采集出来后,仍旧不能直接使用,需要再次进行计算:

// 计算电感测出的 AD 值,得出最终可用的 AD 值
void AdcCalc(void) {

    AdcRead();      // 读取电感测出的 AD 的值

    // 计算左边 水平 电感的值
    adcFirst[0] = adcFirst[1];
    adcFirst[1] = adcFirst[2];
    adcFirst[2] = adcFirst[3];
    adcFirst[3] = adcFirst[4];
    adcFirst[4] = adcVal[0];
    adc[0] = ( adcFirst[0] + adcFirst[1] + \
        adcFirst[2] + adcFirst[3] + adcFirst[4] ) / 5;

    // 计算右边 水平 电感的值
    adcSecond[0] = adcSecond[1];
    adcSecond[1] = adcSecond[2];
    adcSecond[2] = adcSecond[3];
    adcSecond[3] = adcSecond[4];
    adcSecond[4] = adcVal[1];
    adc[1] = ( adcSecond[0] + adcSecond[1] + \
        adcSecond[2] + adcSecond[3] + adcSecond[4] ) / 5;

    // 计算左边 垂直 电感的值
    adcThird[0] = adcThird[1];
    adcThird[1] = adcThird[2];
    adcThird[2] = adcThird[3];
    adcThird[3] = adcThird[4];
    adcThird[4] = adcVal[2];
    adc[2] = ( adcThird[0] + adcThird[1] + \
        adcThird[2] + adcThird[3] + adcThird[4] ) / 5;

    // 计算右边 垂直 电感的值
    adcFourth[0] = adcFourth[1];
    adcFourth[1] = adcFourth[2];
    adcFourth[2] = adcFourth[3];
    adcFourth[3] = adcFourth[4];
    adcFourth[4] = adcVal[3];
    adc[3] = ( adcFourth[0] + adcFourth[1] + \
        adcFourth[2] + adcFourth[3] + adcFourth[4] ) / 5;
}

最终得出的 adc[x] 就是我们需要的电感值。