- 新增完整的CMSIS解决方案配置,包含AC6/GCC/IAR/CLANG编译器支持 - 添加项目配置文件,定义了设备层、系统层、应用层的模块结构 - 配置ARM::CMSIS和GigaDevice::GD32E50x_DFP软件包依赖 - 创建多层代码架构:应用入口(main)、系统层(sys)、设备层(device) - 实现任务管理系统,包含任务调度器和任务执行器分离设计 - 集成ADC、CANFD、定时器、串口、温度采样等核心功能模块 - 添加详细的README文档说明项目结构和代码组织方式 - 配置AC6链接脚本和运行时环境文件 - 设置Git忽略规则以排除编译产物和临时文件
127 lines
4.0 KiB
Plaintext
127 lines
4.0 KiB
Plaintext
#include "main.h"
|
|
#include "device/adc.h"
|
|
#include "sys/systick.h"
|
|
|
|
#define TEMP_ADC ADC0
|
|
#define TEMP_ADC_CHANNEL ADC_CHANNEL_16
|
|
#define VREFINT_ADC_CHANNEL ADC_CHANNEL_17
|
|
#define ADC_MAX_VALUE 4095.0f
|
|
#define VREFINT_TYPICAL_VOLTAGE 1.20f
|
|
#define TEMP_V25 1.43f
|
|
#define TEMP_AVG_SLOPE 0.0043f
|
|
|
|
/**
|
|
* @brief 初始化 ADC 硬件及内部温度/VREF 通道。
|
|
* @param[in] 无。
|
|
* @param[out] 无。
|
|
* @retval 无返回值。
|
|
* @note 完成 ADC 时钟、模式、触发方式、内部通道和校准流程配置。
|
|
*/
|
|
void adc_hw_init(void)
|
|
{
|
|
rcu_periph_clock_enable(RCU_ADC0);
|
|
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
|
|
|
|
adc_deinit(TEMP_ADC);
|
|
adc_mode_config(ADC_MODE_FREE);
|
|
adc_special_function_config(TEMP_ADC, ADC_SCAN_MODE, DISABLE);
|
|
adc_special_function_config(TEMP_ADC, ADC_CONTINUOUS_MODE, DISABLE);
|
|
adc_data_alignment_config(TEMP_ADC, ADC_DATAALIGN_RIGHT);
|
|
adc_channel_length_config(TEMP_ADC, ADC_REGULAR_CHANNEL, 1U);
|
|
adc_external_trigger_source_config(TEMP_ADC, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
|
|
adc_external_trigger_config(TEMP_ADC, ADC_REGULAR_CHANNEL, DISABLE);
|
|
|
|
adc_tempsensor_vrefint_enable();
|
|
delay_ms(2U);
|
|
|
|
adc_enable(TEMP_ADC);
|
|
delay_ms(2U);
|
|
adc_calibration_enable(TEMP_ADC);
|
|
}
|
|
|
|
/**
|
|
* @brief 执行指定通道的一次 ADC 单次采样。
|
|
* @param[in] channel 待采样的 ADC 通道号。
|
|
* @param[out] 无。
|
|
* @retval uint16_t 指定通道的原始 ADC 采样值。
|
|
* @note 函数采用阻塞式等待,直到 EOC 置位后返回。
|
|
*/
|
|
uint16_t adc_single_read(uint8_t channel)
|
|
{
|
|
adc_regular_channel_config(TEMP_ADC, 0U, channel, ADC_SAMPLETIME_239POINT5);
|
|
adc_flag_clear(TEMP_ADC, ADC_FLAG_EOC);
|
|
adc_software_trigger_enable(TEMP_ADC, ADC_REGULAR_CHANNEL);
|
|
while(RESET == adc_flag_get(TEMP_ADC, ADC_FLAG_EOC)) {
|
|
}
|
|
return adc_regular_data_read(TEMP_ADC);
|
|
}
|
|
|
|
/**
|
|
* @brief 读取内部参考电压通道的原始 ADC 值。
|
|
* @param[in] 无。
|
|
* @param[out] 无。
|
|
* @retval uint16_t 内部参考电压通道的原始 ADC 值。
|
|
*/
|
|
uint16_t adc_read_vref_raw(void)
|
|
{
|
|
return adc_single_read(VREFINT_ADC_CHANNEL);
|
|
}
|
|
|
|
/**
|
|
* @brief 读取内部温度通道的原始 ADC 值。
|
|
* @param[in] 无。
|
|
* @param[out] 无。
|
|
* @retval uint16_t 内部温度通道的原始 ADC 值。
|
|
*/
|
|
uint16_t adc_read_temp_raw(void)
|
|
{
|
|
return adc_single_read(TEMP_ADC_CHANNEL);
|
|
}
|
|
|
|
/**
|
|
* @brief 根据内部参考电压原始值计算实际 VDDA。
|
|
* @param[in] vref_raw 内部参考电压通道原始 ADC 数值。
|
|
* @param[out] 无。
|
|
* @retval float 换算得到的 VDDA 电压值,单位 V。
|
|
* @note 当 vref_raw 为 0 时返回默认 3.3V,避免出现除零异常。
|
|
*/
|
|
float adc_calculate_vdda(uint16_t vref_raw)
|
|
{
|
|
if(vref_raw == 0U) {
|
|
return 3.3f;
|
|
}
|
|
return (VREFINT_TYPICAL_VOLTAGE * ADC_MAX_VALUE) / static_cast<float>(vref_raw);
|
|
}
|
|
|
|
/**
|
|
* @brief 根据温度原始值与 VDDA 计算芯片温度。
|
|
* @param[in] temp_raw 内部温度通道原始 ADC 数值。
|
|
* @param[in] vdda 当前供电电压,单位 V。
|
|
* @param[out] 无。
|
|
* @retval float 换算得到的芯片温度,单位 ℃。
|
|
*/
|
|
float adc_calculate_temperature(uint16_t temp_raw, float vdda)
|
|
{
|
|
const float sensor_voltage = (static_cast<float>(temp_raw) * vdda) / ADC_MAX_VALUE;
|
|
return ((TEMP_V25 - sensor_voltage) / TEMP_AVG_SLOPE) + 25.0f;
|
|
}
|
|
|
|
/**
|
|
* @brief 采集一组完整 ADC 样本并完成工程值换算。
|
|
* @param[in] sample 指向输出样本结构体的指针;允许为空。
|
|
* @param[out] sample 当指针非空时,写入温度/VREF 原始值与换算结果。
|
|
* @retval 无返回值。
|
|
* @note 当 sample 为 NULL 时函数直接返回,不执行任何数据写入。
|
|
*/
|
|
void adc_collect_sample(adc_sample_t *sample)
|
|
{
|
|
if(sample == nullptr) {
|
|
return;
|
|
}
|
|
|
|
sample->vref_raw = adc_read_vref_raw();
|
|
sample->temp_raw = adc_read_temp_raw();
|
|
sample->vdda = adc_calculate_vdda(sample->vref_raw);
|
|
sample->temperature = adc_calculate_temperature(sample->temp_raw, sample->vdda);
|
|
}
|