2025-09-15 09:03:37 +00:00
|
|
|
|
/************************************************************
|
|
|
|
|
Copyright (C), 2025, cerlink Tech. Co., Ltd.
|
2025-09-16 02:05:41 +00:00
|
|
|
|
FileName: drv_adc.c
|
2025-09-15 09:03:37 +00:00
|
|
|
|
Author: dufresne Version : 1.0 Date:2025.09.15
|
|
|
|
|
Description: // 模块描述
|
|
|
|
|
Version: // 版本信息
|
|
|
|
|
Function List: // 主要函数及其功能
|
|
|
|
|
1. -------
|
|
|
|
|
History: // 历史修改记录
|
|
|
|
|
<author> <time> <version > <desc>
|
|
|
|
|
David 96/10/12 1.0 build this moudle
|
|
|
|
|
***********************************************************/
|
|
|
|
|
|
2025-09-12 09:53:32 +00:00
|
|
|
|
#include "drv_adc.h"
|
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/*全局声明区*/
|
|
|
|
|
uint16_t USER_ADC_DMA_DATA_BUFF[16] = {0};
|
2025-09-12 09:53:32 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
|
|
|
|
|
void adc_init(void)
|
|
|
|
|
{
|
|
|
|
|
adc_rcu_config();
|
|
|
|
|
adc_gpio_config();
|
|
|
|
|
adc_dma_config();
|
|
|
|
|
adc_config();
|
|
|
|
|
}
|
|
|
|
|
/* 时钟+GPIO */
|
|
|
|
|
void adc_rcu_config(void)
|
2025-09-12 09:53:32 +00:00
|
|
|
|
{
|
2025-09-16 02:05:41 +00:00
|
|
|
|
/* 启用ADC1时钟 */
|
2025-09-12 09:53:32 +00:00
|
|
|
|
rcu_periph_clock_enable(RCU_ADC1);
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* peripheral clock enable */
|
|
|
|
|
rcu_periph_clock_enable(RCU_DMA1);//ADC只能用DMA1
|
2025-09-13 10:04:22 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* 启用GPIOC时钟 */
|
|
|
|
|
rcu_periph_clock_enable(RCU_GPIOC);
|
2025-09-15 09:03:37 +00:00
|
|
|
|
|
|
|
|
|
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
|
2025-09-16 09:20:37 +00:00
|
|
|
|
}
|
2025-09-15 09:03:37 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
void adc_gpio_config(void)
|
|
|
|
|
{
|
2025-09-15 09:03:37 +00:00
|
|
|
|
/* 配置ADC引脚为模拟输入模式 */
|
|
|
|
|
gpio_mode_set(ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, VOLTAGE_ADC_PIN);
|
|
|
|
|
gpio_mode_set(ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, CURRENT_ADC_PIN);
|
2025-09-16 09:20:37 +00:00
|
|
|
|
}
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* DMA配置 */
|
|
|
|
|
static void adc_dma_config(void)
|
|
|
|
|
{
|
|
|
|
|
/* ADC_DMA_channel configuration */
|
|
|
|
|
dma_single_data_parameter_struct dma_single_data_parameter; //这里使用单数据模式,每次只传输一个数据单元,因为总数据量不大,且数据个数不固定
|
|
|
|
|
|
|
|
|
|
/* ADC DMA_channel configuration */
|
|
|
|
|
dma_deinit(DMA1, USER_DMA_ADC_CHANNEL);
|
|
|
|
|
|
|
|
|
|
/* initialize DMA single data mode */
|
|
|
|
|
dma_single_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADCX));//配置外设数据源地址,宏决定ADCx
|
|
|
|
|
dma_single_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//关闭外设增量,只需要每次对该数据源寄存器访问
|
|
|
|
|
|
|
|
|
|
dma_single_data_parameter.memory0_addr = (uint32_t)USER_ADC_DMA_DATA_BUFF;//先写死,然后外部用的话需要extern
|
|
|
|
|
dma_single_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//开启内存增量,以存放不同通道的ADC数据
|
|
|
|
|
|
|
|
|
|
dma_single_data_parameter.periph_memory_width = DMA_PERIPH_WIDTH_16BIT;//ADC数据为16位的寄存器,数据目的地为16位
|
|
|
|
|
|
|
|
|
|
dma_single_data_parameter.circular_mode = DMA_CIRCULAR_MODE_ENABLE;//循环模式,由ADC通知DMA进行
|
|
|
|
|
/* DMA外设到内存模式不开启 */
|
|
|
|
|
dma_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY;//ADC外设到RAM全局变量
|
|
|
|
|
dma_single_data_parameter.number = CHANNEL_LENGTH;//宏决定传输个数
|
|
|
|
|
dma_single_data_parameter.priority = DMA_PRIORITY_ULTRA_HIGH;//优先级设为超高,可改用宏
|
|
|
|
|
dma_single_data_mode_init(DMA1, USER_DMA_ADC_CHANNEL, &dma_single_data_parameter);
|
|
|
|
|
/* 配置 dma 子连接 */
|
|
|
|
|
dma_channel_subperipheral_select(DMA1, USER_DMA_ADC_CHANNEL, USER_DMA_ADC_SUBPERI);
|
|
|
|
|
|
|
|
|
|
/* enable DMA circulation mode */
|
|
|
|
|
dma_circulation_enable(DMA1, USER_DMA_ADC_CHANNEL);// 开启循环模式
|
|
|
|
|
|
|
|
|
|
/* enable DMA channel */
|
|
|
|
|
dma_channel_enable(DMA1, USER_DMA_ADC_CHANNEL);
|
|
|
|
|
|
|
|
|
|
/* enable DMA it */
|
|
|
|
|
dma_interrupt_enable(DMA1,USER_DMA_ADC_CHANNEL,DMA_INT_FTF);//DMA传输完成标志位 打开全部完成中断
|
|
|
|
|
nvic_irq_enable(DMA_ADC_IRQn, DMA_ADC_PRIORITY_PRE, DMA_ADC_PRIORITY_SUB);
|
|
|
|
|
}
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
void adc_config(void)
|
|
|
|
|
{
|
|
|
|
|
adc_deinit();// 复位ADC配置(可选,但建议初始化时做一次)
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
adc_special_function_config(ADCX, ADC_SCAN_MODE, SCAN_STATUS);// 打开扫描模式
|
|
|
|
|
adc_special_function_config(ADCX, ADC_CONTINUOUS_MODE, CONTINUOUS_STATUS);// 禁止连续模式 -> 单次转换模式
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
adc_data_alignment_config(ADCX, ADC_DATAALIGN_RIGHT);// 配置数据对齐方式为右对齐
|
|
|
|
|
adc_resolution_config(ADCX, ADC_RESOLUTION_12B);// 配置ADC分辨率:12位
|
|
|
|
|
|
|
|
|
|
/* 设置转换通道序列 */
|
|
|
|
|
adc_channel_length_config(ADCX, SEQUENCE_CHANNEL, CHANNEL_LENGTH);// 配置规则序列的长度:2个通道
|
2025-09-12 09:53:32 +00:00
|
|
|
|
|
2025-09-15 09:03:37 +00:00
|
|
|
|
adc_routine_channel_config(ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
|
2025-09-16 09:20:37 +00:00
|
|
|
|
adc_routine_channel_config(ADCX, 1, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
|
|
|
|
|
|
2025-09-15 09:03:37 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* 使能外部触发:这里使用软件触发,所以先禁用硬件触发 */
|
|
|
|
|
adc_external_trigger_source_config(ADCX, SEQUENCE_CHANNEL, ADC_EXTTRIG_ROUTINE_T0_CH0);
|
|
|
|
|
adc_external_trigger_config(ADCX, SEQUENCE_CHANNEL, DISABLE);
|
2025-09-13 10:04:22 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* ADC dma config */
|
|
|
|
|
adc_dma_request_after_last_enable(ADCX);
|
|
|
|
|
adc_dma_mode_enable(ADCX);
|
2025-09-12 09:53:32 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
adc_enable(ADCX);// 开启ADC
|
|
|
|
|
rt_thread_mdelay(50);// 等待ADC稳定后续接校准
|
|
|
|
|
adc_calibration_enable(ADCX);// 执行ADC自校准
|
|
|
|
|
|
|
|
|
|
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief 根据转换序列的序列号,获取转换序列中的ADC测量值
|
|
|
|
|
* @param 配置ADC通道结构体中的成员序号
|
|
|
|
|
* @return 测量并转换后的值
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
uint16_t BSP_ADCDataAcquire(uint8_t _index)
|
|
|
|
|
{
|
|
|
|
|
return USER_ADC_DMA_DATA_BUFF[_index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ---------------------------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
|
|
// adc电压采集
|
|
|
|
|
float ptz_Voltage_collect_adc1_task()
|
|
|
|
|
{
|
2025-09-15 09:03:37 +00:00
|
|
|
|
static float adc1_v[LB_V_TIMES];
|
|
|
|
|
static float curadc1_out_v;
|
|
|
|
|
static uint8_t adc1_v_num;
|
2025-09-13 10:04:22 +00:00
|
|
|
|
int j,k;
|
|
|
|
|
float tem;
|
|
|
|
|
float curadc1;
|
|
|
|
|
uint16_t value_V = 0;
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
/* 配置规则序列:序号0是电压通道,序号1是电流通道 */
|
|
|
|
|
adc_routine_channel_config(ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
|
|
|
|
|
|
|
|
|
|
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
|
2025-09-13 10:04:22 +00:00
|
|
|
|
while(adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束
|
|
|
|
|
value_V = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-15 09:03:37 +00:00
|
|
|
|
/* 间接测量,11倍分压/放大 */
|
|
|
|
|
adc1_v[adc1_v_num] = (float)value_V / 4095.0 * 3.3;
|
|
|
|
|
|
|
|
|
|
adc1_v_num++;
|
|
|
|
|
if(adc1_v_num >= LB_V_TIMES)
|
|
|
|
|
{
|
|
|
|
|
adc1_v_num = 0;
|
2025-09-16 09:20:37 +00:00
|
|
|
|
for(j = 0; j < LB_V_TIMES-1; j++)// 采样值由小到大排列
|
2025-09-15 09:03:37 +00:00
|
|
|
|
{
|
|
|
|
|
for(k = 0; k < LB_V_TIMES-j-1; k++)
|
|
|
|
|
{
|
|
|
|
|
if(adc1_v[k] > adc1_v[k+1])
|
|
|
|
|
{
|
|
|
|
|
tem = adc1_v[k];
|
|
|
|
|
adc1_v[k] = adc1_v[k+1];
|
|
|
|
|
adc1_v[k+1] = tem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(uint8_t i = 1; i < LB_V_TIMES - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
curadc1 = curadc1 + adc1_v[i];
|
|
|
|
|
}
|
2025-09-16 09:20:37 +00:00
|
|
|
|
curadc1 = curadc1 /((float)(LB_V_TIMES - 2));// 去掉一个最大值和一个最小值求平均值
|
2025-09-15 09:03:37 +00:00
|
|
|
|
// g_ptz.Voltage = curadc1;
|
2025-09-16 09:20:37 +00:00
|
|
|
|
memset(adc1_v, 0, sizeof(adc1_v));// adc1_v 快速清零
|
2025-09-15 09:03:37 +00:00
|
|
|
|
curadc1_out_v = curadc1;
|
|
|
|
|
}
|
|
|
|
|
return curadc1_out_v;
|
2025-09-12 09:53:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-15 09:03:37 +00:00
|
|
|
|
// adc电流采集
|
|
|
|
|
float ptz_Current_collect_adc1_task()
|
|
|
|
|
{
|
|
|
|
|
static float adc1_i[LB_I_TIMES];
|
|
|
|
|
static float curadc1_out_i;
|
|
|
|
|
static uint8_t adc1_i_num;
|
|
|
|
|
int j,k;
|
|
|
|
|
float tem;
|
|
|
|
|
float curadc1;
|
|
|
|
|
uint16_t value_I = 0;
|
|
|
|
|
|
2025-09-16 09:20:37 +00:00
|
|
|
|
// 配置规则序列:序号0是电压通道,序号1是电流通道
|
|
|
|
|
adc_routine_channel_config(ADCX, 0, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
|
|
|
|
|
|
|
|
|
|
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
|
|
|
|
|
while(adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束->等到SET
|
2025-09-15 09:03:37 +00:00
|
|
|
|
value_I = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
|
|
|
|
|
|
|
|
|
|
/* 间接测量,11倍分压/放大 */
|
|
|
|
|
adc1_i[adc1_i_num] = (((float)value_I / 4096.0 * 3.3) - 3.3 / 2) / 0.132;
|
|
|
|
|
|
|
|
|
|
adc1_i_num++;
|
|
|
|
|
if(adc1_i_num >= LB_I_TIMES)
|
|
|
|
|
{
|
|
|
|
|
adc1_i_num = 0;
|
|
|
|
|
for(j = 0; j < LB_I_TIMES-1; j++)//采样值由小到大排列
|
|
|
|
|
{
|
|
|
|
|
for(k = 0; k < LB_I_TIMES-j-1; k++)
|
|
|
|
|
{
|
|
|
|
|
if(adc1_i[k] > adc1_i[k+1])
|
|
|
|
|
{
|
|
|
|
|
tem = adc1_i[k];
|
|
|
|
|
adc1_i[k] = adc1_i[k+1];
|
|
|
|
|
adc1_i[k+1] = tem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(uint8_t i = 1; i < LB_I_TIMES - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
curadc1 = curadc1 + adc1_i[i];
|
|
|
|
|
}
|
|
|
|
|
curadc1 = curadc1 /((float)(LB_I_TIMES - 2));//去掉一个最大值和一个最小值求平均值
|
|
|
|
|
// g_ptz.Voltage = curadc1;
|
|
|
|
|
memset(adc1_i, 0, sizeof(adc1_i));//adc1_i 快速清零
|
|
|
|
|
curadc1_out_i = curadc1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return curadc1_out_i;
|
|
|
|
|
}
|
2025-09-13 09:22:00 +00:00
|
|
|
|
|
2025-09-15 09:03:37 +00:00
|
|
|
|
|
|
|
|
|
//温度采集
|
|
|
|
|
float ptz_temperature_collect_tmp75_task()
|
|
|
|
|
{
|
|
|
|
|
static float tmp75[5];
|
|
|
|
|
static unsigned char tmp75_num;
|
|
|
|
|
static float curtmp75_out;
|
|
|
|
|
float curtmp75;
|
|
|
|
|
float tem;
|
|
|
|
|
int j,k;
|
|
|
|
|
tmp75[tmp75_num] = tmp75_read_temp();
|
|
|
|
|
tmp75_num ++;
|
|
|
|
|
|
|
|
|
|
if(tmp75_num >= LB_T_TIMES)
|
|
|
|
|
{
|
|
|
|
|
tmp75_num = 0;
|
|
|
|
|
for(j = 0; j < LB_T_TIMES-1; j++)//采样值由小到大排列
|
|
|
|
|
{
|
|
|
|
|
for(k = 0; k < LB_T_TIMES-j-1; k++)
|
|
|
|
|
{
|
|
|
|
|
if(tmp75[k] > tmp75[k+1])
|
|
|
|
|
{
|
|
|
|
|
tem = tmp75[k];
|
|
|
|
|
tmp75[k] = tmp75[k+1];
|
|
|
|
|
tmp75[k+1] = tem;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(uint8_t i = 1; i < LB_T_TIMES - 1; i++)
|
|
|
|
|
{
|
|
|
|
|
curtmp75 = curtmp75 + tmp75[i];//去掉一个最大值和一个最小值
|
|
|
|
|
}
|
|
|
|
|
curtmp75 = curtmp75 / ((float)(LB_T_TIMES - 2));
|
|
|
|
|
curtmp75_out = curtmp75;
|
|
|
|
|
memset(tmp75, 0, sizeof(tmp75));
|
|
|
|
|
}
|
|
|
|
|
return curtmp75_out;
|
|
|
|
|
}
|