逐飞 K60 电感测量 AD 值方法
2019 年我参加的一个智能车小项目里的代码,今天共享出来以便于我后期回顾。
程序使用逐飞库
智能小车通过电感测量地面电磁线,得出 AD 值,通常会再将 AD 值交给 PID 进行运算,从而控制舵机的转向运行,闭环控制在本文这里暂时不谈。
本项目使用了四个电感,安装位置分别为小车左侧水平放置、左侧垂直放置、右侧水平放置、右侧垂直放置。如下俯视图(请忽略我糟糕的绘图技能/doge)
首先需要初始化相关变量以及电感:
#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] 就是我们需要的电感值。