Files

304 lines
8.8 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "gd32h7xx.h"
#include "adc_temp.h"
#include <string.h>
#include <math.h>
#include "usart.h"
#include "sys_drv_init.h"
#include "gd32h7xx_dma.h"
/* 忙等待延时函数 */
static void delay_ms(uint32_t ms)
{
/* 使用固定的时钟频率 600MHz 来计算延时,避免 SystemCoreClock 未初始化的问题 */
for(volatile uint32_t i = 0; i < (600000000 / 4000) * ms; i++)
{
__NOP();
}
}
/* ADC2 DMA连续采样缓冲:DMA中断只负责“完成标记”,数据处理放在 get_adc_data()。 */
#define ADC_TEMP_DMA_PERIPH DMA1
#define ADC_TEMP_DMA_CH DMA_CH0
#define ADC_TEMP_DMA_IRQN DMA1_Channel0_IRQn
#define ADC_TEMP_DMA_SAMPLE_CNT (16U)
static __IO uint32_t g_adc_dma_buf[ADC_TEMP_DMA_SAMPLE_CNT];
static volatile uint32_t g_adc_dma_frame_cnt;
__IO uint32_t adc_value[4];
void init_adc(void)
{
dma_single_data_parameter_struct dma_init_struct;
/* GPIO时钟使能 */
rcu_periph_clock_enable(RCU_GPIOC);
/* ADC时钟使能 */
rcu_periph_clock_enable(RCU_ADC2);
/* DMA时钟使能 */
rcu_periph_clock_enable(RCU_DMA1);
/* GPIO参数配置*/
gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_2);
/* ADC初始化 -- 根据数据手册,ADC2_IN0--PC2端子仅能使用ADC2第0个通道 */
adc_deinit(ADC2);
/* ADC时钟配置 */
adc_clock_config(ADC2, ADC_CLK_SYNC_HCLK_DIV6);
/* 单通道连续转换 + DMA */
adc_special_function_config(ADC2, ADC_SCAN_MODE, DISABLE);
adc_special_function_config(ADC2, ADC_CONTINUOUS_MODE, ENABLE);
/* 转换结果(12/14位)存放在 32 位寄存器的低 16 位中 */
adc_data_alignment_config(ADC2, ADC_DATAALIGN_RIGHT);
/* ADC 通道配置(规则通道组,单通道) */
adc_channel_length_config(ADC2, ADC_REGULAR_CHANNEL, 1);
/* 配置规则通道序列,决定 ADC 在转换时,对 PC2 引脚电压进行采样的时间长度*/
adc_regular_channel_config(ADC2, 0, ADC_CHANNEL_0, 240);
/* 禁用外部触发*/
adc_external_trigger_config(ADC2, ADC_REGULAR_CHANNEL, EXTERNAL_TRIGGER_DISABLE);
/* DMA配置:ADC2 regular data -> g_adc_dma_buf[] (循环) */
dma_deinit(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH);
dma_single_data_para_struct_init(&dma_init_struct);
dma_init_struct.request = DMA_REQUEST_ADC2;
dma_init_struct.periph_addr = (uint32_t)&ADC_RDATA(ADC2);
dma_init_struct.periph_inc = DMA_MEMORY_INCREASE_DISABLE;
dma_init_struct.memory0_addr = (uint32_t)g_adc_dma_buf;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_ENABLE;
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_init_struct.priority = DMA_PRIORITY_HIGH;
dma_init_struct.number = ADC_TEMP_DMA_SAMPLE_CNT;
dma_single_data_mode_init(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, &dma_init_struct);
dma_interrupt_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_HTF);
dma_interrupt_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FTF);
nvic_irq_enable(ADC_TEMP_DMA_IRQN, 6U, 0U);
/* 使能 ADC2 模块 */
adc_enable(ADC2);
/* wait for ADC stability */
delay_ms(1);
/* 配置校准模式,偏移量校准,用于纠正 ADC 自身的零点误差 */
adc_calibration_mode_config(ADC2, ADC_CALIBRATION_OFFSET);
/* 配置校准次数 */
adc_calibration_number(ADC2, ADC_CALIBRATION_NUM1);
/*执行校准 */
adc_calibration_enable(ADC2);
/* 启动DMA与ADC连续转换 */
memset((void *)g_adc_dma_buf, 0, sizeof(g_adc_dma_buf));
g_adc_dma_frame_cnt = 0U;
dma_channel_enable(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH);
adc_dma_mode_enable(ADC2);
adc_dma_request_after_last_enable(ADC2);
adc_software_trigger_enable(ADC2, ADC_REGULAR_CHANNEL);
}
uint32_t adc_channel_sample(uint8_t channel)
{
uint32_t timeout = 1000000U;
/* 重新配置规则通道 */
adc_regular_channel_config(ADC2, 0U, channel, 240);
/* 软件触发转换 */
adc_software_trigger_enable(ADC2, ADC_REGULAR_CHANNEL);
/* 等待转换结束 */
while(!adc_flag_get(ADC2, ADC_FLAG_EOC)){
if (timeout-- == 0U) {
return 0U;
}
}
/* 清除标志 */
adc_flag_clear(ADC2, ADC_FLAG_EOC);
/* 读取结果并返回 */
return (adc_regular_data_read(ADC2));
}
void DMA1_Channel0_IRQHandler(void)
{
if (SET == dma_interrupt_flag_get(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_HTF)) {
dma_interrupt_flag_clear(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_HTF);
g_adc_dma_frame_cnt++;
}
if (SET == dma_interrupt_flag_get(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(ADC_TEMP_DMA_PERIPH, ADC_TEMP_DMA_CH, DMA_INT_FLAG_FTF);
g_adc_dma_frame_cnt++;
}
}
void select_temp_channel(uint8_t flag_set)
{
//温度采集选通,
/*
OUT8、OUT7设置为高电平,A枪正温度
OUT8设置为高电平,OUT7设置为低电平,A枪负温度
OUT8设置为低电平,OUT7设置为高电平,B枪正温度
OUT8、OUT7设置为低电平,B枪负温度
*/
if(flag_set == 0)
{
TEMP_MULT_CTRA(1);
TEMP_MULT_CTRB(1);
TEMP_MULT_CTRC(1);
}
else if(flag_set == 1)
{
TEMP_MULT_CTRA(0);
TEMP_MULT_CTRB(1);
TEMP_MULT_CTRC(1);
}
else if(flag_set == 2)
{
TEMP_MULT_CTRA(1);
TEMP_MULT_CTRB(0);
TEMP_MULT_CTRC(1);
}
else if(flag_set == 3)
{
TEMP_MULT_CTRA(0);
TEMP_MULT_CTRB(0);
TEMP_MULT_CTRC(1);
}
else if(flag_set == 4)
{
TEMP_MULT_CTRA(1);
TEMP_MULT_CTRB(1);
TEMP_MULT_CTRC(0);
}
else if(flag_set == 5)
{
TEMP_MULT_CTRA(0);
TEMP_MULT_CTRB(1);
TEMP_MULT_CTRC(0);
}
else if(flag_set == 6)
{
TEMP_MULT_CTRA(1);
TEMP_MULT_CTRB(0);
TEMP_MULT_CTRC(0);
}
else if(flag_set == 7)
{
TEMP_MULT_CTRA(0);
TEMP_MULT_CTRB(0);
TEMP_MULT_CTRC(0);
}
}
double double_Vol_to_resistance(double vol)
{
double ret = 0;
//BL1117-50CX输出+5V_Tem,可通过测量VOL_Vin2校准+5V_Tem,Rt=3kΩ*Vo/+5V_Tem-Vo
ret = (3000 * vol) / (5.04 - vol);
return ret / 1000.0;
}
double PT1000_Vol_To_Temperature(double vol)
{
// 定义PT1000常数
double R;
const double R0 = 1000.0; // 0°C时的电阻值
const double A = 3.9083e-3; // IEC751系数
const double B = -5.775e-7;
const double C = -4.183e-12; // 负温度区系数
// 计算电阻值(kΩ单位)
R = double_Vol_to_resistance(vol);
/* 校准系数(保持kΩ单位) */
if (R > 1.219)
{
R = R * 1.01778; // 高温区补偿
}
else if (R > 1)
{
R = R * 1.00395; // 常温区补偿
}
else
{
R = R * 0.98884; // 低温区补偿
}
// 转换为Ω单位
double R_ohm = R * 1000.0;
// 计算温度
if (R_ohm >= R0)
{
// 正温度区使用二次方程
double discriminant = A * A - 4 * B * (1 - R_ohm / R0);
return (-A + sqrt(discriminant)) / (2 * B);
}
else
{
// 负温度区使用牛顿迭代法
const int max_iter = 100; // 最大迭代次数
const double tol = 1e-6; // 收敛误差
double T = -50.0; // 初始温度估计值
for (int i = 0; i < max_iter; i++)
{
double T2 = T * T;
double T3 = T2 * T;
// Callendar-Van Dusen方程
double f = R0 * (1 + A * T + B * T2 + C * (T - 100) * T3) - R_ohm;
// 检查是否收敛
if (fabs(f) < tol)
{
return T;
}
// 导数计算
double df = R0 * (A + 2 * B * T + C * (4 * T3 - 300 * T2));
// 避免除零错误
if (fabs(df) < 1e-10)
{
break;
}
// 牛顿迭代法更新
T -= f / df;
}
// 返回收敛值
return T;
}
}
uint32_t get_adc_data(void)
{
uint64_t sum = 0U;
uint32_t i;
/* 仅处理DMA中断已写入的采样数据,不触发硬件采样。 */
for (i = 0U; i < ADC_TEMP_DMA_SAMPLE_CNT; i++)
{
sum += g_adc_dma_buf[i];
// printf("data = %d\n", g_adc_dma_buf[i]);
}
return (uint32_t)(sum / ADC_TEMP_DMA_SAMPLE_CNT);
}
uint32_t adc_readval(void)
{
float ret, temp_data = 0.0f;
ret = (get_adc_data() * 3.0f) / 4095.0f;
temp_data = PT1000_Vol_To_Temperature(ret);
return temp_data;
}
void adc_test(uint8_t i)
{
float val_value;
(void)i;
delay_ms(1000);
adc_value[0] = adc_channel_sample(ADC_CHANNEL_0);
val_value = (adc_value[0] * 3.0f) / 4095.0f;
(void)val_value;
}