current_v/Src/adc_sample.c
2025-12-31 08:21:43 +08:00

538 lines
20 KiB
C
Raw 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.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file adc_sample.c
* @author Motor Control SDK Team, Yuwell Software XiangenWang
* @brief Voice Recognition Module Initialization Section,
including peripheral initialization and message node insertion, etc.
* @version 1.0
* @changelog version 1.0 初始版本 2025.12.01
- 新增:新建第一个版本的软件,待完善解析命令后的程序执行部分
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Yuwell Software nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for Yuwell Software.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY Yuwell Software AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL Yuwell Software OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* USER CODE END Header */
#include "adc_sample.h"
#include <stdint.h>
static uint16_t adc_result[ADC_SAMPLE_COUNT] = {0, 0, 0, 0, 0};
/**
* @brief 温度-标称电阻值映射表0~120℃
* @param NONE
* @retval NONE
* @note 关于配置说明:
* 1.数组索引0对应0℃索引n对应n℃直至索引120对应120℃
* 2.电阻值放大10000倍存储如100kΩ存储为1000000单位0.0001kΩ)
* 3.数据来源为NTC热敏电阻官方校准表标称电阻值
* @author jarvis
* @date 2025.11.25
*/
static const uint32_t ntc_res_standard[] = {
3270195, //0℃: 327.0195kΩ → 3270195 (×10000)
3107640, //1℃: 310.7640kΩ
2954121, //2℃: 295.4121kΩ
2809084, //3℃: 280.9084kΩ
2672014, //4℃: 267.2014kΩ
2542428, //5℃: 254.2428kΩ
2419877, //6℃: 241.9877kΩ
2303940, //7℃: 230.3940kΩ
2194224, //8℃: 219.4224kΩ
2090361, //9℃: 209.0361kΩ
1992007, //10℃: 199.2007kΩ
1898841, //11℃: 189.8841kΩ
1810559, //12℃: 181.0559kΩ
1726881, //13℃: 172.6881kΩ
1647540, //14℃: 164.7540kΩ
1572290, //15℃: 157.2290kΩ
1500898, //16℃: 150.0898kΩ
1433144, //17℃: 143.3144kΩ
1368825, //18℃: 136.8825kΩ
1307749, //19℃: 130.7749kΩ
1249734, //20℃: 124.9734kΩ
1194612, //21℃: 119.4612kΩ
1142223, //22℃: 114.2223kΩ
1092417, //23℃: 109.2417kΩ
1045053, //24℃: 104.5053kΩ
1000000, //25℃: 100.0000kΩ
957132, //26℃: 95.7132kΩ
916333, //27℃: 91.6333kΩ
877492, //28℃: 87.7492kΩ
840505, //29℃: 84.0505kΩ
805274, //30℃: 80.5274kΩ
771707, //31℃: 77.1707kΩ
739717, //32℃: 73.9717kΩ
709222, //33℃: 70.9222kΩ
680144, //34℃: 68.0144kΩ
652411, //35℃: 65.2411kΩ
625954, //36℃: 62.5954kΩ
600707, //37℃: 60.0707kΩ
576610, //38℃: 57.6610kΩ
553604, //39℃: 55.3604kΩ
531635, //40℃: 53.1635kΩ
510651, //41℃: 51.0651kΩ
490602, //42℃: 49.0602kΩ
471443, //43℃: 47.1443kΩ
453130, //44℃: 45.3130kΩ
435621, //45℃: 43.5621kΩ
418878, //46℃: 41.8878kΩ
402862, //47℃: 40.2862kΩ
387539, //48℃: 38.7539kΩ
372876, //49℃: 37.2876kΩ
358842, //50℃: 35.8842kΩ
345405, //51℃: 34.5405kΩ
332538, //52℃: 33.2538kΩ
320214, //53℃: 32.0214kΩ
308408, //54℃: 30.8408kΩ
297096, //55℃: 29.7096kΩ
286253, //56℃: 28.6253kΩ
275860, //57℃: 27.5860kΩ
265895, //58℃: 26.5895kΩ
256338, //59℃: 25.6338kΩ
247171, //60℃: 24.7171kΩ
238376, //61℃: 23.8376kΩ
229937, //62℃: 22.9937kΩ
221836, //63℃: 22.1836kΩ
214061, //64℃: 21.4061kΩ
206594, //65℃: 20.6594kΩ
199424, //66℃: 19.9424kΩ
192537, //67℃: 19.2537kΩ
185920, //68℃: 18.5920kΩ
179562, //69℃: 17.9562kΩ
173452, //70℃: 17.3452kΩ
167578, //71℃: 16.7578kΩ
161930, //72℃: 16.1930kΩ
156499, //73℃: 15.6499kΩ
151276, //74℃: 15.1276kΩ
146251, //75℃: 14.6251kΩ
141417, //76℃: 14.1417kΩ
136764, //77℃: 13.6764kΩ
132286, //78℃: 13.2286kΩ
127976, //79℃: 12.7976kΩ
123825, //80℃: 12.3825kΩ
119828, //81℃: 11.9828kΩ
115978, //82℃: 11.5978kΩ
112270, //83℃: 11.2270kΩ
108697, //84℃: 10.8697kΩ
105254, //85℃: 10.5254kΩ
101935, //86℃: 10.1935kΩ
98736, //87℃: 9.8736kΩ
95652, //88℃: 9.5652kΩ
92678, //89℃: 9.2678kΩ
89809, //90℃: 8.9809kΩ
87042, //91℃: 8.7042kΩ
84373, //92℃: 8.4373kΩ
81797, //93℃: 8.1797kΩ
79312, //94℃: 7.9312kΩ
76912, //95℃: 7.6912kΩ
74596, //96℃: 7.4596kΩ
72360, //97℃: 7.2360kΩ
70201, //98℃: 7.0201kΩ
68115, //99℃: 6.8115kΩ
66101, //100℃: 6.6101kΩ
64155, //101℃: 6.4155kΩ
62274, //102℃: 6.2274kΩ
60457, //103℃: 6.0457kΩ
58701, //104℃: 5.8701kΩ
57003, //105℃: 5.7003kΩ
55362, //106℃: 5.5362kΩ
53775, //107℃: 5.3775kΩ
52240, //108℃: 5.2240kΩ
50755, //109℃: 5.0755kΩ
49319, //110℃: 4.9319kΩ
47930, //111℃: 4.7930kΩ
46586, //112℃: 4.6586kΩ
45285, //113℃: 4.5285kΩ
44026, //114℃: 4.4026kΩ
42807, //115℃: 4.2807kΩ
41627, //116℃: 4.1627kΩ
40484, //117℃: 4.0484kΩ
39378, //118℃: 3.9378kΩ
38306, //119℃: 3.8306kΩ
37268 //120℃: 3.7268kΩ
};
/**
* @brief 全局宏定义配置
* @param NONE
* @retval NONE
* @note 关于配置说明:
* 1.TEMP_MIN/TEMP_MAX定义温度检测范围0~120℃
* 2.电阻值放大10000倍存储提升整数插值精度
* @author jarvis
* @date 2025.11.25
*/
#define TEMP_MIN 0
#define TEMP_MAX 120
#define ARRAY_LEN (sizeof(ntc_res_standard)/sizeof(ntc_res_standard[0]))
/**
* @brief 从NTC电阻值插值计算温度
* @param ntc_res: NTC电阻值放大1000倍如100kΩ=100000
* @retval 计算得到的温度值(℃)
* @note 关于配置说明:
* 1.采用线性插值算法,全程无浮点运算
* 2.插值前放大1000倍计算提升整数运算精度
* 3.超出温度范围时返回边界值0℃或120℃
* 4.输入电阻值为×1000内部转换为×10000匹配数组
* @author jarvis
* @date 2025.11.25
*/
static uint8_t calc_temp_by_res(uint32_t ntc_res)
{
// 1. 输入电阻值转换×1000 → ×10000匹配数组存储精度
uint32_t ntc_res_scaled = ntc_res * 10;
// 2. 边界保护:电阻值越小温度越高
if (ntc_res_scaled > ntc_res_standard[0]) { // 电阻>0℃值 → 温度<0℃
return TEMP_MIN;
}
if (ntc_res_scaled < ntc_res_standard[ARRAY_LEN-1]) { // 电阻<120℃值 → 温度>120℃
return TEMP_MAX;
}
// 3. 查找电阻值所在的温度区间
uint8_t idx = 0;
for (idx = 0; idx < ARRAY_LEN-1; idx++)
{
if ((ntc_res_scaled <= ntc_res_standard[idx]) && (ntc_res_scaled >= ntc_res_standard[idx+1]))
{
break;
}
}
return (uint8_t)idx;
}
/**
* @brief 从ADC采样电压计算温度
* @param adc_val: ADC采样值3000对应3V5000对应5V
* @retval 计算得到的温度值(℃)
* @note 关于配置说明:
* 1.电路为NTC与100kΩ并联后再与10kΩ串联分压
* 2.反向推导公式R_NTC = (R并 × R13) / (R13 - R并)
* 3.增加SCALE放大倍数避免整数除法精度丢失
* @author jarvis
* @date 2025.11.25
*/
static uint8_t calc_temp_by_adc(uint16_t adc_val)
{
uint32_t r_parallel_ohm = (uint32_t)adc_val * 10000;
r_parallel_ohm /= (5000 - adc_val);
r_parallel_ohm /= 1000;
uint32_t r_ntc_ohm = r_parallel_ohm * 100;
if(r_parallel_ohm >= 100) // 防止电阻焊接错误
{
r_parallel_ohm = 99;
}
r_ntc_ohm /= (100 - r_parallel_ohm);
return calc_temp_by_res(r_ntc_ohm*1000);
}
// 校准数据表:采样值-实际电压你的4组核心数据
typedef struct {
uint16_t adc_val; // 采样值
uint16_t voltage; // 实际电压(V)
} CalibData_t;
static const CalibData_t calib_table[] =
{
{802, 160},
{864, 170},
{925, 180},
{985, 190},
{1045, 200},
{1105, 210},
{1164, 220},
{1225, 230},
{1284, 240},
{1345, 250},
{1405, 260},
{1465, 270},
{1524, 280},
};
#define CALIB_LEN (sizeof(calib_table)/sizeof(calib_table[0]))
/**
* @brief 采样值转实际电压(查表+线性插值,无浮点)
* @param adc_val: 采样值如1172
* @retval 实际电压(V)
*/
uint16_t calc_220v_voltage(uint16_t adc_val)
{
// 边界保护
if (adc_val <= calib_table[0].adc_val)
{
return calib_table[0].voltage;
}
if (adc_val >= calib_table[CALIB_LEN-1].adc_val)
{
return calib_table[CALIB_LEN-1].voltage;
}
// 查找采样值所在区间
uint16_t idx = 0;
for (idx = 0; idx < CALIB_LEN-1; idx++)
{
if (adc_val >= calib_table[idx].adc_val && adc_val <= calib_table[idx+1].adc_val)
{
break;
}
}
// 线性插值纯整数运算放大1000倍提升精度
int32_t x1 = calib_table[idx].adc_val;
int32_t y1 = calib_table[idx].voltage;
int32_t x2 = calib_table[idx+1].adc_val;
int32_t y2 = calib_table[idx+1].voltage;
uint16_t voltage = y1 + ((adc_val - x1) * (y2 - y1)) / (x2 - x1);
return voltage;
}
/**
* @brief ADC采样初始化
* @param NONE
* @retval NONE
* @note 关于配置说明:
* 1.使用BSTIM16定时器每隔100ms进行一次ADC转换触发
* 2.配置DMA进行持续数据移动将外设数据移动至RAM
* 3.采用16次过采样硬件滤波策略提升精度同时抑制噪声
* @author jarvis
* @data 2025.11.25
*/
void adc_sample_init(void)
{
// 初始化ADC采样的GPIO
FL_GPIO_InitTypeDef GPIO_InitStruct;
FL_BSTIM16_InitTypeDef InitStructer;
FL_ADC_InitTypeDef ADC_InitStruct;
FL_ADC_CommonInitTypeDef Common_InitStruct;
FL_DMA_InitTypeDef DMA_InitStruct = {0};
FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};
/************************************************** 配置用于触发ADC的定时器频率 **********************************************************/
InitStructer.prescaler = 63; /* 配置BSTIM16预分频 */
InitStructer.autoReload = 9999; /* 配置BSTIM16目标寄存器 */
InitStructer.autoReloadState = FL_ENABLE; /* 配置BSTIM16预装载功能 */
InitStructer.clockSource = FL_CMU_BSTIM16_CLK_SOURCE_APBCLK; /* 配置BSTIM16工作时钟源 */
(void)FL_BSTIM16_Init(BSTIM16, &InitStructer);
FL_BSTIM16_SetTriggerOutput(BSTIM16, FL_BSTIM16_TRGO_UPDATE); /* 配置BSTIM16 Trigger事件 */
FL_BSTIM16_ClearFlag_Update(BSTIM16); /* 清updata标志 */
/************************************************** 配置ADC通用配置 **********************************************************/
Common_InitStruct.clockSource = FL_ADC_CLK_SOURCE_APBCLK; /* 配置ADC工作时钟源 */
Common_InitStruct.clockPrescaler = FL_ADC_CLK_PSC_DIV2; /* 配置ADC工作时钟分配 */
Common_InitStruct.referenceSource = FL_ADC_REF_SOURCE_VDDA; /* 配置ADC参考源 */
Common_InitStruct.bitWidth = FL_ADC_BIT_WIDTH_12B; /* 配置ADC输出位宽 */
(void)FL_ADC_CommonInit(&Common_InitStruct);
/************************************************** 配置GPIO引脚状态 **********************************************************/
GPIO_InitStruct.pin = ADC_PRESS_GPIO_PIN; /* 配置GPIO的引脚号 */
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG; /* 配置GPIO的功能模式 */
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL; /* 配置GPIO的输出模式 */
GPIO_InitStruct.pull = FL_DISABLE; /* 配置GPIO输上拉模式 */
GPIO_InitStruct.remapPin = FL_DISABLE; /* 配置GPIO数字重定向功能 */
GPIO_InitStruct.analogSwitch = FL_DISABLE; /* 配置GPIO模拟开关功能 */
(void)FL_GPIO_Init(ADC_PRESS_GPIO_PORT, &GPIO_InitStruct); /* GPIO初始化 */
GPIO_InitStruct.pin = ADC_NTC_GPIO_PIN;
(void)FL_GPIO_Init(ADC_NTC_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.pin = ADC_220V_GPIO_PIN;
(void)FL_GPIO_Init(ADC_220V_GPIO_PORT, &GPIO_InitStruct);
GPIO_InitStruct.pin = ADC_ELEC_GPIO_PIN;
(void)FL_GPIO_Init(ADC_ELEC_GPIO_PORT, &GPIO_InitStruct);
/************************************************** 配置ADC工作通道 **********************************************************/
// 初始化ADC采样通道
ADC_InitStruct.conversionMode = FL_ADC_CONV_MODE_SINGLE; /* 配置ADC转换模式 */
ADC_InitStruct.autoMode = FL_ADC_SINGLE_CONV_MODE_AUTO; /* 配置ADC转换流程仅对单次转换有效 */
ADC_InitStruct.waitMode = FL_DISABLE; /* 配置ADC等待模式 */
ADC_InitStruct.overrunMode = FL_ENABLE; /* 配置ADC_Overrun模式 */
ADC_InitStruct.scanDirection = FL_ADC_SEQ_SCAN_DIR_FORWARD; /* 配置ADC扫描顺序 */
ADC_InitStruct.externalTrigConv = FL_ADC_TRIGGER_EDGE_RISING; /* 配置非软件触发使能及极性 */
ADC_InitStruct.triggerSource = FL_ADC_TRGI_BSTIM16; /* 配置ADC非软件触发源 */
ADC_InitStruct.fastChannelTime = FL_ADC_FAST_CH_SAMPLING_TIME_16_ADCCLK; /* 配置ADC快速通道采样时间 */
ADC_InitStruct.lowChannelTime = FL_ADC_SLOW_CH_SAMPLING_TIME_512_ADCCLK; /* 配置ADC慢速通道采样时间 */
ADC_InitStruct.oversamplingMode = FL_ENABLE; /* 配置ADC过采样模式 */
ADC_InitStruct.overSampingMultiplier = FL_ADC_OVERSAMPLING_MUL_16X; /* 配置ADC过采样率 */
ADC_InitStruct.oversamplingShift = FL_ADC_OVERSAMPLING_SHIFT_4B; /* 配置ADC过采样结果移位 */
(void)FL_ADC_Init(ADC, &ADC_InitStruct);
FL_ADC_EnableSequencerChannel(ADC, ADC_PRESS_CHANNEL); /*通道选择*/
FL_ADC_EnableSequencerChannel(ADC, ADC_NTC_CHANNEL);
FL_ADC_EnableSequencerChannel(ADC, ADC_220V_CHANNEL);
FL_ADC_EnableSequencerChannel(ADC, ADC_ELEC_CHANNEL);
FL_ADC_EnableSequencerChannel(ADC, FL_ADC_INTERNAL_VREF1P2);
FL_VREF_EnableVREFBuffer(VREF);
FL_ADC_EnableDMAReq(ADC); /*配置ADC_DMA*/
/************************************************** 配置DMA转换 **********************************************************/
DMA_InitStruct.periphAddress = FL_DMA_PERIPHERAL_FUNCTION1; //配置DMA通道功能
DMA_InitStruct.direction = FL_DMA_DIR_PERIPHERAL_TO_RAM; //配置DMA通道方向
DMA_InitStruct.memoryAddressIncMode = FL_DMA_MEMORY_INC_MODE_INCREASE; //配置RAM的增减方向
DMA_InitStruct.dataSize = FL_DMA_BANDWIDTH_16B; //配置DMA传输位宽
DMA_InitStruct.priority = FL_DMA_PRIORITY_HIGH; //配置DMA通道优先级
DMA_InitStruct.circMode = FL_ENABLE; //配置DMA通道循环缓存
(void)FL_DMA_Init(DMA, &DMA_InitStruct, FL_DMA_CHANNEL_0);
FL_DMA_Enable(DMA); //配置DMA全局开关
/************************************************** 配置DMA通道 **********************************************************/
DMA_ConfigStruct.memoryAddress = (uint32_t)adc_result; //配置DMA_RAM地址
DMA_ConfigStruct.transmissionCount = ADC_SAMPLE_COUNT - 1; //配置DMA传输长度
(void)FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_0);
FL_ADC_ClearFlag_EndOfConversion(ADC);
FL_ADC_Enable(ADC);
FL_BSTIM16_Enable(BSTIM16);
}
void sample_adc_process_task(void)
{
// 对采样结果进行修改
MsgQueueItem queue_item;
int32_t temp_press;
queue_item.type = MSG_TYPE_AD_SAMPLING;
queue_item.data.adc_data.adc_elec_value = adc_result[ADC_IDX_ELEC];
queue_item.data.adc_data.adc_ntc_value = adc_result[ADC_IDX_NTC];
queue_item.data.adc_data.adc_press_value = adc_result[ADC_IDX_PRESS];
queue_item.data.adc_data.adc_220v_value = adc_result[ADC_IDX_220V];
// 计算各个通道的真实电压
queue_item.data.adc_data.voltage_elec = (uint32_t)(((uint64_t)adc_result[ADC_IDX_ELEC] * ADC_VREF * 3000) / ((uint64_t)adc_result[ADC_IDX_INTERNAL_VREF1P2] * 4095));
queue_item.data.adc_data.voltage_ntc = (uint32_t)(((uint64_t)adc_result[ADC_IDX_NTC] * ADC_VREF * 3000) / ((uint64_t)adc_result[ADC_IDX_INTERNAL_VREF1P2] * 4095));
queue_item.data.adc_data.voltage_press = (uint32_t)(((uint64_t)adc_result[ADC_IDX_PRESS] * ADC_VREF * 3000) / ((uint64_t)adc_result[ADC_IDX_INTERNAL_VREF1P2] * 4095));
queue_item.data.adc_data.voltage_220v = (uint32_t)(((uint64_t)adc_result[ADC_IDX_220V] * ADC_VREF * 3000) / ((uint64_t)adc_result[ADC_IDX_INTERNAL_VREF1P2] * 4095));
// 计算真实压力值
temp_press = (int32_t)1908 * queue_item.data.adc_data.voltage_press - 852000;
if(temp_press < 0)
{
temp_press = 0;
}
queue_item.data.adc_data.real_press = temp_press / 10000;
// 计算真实温度值
queue_item.data.adc_data.real_ntc = calc_temp_by_adc(queue_item.data.adc_data.voltage_ntc);
// 计算真实网电压值
queue_item.data.adc_data.real_220V = calc_220v_voltage(queue_item.data.adc_data.voltage_220v);
// 计算真实压缩机电流值
queue_item.data.adc_data.real_elec = queue_item.data.adc_data.voltage_elec * 639/100;
modify_or_add_queue_node_by_type(&global_queue, queue_item.type, queue_item); // 每隔100ms修改队列中的AD采样数据
}
/************************ (C) COPYRIGHT YUWELL *****END OF FILE****/