268 lines
7.3 KiB
C
268 lines
7.3 KiB
C
/**
|
||
* @file adcs.c
|
||
* @author xxx
|
||
* @date 2023-09-04 15:59:16
|
||
* @brief LL库ADC驱动
|
||
* @copyright Copyright (c) 2023 by xxx, All Rights Reserved.
|
||
*/
|
||
|
||
#include "adcs.h"
|
||
|
||
#define ADC_CH_NUM INMAX
|
||
#define ADC_COLL 20 /* 通道单采集次数*/
|
||
#define ADC_SUM ADC_CH_NUM *ADC_COLL /* 总采集次数 */
|
||
|
||
__IO static uint16_t adc_value[ADC_COLL][INMAX]; /* 存储ADC原始值 */
|
||
__IO static BOOL _flag = FALSE; /* DMA传输完成标志 */
|
||
static BOOL init_flag = FALSE; /* ADC初始化标志 */
|
||
/**
|
||
* @brief 这是一个用于处理ADC转换完成回调的函数
|
||
* @param {adc_t} handle - 包含ADC句柄的信息
|
||
* @return {*} 无
|
||
*/
|
||
void adc_convert_callback(adc_t handle)
|
||
{
|
||
// 检查DMA1的传输完成标志是否为1,如果是,则清除该标志
|
||
if (LL_DMA_IsActiveFlag_TC1(handle.dma) != 0)
|
||
{
|
||
LL_DMA_ClearFlag_TC1(handle.dma);
|
||
// 停止ADC转换
|
||
LL_ADC_REG_StopConversion(handle.adc);
|
||
// 关闭ADC,可以不关闭但是校准无法清除
|
||
// LL_ADC_Disable(handle.adc);
|
||
adc_completed_state_change(TRUE);
|
||
}
|
||
// 检查DMA1的传输错误标志是否为1,如果是,则清除该标志
|
||
if (LL_DMA_IsActiveFlag_TE1(handle.dma) != 0)
|
||
{
|
||
LL_DMA_ClearFlag_TE1(handle.dma);
|
||
}
|
||
// ...
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化ADC
|
||
* @param {adc_t} handle
|
||
* @return {*}
|
||
* @note TCONV(转换时间) = 采样时间+ 12.5 个周期
|
||
*/
|
||
void adc_init(adc_t handle)
|
||
{
|
||
init_flag = TRUE;
|
||
uint32_t backup_setting_adc_dma_transfer = 0U;
|
||
backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(handle.adc);
|
||
LL_ADC_REG_SetDMATransfer(handle.adc, LL_ADC_REG_DMA_TRANSFER_NONE);
|
||
// ADC开始校准
|
||
LL_ADC_StartCalibration(handle.adc);
|
||
// 等待校准完成
|
||
while (LL_ADC_IsCalibrationOnGoing(handle.adc))
|
||
;
|
||
LL_ADC_REG_SetDMATransfer(handle.adc, backup_setting_adc_dma_transfer);
|
||
|
||
LL_mDelay(10);
|
||
LL_ADC_Enable(handle.adc);
|
||
LL_mDelay(10);
|
||
|
||
LL_DMA_SetDataLength(handle.dma, handle.dma_channel, ADC_SUM);
|
||
LL_DMA_SetPeriphAddress(handle.dma, handle.dma_channel, LL_ADC_DMA_GetRegAddr(handle.adc, LL_ADC_DMA_REG_REGULAR_DATA));
|
||
LL_DMA_SetMemoryAddress(handle.dma, handle.dma_channel, (uint32_t)&adc_value);
|
||
LL_DMA_EnableChannel(handle.dma, handle.dma_channel);
|
||
|
||
if (backup_setting_adc_dma_transfer == LL_ADC_REG_DMA_TRANSFER_UNLIMITED)
|
||
{
|
||
LL_ADC_REG_StartConversion(handle.adc); // 开始转换
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 开始转换ADC
|
||
* @param {adc_t} handle
|
||
* @return {*}
|
||
* @note 单次采集需要每次调用
|
||
*/
|
||
void adc_start(adc_t handle)
|
||
{
|
||
if (TRUE == init_flag)
|
||
{
|
||
LL_ADC_REG_StartConversion(handle.adc); // 开始转换
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 设置ADC转换完成状态变化回调函数
|
||
* @param {BOOL} state
|
||
* @return {*}
|
||
*/
|
||
void adc_completed_state_change(BOOL state)
|
||
{
|
||
_flag = state;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取ADC转换完成状态
|
||
* @return {BOOL} ADC转换完成标志
|
||
*/
|
||
BOOL adc_completed(void)
|
||
{
|
||
return _flag;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取ADC第0个通道的读取结果
|
||
* @param {uint8_t} in_num
|
||
* @return {uint16_t} 返回当前值
|
||
*/
|
||
uint16_t adc_get_result0(uint8_t in_num)
|
||
{
|
||
return adc_value[0][in_num];
|
||
}
|
||
|
||
/**
|
||
* @brief 获取ADC所有通道的读取结果平均值
|
||
* @param {uint8_t} adc_num
|
||
* @return {uint16_t} 返回平均值
|
||
*/
|
||
uint16_t adc_get_result_average(uint8_t adc_num)
|
||
{
|
||
uint32_t adc_sum = 0; // 用于存储所有ADC通道数据的和
|
||
uint16_t adc_average = 0; // 用于存储平均值
|
||
uint16_t i = 0; // 用于循环的变量
|
||
|
||
for (i = 0; i < ADC_COLL; i++) // 遍历所有ADC通道
|
||
{
|
||
adc_sum += adc_value[i][adc_num]; // 将每个ADC通道的数据累加到adc_sum中
|
||
}
|
||
|
||
adc_average = adc_sum / ADC_COLL; // 计算平均值并存储在adc_average中
|
||
return adc_average; // 返回平均值
|
||
}
|
||
|
||
/**
|
||
* @brief 获取ADC所有通道的读取结果平均值,按照从小到大排序,取中间N个数据
|
||
* @param {uint8_t} adc_num
|
||
* @return {uint16_t} 返回平均值
|
||
*/
|
||
uint16_t adc_get_n_result_average(uint8_t adc_num)
|
||
{
|
||
uint32_t adc_sum = 0;
|
||
uint16_t adc_average = 0;
|
||
uint16_t array[ADC_COLL];
|
||
uint8_t n = ADC_COLL / 4;
|
||
uint8_t count = ADC_COLL > (2 * n) ? n : 0;
|
||
|
||
for (uint16_t i = 0; i < ADC_COLL; i++)
|
||
{
|
||
array[i] = adc_value[i][adc_num];
|
||
}
|
||
|
||
osel_quick_sort(array, 0, ADC_COLL - 1);
|
||
|
||
for (uint16_t i = count; i < ADC_COLL - count; i++)
|
||
{
|
||
adc_sum += array[i];
|
||
}
|
||
|
||
adc_average = adc_sum / (ADC_COLL - 2 * count);
|
||
|
||
return adc_average;
|
||
}
|
||
|
||
/**
|
||
* @brief 中位值滤波
|
||
* @param {uint8_t} adc_num
|
||
* @return {uint16_t} 返回中位数
|
||
*/
|
||
uint16_t adc_get_result_median(uint8_t adc_num)
|
||
{
|
||
uint16_t adc_temp[ADC_COLL];
|
||
uint16_t i = 0, j = 0;
|
||
uint16_t temp = 0;
|
||
for (i = 0; i < ADC_COLL; i++)
|
||
{
|
||
adc_temp[i] = adc_value[i][adc_num];
|
||
}
|
||
for (i = 0; i < ADC_COLL - 1; i++)
|
||
{
|
||
for (j = 0; j < ADC_COLL - 1 - i; j++)
|
||
{
|
||
if (adc_temp[j] > adc_temp[j + 1])
|
||
{
|
||
temp = adc_temp[j];
|
||
adc_temp[j] = adc_temp[j + 1];
|
||
adc_temp[j + 1] = temp;
|
||
}
|
||
}
|
||
}
|
||
return adc_temp[ADC_COLL / 2];
|
||
}
|
||
|
||
/**
|
||
* @brief 中位值平均滤波
|
||
* @param {uint8_t} adc_num
|
||
* @return {uint16_t} 返回中位数
|
||
*/
|
||
uint16_t adc_get_result_median_average(uint8_t adc_num)
|
||
{
|
||
uint16_t adc_temp[ADC_COLL];
|
||
uint16_t i = 0, j = 0;
|
||
uint16_t temp = 0;
|
||
uint32_t adc_sum = 0; // 用于存储所有ADC通道数据的和
|
||
uint16_t adc_average = 0; // 用于存储平均值
|
||
for (i = 0; i < ADC_COLL; i++)
|
||
{
|
||
adc_temp[i] = adc_value[i][adc_num];
|
||
}
|
||
for (i = 0; i < ADC_COLL - 1; i++)
|
||
{
|
||
for (j = 0; j < ADC_COLL - 1 - i; j++)
|
||
{
|
||
if (adc_temp[j] > adc_temp[j + 1])
|
||
{
|
||
temp = adc_temp[j];
|
||
adc_temp[j] = adc_temp[j + 1];
|
||
adc_temp[j + 1] = temp;
|
||
}
|
||
}
|
||
}
|
||
for (i = 0; i < ADC_COLL; i++) // 遍历所有ADC通道
|
||
{
|
||
adc_sum += adc_temp[i]; // 将每个ADC通道的数据累加到adc_sum中
|
||
}
|
||
|
||
adc_average = adc_sum / ADC_COLL; // 计算平均值并存储在adc_average中
|
||
return adc_average; // 返回平均值
|
||
}
|
||
|
||
/**
|
||
* @brief 计算温度值
|
||
* @param {uint16_t} measure - ADC读取到的温度值
|
||
* @return {int32_t} 返回温度值
|
||
* @note: 计算公式为:(measure * VDD_APPLI / VDD_CALIB) - (int32_t)*TEMP30_CAL_ADDR) * (int32_t)(130 - 30) / (int32_t)(*TEMP130_CAL_ADDR - *TEMP30_CAL_ADDR)) + 30
|
||
*/
|
||
int32_t compute_temperature(uint16_t measure)
|
||
{
|
||
#define TEMP130_CAL_ADDR ((uint16_t *)((uint32_t)0x1FF8007E))
|
||
#define TEMP30_CAL_ADDR ((uint16_t *)((uint32_t)0x1FF8007A))
|
||
#define VDD_CALIB ((uint16_t)(300))
|
||
#define VDD_APPLI ((uint16_t)(330))
|
||
int32_t tmp;
|
||
tmp = ((measure * VDD_APPLI / VDD_CALIB) -
|
||
(int32_t)*TEMP30_CAL_ADDR);
|
||
tmp = tmp * (int32_t)(130 - 30);
|
||
tmp = tmp / (int32_t)(*TEMP130_CAL_ADDR -
|
||
*TEMP30_CAL_ADDR);
|
||
tmp = tmp + 30;
|
||
return (tmp);
|
||
}
|
||
|
||
/**
|
||
* @brief 计算本地值
|
||
* @param {uint16_t} measure - ADC读取到的电压值
|
||
* @return {int32_t} 返回本地值
|
||
* @note: 计算公式为:(1224.0 / measure) * 4096
|
||
*/
|
||
int32_t compute_value_local(uint16_t measure)
|
||
{
|
||
return (1224.0 / measure) * 4096;
|
||
}
|