1. 项目概述
这个基于STM32的RLC测量仪项目,是我在调试电路板时经常需要测量元器件参数而萌生的想法。市面上的LCR表动辄上千元,而实际工作中我们往往只需要基础测量功能。于是我用STM32F103C8T6这款性价比极高的单片机,配合NE555振荡电路,实现了一个成本不到百元但足够实用的RLC测量方案。
整套系统包含以下几个核心模块:
- STM32F103C8T6最小系统板(主控)
- LCD1602液晶显示屏(显示测量结果)
- NE555多谐振荡电路(参数-频率转换)
- HC-05蓝牙模块(无线数据传输)
- 按键和LED指示灯(人机交互)
这个设计的巧妙之处在于利用NE555将被测元件的参数值转换为频率信号,再由STM32通过测量频率反推出元件参数。相比直接测量法,这种方法硬件简单、成本低,且能达到不错的测量精度。
2. 硬件设计详解
2.1 核心电路设计
2.1.1 NE555振荡电路
这是整个设计的核心转换电路。我采用了经典的NE555多谐振荡器配置,通过切换不同的外围元件连接方式,使其可以分别测量电阻、电容和电感。
对于电阻测量,电路工作在单稳态模式:
code复制 +Vcc
|
R1
|
555 Pin7--+--[被测电阻Rx]--GND
电容测量采用无稳态模式:
code复制 +Vcc
|
R1
|
555 Pin7--+--[被测电容Cx]--GND
电感测量则使用LC振荡模式:
code复制 +Vcc
|
R1
|
555 Pin7--+--[Lx]--[Cref]--GND
实测表明,这种设计在指定量程内线性度良好。需要注意的是,NE555的供电电压要稳定,我使用了AMS1117-5.0稳压芯片,确保供电电压波动不影响测量结果。
2.1.2 STM32频率测量
STM32通过输入捕获功能测量NE555输出的方波频率。具体配置如下:
- 使用TIM2的Channel1作为输入捕获通道
- 配置为上升沿触发
- 72MHz主频下,预分频设置为71,得到1MHz的计数频率
- 通过捕获两个上升沿之间的计数值计算频率
测量代码关键部分:
c复制void TIM2_IRQHandler(void) {
if(TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET) {
static uint32_t lastCapture = 0;
uint32_t currentCapture = TIM_GetCapture1(TIM2);
if(lastCapture != 0) {
uint32_t period = (currentCapture > lastCapture) ?
(currentCapture - lastCapture) :
(0xFFFF - lastCapture + currentCapture);
measuredFreq = 1000000.0f / period; // 转换为Hz
}
lastCapture = currentCapture;
}
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
}
2.2 量程设计与校准
2.2.1 电阻测量(100Ω-1MΩ)
电阻测量采用单稳态模式,振荡周期公式为:
T = 1.1 × R × C
其中C使用固定值0.1μF的陶瓷电容。通过测量周期T,可以反推出R值。量程切换通过改变参考电阻R1实现:
- 100Ω-1kΩ档:R1=100Ω
- 1kΩ-10kΩ档:R1=1kΩ
- 10kΩ-1MΩ档:R1=10kΩ
2.2.2 电容测量(100pF-10000pF)
电容测量采用无稳态模式,振荡频率公式为:
f = 1.44 / ((R1 + 2×R2) × C)
固定R1=1kΩ,R2=10kΩ,通过测量频率反推C值。小电容测量时需要注意PCB的寄生电容影响,我通过将测试端子做成弹簧夹形式减少分布电容。
2.2.3 电感测量(100μH-10mH)
电感测量采用LC振荡模式,谐振频率公式为:
f = 1 / (2π√(L×C))
使用0.1μF的参考电容,通过测量频率反推L值。实测发现当电感小于50μH时精度下降明显,因此将下限设为100μH。
校准技巧:准备一组精度1%的标准元件,在代码中建立频率-参数对照表,通过线性插值提高测量精度。我使用了10个校准点,实测精度可达±3%。
2.3 蓝牙无线传输设计
采用HC-05蓝牙模块实现数据无线传输,硬件连接非常简单:
- VCC → 5V
- GND → GND
- TXD → PA10 (USART1_RX)
- RXD → PA9 (USART1_TX)
STM32端配置USART1为115200波特率,每500ms发送一次当前测量数据:
c复制void sendBluetoothData(void) {
char buffer[32];
switch(currentMode) {
case MODE_RESISTOR:
sprintf(buffer, "R:%.2f%s\n", resValue, resUnit);
break;
case MODE_CAPACITOR:
sprintf(buffer, "C:%.2f%s\n", capValue, capUnit);
break;
case MODE_INDUCTOR:
sprintf(buffer, "L:%.2f%s\n", indValue, indUnit);
break;
}
USART_SendData(USART1, (uint8_t*)buffer, strlen(buffer));
}
手机端可以使用任意蓝牙串口APP接收数据,我推荐"Serial Bluetooth Terminal"这款免费应用,界面简洁且支持数据记录功能。
3. 软件设计实现
3.1 主程序流程
系统软件采用状态机设计,主循环处理流程如下:
flow复制st=>start: 系统初始化
op1=>operation: 读取按键状态
cond1=>condition: 模式切换?
op2=>operation: 更新LED指示
op3=>operation: 频率测量
op4=>operation: 参数计算
op5=>operation: LCD显示更新
op6=>operation: 蓝牙数据发送
e=>end: 循环执行
st->op1->cond1
cond1(yes)->op2->op3
cond1(no)->op3
op3->op4->op5->op6->op1
3.2 关键算法实现
3.2.1 数字滤波处理
由于NE555输出频率可能存在微小波动,我采用了移动平均滤波算法:
c复制#define FILTER_SIZE 5
float filterBuffer[FILTER_SIZE];
uint8_t filterIndex = 0;
float applyFilter(float newValue) {
filterBuffer[filterIndex] = newValue;
filterIndex = (filterIndex + 1) % FILTER_SIZE;
float sum = 0;
for(int i=0; i<FILTER_SIZE; i++) {
sum += filterBuffer[i];
}
return sum / FILTER_SIZE;
}
3.2.2 量程自动切换
为提高测量精度,软件实现了自动量程切换功能:
c复制void autoRangeSelection(void) {
switch(currentMode) {
case MODE_RESISTOR:
if(resValue < 1000) { // <1kΩ
setReferenceResistor(100);
} else if(resValue < 10000) { // 1k-10kΩ
setReferenceResistor(1000);
} else { // >10kΩ
setReferenceResistor(10000);
}
break;
// 电容和电感量程切换逻辑类似...
}
}
3.3 用户界面设计
3.3.1 LCD1602显示布局
LCD显示分为两行,第一行显示测量模式和单位,第二行显示测量值:
code复制RESISTOR MODE Ω
Value: 4.72k
通过以下函数更新显示:
c复制void updateLCD(void) {
LCD_SetCursor(0,0);
switch(currentMode) {
case MODE_RESISTOR:
LCD_Printf("RESISTOR MODE ");
LCD_PutChar(0xFF); // 显示Ω符号
break;
// 其他模式类似...
}
LCD_SetCursor(0,1);
LCD_Printf("Value: ");
switch(currentMode) {
case MODE_RESISTOR:
if(resValue >= 1000) {
LCD_Printf("%.2fk", resValue/1000);
} else {
LCD_Printf("%.0f", resValue);
}
break;
// 其他模式类似...
}
}
3.3.2 按键与LED指示
三个按键分别对应三种测量模式切换,同时点亮相应颜色的LED:
- KEY1(PA0):电阻模式 → 红色LED
- KEY2(PA1):电容模式 → 绿色LED
- KEY3(PA2):电感模式 → 蓝色LED
按键检测采用定时扫描方式,10ms检测一次:
c复制void checkButtons(void) {
static uint8_t lastState[3] = {1,1,1};
uint8_t currentState[3] = {
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0),
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1),
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2)
};
for(int i=0; i<3; i++) {
if(lastState[i] && !currentState[i]) { // 下降沿
currentMode = i;
updateLEDs();
beep(100); // 短提示音
}
lastState[i] = currentState[i];
}
}
4. 制作与调试要点
4.1 PCB设计注意事项
- 电源去耦:每个IC附近都要放置0.1μF去耦电容,NE555的供电引脚尤其重要
- 信号隔离:将模拟部分(NE555电路)与数字部分(STM32)适当隔离
- 测试端子:使用镀金弹簧测试夹,减少接触电阻对测量的影响
- 接地设计:采用星型接地,模拟地和数字地在电源处单点连接
4.2 校准步骤
- 准备一组精度1%的标准元件,覆盖各量程
- 进入校准模式(长按中间按键5秒)
- 按提示依次连接标准元件
- 系统会自动记录频率-参数对应关系
- 校准数据保存在STM32的Flash中
校准模式关键代码:
c复制void enterCalibrationMode(void) {
float knownValues[] = {100,1e3,10e3,100e3,1e6}; // 标准电阻值
float measuredFreqs[5];
LCD_Clear();
LCD_Printf("Connect 100R");
delay_ms(2000);
measuredFreqs[0] = getFilteredFrequency();
// 依次测量其他标准元件...
// 计算校准系数
for(int i=0; i<5; i++) {
calibCoeff[i] = knownValues[i] / measuredFreqs[i];
}
// 保存到Flash
FLASH_Unlock();
FLASH_ErasePage(0x0800FC00);
for(int i=0; i<5; i++) {
FLASH_ProgramWord(0x0800FC00 + i*4, *(uint32_t*)&calibCoeff[i]);
}
FLASH_Lock();
}
4.3 常见问题排查
-
测量值不稳定
- 检查NE555供电电压是否稳定
- 增加软件滤波的窗口大小
- 检查测试夹是否接触良好
-
蓝牙连接失败
- 确认HC-05已进入配对模式(LED快闪)
- 检查手机是否已授权配对
- 确认串口波特率设置为115200
-
LCD显示异常
- 调整对比度电位器
- 检查排线连接是否牢固
- 确认初始化时序正确
-
某量程测量不准
- 检查该量程的参考元件值是否准确
- 重新校准该量程
- 可能是PCB漏电导致,检查清洁度
5. 项目优化与扩展
在实际使用几个月后,我发现还可以做以下改进:
- 增加自动关机功能:当10分钟无操作时自动关机,节省电池电量
- 改进蓝牙协议:采用二进制协议替代文本协议,提高传输效率
- 添加温度补偿:测量环境温度,对元件参数进行温度补偿
- 扩展量程:通过继电器切换不同参考元件,扩展测量范围
- 外壳设计:3D打印专用外壳,提升产品质感
这个项目最让我满意的是它的性价比——总成本不到100元,但实现了商业LCR表的基础功能。特别是在维修现场快速判断元件好坏时,这个便携的小工具非常实用。对于想要学习嵌入式开发和电子测量的朋友,这也是个很好的练手项目。
