#include "gd32h7xx.h" #include "adc_temp.h" #include #include #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; }