前言
本篇将介绍电感摆放以及单片机stc32g12k128读取adc值的处理方案
一、电感摆放
对于负压电磁组,电感就相当于眼睛,是最重要的传感器,一个好的电感摆放方式将会十分有利于车模的控制。
我也查过往届取得优秀成绩的组别采用的电感摆放方式,最后确定为4电感循迹,3电感判断元素。电感摆放方式为三水平、两竖直、两内八,具体摆放位置如图:
其中最外两水平电感以及两竖直电感用来循迹,两内八电感和中间水平电感用来判断圆环以及坡道。
对于adc值的读取,提供3种方案,前面两种相似
(1)直接取均值
//-------------------------------------------------------------------------------------------------------------------
// @brief ADC均值滤波
// @param adcn 选择ADC通道
// @param count 采集次数
// @param resolution 分辨率
// @return void
// Sample usage: adc_mean_filter(ADC_P10, 10,ADC_10BIT);
//-------------------------------------------------------------------------------------------------------------------
uint16 adc_mean_filter(ADCN_enum adcn, uint8 count,ADCRES_enum resolution)
{
uint8 i;
uint16 adc_value = 0;
for (i = 0;i < count;i++)
{
adc_value += adc_once(adcn,resolution);
}
adc_value = adc_value / count;
return adc_value;
}
(2)去除最大值以及最小值取均值
//-------------------------------------------------------------------------------------------------------------------
// @brief ADC均值滤波去除最大值和最小值 默认精度为12位
// @param adcn 选择ADC通道
// @param count 采集次数
// @param resolution 分辨率
// @return void
// Sample usage: adc_mean_filter_remove_max_min(ADC_P10, 10,ADC_10BIT);
//-------------------------------------------------------------------------------------------------------------------
uint16 adc_mean_filter_remove_max_min(ADCN_enum adcn, uint8 count,ADCRES_enum resolution)
{
uint8 i;
uint16 adc_value = 0;
uint16 max = 0,min = 4096;
uint16 dat = 0;
for (i = 0;i < count + 2;i++)
{
dat = adc_once(adcn,resolution);//使用变量dat读取一次ADC即可,避免多次读取ADC
adc_value += dat;
if(max < dat)
max = dat;
if(min > dat)
min = dat;
}
adc_value = (adc_value - max - min)/ count;
return adc_value;
}
(3)滑动滤波
#define filter_n 3//数组长度
float adc_buf[7][filter_n + 1]={0};
uint8 adc_buf_flag[7] = {0};
/*
adcn:adc通道
resolution:精度
L_n:第几个电感
*/
uint16 adc_slid_filter(ADCN_enum adcn,ADCRES_enum resolution,uint8 L_n)
{
uint8 i;
uint16 filter_sum = 0;
adc_buf[L_n][filter_n] = adc_once(adcn,resolution);//放入最后一个位置
if(adc_buf_flag[L_n] < filter_n)//还没获取到filter_n个
{
adc_buf_flag[L_n] += 1;
for(i=0;i<filter_n;i++)
{
adc_buf[L_n][i] = adc_buf[L_n][i+1];//所有数据左移
adc_buf[L_n][i+1] = 0;//将i+1数据置为0,下一次循环会重新赋值
filter_sum += adc_buf[L_n][i];
}
return filter_sum / adc_buf_flag[L_n];
}
else
{
for(i=0;i<filter_n;i++)
{
adc_buf[L_n][i] = adc_buf[L_n][i+1];//所有数据左移
adc_buf[L_n][i+1] = 0;//将i+1数据置为0,下一次循环会重新赋值
filter_sum += adc_buf[L_n][i];
}
return filter_sum / filter_n;
}
}
对adc原始值做处理是为了避免噪声干扰,引起adc值变化较大。
二、电感归一化
归一化是为了让车模适应不同赛道,根据今年赛道来说,赛道上采出来的adc值比在平时跑的场地adc值会大不少,故归一化十分重要!!!
typedef struct
{
uint16 L_lsp_real; //左水平电感实际值
uint16 L_lsz_real; //左竖直电感实际值
uint16 L_lx_real; //左斜电感实际值
uint16 L_mid_real; //中间水平电感实际值
uint16 L_rx_real; //右斜电感实际值
uint16 L_rsz_real; //右竖直电感实际值
uint16 L_rsp_real; //右水平电感实际值
uint16 L_lsp_max;//左水平电感检测到的最大值
uint16 L_lsz_max;//左竖直电感检测到的最大值
uint16 L_lx_max;//左斜电感检测到的最大值
uint16 L_mid_max;//中间水平电感检测到的最大值
uint16 L_rx_max;//右斜电感检测到的最大值
uint16 L_rsz_max;//右竖直电感检测到的最大值
uint16 L_rsp_max;//右水平电感检测到的最大值
float L_lsp_once;//左水平电感一次归一化后
float L_lsz_once;//左竖直电感一次归一化后
float L_lx_once;//左斜电感一次归一化后
float L_mid_once;//中间水平电感一次归一化后
float L_rx_once;//右斜电感一次归一化后
float L_rsz_once;//右竖直电感一次归一化后
float L_rsp_once;//右水平电感一次归一化后
float L_lsp_twice;//左水平电感二次归一化后
float L_lsz_twice;//左竖直电感二次归一化后
float L_lx_twice;//左斜电感二次归一化后
float L_mid_twice;//中间水平电感二次归一化后
float L_rx_twice;//右斜电感二次归一化后
float L_rsz_twice;//右竖直电感二次归一化后
float L_rsp_twice;//右水平电感二次归一化后
}DG_state;
//滑动滤波
void Get_ADC_values_slid_filter(void)
{
dg_state.L_lsp_real = adc_slid_filter(L_lsp,ADC_12BIT,0);//10次滑动
dg_state.L_lsz_real = adc_slid_filter(L_lsz,ADC_12BIT,1);//10次滑动
dg_state.L_lx_real = adc_slid_filter(L_lx,ADC_12BIT,2);//10次滑动
dg_state.L_mid_real = adc_slid_filter(L_mid,ADC_12BIT,3);//10次滑动
dg_state.L_rx_real = adc_slid_filter(L_rx,ADC_12BIT,4);//10次滑动
dg_state.L_rsz_real = adc_slid_filter(L_rsz,ADC_12BIT,5);//10次滑动
dg_state.L_rsp_real = adc_slid_filter(L_rsp,ADC_12BIT,6);//10次滑动
}
void DG_Normal(void)
{
// Get_ADC_values_mean_filter();//均值获取电感值
Get_ADC_values_slid_filter();//滑动滤波获取电感值
//一次归一化
dg_state.L_lsp_once = ((float)dg_state.L_lsp_real) * 100 / dg_state.L_lsp_max;
dg_state.L_lsz_once = ((float)dg_state.L_lsz_real) * 100 / dg_state.L_lsz_max;
dg_state.L_lx_once = ((float)dg_state.L_lx_real) * 100 / dg_state.L_lx_max;
dg_state.L_mid_once = ((float)dg_state.L_mid_real) * 100 / dg_state.L_mid_max;
dg_state.L_rx_once = ((float)dg_state.L_rx_real) * 100 / dg_state.L_rx_max;
dg_state.L_rsz_once = ((float)dg_state.L_rsz_real) * 100 / dg_state.L_rsz_max;
dg_state.L_rsp_once = ((float)dg_state.L_rsp_real) * 100 / dg_state.L_rsp_max;
dg_state.L_lsp_once = constrain_float(dg_state.L_lsp_once,0,100);//限幅0-100
dg_state.L_lsz_once = constrain_float(dg_state.L_lsz_once,0,100);//限幅0-100
dg_state.L_lx_once = constrain_float(dg_state.L_lx_once,0,100);//限幅0-100
dg_state.L_mid_once = constrain_float(dg_state.L_mid_once,0,100);//限幅0-100
dg_state.L_rx_once = constrain_float(dg_state.L_rx_once,0,100);//限幅0-100
dg_state.L_rsz_once = constrain_float(dg_state.L_rsz_once,0,100);//限幅0-100
dg_state.L_rsp_once = constrain_float(dg_state.L_rsp_once,0,100);//限幅0-100
//二次归一化
dg_state.L_lsp_twice = dg_state.L_lsp_once;//处理待定
dg_state.L_lsz_twice = dg_state.L_lsz_once;//处理待定
dg_state.L_lx_twice = dg_state.L_lx_once;//处理待定
dg_state.L_mid_twice = dg_state.L_mid_once;//处理待定
dg_state.L_rx_twice = dg_state.L_rx_once;//处理待定
dg_state.L_rsz_twice = dg_state.L_rsz_once;//处理待定
dg_state.L_rsp_twice = dg_state.L_rsp_once;//处理待定
}
在程序中,出现了电感二次归一化的变量,该变量最开始想着需要对电感进行二次归一化,使电感值归一化计算偏差时,使得偏差线性,然而在实际测试时发现只需要一次归一化就可以,就没删。
至此adc读取以及处理完成,下一篇将介绍舵机方向控制。
十八届智能车负压电磁组(二):舵机方向控制篇