newPtz/drivers/drv_adc.c

342 lines
11 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.

/************************************************************
Copyright (C), 2025, cerlink Tech. Co., Ltd.
FileName: drv_adc.c
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
***********************************************************/
#include "drv_adc.h"
#ifdef DMAX
/*全局声明区*/
uint16_t USER_ADC_DMA_DATA_BUFF[16] = {0};
uint32_t ctl = 0;
#endif
void adc_init(void)
{
adc_rcu_config();
adc_gpio_config();
#ifdef DMAX
adc_dma_config();
#endif
adc_config();
adc_interrupt_int();
#ifdef DMAX
ctl = DMA_CHCTL(DMAX, USER_DMA_ADC_CHANNEL);
if (ctl == 33762576)
{
// dma_channel_enable (DMA1, USER_DMA_ADC_CHANNEL);
// ttest.status = 5;
dma_channel_enable (DMA1, USER_DMA_ADC_CHANNEL);// enable DMA channel
}
else if (ctl == 33762577)
{
// ttest.status = 4;
}
#endif
}
/* 时钟+GPIO */
void adc_rcu_config(void)
{
/* 启用ADC1时钟 */
rcu_periph_clock_enable(RCU_ADC1);
#ifdef DMAX
/* peripheral clock enable */
rcu_periph_clock_enable(RCU_DMA1);//ADC只能用DMA1
#endif
/* 启用GPIOC时钟 */
rcu_periph_clock_enable(RCU_GPIOC);
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
}
void adc_gpio_config(void)
{
/* 配置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);
}
#ifdef DMAX
/* DMA配置 */
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_single_data_parameter.direction = DMA_PERIPH_TO_MEMORY; //ADC外设到RAM全局变量 DMA外设到内存模式开启
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 it */
dma_interrupt_enable (DMA1,USER_DMA_ADC_CHANNEL,DMA_INT_FTF);//DMA传输完成标志位 打开全部完成中断
dma_interrupt_enable (DMA1,USER_DMA_ADC_CHANNEL,DMA_INT_TAE);
dma_interrupt_enable (DMA1,USER_DMA_ADC_CHANNEL,DMA_INT_FEE);
nvic_irq_enable (DMA_ADC_IRQn, DMA_ADC_PRIORITY_PRE, DMA_ADC_PRIORITY_SUB);
dma_channel_enable (DMA1, USER_DMA_ADC_CHANNEL);// enable DMA channel
}
/**
* @brief 根据转换序列的序列号获取转换序列中的ADC测量值
* @param 配置ADC通道结构体中的成员序号
* @return 测量并转换后的值
*/
uint16_t BSP_ADCDataAcquire(uint8_t _index)
{
return USER_ADC_DMA_DATA_BUFF[_index];
}
/*
*****************************************************************************
* 函数名 : DMA1_Channel0_IRQHandler
* 功能说明: DMA_ADC中断服务回调函数
* 形 参 : 无
* 返回值 : 无
*****************************************************************************
*/
__weak void DMA1_Channel0_IRQHandler(void)
{
}
#endif
void adc_config(void)
{
adc_deinit();// 复位ADC配置可选但建议初始化时做一次
adc_special_function_config (ADCX, ADC_SCAN_MODE, SCAN_STATUS);// 扫描模式
adc_special_function_config (ADCX, ADC_CONTINUOUS_MODE, CONTINUOUS_STATUS);// 连续模式
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个通道
if (SEQUENCE_CHANNEL == ADC_INSERTED_CHANNEL)
{
//通道注入顺序
/* 配置规则序列序号0是电压通道序号1是电流通道 */
adc_inserted_channel_config (ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);//电压
adc_inserted_channel_config (ADCX, 1, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);//电流
}
/* 使能外部触发:这里使用软件触发,所以先禁用硬件触发 */
// adc_external_trigger_source_config(ADCX, SEQUENCE_CHANNEL, ADC_EXTTRIG_ROUTINE_T0_CH0);
adc_external_trigger_config (ADCX, SEQUENCE_CHANNEL, DISABLE);
#ifdef DMAX
/* ADC dma config */
adc_dma_request_after_last_enable (ADCX);
adc_dma_mode_enable (ADCX);
#endif
adc_enable (ADCX); // 开启ADC
rt_thread_mdelay(50); // 等待ADC稳定后续接校准
adc_calibration_enable (ADCX); // 执行ADC自校准
#ifdef DMAX
adc_software_trigger_enable (ADCX, SEQUENCE_CHANNEL); // 软件触发使能 后续接读取
#endif
}
void adc_interrupt_int(void)
{
adc_interrupt_enable (ADCX, ADC_INT_EOC);
nvic_irq_enable (ADCX_IRQn, ADCX_PRIORITY_PRE, ADCX_PRIORITY_SUB);
}
/* ---------------------------------------------------------------------------------------------------------------- */
// adc电压采集
float ptz_Voltage_collect_adc1_task()
{
static float adc1_v[LB_V_TIMES];
static float curadc1_out_v;
static uint8_t adc1_v_num;
int j,k;
float tem;
float curadc1;
uint16_t value_V = 0;
if (SEQUENCE_CHANNEL == ADC_ROUTINE_CHANNEL)
{
adc_routine_channel_config(ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
}
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
if (SEQUENCE_CHANNEL == ADC_ROUTINE_CHANNEL)
{
while(adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束
adc_flag_clear(ADCX, ADC_FLAG_EOC);
value_V = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
}
else if (SEQUENCE_CHANNEL == ADC_INSERTED_CHANNEL)
{
while(adc_flag_get(ADCX, ADC_FLAG_EOIC) == RESET); // 等待转换结束
adc_flag_clear(ADCX, ADC_FLAG_EOIC);
value_V = adc_inserted_data_read(ADCX, ADC_INSERTED_CHANNEL_0); // 读取注入组数据寄存器
}
/* 间接测量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;
for(j = 0; j < LB_V_TIMES-1; j++)// 采样值由小到大排列
{
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 = LB_V_DEL; i < LB_V_TIMES - LB_V_DEL; i++)
{
curadc1 = curadc1 + adc1_v[i];
}
curadc1 = curadc1 /((float)(LB_V_TIMES - LB_V_DEL * 2));// 去掉一个最大值和一个最小值求平均值
// g_ptz.Voltage = curadc1;
memset(adc1_v, 0, sizeof(adc1_v));// adc1_v 快速清零
curadc1_out_v = curadc1;
}
return curadc1_out_v;
}
// 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;
if (SEQUENCE_CHANNEL == ADC_ROUTINE_CHANNEL)
{
adc_routine_channel_config(ADCX, 0, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
}
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
if (SEQUENCE_CHANNEL == ADC_ROUTINE_CHANNEL)
{
while (adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束->等到SET
adc_flag_clear(ADCX, ADC_FLAG_EOC);
value_I = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
}
else if (SEQUENCE_CHANNEL == ADC_INSERTED_CHANNEL)
{
while (adc_flag_get(ADCX, ADC_FLAG_EOIC) == RESET); // 等待转换结束
adc_flag_clear(ADCX, ADC_FLAG_EOIC);
value_I = adc_inserted_data_read(ADCX, ADC_INSERTED_CHANNEL_1); // 读取注入组数据寄存器
}
/* 间接测量11倍分压/放大 */
adc1_i[adc1_i_num] = (((float)value_I / 4095.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 = LB_I_DEL; i < LB_I_TIMES - LB_I_DEL; i++)
{
curadc1 = curadc1 + adc1_i[i];
}
curadc1 = curadc1 /((float)(LB_I_TIMES - LB_I_DEL * 2));//去掉一个最大值和一个最小值求平均值
// g_ptz.Voltage = curadc1;
memset(adc1_i, 0, sizeof(adc1_i));//adc1_i 快速清零
curadc1_out_i = curadc1;
}
return curadc1_out_i;
}
//温度采集
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;
}