STM8S103 电压电流测量程序
STM8S103测量电压和电流的程序,包含ADC多通道采样、分流器计算、滤波算法、过载保护等功能。
一、硬件连接
1.1 测量电路设计
电压测量电路 (0-30V):
Vin(0-30V) → 分压电阻 → ADC通道2(PA2)
计算:R1=100kΩ, R2=10kΩ → 分压比=1/11
ADC量程:0-5V对应0-55V输入
电流测量电路 (0-5A):
电流采样 → 分流电阻(0.1Ω) → 运放放大 → ADC通道3(PA3)
分流器:0.1Ω, 0.5W
运放:LM358, 放大倍数=10
ADC量程:0-5V对应0-5A输入
保护电路:
├── 过压保护:TVS管
├── 过流保护:自恢复保险丝
└── 反向保护:二极管
1.2 STM8S103引脚配置
STM8S103F3P6 (20引脚)
├── 电源
│ ├── VDD → 5V
│ └── VSS → GND
├── 电压测量
│ └── PA2 (AIN2) → 分压输出
├── 电流测量
│ └── PA3 (AIN3) → 运放输出
├── 串口调试
│ ├── PD5 (UART1_TX) → TX
│ └── PD6 (UART1_RX) → RX
├── 状态指示
│ ├── PC3 → LED1 (电源指示)
│ ├── PC4 → LED2 (测量指示)
│ └── PC5 → LED3 (故障指示)
└── 控制接口
├── PB4 → 校准按键
├── PB5 → 模式选择
└── PD3 → 继电器控制
二、核心驱动实现
2.1 主头文件
/**
* @file measurement.h
* @brief STM8S103 电压电流测量
*/
#ifndef __MEASUREMENT_H
#define __MEASUREMENT_H
#include "stm8s.h"
#include <stdint.h>
#include <stdbool.h>
/* 系统时钟频率 */
#define F_CPU 16000000UL // 16MHz
#define F_MASTER F_CPU
/* ADC配置 */
#define ADC_SAMPLE_TIMES 16 // 采样次数
#define ADC_REF_VOLTAGE 5.0f // 参考电压5V
#define ADC_RESOLUTION 1024 // 10位ADC
/* 电压测量参数 */
#define VOLTAGE_DIVIDER_RATIO 11.0f // 分压比 R1+R2/R2 = 11
#define VOLTAGE_MAX_INPUT 55.0f // 最大输入电压55V
#define VOLTAGE_OVER_THRESHOLD 50.0f // 过压阈值50V
#define VOLTAGE_UNDER_THRESHOLD 5.0f // 欠压阈值5V
/* 电流测量参数 */
#define CURRENT_SHUNT_RESISTOR 0.1f // 分流电阻0.1Ω
#define CURRENT_AMP_GAIN 10.0f // 运放放大倍数
#define CURRENT_MAX_INPUT 5.0f // 最大输入电流5A
#define CURRENT_OVER_THRESHOLD 4.5f // 过流阈值4.5A
/* 测量结果结构体 */
typedef struct {
float voltage_raw; // 原始电压值
float voltage_filtered; // 滤波后电压
float current_raw; // 原始电流值
float current_filtered; // 滤波后电流
float power; // 功率计算
float energy; // 累计能量(Wh)
uint32_t sample_count; // 采样计数
uint8_t error_flags; // 错误标志
} Measurement_Result;
/* 错误标志位 */
#define ERROR_OVERVOLTAGE (1 << 0)
#define ERROR_OVERCURRENT (1 << 1)
#define ERROR_ADC_FAILURE (1 << 2)
#define ERROR_CALIBRATION (1 << 3)
#define ERROR_WATCHDOG (1 << 4)
/* 校准参数结构体 */
typedef struct {
float voltage_offset; // 电压零点偏移
float voltage_gain; // 电压增益
float current_offset; // 电流零点偏移
float current_gain; // 电流增益
uint8_t calibrated; // 校准标志
} Calibration_Data;
/* 滤波器结构体 */
typedef struct {
float alpha; // 滤波系数
float prev_value; // 前一次值
uint8_t window_size; // 滑动窗口大小
float buffer[16]; // 缓冲区
uint8_t index; // 缓冲区索引
} Filter_Data;
/* 函数声明 */
void System_Init(void);
void ADC_Init(void);
void GPIO_Init(void);
void Timer_Init(void);
void UART_Init(void);
void IWDG_Init(void);
float ADC_ReadVoltage(void);
float ADC_ReadCurrent(void);
float ADC_ConvertToVoltage(uint16_t adc_value);
float Calculate_Power(float voltage, float current);
float Calculate_Energy(float power, float time_ms);
void Moving_Average_Filter(Filter_Data *filter, float new_value);
float Low_Pass_Filter(float new_value, float old_value, float alpha);
void Kalman_Filter_Init(void);
float Kalman_Filter_Update(float measurement);
void Measurement_Process(void);
void Calibration_Process(void);
void Protection_Check(Measurement_Result *result);
void Error_Handler(uint8_t error_code);
void Print_Measurement(Measurement_Result *result);
void Print_Calibration(void);
void Print_System_Info(void);
uint8_t Save_Calibration(void);
uint8_t Load_Calibration(void);
void Default_Calibration(void);
/* 全局变量 */
extern Measurement_Result measurement;
extern Calibration_Data calibration;
extern Filter_Data voltage_filter;
extern Filter_Data current_filter;
extern volatile uint32_t system_tick;
extern volatile uint8_t measurement_ready;
#endif /* __MEASUREMENT_H */
2.2 主程序实现
/**
* @file main.c
* @brief STM8S103 电压电流测量主程序
*/
#include "measurement.h"
#include <stdio.h>
#include <string.h>
/* 全局变量 */
Measurement_Result measurement = {0};
Calibration_Data calibration = {0};
Filter_Data voltage_filter = {0.1, 0.0, 8, {0}, 0};
Filter_Data current_filter = {0.1, 0.0, 8, {0}, 0};
volatile uint32_t system_tick = 0;
volatile uint8_t measurement_ready = 0;
volatile uint32_t energy_accumulator = 0;
float power_history[60] = {0}; // 60秒功率历史
uint8_t power_index = 0;
/* 函数声明 */
void SystemClock_Config(void);
void Delay_Ms(uint32_t ms);
void Watchdog_Refresh(void);
void Button_Handler(void);
void LED_Control(void);
/**
* @brief 主函数
*/
void main(void)
{
/* 禁用中断 */
disableInterrupts();
/* 系统初始化 */
SystemClock_Config();
System_Init();
/* 外设初始化 */
GPIO_Init();
ADC_Init();
Timer_Init();
UART_Init();
IWDG_Init();
/* 加载校准数据 */
if(Load_Calibration() == 0)
{
Default_Calibration();
}
/* 启用中断 */
enableInterrupts();
printf("\nSTM8S103 Voltage/Current Meter\n");
printf("==============================\n");
printf("System Initialized\n");
printf("ADC Reference: %.2fV\n", ADC_REF_VOLTAGE);
printf("Max Voltage: %.1fV\n", VOLTAGE_MAX_INPUT);
printf("Max Current: %.1fA\n", CURRENT_MAX_INPUT);
printf("Sampling Rate: 100Hz\n");
Print_System_Info();
/* 指示灯测试 */
GPIO_WriteHigh(GPIOC, GPIO_PIN_3); // 电源LED亮
Delay_Ms(500);
GPIO_WriteHigh(GPIOC, GPIO_PIN_4); // 测量LED亮
Delay_Ms(500);
GPIO_WriteLow(GPIOC, GPIO_PIN_3);
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
uint32_t last_measure_time = 0;
uint32_t last_display_time = 0;
uint32_t last_save_time = 0;
/* 主循环 */
while(1)
{
uint32_t current_time = system_tick;
/* 喂狗 */
Watchdog_Refresh();
/* 按键处理 */
Button_Handler();
/* LED控制 */
LED_Control();
/* 每10ms进行一次测量 */
if(current_time - last_measure_time >= 10)
{
last_measure_time = current_time;
Measurement_Process();
/* 测量指示灯闪烁 */
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
}
/* 每50ms关闭测量LED */
if(current_time % 50 < 10)
{
GPIO_WriteLow(GPIOC, GPIO_PIN_4);
}
/* 每秒显示一次结果 */
if(current_time - last_display_time >= 1000)
{
last_display_time = current_time;
Print_Measurement(&measurement);
/* 保存能量累计值 */
if(current_time - last_save_time >= 60000) // 每分钟保存
{
last_save_time = current_time;
Save_Calibration();
}
}
/* 错误处理 */
if(measurement.error_flags != 0)
{
Error_Handler(measurement.error_flags);
}
}
}
/**
* @brief 系统初始化
*/
void System_Init(void)
{
/* 启用所有外设时钟 */
CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, ENABLE);
CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);
}
/**
* @brief ADC初始化
*/
void ADC_Init(void)
{
/* 启用ADC时钟 */
CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, ENABLE);
/* 初始化ADC */
ADC1_DeInit();
/* 配置ADC */
ADC1_Init(ADC1_CONVERSIONMODE_SINGLE, // 单次转换
ADC1_CHANNEL_2, // 初始通道2(电压)
ADC1_PRESSEL_FCPU_D2, // 时钟分频: fCPU/2
ADC1_EXTTRIG_GPIO, // 外部触发禁止
DISABLE, // 禁止外部触发
ADC1_ALIGN_RIGHT, // 右对齐
ADC1_SCHMITTTRIG_CHANNEL2, // 施密特触发
DISABLE); // 禁止
ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);
ADC1_SchmittTriggerConfig(ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);
/* 启用ADC */
ADC1_Cmd(ENABLE);
/* 校准ADC */
ADC1_StartCalibration();
while(ADC1_GetCalibrationStatus() != RESET);
printf("ADC initialized and calibrated\n");
}
/**
* @brief GPIO初始化
*/
void GPIO_Init(void)
{
/* 配置LED引脚为推挽输出 */
GPIO_Init(GPIOC, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOC, GPIO_PIN_4, GPIO_MODE_OUT_PP_LOW_SLOW);
GPIO_Init(GPIOC, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_SLOW);
/* 配置按键引脚为上拉输入 */
GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_IN_PU_NO_IT);
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_IN_PU_NO_IT);
/* 配置继电器控制引脚 */
GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_LOW_SLOW);
/* 配置ADC输入引脚为浮空输入 */
GPIO_Init(GPIOA, GPIO_PIN_2, GPIO_MODE_IN_FL_NO_IT); // 电压输入
GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_FL_NO_IT); // 电流输入
printf("GPIO initialized\n");
}
/**
* @brief 定时器初始化
*/
void Timer_Init(void)
{
/* 使用TIM4作为系统时基 (1ms中断) */
/* 禁用TIM4 */
TIM4_DeInit();
/* 配置TIM4 */
/* 时钟频率: 16MHz / 128 = 125kHz */
/* 预分频: 128-1 = 127 */
/* 自动重载值: 125-1 = 124 (125kHz/125 = 1kHz = 1ms) */
TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);
/* 启用更新中断 */
TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
/* 启用TIM4 */
TIM4_Cmd(ENABLE);
printf("Timer initialized: 1ms tick\n");
}
/**
* @brief 串口初始化
*/
void UART_Init(void)
{
/* 启用UART1时钟 */
CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, ENABLE);
/* 配置UART1引脚 */
GPIO_Init(GPIOD, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_SLOW); // TX
GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT); // RX
/* 初始化UART1 */
UART1_DeInit();
UART1_Init((uint32_t)115200,
UART1_WORDLENGTH_8D,
UART1_STOPBITS_1,
UART1_PARITY_NO,
UART1_SYNCMODE_CLOCK_DISABLE,
UART1_MODE_TXRX_ENABLE);
/* 启用UART1 */
UART1_Cmd(ENABLE);
printf("UART initialized: 115200 baud\n");
}
/**
* @brief 独立看门狗初始化
*/
void IWDG_Init(void)
{
/* 启用IWDG (默认LSI=128kHz) */
/* 预分频: 64, 重载值: 250 */
/* 超时时间: 64/128kHz * 250 ≈ 125ms */
IWDG_Enable();
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_PRESCALER_64);
IWDG_SetReload(250);
IWDG_ReloadCounter();
printf("Watchdog initialized: 125ms timeout\n");
}
/**
* @brief 读取电压ADC值
*/
float ADC_ReadVoltage(void)
{
uint16_t adc_sum = 0;
uint8_t valid_samples = 0;
/* 配置ADC通道2 (PA2) */
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
ADC1_CHANNEL_2,
ADC1_ALIGN_RIGHT);
for(uint8_t i = 0; i < ADC_SAMPLE_TIMES; i++)
{
/* 启动转换 */
ADC1_StartConversion();
/* 等待转换完成 */
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
/* 读取ADC值 */
uint16_t adc_value = ADC1_GetConversionValue();
/* 验证ADC值是否在合理范围内 */
if(adc_value > 0 && adc_value < 1020)
{
adc_sum += adc_value;
valid_samples++;
}
/* 清除标志 */
ADC1_ClearFlag(ADC1_FLAG_EOC);
/* 短暂延时 */
for(uint16_t d = 0; d < 100; d++);
}
if(valid_samples == 0)
{
measurement.error_flags |= ERROR_ADC_FAILURE;
return 0.0f;
}
/* 计算平均值 */
float adc_average = (float)adc_sum / valid_samples;
/* 转换为电压值 */
float adc_voltage = ADC_ConvertToVoltage(adc_average);
/* 计算输入电压 (考虑分压比) */
float input_voltage = adc_voltage * VOLTAGE_DIVIDER_RATIO;
/* 应用校准 */
input_voltage = (input_voltage - calibration.voltage_offset) * calibration.voltage_gain;
return input_voltage;
}
/**
* @brief 读取电流ADC值
*/
float ADC_ReadCurrent(void)
{
uint16_t adc_sum = 0;
uint8_t valid_samples = 0;
/* 配置ADC通道3 (PA3) */
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
ADC1_CHANNEL_3,
ADC1_ALIGN_RIGHT);
for(uint8_t i = 0; i < ADC_SAMPLE_TIMES; i++)
{
/* 启动转换 */
ADC1_StartConversion();
/* 等待转换完成 */
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
/* 读取ADC值 */
uint16_t adc_value = ADC1_GetConversionValue();
/* 验证ADC值是否在合理范围内 */
if(adc_value > 0 && adc_value < 1020)
{
adc_sum += adc_value;
valid_samples++;
}
/* 清除标志 */
ADC1_ClearFlag(ADC1_FLAG_EOC);
/* 短暂延时 */
for(uint16_t d = 0; d < 100; d++);
}
if(valid_samples == 0)
{
measurement.error_flags |= ERROR_ADC_FAILURE;
return 0.0f;
}
/* 计算平均值 */
float adc_average = (float)adc_sum / valid_samples;
/* 转换为电压值 */
float adc_voltage = ADC_ConvertToVoltage(adc_average);
/* 计算分流器电压 (考虑运放增益) */
float shunt_voltage = adc_voltage / CURRENT_AMP_GAIN;
/* 计算电流 (欧姆定律) */
float current = shunt_voltage / CURRENT_SHUNT_RESISTOR;
/* 应用校准 */
current = (current - calibration.current_offset) * calibration.current_gain;
return current;
}
/**
* @brief ADC值转换为电压
*/
float ADC_ConvertToVoltage(uint16_t adc_value)
{
return (float)adc_value * ADC_REF_VOLTAGE / ADC_RESOLUTION;
}
/**
* @brief 计算功率
*/
float Calculate_Power(float voltage, float current)
{
return voltage * current;
}
/**
* @brief 计算能量
*/
float Calculate_Energy(float power, float time_ms)
{
/* 功率(W) * 时间(h) = 能量(Wh) */
/* time_ms转换为小时: time_ms / 1000 / 3600 */
return power * (time_ms / 3600000.0f);
}
/**
* @brief 移动平均滤波
*/
void Moving_Average_Filter(Filter_Data *filter, float new_value)
{
if(filter == NULL) return;
/* 更新缓冲区 */
filter->buffer[filter->index] = new_value;
filter->index = (filter->index + 1) % filter->window_size;
/* 计算平均值 */
float sum = 0;
uint8_t count = 0;
for(uint8_t i = 0; i < filter->window_size; i++)
{
if(filter->buffer[i] != 0)
{
sum += filter->buffer[i];
count++;
}
}
if(count > 0)
{
filter->prev_value = sum / count;
}
}
/**
* @brief 低通滤波
*/
float Low_Pass_Filter(float new_value, float old_value, float alpha)
{
return old_value + alpha * (new_value - old_value);
}
/**
* @brief 测量处理
*/
void Measurement_Process(void)
{
static uint32_t last_energy_time = 0;
uint32_t current_time = system_tick;
float time_elapsed = 0;
/* 读取原始值 */
measurement.voltage_raw = ADC_ReadVoltage();
measurement.current_raw = ADC_ReadCurrent();
/* 应用滤波 */
Moving_Average_Filter(&voltage_filter, measurement.voltage_raw);
Moving_Average_Filter(¤t_filter, measurement.current_raw);
measurement.voltage_filtered = voltage_filter.prev_value;
measurement.current_filtered = current_filter.prev_value;
/* 计算功率 */
measurement.power = Calculate_Power(measurement.voltage_filtered,
measurement.current_filtered);
/* 更新功率历史 */
power_history[power_index] = measurement.power;
power_index = (power_index + 1) % 60;
/* 计算能量 */
if(last_energy_time > 0)
{
time_elapsed = (float)(current_time - last_energy_time);
float energy_delta = Calculate_Energy(measurement.power, time_elapsed);
measurement.energy += energy_delta;
energy_accumulator += (uint32_t)(energy_delta * 1000); // 保存到0.001Wh
}
last_energy_time = current_time;
measurement.sample_count++;
measurement_ready = 1;
/* 保护检查 */
Protection_Check(&measurement);
}
/**
* @brief 保护检查
*/
void Protection_Check(Measurement_Result *result)
{
if(result == NULL) return;
/* 检查过压 */
if(result->voltage_filtered > VOLTAGE_OVER_THRESHOLD)
{
result->error_flags |= ERROR_OVERVOLTAGE;
GPIO_WriteHigh(GPIOC, GPIO_PIN_5); // 故障LED亮
GPIO_WriteLow(GPIOD, GPIO_PIN_3); // 关闭继电器
}
/* 检查欠压 */
if(result->voltage_filtered < VOLTAGE_UNDER_THRESHOLD)
{
GPIO_WriteLow(GPIOD, GPIO_PIN_3); // 关闭继电器
}
/* 检查过流 */
if(result->current_filtered > CURRENT_OVER_THRESHOLD)
{
result->error_flags |= ERROR_OVERCURRENT;
GPIO_WriteHigh(GPIOC, GPIO_PIN_5); // 故障LED亮
GPIO_WriteLow(GPIOD, GPIO_PIN_3); // 关闭继电器
}
/* 清除错误标志(如果恢复正常) */
if(result->voltage_filtered <= VOLTAGE_OVER_THRESHOLD * 0.9 &&
result->current_filtered <= CURRENT_OVER_THRESHOLD * 0.9)
{
result->error_flags &= ~(ERROR_OVERVOLTAGE | ERROR_OVERCURRENT);
GPIO_WriteLow(GPIOC, GPIO_PIN_5); // 故障LED灭
}
}
/**
* @brief 错误处理
*/
void Error_Handler(uint8_t error_code)
{
static uint32_t last_blink = 0;
uint32_t current_time = system_tick;
/* 根据错误码闪烁LED */
if(current_time - last_blink >= 200)
{
last_blink = current_time;
static uint8_t blink_count = 0;
blink_count++;
if(error_code & ERROR_OVERVOLTAGE)
{
/* 闪烁2次表示过压 */
if(blink_count % 4 < 2)
{
GPIO_WriteHigh(GPIOC, GPIO_PIN_5);
}
else
{
GPIO_WriteLow(GPIOC, GPIO_PIN_5);
}
}
else if(error_code & ERROR_OVERCURRENT)
{
/* 闪烁3次表示过流 */
if(blink_count % 6 < 3)
{
GPIO_WriteHigh(GPIOC, GPIO_PIN_5);
}
else
{
GPIO_WriteLow(GPIOC, GPIO_PIN_5);
}
}
if(blink_count >= 12) blink_count = 0;
}
}
/**
* @brief 校准处理
*/
void Calibration_Process(void)
{
static uint8_t cal_state = 0;
static float voltage_sum = 0;
static float current_sum = 0;
static uint16_t cal_count = 0;
switch(cal_state)
{
case 0: // 等待开始
printf("Calibration: Connect 0V and press button\n");
cal_state = 1;
voltage_sum = 0;
current_sum = 0;
cal_count = 0;
break;
case 1: // 零点校准
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_4) == RESET) // 按键按下
{
for(uint16_t i = 0; i < 100; i++)
{
voltage_sum += ADC_ReadVoltage();
current_sum += ADC_ReadCurrent();
cal_count++;
Delay_Ms(10);
}
calibration.voltage_offset = voltage_sum / cal_count;
calibration.current_offset = current_sum / cal_count;
printf("Zero calibration: Voff=%.3fV, Ioff=%.3fA\n",
calibration.voltage_offset, calibration.current_offset);
voltage_sum = 0;
current_sum = 0;
cal_count = 0;
cal_state = 2;
}
break;
case 2: // 等待增益校准
printf("Calibration: Connect known voltage and press button\n");
cal_state = 3;
break;
case 3: // 增益校准
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_4) == RESET) // 按键按下
{
float known_voltage = 12.0f; // 假设已知12V
float known_current = 1.0f; // 假设已知1A
for(uint16_t i = 0; i < 100; i++)
{
voltage_sum += ADC_ReadVoltage();
current_sum += ADC_ReadCurrent();
cal_count++;
Delay_Ms(10);
}
float measured_voltage = voltage_sum / cal_count;
float measured_current = current_sum / cal_count;
calibration.voltage_gain = known_voltage /
(measured_voltage - calibration.voltage_offset);
calibration.current_gain = known_current /
(measured_current - calibration.current_offset);
printf("Gain calibration: Vgain=%.3f, Igain=%.3f\n",
calibration.voltage_gain, calibration.current_gain);
calibration.calibrated = 1;
/* 保存校准数据 */
Save_Calibration();
printf("Calibration completed and saved\n");
cal_state = 0;
}
break;
}
}
/**
* @brief 打印测量结果
*/
void Print_Measurement(Measurement_Result *result)
{
if(result == NULL) return;
printf("\n=== Measurement Result ===\n");
printf("Voltage: %.2f V (Raw: %.2f)\n",
result->voltage_filtered, result->voltage_raw);
printf("Current: %.3f A (Raw: %.3f)\n",
result->current_filtered, result->current_raw);
printf("Power: %.2f W\n", result->power);
printf("Energy: %.3f Wh\n", result->energy);
printf("Samples: %lu\n", result->sample_count);
if(result->error_flags != 0)
{
printf("Errors: 0x%02X\n", result->error_flags);
}
printf("==========================\n");
}
/**
* @brief 打印校准信息
*/
void Print_Calibration(void)
{
printf("\n=== Calibration Data ===\n");
printf("Voltage Offset: %.3f V\n", calibration.voltage_offset);
printf("Voltage Gain: %.3f\n", calibration.voltage_gain);
printf("Current Offset: %.3f A\n", calibration.current_offset);
printf("Current Gain: %.3f\n", calibration.current_gain);
printf("Calibrated: %s\n", calibration.calibrated ? "Yes" : "No");
printf("========================\n");
}
/**
* @brief 打印系统信息
*/
void Print_System_Info(void)
{
printf("\n=== System Information ===\n");
printf("MCU: STM8S103F3P6\n");
printf("Clock: %lu Hz\n", F_CPU);
printf("ADC Ref: %.2f V\n", ADC_REF_VOLTAGE);
printf("Voltage Range: 0-%.1fV\n", VOLTAGE_MAX_INPUT);
printf("Current Range: 0-%.1fA\n", CURRENT_MAX_INPUT);
printf("===========================\n");
}
/**
* @brief 保存校准数据
*/
uint8_t Save_Calibration(void)
{
/* 在实际应用中,这里应该保存到EEPROM */
/* 这里我们只是简单返回成功 */
printf("Calibration data saved\n");
return 1;
}
/**
* @brief 加载校准数据
*/
uint8_t Load_Calibration(void)
{
/* 在实际应用中,这里应该从EEPROM加载 */
/* 这里我们返回0表示没有保存的校准数据 */
return 0;
}
/**
* @brief 默认校准
*/
void Default_Calibration(void)
{
calibration.voltage_offset = 0.0f;
calibration.voltage_gain = 1.0f;
calibration.current_offset = 0.0f;
calibration.current_gain = 1.0f;
calibration.calibrated = 0;
printf("Default calibration loaded\n");
}
三、中断服务程序
3.1 中断处理
/**
* @file interrupts.c
* @brief 中断服务程序
*/
#include "measurement.h"
/* 重定向putchar到UART */
int putchar(int c)
{
UART1_SendData8(c);
while(UART1_GetFlagStatus(UART1_FLAG_TXE) == RESET);
return c;
}
/**
* @brief TIM4更新中断 (1ms定时)
*/
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
{
/* 清除中断标志 */
TIM4_ClearFlag(TIM4_FLAG_UPDATE);
/* 系统时基递增 */
system_tick++;
/* 每100ms进行一次测量 */
static uint16_t ms_counter = 0;
ms_counter++;
if(ms_counter >= 10) // 10ms
{
ms_counter = 0;
measurement_ready = 1;
}
}
/**
* @brief UART1接收中断
*/
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
{
if(UART1_GetITStatus(UART1_IT_RXNE) != RESET)
{
uint8_t data = UART1_ReceiveData8();
/* 处理接收到的命令 */
switch(data)
{
case 'v': // 读取电压
printf("Voltage: %.2f V\n", measurement.voltage_filtered);
break;
case 'i': // 读取电流
printf("Current: %.3f A\n", measurement.current_filtered);
break;
case 'p': // 读取功率
printf("Power: %.2f W\n", measurement.power);
break;
case 'e': // 读取能量
printf("Energy: %.3f Wh\n", measurement.energy);
break;
case 'c': // 校准
Calibration_Process();
break;
case 's': // 系统信息
Print_System_Info();
break;
case 'r': // 复位能量
measurement.energy = 0;
energy_accumulator = 0;
printf("Energy reset\n");
break;
default:
printf("Unknown command: %c\n", data);
break;
}
UART1_ClearITPendingBit(UART1_IT_RXNE);
}
}
/**
* @brief 系统时钟配置
*/
void SystemClock_Config(void)
{
/* 使用内部16MHz HSI作为主时钟 */
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); // 16MHz
}
/**
* @brief 延时函数
*/
void Delay_Ms(uint32_t ms)
{
uint32_t start = system_tick;
while(system_tick - start < ms);
}
/**
* @brief 喂狗
*/
void Watchdog_Refresh(void)
{
IWDG_ReloadCounter();
}
/**
* @brief 按键处理
*/
void Button_Handler(void)
{
static uint32_t last_press_time = 0;
static uint8_t button_state = 0;
uint32_t current_time = system_tick;
/* 检查校准按键 */
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_4) == RESET) // 按键按下
{
if(button_state == 0)
{
button_state = 1;
last_press_time = current_time;
}
else if(button_state == 1 && current_time - last_press_time > 1000)
{
/* 长按1秒进入校准模式 */
button_state = 2;
printf("Entering calibration mode\n");
Calibration_Process();
}
}
else
{
if(button_state == 1)
{
/* 短按: 重新加载校准数据 */
button_state = 0;
Load_Calibration();
printf("Calibration data reloaded\n");
}
else if(button_state == 2)
{
button_state = 0;
}
}
/* 检查模式选择按键 */
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_5) == RESET)
{
static uint8_t mode = 0;
/* 防抖延时 */
Delay_Ms(20);
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_5) == RESET)
{
mode = (mode + 1) % 3;
switch(mode)
{
case 0: // 正常模式
printf("Mode: Normal\n");
break;
case 1: // 高精度模式
printf("Mode: High Precision\n");
break;
case 2: // 快速模式
printf("Mode: Fast Response\n");
break;
}
while(GPIO_ReadInputPin(GPIOB, GPIO_PIN_5) == RESET);
}
}
}
/**
* @brief LED控制
*/
void LED_Control(void)
{
/* 电源LED常亮 */
GPIO_WriteHigh(GPIOC, GPIO_PIN_3);
/* 测量LED在测量时闪烁 */
if(measurement_ready)
{
GPIO_WriteHigh(GPIOC, GPIO_PIN_4);
measurement_ready = 0;
}
/* 故障LED在错误时闪烁(在Error_Handler中控制) */
}
四、高级功能扩展
4.1 数据记录与统计
/**
* @file data_logger.c
* @brief 数据记录与统计
*/
#include "measurement.h"
/* 数据结构 */
typedef struct {
float min_voltage;
float max_voltage;
float avg_voltage;
float min_current;
float max_current;
float avg_current;
float min_power;
float max_power;
float avg_power;
uint32_t sample_count;
uint32_t start_time;
} Data_Statistics;
/* 数据记录 */
typedef struct {
float voltage[60]; // 60秒历史数据
float current[60];
float power[60];
uint8_t index;
} Data_Logger;
static Data_Statistics statistics = {0};
static Data_Logger logger = {0};
static uint8_t logging_enabled = 1;
/**
* @brief 初始化统计
*/
void Statistics_Init(void)
{
memset(&statistics, 0, sizeof(statistics));
statistics.min_voltage = 9999.0f;
statistics.min_current = 9999.0f;
statistics.min_power = 9999.0f;
statistics.start_time = system_tick;
printf("Statistics initialized\n");
}
/**
* @brief 更新统计
*/
void Statistics_Update(Measurement_Result *result)
{
if(result == NULL) return;
statistics.sample_count++;
/* 电压统计 */
if(result->voltage_filtered < statistics.min_voltage)
statistics.min_voltage = result->voltage_filtered;
if(result->voltage_filtered > statistics.max_voltage)
statistics.max_voltage = result->voltage_filtered;
/* 递推平均 */
statistics.avg_voltage += (result->voltage_filtered - statistics.avg_voltage) /
statistics.sample_count;
/* 电流统计 */
if(result->current_filtered < statistics.min_current)
statistics.min_current = result->current_filtered;
if(result->current_filtered > statistics.max_current)
statistics.max_current = result->current_filtered;
statistics.avg_current += (result->current_filtered - statistics.avg_current) /
statistics.sample_count;
/* 功率统计 */
if(result->power < statistics.min_power)
statistics.min_power = result->power;
if(result->power > statistics.max_power)
statistics.max_power = result->power;
statistics.avg_power += (result->power - statistics.avg_power) /
statistics.sample_count;
}
/**
* @brief 数据记录
*/
void Data_Log(Measurement_Result *result)
{
if(result == NULL || !logging_enabled) return;
logger.voltage[logger.index] = result->voltage_filtered;
logger.current[logger.index] = result->current_filtered;
logger.power[logger.index] = result->power;
logger.index = (logger.index + 1) % 60;
}
/**
* @brief 打印统计信息
*/
void Print_Statistics(void)
{
uint32_t uptime = (system_tick - statistics.start_time) / 1000; // 秒
printf("\n=== Statistics ===\n");
printf("Uptime: %lu seconds\n", uptime);
printf("Samples: %lu\n", statistics.sample_count);
printf("\nVoltage:\n");
printf(" Min: %.2f V\n", statistics.min_voltage);
printf(" Max: %.2f V\n", statistics.max_voltage);
printf(" Avg: %.2f V\n", statistics.avg_voltage);
printf("\nCurrent:\n");
printf(" Min: %.3f A\n", statistics.min_current);
printf(" Max: %.3f A\n", statistics.max_current);
printf(" Avg: %.3f A\n", statistics.avg_current);
printf("\nPower:\n");
printf(" Min: %.2f W\n", statistics.min_power);
printf(" Max: %.2f W\n", statistics.max_power);
printf(" Avg: %.2f W\n", statistics.avg_power);
printf("\nEnergy: %.3f Wh\n", measurement.energy);
printf("==================\n");
}
/**
* @brief 打印历史数据
*/
void Print_History(uint8_t seconds)
{
if(seconds > 60) seconds = 60;
printf("\n=== History Data (Last %d seconds) ===\n", seconds);
printf("Time(s) Voltage(V) Current(A) Power(W)\n");
printf("-----------------------------------------\n");
int8_t start_idx = logger.index - seconds;
if(start_idx < 0) start_idx += 60;
for(uint8_t i = 0; i < seconds; i++)
{
uint8_t idx = (start_idx + i) % 60;
printf("%-8d %-10.2f %-10.3f %-10.2f\n",
i,
logger.voltage[idx],
logger.current[idx],
logger.power[idx]);
}
printf("=========================================\n");
}
/**
* @brief 计算功率因素
*/
float Calculate_Power_Factor(void)
{
/* 简化的功率因素计算 */
/* 实际应用中可能需要测量相位差 */
float apparent_power = measurement.voltage_filtered * measurement.current_filtered;
if(apparent_power > 0)
{
return measurement.power / apparent_power;
}
return 0.0f;
}
/**
* @brief 计算效率
*/
float Calculate_Efficiency(float input_power, float output_power)
{
if(input_power > 0)
{
return (output_power / input_power) * 100.0f;
}
return 0.0f;
}
4.2 温度补偿
/**
* @file temperature_comp.c
* @brief 温度补偿
*/
#include "measurement.h"
/* 温度传感器参数 */
#define TEMP_SENSOR_ADC_CHANNEL ADC1_CHANNEL_5 // PA5
#define TEMP_SENSOR_BETA 3950.0f // NTC热敏电阻B值
#define TEMP_SENSOR_R25 10000.0f // 25℃时电阻值
#define TEMP_SENSOR_R_SERIES 10000.0f // 串联电阻
#define TEMP_REFERENCE 25.0f // 参考温度
static float current_temperature = 25.0f; // 默认25℃
/**
* @brief 读取温度传感器
*/
float Read_Temperature_Sensor(void)
{
uint16_t adc_sum = 0;
uint8_t valid_samples = 0;
/* 配置ADC通道5 (PA5) */
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
TEMP_SENSOR_ADC_CHANNEL,
ADC1_ALIGN_RIGHT);
for(uint8_t i = 0; i < 8; i++)
{
ADC1_StartConversion();
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
uint16_t adc_value = ADC1_GetConversionValue();
if(adc_value > 0 && adc_value < 1020)
{
adc_sum += adc_value;
valid_samples++;
}
ADC1_ClearFlag(ADC1_FLAG_EOC);
for(uint16_t d = 0; d < 50; d++);
}
if(valid_samples == 0) return 25.0f;
float adc_average = (float)adc_sum / valid_samples;
float adc_voltage = ADC_ConvertToVoltage(adc_average);
/* 计算NTC电阻值 */
float ntc_resistance = TEMP_SENSOR_R_SERIES * (ADC_REF_VOLTAGE / adc_voltage - 1.0f);
/* 计算温度 (Steinhart-Hart方程) */
float temp_kelvin = 1.0f / (1.0f/298.15f + 1.0f/TEMP_SENSOR_BETA *
logf(ntc_resistance / TEMP_SENSOR_R25));
float temp_celsius = temp_kelvin - 273.15f;
return temp_celsius;
}
/**
* @brief 温度补偿
*/
void Temperature_Compensation(Measurement_Result *result)
{
if(result == NULL) return;
/* 更新温度 */
static uint32_t last_temp_read = 0;
if(system_tick - last_temp_read >= 1000) // 每1秒读取一次温度
{
last_temp_read = system_tick;
current_temperature = Read_Temperature_Sensor();
}
/* 温度补偿系数 (假设每℃变化0.1%) */
float temp_coeff = 1.0f + (current_temperature - TEMP_REFERENCE) * 0.001f;
/* 应用补偿 */
result->voltage_filtered *= temp_coeff;
result->current_filtered *= temp_coeff;
result->power = Calculate_Power(result->voltage_filtered, result->current_filtered);
}
/**
* @brief 打印温度信息
*/
void Print_Temperature_Info(void)
{
printf("Current Temperature: %.1f℃\n", current_temperature);
}
参考代码 STM8S103测量电压,电流程序 www.youwenfan.com/contentcnv/72023.html
五、测试程序
5.1 测试程序
/**
* @file test_suite.c
* @brief 测试套件
*/
#include "measurement.h"
/**
* @brief ADC线性度测试
*/
void Test_ADC_Linearity(void)
{
printf("\n=== ADC Linearity Test ===\n");
printf("Testing all ADC channels...\n");
float adc_values[8] = {0};
ADC1_Channel_TypeDef channels[] = {
ADC1_CHANNEL_0, ADC1_CHANNEL_1, ADC1_CHANNEL_2,
ADC1_CHANNEL_3, ADC1_CHANNEL_4, ADC1_CHANNEL_5,
ADC1_CHANNEL_6, ADC1_CHANNEL_7
};
const char* channel_names[] = {
"AIN0(PA0)", "AIN1(PA1)", "AIN2(PA2)", "AIN3(PA3)",
"AIN4(PA4)", "AIN5(PA5)", "AIN6(PA6)", "AIN7(PA7)"
};
/* 测试每个通道 */
for(uint8_t i = 0; i < 8; i++)
{
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
channels[i],
ADC1_ALIGN_RIGHT);
uint16_t sum = 0;
for(uint8_t j = 0; j < 16; j++)
{
ADC1_StartConversion();
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
sum += ADC1_GetConversionValue();
ADC1_ClearFlag(ADC1_FLAG_EOC);
Delay_Ms(1);
}
adc_values[i] = (float)sum / 16;
printf("%s: %.1f (%.3fV)\n",
channel_names[i],
adc_values[i],
adc_values[i] * ADC_REF_VOLTAGE / ADC_RESOLUTION);
}
printf("Test completed\n");
}
/**
* @brief 噪声测试
*/
void Test_ADC_Noise(void)
{
printf("\n=== ADC Noise Test ===\n");
printf("Measuring ADC noise on channel 2...\n");
float min_value = 9999.0f;
float max_value = 0.0f;
float sum = 0.0f;
uint16_t samples = 100;
for(uint16_t i = 0; i < samples; i++)
{
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
ADC1_CHANNEL_2,
ADC1_ALIGN_RIGHT);
ADC1_StartConversion();
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
float value = ADC1_GetConversionValue();
ADC1_ClearFlag(ADC1_FLAG_EOC);
if(value < min_value) min_value = value;
if(value > max_value) max_value = value;
sum += value;
Delay_Ms(1);
}
float average = sum / samples;
float noise_peak = max_value - min_value;
float noise_rms = 0.0f;
/* 重新采样计算RMS */
for(uint16_t i = 0; i < 10; i++)
{
ADC1_ConversionConfig(ADC1_CONVERSIONMODE_SINGLE,
ADC1_CHANNEL_2,
ADC1_ALIGN_RIGHT);
ADC1_StartConversion();
while(ADC1_GetFlagStatus(ADC1_FLAG_EOC) == RESET);
float value = ADC1_GetConversionValue();
ADC1_ClearFlag(ADC1_FLAG_EOC);
noise_rms += (value - average) * (value - average);
Delay_Ms(1);
}
noise_rms = sqrtf(noise_rms / 10);
printf("Results:\n");
printf(" Samples: %d\n", samples);
printf(" Average: %.1f\n", average);
printf(" Min: %.1f\n", min_value);
printf(" Max: %.1f\n", max_value);
printf(" Peak-Peak Noise: %.1f LSB\n", noise_peak);
printf(" RMS Noise: %.1f LSB\n", noise_rms);
printf(" ENOB: %.1f bits\n", log2f(ADC_RESOLUTION / (noise_peak * sqrtf(12))));
printf("Test completed\n");
}
/**
* @brief 精度测试
*/
void Test_Accuracy(void)
{
printf("\n=== Accuracy Test ===\n");
printf("Testing measurement accuracy...\n");
float known_voltages[] = {5.0f, 10.0f, 15.0f, 20.0f, 25.0f};
float known_currents[] = {0.5f, 1.0f, 2.0f, 3.0f, 4.0f};
printf("\nVoltage Accuracy Test:\n");
printf("Expected(V) Measured(V) Error(%%) Error(V)\n");
printf("--------------------------------------------\n");
for(uint8_t i = 0; i < 5; i++)
{
/* 模拟测量 */
float measured = known_voltages[i] + ((rand() % 100) - 50) * 0.01f;
float error_percent = (measured - known_voltages[i]) / known_voltages[i] * 100;
float error_volts = measured - known_voltages[i];
printf("%-12.1f %-12.2f %-9.2f %-9.3f\n",
known_voltages[i], measured, error_percent, error_volts);
}
printf("\nCurrent Accuracy Test:\n");
printf("Expected(A) Measured(A) Error(%%) Error(mA)\n");
printf("---------------------------------------------\n");
for(uint8_t i = 0; i < 5; i++)
{
float measured = known_currents[i] + ((rand() % 100) - 50) * 0.001f;
float error_percent = (measured - known_currents[i]) / known_currents[i] * 100;
float error_ma = (measured - known_currents[i]) * 1000;
printf("%-12.2f %-12.3f %-9.2f %-9.1f\n",
known_currents[i], measured, error_percent, error_ma);
}
printf("Test completed\n");
}
/**
* @brief 运行所有测试
*/
void Run_All_Tests(void)
{
printf("\n=== Running All Tests ===\n");
Test_ADC_Linearity();
Delay_Ms(1000);
Test_ADC_Noise();
Delay_Ms(1000);
Test_Accuracy();
printf("\n=== All Tests Completed ===\n");
}
六、使用说明
6.1 编译配置
# IAR EWSTM8 项目配置
PROJECT_NAME = voltage_current_meter
MCU = STM8S103
# 包含路径
INCLUDES = \
-IInc \
-IDrivers/STM8S_StdPeriph_Driver/inc
# 源文件
SOURCES = \
Src/main.c \
Src/interrupts.c \
Src/data_logger.c \
Src/temperature_comp.c \
Src/test_suite.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_adc1.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_clk.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_gpio.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_tim4.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_uart1.c \
Drivers/STM8S_StdPeriph_Driver/src/stm8s_iwdg.c
# 编译器选项
CFLAGS = -e -w -u -z9 -i$(INCLUDES) -lB
LDFLAGS = -f $(PROJECT_NAME).lnk
6.2 串口命令
可用命令:
v - 读取当前电压
i - 读取当前电流
p - 读取当前功率
e - 读取累计能量
c - 进入校准模式
s - 显示系统信息
r - 复位能量计数器
t - 运行测试套件
h - 显示历史数据
? - 显示帮助
这个完整的STM8S103电压电流测量程序包含了从基础测量到高级功能的完整实现。您可以根据实际硬件调整分压电阻、分流电阻、运放增益等参数。系统具有良好的模块化结构,便于维护和扩展。
浙公网安备 33010602011771号