newPtz/drivers/drv_adc.c

378 lines
11 KiB
C
Raw Permalink Normal View History

/************************************************************
Copyright (C), 2025, cerlink Tech. Co., Ltd.
2025-09-16 02:05:41 +00:00
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
***********************************************************/
2025-09-12 09:53:32 +00:00
#include "drv_adc.h"
2025-09-18 05:33:48 +00:00
#ifdef DMAX
2025-09-23 10:07:24 +00:00
2025-09-16 09:20:37 +00:00
/*全局声明区*/
uint16_t USER_ADC_DMA_DATA_BUFF[16] = {0};
2025-09-23 10:07:24 +00:00
2025-09-18 05:33:48 +00:00
#endif
2025-09-16 09:20:37 +00:00
2025-09-24 02:46:14 +00:00
float adc1_v[LB_V_TIMES];
float curadc1_out_v;
uint8_t adc1_v_num = 0;
float adc1_i[LB_I_TIMES];
float curadc1_out_i;
uint8_t adc1_i_num = 0;
float tmp75[LB_T_TIMES];
float curtmp75_out;
uint8_t tmp75_num;
2025-09-18 10:05:04 +00:00
bool filter_v_flag = 0;//滤波开启标志位,全局改变一次
bool filter_i_flag = 0;//滤波开启标志位,全局改变一次
bool filter_t_flag = 0;//滤波开启标志位,全局改变一次
/* ---------------------------------------------------配置---------------------------------------------------- */
2025-09-16 09:20:37 +00:00
void adc_init(void)
{
adc_rcu_config();
adc_gpio_config();
2025-09-17 09:19:20 +00:00
#ifdef DMAX
2025-09-16 09:20:37 +00:00
adc_dma_config();
2025-09-17 09:19:20 +00:00
#endif
2025-09-16 09:20:37 +00:00
adc_config();
2025-09-18 10:05:04 +00:00
#ifdef ADCX_IRQn
2025-09-18 06:28:40 +00:00
adc_interrupt_int();
2025-09-18 10:05:04 +00:00
#endif
2025-09-16 09:20:37 +00:00
}
/* 时钟+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-17 09:19:20 +00:00
#ifdef DMAX
2025-09-16 09:20:37 +00:00
/* peripheral clock enable */
rcu_periph_clock_enable(RCU_DMA1);//ADC只能用DMA1
2025-09-17 09:19:20 +00:00
#endif
2025-09-16 09:20:37 +00:00
/* 启用GPIOC时钟 */
rcu_periph_clock_enable(RCU_GPIOC);
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
2025-09-16 09:20:37 +00:00
}
2025-09-16 09:20:37 +00:00
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);
2025-09-16 09:20:37 +00:00
}
2025-09-13 09:22:00 +00:00
2025-09-17 09:19:20 +00:00
#ifdef DMAX
2025-09-13 09:22:00 +00:00
2025-09-16 09:20:37 +00:00
/* DMA配置 */
2025-09-17 09:19:20 +00:00
void adc_dma_config(void)
2025-09-16 09:20:37 +00:00
{
/* ADC_DMA_channel configuration */
dma_single_data_parameter_struct dma_single_data_parameter; //这里使用单数据模式,每次只传输一个数据单元,因为总数据量不大,且数据个数不固定
/* ADC DMA_channel configuration */
2025-09-17 09:19:20 +00:00
dma_deinit (DMA1, USER_DMA_ADC_CHANNEL);
2025-09-16 09:20:37 +00:00
/* initialize DMA single data mode */
2025-09-17 09:19:20 +00:00
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; //优先级设为超高,可改用宏
2025-09-23 10:07:24 +00:00
dma_single_data_mode_init (DMAX, USER_DMA_ADC_CHANNEL, &dma_single_data_parameter);
2025-09-16 09:20:37 +00:00
/* 配置 dma 子连接 */
2025-09-23 10:07:24 +00:00
dma_channel_subperipheral_select (DMAX, USER_DMA_ADC_CHANNEL, USER_DMA_ADC_SUBPERI);
2025-09-16 09:20:37 +00:00
/* enable DMA circulation mode */
2025-09-23 10:07:24 +00:00
dma_circulation_enable (DMAX, USER_DMA_ADC_CHANNEL);// 开启循环模式
2025-09-16 09:20:37 +00:00
/* enable DMA it */
2025-09-23 10:07:24 +00:00
dma_interrupt_enable (DMAX,USER_DMA_ADC_CHANNEL,DMA_INT_FTF);//DMA传输完成标志位 打开全部完成中断 4
// dma_interrupt_enable (DMAX,USER_DMA_ADC_CHANNEL,DMA_INT_TAE);//传输错误中断使能位 2
// dma_interrupt_enable (DMAX,USER_DMA_ADC_CHANNEL,DMA_INT_FEE);// 7
2025-09-17 09:19:20 +00:00
nvic_irq_enable (DMA_ADC_IRQn, DMA_ADC_PRIORITY_PRE, DMA_ADC_PRIORITY_SUB);
2025-09-23 10:07:24 +00:00
dma_channel_enable (DMAX, USER_DMA_ADC_CHANNEL);// enable DMA channel
2025-09-16 09:20:37 +00:00
}
2025-09-13 09:22:00 +00:00
2025-09-17 09:19:20 +00:00
/**
* @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
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-17 09:19:20 +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-17 09:19:20 +00:00
adc_data_alignment_config (ADCX, ADC_DATAALIGN_RIGHT);// 配置数据对齐方式为右对齐
adc_resolution_config (ADCX, ADC_RESOLUTION_12B);// 配置ADC分辨率12位
2025-09-16 09:20:37 +00:00
/* 设置转换通道序列 */
2025-09-17 09:19:20 +00:00
adc_channel_length_config (ADCX, SEQUENCE_CHANNEL, CHANNEL_LENGTH);// 配置规则序列的长度2个通道
2025-09-12 09:53:32 +00:00
2025-09-18 05:33:48 +00:00
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);//电流
}
2025-09-23 10:07:24 +00:00
#ifdef DMAX
adc_routine_channel_config(ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
adc_routine_channel_config(ADCX, 1, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
#endif
2025-09-16 09:20:37 +00:00
/* 使能外部触发:这里使用软件触发,所以先禁用硬件触发 */
2025-09-17 09:19:20 +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-17 09:19:20 +00:00
#ifdef DMAX
2025-09-16 09:20:37 +00:00
/* ADC dma config */
2025-09-17 09:19:20 +00:00
adc_dma_request_after_last_enable (ADCX);
adc_dma_mode_enable (ADCX);
#endif
adc_enable (ADCX); // 开启ADC
2025-09-29 09:41:58 +00:00
// rt_thread_mdelay(50); // 等待ADC稳定后续接校准
delay_ms(50);
2025-09-17 09:19:20 +00:00
adc_calibration_enable (ADCX); // 执行ADC自校准
#ifdef DMAX
adc_software_trigger_enable (ADCX, SEQUENCE_CHANNEL); // 软件触发使能 后续接读取
#endif
2025-09-16 09:20:37 +00:00
}
2025-09-18 10:05:04 +00:00
#ifdef ADCX_IRQn
2025-09-18 06:28:40 +00:00
void adc_interrupt_int(void)
{
adc_interrupt_enable (ADCX, ADC_INT_EOC);
nvic_irq_enable (ADCX_IRQn, ADCX_PRIORITY_PRE, ADCX_PRIORITY_SUB);
}
2025-09-18 10:05:04 +00:00
#endif
2025-09-18 06:28:40 +00:00
2025-09-24 02:46:14 +00:00
2025-09-18 10:05:04 +00:00
/* ---------------------------------------------------采集---------------------------------------------------- */
2025-09-16 09:20:37 +00:00
// adc电压采集
float ptz_Voltage_collect_adc1_task()
{
uint16_t value_V = 0;
2025-09-18 10:05:04 +00:00
2025-09-24 02:46:14 +00:00
#ifdef ADC_MODE_0
/* 模式1需先配置 */
adc_routine_channel_config(ADCX, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
#endif
2025-09-16 09:20:37 +00:00
2025-09-24 02:46:14 +00:00
#if (defined ADC_MODE_0) || (defined ADC_MODE_1)
/* 模式1 + 2 */
2025-09-16 09:20:37 +00:00
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
2025-09-24 02:46:14 +00:00
#endif
#ifdef ADC_MODE_0
while(adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束
adc_flag_clear(ADCX, ADC_FLAG_EOC);
value_V = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
#endif
#ifdef ADC_MODE_1
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); // 读取注入组数据寄存器
#endif
#ifdef ADC_MODE_3
value_V = BSP_ADCDataAcquire(0);
#endif
/* 间接测量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-18 10:05:04 +00:00
filter_v_flag = 1;
}
2025-09-18 10:05:04 +00:00
2025-09-24 02:46:14 +00:00
if (filter_v_flag)//等读满一组开始滤波
2025-09-18 10:05:04 +00:00
{
return Filtering(adc1_v, LB_V_TIMES, LB_V_DEL);
}
return 0;
2025-09-12 09:53:32 +00:00
}
2025-09-13 09:22:00 +00:00
// adc电流采集
float ptz_Current_collect_adc1_task()
{
uint16_t value_I = 0;
2025-09-16 09:20:37 +00:00
2025-09-24 02:46:14 +00:00
#ifdef ADC_MODE_0
/* 模式1需先配置 */
adc_routine_channel_config(ADCX, 0, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
#endif
#if (defined ADC_MODE_0) || (defined ADC_MODE_1)
/* 模式1 + 2 */
2025-09-16 09:20:37 +00:00
adc_software_trigger_enable(ADCX, SEQUENCE_CHANNEL);// 软件触发使能 后续接读取
2025-09-24 02:46:14 +00:00
#endif
2025-09-18 05:33:48 +00:00
2025-09-24 02:46:14 +00:00
#ifdef ADC_MODE_0
while(adc_flag_get(ADCX, ADC_FLAG_EOC) == RESET); // 等待转换结束
adc_flag_clear(ADCX, ADC_FLAG_EOC);
value_I = adc_routine_data_read(ADCX); // 读取规则组数据寄存器
#endif
#ifdef ADC_MODE_1
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); // 读取注入组数据寄存器
#endif
#ifdef ADC_MODE_3
value_I = BSP_ADCDataAcquire(1);
#endif
/* 间接测量11倍分压/放大 */
2025-09-18 05:33:48 +00:00
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;
2025-09-18 10:05:04 +00:00
filter_i_flag = 1;
}
2025-09-18 10:05:04 +00:00
if (filter_i_flag)
{
return Filtering(adc1_i, LB_I_TIMES, LB_I_DEL);
}
return 0;
}
2025-09-13 09:22:00 +00:00
2025-09-24 02:46:14 +00:00
/* 温度采集 */
float ptz_temperature_collect_tmp75_task()
{
2025-09-26 10:17:39 +00:00
#ifdef HARDWARE_I2C
uint8_t tempHL[2];
uint16_t tempCode = 0;
float temp = 0;
2025-09-29 09:41:58 +00:00
uint8_t temp_addr[1] = {TEMP_REGISTER_ADDRESS};
2025-09-29 09:41:58 +00:00
i2c_write(temp_addr, 1, TMP75_ADDRESS);
2025-09-26 10:17:39 +00:00
i2c_read(tempHL, 2, TMP75_ADDRESS);
2025-09-29 09:41:58 +00:00
tempCode = (tempHL[0] << 8) | tempHL[1];
tempCode = tempCode >> 6;
if (tempCode & 0x200) // 负温度
{
tempCode &= 0x1ff;
temp = ((float)tempCode - 512) / 4;
}
else
{
temp = (float)tempCode / 4;
}
tmp75[tmp75_num] = temp;
2025-09-26 10:17:39 +00:00
#endif
#ifdef SOFTWARE_I2C
2025-09-26 10:17:39 +00:00
tmp75[tmp75_num] = tmp75_read_temp();
#endif
tmp75_num ++;
if(tmp75_num >= LB_T_TIMES)
{
tmp75_num = 0;
2025-09-18 10:05:04 +00:00
filter_t_flag = 1;
}
2025-09-18 10:05:04 +00:00
if (filter_t_flag)
{
return Filtering(tmp75, LB_T_TIMES, LB_T_DEL);
}
return 0;
}
2025-09-18 10:05:04 +00:00
2025-09-24 02:46:14 +00:00
/* 滤波函数 */
2025-09-18 10:05:04 +00:00
float Filtering(float *filter, uint8_t filterlens, uint8_t filterdel)
{
uint8_t j,k;
float tem;
float curadc = 0;
for(j = 0; j < filterlens - 1; j++)// 采样值由小到大排列
{
for(k = 0; k < filterlens - j - 1; k++)
{
if(filter[k] > filter[k + 1])
{
tem = filter[k];
filter[k] = filter[k + 1];
filter[k + 1] = tem;
}
}
}
for(uint8_t i = filterdel; i < filterlens - filterdel; i++)
{
curadc = curadc + filter[i];
}
curadc = curadc / ((float)(filterlens - filterdel * 2));// 去掉一个最大值和一个最小值求平均值
return curadc;
}