上一期我们介绍到使用AD5933实现对阻抗器件进行扫频得到器件阻抗曲线并显示到OLED显示屏上:
但是在这个板子的设计中,AD5933的反馈电阻是由数字电位器MCP4017来决定的:
在实际的使用中使用了MCP4017-104,最大电阻100K,即AD5933的反馈电阻最大100K。这个反馈电阻直接决定了AD5933的可测量阻抗范围。
因此本期我们在上一期的基础上,实现AD5933的自动化切换量程实现。
680K电阻
470K电阻
4.9K电阻
1000K电阻
1、代码实现
while (1){float sweep_ohm[80];float log_ratio = 1.0f;uint8_t sorted_indices[80];uint8_t median_index = 0;if (kSweepPoints > 1){log_ratio = powf(kSweepEndHz / kSweepStartHz, 1.0f / (kSweepPoints - 1));}for (uint8_t i = 0; i < kSweepPoints; i++){float current_freq = kSweepStartHz * powf(log_ratio, i);AD5933SetDDS(current_freq);AD5933Start(StartSweep);AD5933GetALL(Repeat);sweep_ohm[i] = ad5933data.R;ad5933data.SweepData[i].Frequency = current_freq;ad5933data.SweepData[i].Real = ad5933data.Real;ad5933data.SweepData[i].Imag = ad5933data.Imag;ad5933data.SweepData[i].R = ad5933data.R;sorted_indices[i] = i;}for (uint8_t i = 0; i < kSweepPoints - 1; i++){for (uint8_t j = i + 1; j < kSweepPoints; j++){if (sweep_ohm[sorted_indices[i]] > sweep_ohm[sorted_indices[j]]){uint8_t temp = sorted_indices[i];sorted_indices[i] = sorted_indices[j];sorted_indices[j] = temp;}}}median_index = sorted_indices[kSweepPoints / 2];float median_impedance = ad5933data.SweepData[median_index].R;float actual_rfb = (float)RfbLevels[RfbIndex] * (MCP4017_TOTAL_RES / MCP4017_STEPS);float min_measure_range = actual_rfb;float max_measure_range = actual_rfb * 10.0f;uint8_t need_rescan = 0;if (median_impedance > max_measure_range && RfbIndex < kRfbLevels - 1){RfbIndex++;need_rescan = 1;}elseif (median_impedance < min_measure_range && RfbIndex > 0){RfbIndex--;need_rescan = 1;}if (need_rescan){Rfb = RfbLevels[RfbIndex];MCP4017_SetWiper(Rfb);ad5933data.Rfb = Rfb;for (uint8_t i = 0; i < kSweepPoints; i++){float current_freq = kSweepStartHz * powf(log_ratio, i);AD5933SetDDS(current_freq);AD5933Start(StartSweep);AD5933GetALL(Repeat);sweep_ohm[i] = ad5933data.R;ad5933data.SweepData[i].Frequency = current_freq;ad5933data.SweepData[i].Real = ad5933data.Real;ad5933data.SweepData[i].Imag = ad5933data.Imag;ad5933data.SweepData[i].R = ad5933data.R;sorted_indices[i] = i;}for (uint8_t i = 0; i < kSweepPoints - 1; i++){for (uint8_t j = i + 1; j < kSweepPoints; j++){if (sweep_ohm[sorted_indices[i]] > sweep_ohm[sorted_indices[j]]){uint8_t temp = sorted_indices[i];sorted_indices[i] = sorted_indices[j];sorted_indices[j] = temp;}}}median_index = sorted_indices[kSweepPoints / 2];}ad5933data.SweepPointCount = kSweepPoints;ad5933data.MaxImpedanceIndex = median_index;ad5933data.Frequent = ad5933data.SweepData[median_index].Frequency;ad5933data.Real = ad5933data.SweepData[median_index].Real;ad5933data.Imag = ad5933data.SweepData[median_index].Imag;ad5933data.R = ad5933data.SweepData[median_index].R;UpdateSweepGraph(sweep_ohm, kSweepPoints, kSweepStartHz, kSweepEndHz);u8g2_FirstPage(&u8g2);do{MainGUI(&u8g2);} while (u8g2_NextPage(&u8g2));/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}
第一步,系统上电后,从7个预设档位中取第3档作为初始值。档位表是{5, 20, 35, 50, 65, 80, 100},这些数字是 MCP4017 数字电位器的抽头值,范围0到127。数字电位器总阻值是100kΩ,所以实际反馈电阻=抽头值 × (100kΩ / 127),初始档位35对应实际电阻约 27.6kΩ。
第二步,每轮主循环先做一次完整的80点对数扫频,频率从6kHz 覆盖到100kHz。每个频点调用AD5933GetALL 做3次采样取平均,得到阻抗值,存入sweep_ohm数组和 ad5933data.SweepData结构体中。
第三步,用冒泡排序对80个阻抗值从小到大排序,取出中位数。用中位数而不是平均值是为了避免个别频点的极端数值干扰判断。
第四步,根据当前实际反馈电阻值计算有效测量范围。下限=actual_rfb,上限=actual_rfb × 10。这是AD5933的特性决定的:反馈电阻决定了测量灵敏度,被测阻抗在Rfb到Rfb×10范围内时精度最好。
第五步,比较中位数阻抗和当前测量范围。如果中位数大于上限,且当前不是最高档,就把RfbInde 加 1,切换到更大的反馈电阻。如果中位数小于下限,且当前不是最低档,就把RfbIndex减 1,切换到更小的反馈电阻。如果不需要切换,就跳过重扫。
第六步,如果发生了档位切换,用新抽头值重新配置 MCP4017和ad5933data.Rfb,然后重新执行一遍完整的 80 点扫频,再排序取中位数。注意这里只重扫一次,如果重扫后仍然不在范围内,不会继续递归切档,要等到下一轮主循环。
第七步,把中位数对应的频率、实部、虚部、阻抗写入 ad5933data的显示字段,把80点数据传给 UpdateSweepGraph画曲线图,最后刷新OLED。
AD5933在0.8Rfb-10Rfb范围内都可以呈现线性范围,在这个范围之外精度就会呈现非线性。
Rfb改变时,这条直线的系数会发生改变,每个Rfb对应的直线系数P也是呈线性关系的
floatGetR(float Rfb, float Z){float P1 = 7428.0f * Rfb + 3580.0f;float R = P1 * Z;return R;}
因此可以实现在不同Rfb的情况下也可以精确的计算AD5933所测量的真实阻抗。
234