| 
 
金牌会员  
 
	积分1273金钱1273 注册时间2016-1-23在线时间493 小时 | 
 
| 本帖最后由 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
 
 
 
 | 
 |