金牌会员
 
- 积分
- 1261
- 金钱
- 1261
- 注册时间
- 2016-1-23
- 在线时间
- 491 小时
|
本帖最后由 STM129 于 2025-8-23 12:37 编辑
电子爱好常常要对 电阻R,电容C,电感L 进行测量,电阻R,电容C 万用表就行,对于电感L就有点力不从心
于是问AI,得到一个参考例程:
在实际应用中,校准程序是确保测量准确性的关键步骤。校准程序通常包括对硬件的零点校准和增益校准。对于ADC测量,可以通过测量已知的参考信号来校准ADC的增益和偏移。
以下是一个完整的程序,包括ADC初始化、同步采样、LCR计算、相位角计算以及校准程序。我们将使用两个已知的参考信号(电压和电流)来进行校准。
硬件连接
• 假设使用STM32F103系列单片机。
• 使用ADC1和ADC2进行同步采样,ADC1采样电压信号,ADC2采样电流信号。
• 电压信号和电流信号分别连接到PA1和PA2引脚。
• 基准电阻连接在电流信号路径上,用于测量电流。
配置步骤
• 使能时钟
• 使能GPIOA、ADC1和ADC2的时钟。
• 配置GPIO
• 将PA1和PA2配置为模拟输入模式。
• 配置ADC
• 配置ADC1和ADC2为同步规则模式。
• 设置采样时间、数据对齐方式等参数。
• 启动ADC
• 启动ADC校准。
• 启动ADC转换。
• 读取数据
• 读取ADC1和ADC2的转换结果。
• 计算LCR和相位角
• 根据采样数据计算电感(L)、电容(C)、电阻(R)和相位角(Phase Angle)。
• 校准程序
• 使用已知的参考信号进行零点和增益校准。
示例代码
1.配置文件`adc.h`
```c
#ifndef ADC_H
#define ADC_H
#include "stm32f10x.h"
void ADC_Init_Config(void);
uint16_t ADC_GetValue(ADC_TypeDef* ADCx);
#endif
```
2.配置文件`adc.c`
```c
#include "adc.h"
void ADC_Init_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 使能GPIOA、ADC1和ADC2时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);
// 配置PA1和PA2为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
// 配置ADC2
ADC_InitStructure.ADC_Mode = ADC_Mode_RegInjecSimult;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC2, &ADC_InitStructure);
// 配置ADC1规则组通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_1Cycles5);
// 配置ADC2规则组通道
ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_1Cycles5);
// 启动ADC校准
ADC_StartCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
while(ADC_GetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC2);
while(ADC_GetResetCalibrationStatus(ADC2));
while(ADC_GetCalibrationStatus(ADC2));
// 启动ADC
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
}
uint16_t ADC_GetValue(ADC_TypeDef* ADCx)
{
// 启动ADC转换
ADC_SoftwareStartConvCmd(ADCx, ENABLE);
while(ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC) == RESET); // 等待转换完成
return ADC_GetConversionValue(ADCx); // 获取转换结果
}
```
3.主程序`main.c`
```c
#include "adc.h"
#include "stdio.h"
#include "math.h"
#include "misc.h"
// 假设已配置好串口,用于打印结果
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 使能GPIOA和USART1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
// 配置USART1 TX引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 配置USART1
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
// 使能USART1
USART_Cmd(USART1, ENABLE);
}
// 打印函数
void USART_SendString(char* str)
{
while(*str)
{
USART_SendData(USART1, *str++);
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
}
// 校准函数
void ADC_Calibration(float* voltage_offset, float* current_offset, float* voltage_gain, float* current_gain)
{
// 假设已知的参考电压和电流
float known_voltage = 1.0; // 已知参考电压(V)
float known_current = 0.01; // 已知参考电流(A)
// 读取ADC值
uint16_t adc1_value = ADC_GetValue(ADC1);
uint16_t adc2_value = ADC_GetValue(ADC2);
// 计算偏移和增益
*voltage_offset = (float)adc1_value * 3.3 / 4095.0 - known_voltage;
*current_offset = (float)adc2_value * 3.3 / 4095.0 - known_current;
*voltage_gain = 3.3 / 4095.0;
*current_gain = 3.3 / 4095.0;
}
// 计算LCR和相位角
void Calculate_LCR_Phase(float voltage, float current, float frequency, float reference_resistance, float* resistance, float* inductance, float* capacitance, float* phase_angle)
{
*resistance = voltage / current; // 欧姆定律计算电阻
// 计算相位角
float voltage_phase = atan2f(voltage, current); // 电压相位
float current_phase = 0; // 假设电流相位为0
*phase_angle = voltage_phase - current_phase; // 相位差
// 计算电感和电容
if (frequency > 0)
{
*inductance = (*resistance) / (2 * 3.14159 * frequency);
*capacitance = 1 / (2 * 3.14159 * frequency * (*resistance));
}
else
{
*inductance = 0;
*capacitance = 0;
}
}
int main(void)
{
float voltage, current, resistance, inductance, capacitance, phase_angle;
float voltage_offset, current_offset, voltage_gain, current_gain;
uint16_t adc1_value, adc2_value;
float frequencies[] = {100, 1000, 10000, 25000, 50000};
float reference_resistances[] = {22, 100, 10000};
int num_frequencies = sizeof(frequencies) / sizeof(frequencies[0]);
int num_resistances = sizeof
|
|