polarimeter_software/User/app/tec_control.c

337 lines
9.3 KiB
C
Raw Normal View History

2025-09-30 02:37:23 +00:00
/*
* @Date: 2025-06-23 13:04:20
* @Author: mypx
* @LastEditors: mypx mypx_coder@163.com
* @LastEditTime: 2025-09-25 16:49:59
* @FilePath: tec_control.c
* @Description:
* Copyright (c) 2025 by mypx, All Rights Reserved.
*/
#include "tec_control.h"
#include "ad7793.h"
#include "et_log.h"
#include "etk_utils.h"
#include "mb_interface.h"
#include "pm_board.h"
#include "pm_common.h"
#include "pt100x.h"
#include <stdint.h>
#include <stdio.h>
#if TEC_CONTROL_PERIOD < ADC_SAMPLE_PERIOD
#error "TEC_CONTROL_PERIOD must be greater than ADC_SAMPLE_PERIOD"
#endif
/* Define AD7793 device structure */
ad7793_dev_t ad7793_dev;
extern ad7793_hw_if_t ad7793_hw_if;
#if (USING_SOFT_SPI == 1)
extern soft_spi_t soft_spi;
#endif
tec_control_t *tec_control = NULL;
/* Shared data structure for temperature sampling and TEC control */
static struct
{
float current_temperature;
bool temp_updated;
rt_mutex_t data_mutex;
} temp_shared_data;
float tec_get_target_voltage(float r)
{
double numerator = 135 - 675 * r;
double denominator = 390 * r + 1343;
if (denominator == 0)
{
ET_ERR("Error: Denominator is zero for r = %.2f", r);
return 0.0;
}
return numerator / denominator;
}
/**
* @param voltage: Voltage value in volts
* @return double: Resistance in ohms
*/
static double solve_resistance(double voltage)
{
double numerator = 135 - 1343 * voltage;
double denominator = 390 * voltage + 675;
if (denominator == 0)
{
ET_ERR("Error: Denominator is zero for v = %.2f", voltage);
return 0.0;
}
return numerator * 1000 / denominator;
}
void tec_pid_init(tec_control_t *tec)
{
float kp = 15.0f;
float ki = 0.2f;
float kd = 0.05f;
float threshold = 0.5f; // 积分分离阈值,可根据实际情况调整
et_integral_separation_pid_init(&tec->pid, kp, ki, kd, threshold);
}
float tec_pid_update(tec_control_t *tec, float set_point, float current_temp, float dt)
{
tec->pid.set_point = set_point;
return et_integral_separation_pid_update(&tec->pid, current_temp, dt);
}
void tec_control_reset(void)
{
if (tec_control != NULL)
{
tec_control->target_temper = 0.0f;
}
}
int tec_control_start(void)
{
if (tec_control == NULL)
{
ET_ERR("TEC control not initialized");
return -1;
}
if (tec_control->cur_temper > tec_control->exception_temper)
{
ET_WARN("current temperature is too high, cannot start TEC");
return -2;
}
tec_control->is_control = true;
return 0;
}
int tec_control_stop(void)
{
if (tec_control == RT_NULL)
{
ET_ERR("TEC control not initialized");
return -1;
}
tec_control->is_control = false;
return 0;
}
void tec_calculate_temperature(uint32_t adc_value)
{
float mv = 0;
double resistance;
mv = ad7793_convert_to_voltage(&ad7793_dev, adc_value) * 1000;
ET_DBG("voltage:%.2f", mv);
resistance = solve_resistance(mv / 1000);
//ET_PRINTF_FLOAT("resistance:", resistance);
tec_control->cur_temper = pt_precise_temperature(resistance, PT100);
tec_control->cur_temper = et_ema_filter_process(&tec_control->ema_filter, tec_control->cur_temper);
if (isnan(tec_control->cur_temper))
{
rt_kprintf("Invalid resistance value, cannot calculate temperature.\n");
}
else
{
ET_DBG("temperature:%.2f", tec_control->cur_temper);
/* Update shared data */
rt_mutex_take(temp_shared_data.data_mutex, RT_WAITING_FOREVER);
temp_shared_data.current_temperature = tec_control->cur_temper;
temp_shared_data.temp_updated = true;
rt_mutex_release(temp_shared_data.data_mutex);
}
}
float generate_random_temperature(void)
{
// 生成0到RAND_MAX之间的随机整数
int randomInt = rand();
// 转换为0到1之间的浮点数再映射到0到55范围
float randomFloat = (float)randomInt / RAND_MAX * 55.0f;
return randomFloat;
}
/* Temperature sampling thread entry function */
static void temp_sampling_thread_entry(void *parameter)
{
ETK_UNUSED(parameter);
//uint32_t adc_value = 0;
ET_INFO("Temperature sampling thread started");
while (1)
{
/* Wait for ADC ready and read data */
// if (ad7793_wait_ready(&ad7793_dev, 1000) == true)
// {
// if (ad7793_read_data(&ad7793_dev, &adc_value))
// {
// /* Calculate temperature from ADC value */
// tec_calculate_temperature(adc_value);
// }
// else
// {
// ET_ERR("Failed to read ADC data.\n");
// }
// }
//mb_write_current_temp(tec_control->cur_temper);
mb_write_current_temp(generate_random_temperature()); // test only
mb_write_current_rotation(generate_random_temperature()); // test only
/* Delay for next sampling period */
rt_thread_mdelay(ADC_SAMPLE_PERIOD);
}
}
void tec_control_temperature(tec_control_t *tec)
{
float pid_out = 0;
float current_temp;
if (tec == NULL)
{
ET_ERR("tec is NULL");
return;
}
if (tec->is_control == false)
return;
/* Get current temperature from shared data */
rt_mutex_take(temp_shared_data.data_mutex, RT_WAITING_FOREVER);
current_temp = temp_shared_data.current_temperature;
temp_shared_data.temp_updated = false;
rt_mutex_release(temp_shared_data.data_mutex);
/* Update tec control current temperature */
tec->cur_temper = current_temp;
// dt convert to seconds
pid_out = tec_pid_update(tec, tec->target_temper, current_temp, TEC_CONTROL_PERIOD / 1000.0f);
ET_INFO("pid_out:%.2f", pid_out);
pm_tec_set_duty(pid_out);
}
static void tec_control_thread_entry(void *parameter)
{
ETK_UNUSED(parameter);
rt_tick_t last_ms = rt_tick_get_millisecond();
rt_uint32_t received;
et_ema_filter_init(&tec_control->ema_filter, EMA_FILTER_ALPHA);
tec_pid_init(tec_control);
tec_control->is_control = false; // control disabled by default
pm_tec_start();
pm_fan_start();
tec_control->target_temper = 25.0f;
ET_INFO("TEC control thread started");
while (1)
{
// wait for control events with timeout
rt_event_recv(tec_control->control_event,
TEC_CONTROL_START_EVENT | TEC_CONTROL_STOP_EVENT | TEC_TEMP_UPDATE_EVENT,
RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, TEC_CONTROL_PERIOD / 2, &received);
// handle received events
if (received & TEC_CONTROL_START_EVENT)
{
tec_control_start();
ET_INFO("TEC control started by event");
}
if (received & TEC_CONTROL_STOP_EVENT)
{
tec_control_stop();
ET_INFO("TEC control stopped by event");
}
if (received & TEC_TEMP_UPDATE_EVENT)
{
ET_INFO("Target temperature updated to: %.2f°C", tec_control->target_temper);
}
// perform temperature control at specified period
if (rt_tick_get_millisecond() - last_ms > TEC_CONTROL_PERIOD)
{
last_ms = rt_tick_get_millisecond();
tec_control_temperature(tec_control);
}
}
}
int tec_control_init(tec_control_t *tec)
{
rt_thread_t tid;
rt_thread_t temp_tid;
if (tec == NULL)
{
ET_ERR("tec is NULL");
return -1;
}
pm_tec_init();
tec_control = tec;
// create event object for temperature control
tec_control->control_event = rt_event_create("tec_event", RT_IPC_FLAG_FIFO);
if (tec_control->control_event == RT_NULL)
{
ET_ERR("Failed to create TEC control event");
return -3;
}
// create mutex for shared data protection
temp_shared_data.data_mutex = rt_mutex_create("temp_mutex", RT_IPC_FLAG_FIFO);
if (temp_shared_data.data_mutex == RT_NULL)
{
ET_ERR("Failed to create temperature data mutex");
return -5;
}
// initialize shared data
temp_shared_data.current_temperature = 25.0f;
temp_shared_data.temp_updated = false;
// #if (USING_SOFT_SPI == 1)
// if (ad7793_init(&ad7793_dev, &ad7793_hw_if, soft_spi.cs_pin))
// #else
// if (ad7793_init(&ad7793_dev, &ad7793_hw_if, SPI3_CS_AD7793_Pin))
// #endif
// {
// rt_kprintf("AD7793 device initialized successfully.\n");
// }
// else
// {
// rt_kprintf("Failed to initialize AD7793 device.\n");
// return -2;
// }
// create temperature sampling thread
temp_tid = rt_thread_create("temp-sample", temp_sampling_thread_entry, RT_NULL, TEMP_SAMPLE_THREAD_STACK_SIZE,
TEMP_SAMPLE_THREAD_PRIORITY, TEMP_SAMPLE_THREAD_TIMESLICE);
if (temp_tid == RT_NULL)
{
ET_ERR("Failed to create temperature sampling thread");
return -6;
}
rt_thread_startup(temp_tid);
// create TEC control thread
// tid = rt_thread_create("tec-control", tec_control_thread_entry, RT_NULL, TEC_CONTROL_THREAD_STACK_SIZE,
// TEC_CONTROL_THREAD_PRIORITY, TEC_CONTROL_THREAD_TIMESLICE);
// if (tid != RT_NULL)
// {
// rt_thread_startup(tid);
// return 0;
// }
return -4;
}