单次转换+扫描;规则组

This commit is contained in:
dufresne 2025-09-13 17:22:00 +08:00
parent a47c59a1d3
commit bb4fca415b
5 changed files with 435 additions and 81 deletions

View File

@ -2,6 +2,8 @@
"files.associations": { "files.associations": {
"stdio.h": "c", "stdio.h": "c",
"drv_usart.h": "c", "drv_usart.h": "c",
"rtservice.h": "c" "rtservice.h": "c",
"gd32f4xx_adc.h": "c",
"drv_adc.h": "c"
} }
} }

View File

@ -37,10 +37,11 @@ OF SUCH DAMAGE.
#include "rtthread.h" #include "rtthread.h"
#include "rtservice.h" #include "rtservice.h"
#include <stdio.h> // FILE 类是一个结构体,在 stdio.h 头文件中 #include <stdio.h> // FILE 类是一个结构体,在 stdio.h 头文件中
#include "drv_adc.h"
float voltage = 7.7; float voltage;
uint8_t num = 0; float current;
float current_origin;
/*! /*!
\brief main function \brief main function
@ -57,11 +58,12 @@ int main(void)
// 进入主循环或启动其他任务 // 进入主循环或启动其他任务
while (1) while (1)
{ {
voltage = ptz_Voltage_collect_adc1_task(); // voltage = ptz_Voltage_collect_adc1_task();
num++; // current = ptz_Current_collect_adc1_task();
rt_thread_mdelay(1000); ptz_adc1_collect_task();
current_origin = current*0.132 + 3.3/2;
rt_thread_mdelay(500);
// 主循环代码... // 主循环代码...
} }
return 0;
} }

185
drivers/adc.md Normal file
View File

@ -0,0 +1,185 @@
GD32F4系列搭载了高性能的12位逐次逼近型SARADC提供了非常灵活和强大的数据采集功能。其采集方式可以从**操作模式**和**数据转移方式**两个维度来理解。
### 一、按操作模式划分
操作模式决定了ADC如何执行转换序列主要配置在 `ADC_RSQ0`、`ADC_RSQ1`、`ADC_RSQ2`寄存器(规则序列寄存器)和 `ADC_OSQ`寄存器(注入序列寄存器)。
#### 1. 单次转换模式 (Single Conversion Mode)
* **工作原理**ADC只执行一次转换可以是一个通道也可以是多个通道组成的序列转换完成后自动停止并置位转换结束标志位EOC
* **触发方式**
* **软件触发**:通过设置 `ADC_CTL1``SWRCST`位启动。
* **硬件触发**通过外部信号如定时器TRGO、EXTI线启动。
* **特点**最简单功耗最低转换间隙ADC可自动进入低功耗模式但需要不断重新触发才能进行下一次转换。适用于对采样率要求不高的场合。
* **代码逻辑**`启动 -> 等待EOC -> 读取数据 -> (下次需要时再次启动)`
#### 2. 连续转换模式 (Continuous Conversion Mode)
* **工作原理**ADC完成一次转换序列后**立即自动重新启动**下一次转换,永不停止,连续不断地进行转换。
* **触发方式**:通常由**一次软件或硬件触发**来启动这个连续的进程。
* **特点**一旦启动无需干预即可获得连续的数据流实时性高。但功耗相对较高因为ADC一直处于工作状态。通常需要与DMA配合使用。
* **代码逻辑**`启动 -> (自动循环转换) -> 不断读取数据`
#### 3. 扫描模式 (Scan Mode)
* **工作原理**:此模式**不是独立的**它需要与单次或连续模式结合使用。当使能扫描模式后ADC会按照预先在规则序列寄存器 `ADC_RSQi`或注入序列寄存器 `ADC_OSQ`中设置好的**通道顺序**,依次对多个通道进行转换。
* **特点**:实现了多通道自动轮流采样。**特别注意**
* 在扫描模式下,每次完成**整个序列**的转换后,才会产生一个**EOC**(转换结束)中断标志。
* 如果需要每个通道转换完都产生中断,需要使能 `EOCIE`并配合DMA使用。
* **常见组合**
* **单次扫描模式**:触发一次,按顺序转换所有通道一次,然后停止。
* **连续扫描模式**:触发一次,按顺序循环不停地转换所有通道。
#### 4. 间断模式 (Discontinuous Mode)
* **工作原理**:此模式用于将一个长的转换序列**分批次(短序列)** 完成。您需要设置短序列的长度 `DISNUM`例如n=3。每次由一个硬件触发信号触发时ADC不会转换整个序列而是只转换序列中的**接下来的n个通道**。再次触发再转换接下来的n个通道直到整个序列完成然后循环。
* **特点**:提供了更精细的触发控制,允许用多个触发信号来控制一个长序列的转换。应用相对小众,常用于由定时器精确控制采样点的复杂场景。
---
### 二、按数据转移方式划分
转换完成后的数据需要被CPU读取根据读取方式的不同也决定了系统的效率。
#### 1. 中断方式 (Interrupt)
* **工作原理**使能ADC中断如EOC中断在转换完成后进入中断服务函数ISR在ISR中读取 `ADC_RDATA`寄存器。
* **适用场景**
* **单通道单次转换**:最简单。
* **扫描模式**如果只关心整个序列转换完成可以在EOC中断中读取所有数据但需要自己记录顺序
* **缺点**频繁中断会消耗大量CPU资源尤其在高速、多通道采样时效率低下。
#### 2. DMA方式 (Direct Memory Access)
* **工作原理**:这是**多通道扫描+连续转换模式的标准且高效的解决方案**。使能ADC的DMA请求并配置好DMA控制器。每次ADC转换完成一个通道的数据后会自动触发DMA由DMA控制器**在不占用CPU的情况下**,将 `ADC_RDATA`寄存器的数据直接搬运到指定的内存数组Buffer中。
* **特点**
* **极高效率**CPU只需在数据数组满或半满时进行处理大大解放了CPU。
* **数据对齐**ADC数据寄存器是32位的但数据只有12位。DMA可以轻松处理数据对齐问题左对齐或右对齐
* **适用场景**:几乎所有需要高速、实时、多通道采样的应用,如音频处理、电机控制、数字电源、多路数据采集卡等。
#### 3. 查询方式 (Polling)
* **工作原理**:在主循环或函数中,不断**查询**ADC状态寄存器中的标志位如EOC一旦发现标志位置位就去读取数据。
* **特点**编程简单但CPU利用率最低因为在等待转换完成时CPU什么也做不了一直在空循环。**不推荐在实际项目中使用**,仅用于简单测试。
---
### 三、特殊模式双ADC模式 (Dual ADC Mode)
GD32F4系列通常有多个ADC单元如ADC0, ADC1, ADC2。它们可以协同工作组成更高级的采样模式用于需要精确同步采样的场景。
* **同步注入模式**一个主ADC被触发后从ADC同时被触发进行注入组转换。
* **同步规则模式**主从ADC同步进行规则组转换。
* **交替触发模式**定时器触发后主从ADC交替采样**同一个通道**,可以实现**2倍于单个ADC**的采样率。
* **交替模式**主从ADC交替采样每次触发交替转换。
* **混合模式**:规则组和注入组可以分别配置为不同的同步模式。
### 总结与对比
| 模式分类 | 模式名称 | 特点 | 适用场景 |
| :----------------- | :------------------ | :-------------------------------------------------- | :--------------------------------------------------- |
| **操作模式** | **单次转换** | 转换一次即停止,低功耗,需反复触发 | 低速、单点采样,电池供电设备 |
| | **连续转换** | 转换一次后自动开始下一次,连续不断 | 高速、实时数据流采集 |
| | **扫描模式** | 按预设顺序自动转换多个通道 | **多通道**数据采集(必须配合单次/连续模式) |
| | **间断模式** | 分多次触发完成一个长序列 | 由外部信号精细控制采样节奏的复杂应用 |
| **数据转移** | **查询方式** | CPU不断查询状态标志效率最低 | 简单测试,不推荐用于实际项目 |
| | **中断方式** | 转换完成产生中断CPU在ISR中读取数据 | 中低速、通道数较少的应用 |
| | **DMA方式** | **自动**将数据搬运到内存,**不占用CPU** | **高速、多通道、实时**采集的**首选方案** |
| **ADC组合** | **双ADC模式** | 多个ADC单元协同工作同步或交替采样 | 需要高采样率或通道间严格同步的高精度应用 |
### 如何选择?
1. **单通道、低速采样**:单次转换 + 中断。
2. **多通道、低速采样**:单次扫描 + DMA或中断但DMA更优
3. **多通道、高速采样****连续扫描 + DMA** (这是最常用、最经典的配置)。
4. **极限采样率(单通道)**使用双ADC的交替模式配合DMA。
5. **需要同步采样两个相关信号**使用双ADC的同步模式。
这是一个非常核心且优秀的问题它触及了ADC模块设计思想的本质。
**规则组和注入组** 与 **操作模式****数据转移方式** 是不同维度的概念,但它们之间**存在着紧密的协作和配合关系**。您可以这样理解:
* **规则组 vs 注入组**:定义的是 **“要转换什么”**What即ADC转换任务的**内容**和**队列**。它们就像是两个不同的**任务列表**。
* **操作模式**:定义的是 **“如何执行转换”**How即如何对待上述任务列表是执行一次还是循环执行是软件启动还是硬件启动。它定义了任务的**执行策略**。
* **数据转移方式**:定义的是 **“转换完成后如何处理数据”**What to do with the result即如何获取转换结果。它定义了任务结果的**收集方式**。
它们之间的关系可以用下面的图表来清晰地展示:
```mermaid
flowchart TD
subgraph A[任务内容What]
direction LR
A1[规则组<br>常规任务队列]
A2[注入组<br>高优先级任务队列]
end
subgraph B[执行策略How]
B1[操作模式<br>单次/连续/扫描/间断]
end
subgraph C[结果收集What to do]
direction LR
C1[数据转移方式<br>查询/中断/DMA]
end
D[原始模拟信号] --> A
A -- 任务列表 --> B
B -- 执行转换 --> C
C -- 获取结果 --> E[数字转换结果]
B -.->|执行策略同时<br>应用于两个组| A1
B -.->|执行策略同时<br>应用于两个组| A2
C1 -->|读取规则组<br>需及时处理| A1
C1 -->|读取注入组<br>有专用寄存器| A2
```
下面我们进行详细的解读。
---
### 1. 规则组/注入组 与 操作模式 的关系
操作模式(单次、连续、扫描)**同时适用于规则组和注入组**,但两者的行为有一些关键区别。
| 特性 | 规则组 (Routine Group) | 注入组 (Injected Group) |
| :--------------------- | :--------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **扫描模式** | **必须启用**才能转换多通道序列。 | 注入组**本身就是一个短序列**,其通道数由 `IL`(Injected Length) 决定,**无需**单独的“扫描模式”使能。 |
| **单次 vs 连续** | 决定了规则序列是执行一次还是循环执行。 | 决定了注入序列是执行一次还是循环执行。**注意**:一个注入触发信号通常只执行一次注入序列,除非配置为连续模式。 |
| **触发源** | 可以使用软件触发或硬件触发(如定时器)。 | 同样可以使用软件触发或**独立的**硬件触发源。**关键**:注入组的硬件触发可以**中断**当前正在进行的规则组转换立即执行注入序列完成后自动恢复规则组转换。这就是“注入”Injected的含义——高优先级任务插入。 |
**关系小结**:操作模式定义了各组转换的**执行流程**。规则组是“常规任务流程”,而注入组是可打断常规流程的“高优先级中断任务流程”。
---
### 2. 规则组/注入组 与 数据转移方式 的关系
这是关系最紧密的部分,**数据转移方式的选择直接受到所用组别的严重影响**。
| 特性 | 规则组 (Routine Group) | 注入组 (Injected Group) |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **数据寄存器** | 只有**一个**数据寄存器 `ADC_RDATA`。所有规则通道的转换结果都放在这里。**如果不及时读取,就会被下一个通道的结果覆盖**。 | 有**多个**独立的数据寄存器(如 `ADC_IDATA0`, `ADC_IDATA1`, `ADC_IDATA2`, `ADC_IDATA3`)。每个注入通道都有自己专用的寄存器,结果不会被覆盖。 |
| **数据转移方式** | **强烈依赖DMA**。因为在扫描模式下多个通道快速连续转换CPU很难及时读取单个寄存器而不丢失数据。DMA可以自动将每个通道的结果搬运到指定数组。 | **非常适合使用中断**。因为注入组通道数少且每个结果都有独立的寄存器不会丢失。可以在注入转换完成中断JEOC中安全地读取所有 `ADC_IDATAx` 寄存器。 |
| **标志位** | 转换结束标志 `EOC` 在**每个通道**转换完成后都置位。序列结束标志 `EOS` 在**整个规则序列**转换完成后置位。 | 注入组转换结束标志 `JEOC` 在**整个注入序列**转换完成后置位。 |
**关系小结**
* **规则组 + 多通道 + 扫描模式 => 几乎必须使用DMA**来高效可靠地搬运数据。
* **注入组 + 少数通道 => 使用查询或中断**即可安全地读取数据,因为结果有专属“座位”(寄存器),不会丢。
---
### 实际应用场景举例(结合三者)
**场景:云台系统监控**
* **规则组**(常规任务):用于**周期性采集**电机编码器位置、系统电压、系统电流。配置为**连续扫描模式 + DMA**。ADC在后台持续采样DMA自动将三个通道的数据循环写入内存数组主循环只需读取数组即可极其高效。
* **注入组**(紧急任务):用于**过流保护**。配置一个电流通道,设置为**单次转换模式 + 中断**并由一个比较器的硬件输出信号作为触发源。当电流突然超过阈值比较器触发信号立即产生ADC**中断**正在进行的规则组转换,**立即**执行注入转换采集电流,并在转换完成后进入中断服务程序。在中断中,程序可以立即读取 `ADC_IDATA0` 得到电流值,并紧急停止电机。
在这个例子中,您可以看到:
* **What** (规则组/注入组):定义了监控和保护两个任务。
* **How** (连续扫描/单次):定义了任务的执行节奏。
* **What to do** (DMA/中断):定义了结果数据的处理方式。
三者协同工作,共同构成了一个高效、可靠且响应及时的数据采集系统。

View File

@ -2,90 +2,240 @@
#include "stdlib.h" #include "stdlib.h"
#include "string.h" #include "string.h"
#include "gd32f4xx.h" #include "gd32f4xx.h"
#include "gd32f4xx_adc.h"
#include "gd32f4xx_dma.h"
#include "rtthread.h" #include "rtthread.h"
#define ADC_BASIC 3300 /* 自定义宏,方便修改通道和引脚 */
void ADC_Init() uint16_t buff[2] = {0};
float curadc[ADC_CHANNEL_NUM];
void adc_gpio_config(void)
{ {
//配置引脚时钟 /* 启用GPIOA时钟 */
rcu_periph_clock_enable(RCU_GPIOC); rcu_periph_clock_enable(RCU_GPIOC);
//引脚复用PC2——电压ADC1-CH12PC3——电流ADC1-CH13 /* 启用ADC0时钟 */
gpio_mode_set(GPIOC,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_2);
gpio_mode_set(GPIOC,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_3);
rcu_periph_clock_enable(RCU_ADC1); rcu_periph_clock_enable(RCU_ADC1);
//总线时钟20分频=6MHZ
/* 配置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);
}
void adc_config(void)
{
/* ########## ADC 基础配置 ########## */
// 复位ADC配置可选但建议初始化时做一次
adc_deinit();
// 配置数据对齐方式为右对齐
adc_data_alignment_config(TEST, ADC_DATAALIGN_RIGHT);
// 配置ADC分辨率12位
adc_resolution_config(TEST, ADC_RESOLUTION_12B);
/* ########## 设置转换通道序列 ########## */
// 配置规则序列的长度2个通道
// adc_channel_length_config(TEST, ADC_INSERTED_CHANNEL, 2);
adc_channel_length_config(TEST, ADC_ROUTINE_CHANNEL, ADC_CHANNEL_NUM);
// 配置规则序列序号0是电压通道序号1是电流通道
adc_routine_channel_config(TEST, 0, VOLTAGE_ADC_CHANNEL, ADC_SAMPLETIME_480);
adc_routine_channel_config(TEST, 1, CURRENT_ADC_CHANNEL, ADC_SAMPLETIME_480);
// adc_inserted_channel_config(TEST, 0, CURRENT_ADC_CHANNEL,ADC_SAMPLETIME_480);//电流
// adc_inserted_channel_config(TEST, 1, VOLTAGE_ADC_CHANNEL,ADC_SAMPLETIME_480);//电压
// 打开扫描模式
adc_special_function_config(TEST, ADC_SCAN_MODE, ENABLE);
// 禁止连续模式 -> 单次转换模式
adc_special_function_config(TEST, ADC_CONTINUOUS_MODE, DISABLE);
// DMA
adc_dma_request_after_last_enable(ADC0);
adc_dma_mode_enable(ADC0);
/* ########## 其他设置 ########## */
// 使能外部触发:这里使用软件触发,所以先禁用硬件触发
adc_external_trigger_config(TEST, ADC_ROUTINE_CHANNEL, DISABLE);
// adc_external_trigger_config(TEST, ADC_INSERTED_CHANNEL, DISABLE);
// 开启ADC
adc_enable(TEST);
// 等待ADC稳定
rt_thread_mdelay(100);
// 执行ADC自校准
adc_calibration_enable(TEST);
adc_clock_config(ADC_ADCCK_PCLK2_DIV4); adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
/***********************************************/
adc_software_trigger_enable(TEST, ADC_ROUTINE_CHANNEL);
//对齐方式 ADC_INSERTED_CHANNEL
adc_data_alignment_config(ADC1,ADC_DATAALIGN_RIGHT);
//扫描模式
adc_special_function_config(ADC1,ADC_SCAN_MODE,ENABLE);
//外部触发关闭
adc_external_trigger_config(ADC1,ADC_INSERTED_CHANNEL,DISABLE);
//采集通道数
adc_channel_length_config(ADC1,ADC_INSERTED_CHANNEL,2);
//通道注入顺序
adc_inserted_channel_config(ADC1,0,ADC_CHANNEL_13,ADC_SAMPLETIME_480);//电流
adc_inserted_channel_config(ADC1,1,ADC_CHANNEL_12,ADC_SAMPLETIME_480);//电压
adc_enable(ADC1);
adc_calibration_enable(ADC1);
} }
//电压采集 static void DMA_config()
float ptz_Voltage_collect_adc1_task()
{ {
static float adc1_v[5]; uint32_t dmax = DMA1;
static unsigned char adc1_num; uint32_t dmax_rcu = RCU_DMA1;
int j,k; uint32_t dmax_ch = DMA_CH0;
float tem; uint32_t damx_sub = DMA_SUBPERI0;
float curadc1; uint32_t dmax_dirction = DMA_PERIPH_TO_MEMORY;
uint16_t value_V; uint32_t dmax_src = (uint32_t)(&ADC_RDATA(ADC1));
uint32_t dmax_src_inc = DMA_PERIPH_INCREASE_DISABLE;
uint32_t dmax_src_width = DMA_PERIPH_WIDTH_16BIT;
uint32_t dmax_src_len = 2;
uint32_t dmax_dst = (uint32_t)(buff);
uint32_t dmax_dst_inc = DMA_MEMORY_INCREASE_ENABLE;
/**************** DMA p2m *******************/
// 时钟
rcu_periph_clock_enable(dmax_rcu);
// 重置dma
dma_deinit(dmax, dmax_ch);
//////// dma 配置
dma_single_data_parameter_struct dsdps;
dma_single_data_para_struct_init(&dsdps);
// 方向
dsdps.direction = DMA_PERIPH_TO_MEMORY;
// 内存: dst
dsdps.memory0_addr = dmax_dst;
dsdps.memory_inc = dmax_dst_inc;
// 外设: src
dsdps.periph_addr = dmax_src;
dsdps.periph_inc = dmax_src_inc;
// 数据长度
dsdps.number = dmax_src_len;
// dst数据宽度
dsdps.periph_memory_width = dmax_src_width;
// 传输优先级
dsdps.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(dmax, dmax_ch, &dsdps);
//////// 配置 dma 子连接
dma_channel_subperipheral_select(dmax, dmax_ch, damx_sub);
dma_circulation_enable(dmax, dmax_ch);
// 默认开启接收
dma_flag_clear(dmax, dmax_ch, DMA_FLAG_FTF);
dma_channel_enable(dmax, dmax_ch);
}
// adc采集
float ptz_adc1_collect_task()
{
// static float adc1_v[LB_TIMES];
// static float curadc1_out;
// static uint8_t adc1_num = 0;
// int j,k;
// float tem;
// float curadc1;
// uint16_t value_V = 0;
uint16_t value = buff[0];
curadc[0] = (float)buff[0] / 4096.0 * 3.3;
curadc[1] = (float)buff[1] / 4096.0 * 3.3;
//软件触发使能 //软件触发使能
adc_software_trigger_enable(ADC1,ADC_INSERTED_CHANNEL); // adc_software_trigger_enable(TEST, ADC_ROUTINE_CHANNEL);
value_V = ADC_IDATA1(ADC1); // adc_software_trigger_enable(TEST, ADC_INSERTED_CHANNEL);
adc1_v[adc1_num] = (float)value_V / 4096.0 * 11 *3.3;//(float)value_V;// // while(adc_flag_get(TEST, ADC_FLAG_EOC) == RESET); // 等待转换结束
adc1_num++; // value_V = adc_routine_data_read(TEST); // 读取规则组数据寄存器
if(adc1_num >= 5) // value_V = adc_inserted_data_read(TEST, VOLTAGE_ADC_CHANNEL); // 读取规则组数据寄存器
{
adc1_num = 0; // ... 后面的中位值平均滤波处理保持不变 ...
for(j = 0; j < 5-1; j++)//采样值由小到大排列 // *11硬件需要
{ // adc1_v[adc1_num] = (float)value_V / 4096.0 * 3.3; // 间接测量11倍分压/放大
for(k = 0; k < 5-j-1; k++)
{ // ...
if(adc1_v[k] > adc1_v[k+1])
{ // adc1_num++;
tem = adc1_v[k]; // if(adc1_num >= LB_TIMES)
adc1_v[k] = adc1_v[k+1]; // {
adc1_v[k+1] = tem; // adc1_num = 0;
} // for(j = 0; j < LB_TIMES-1; j++)//采样值由小到大排列
} // {
} // for(k = 0; k < LB_TIMES-j-1; k++)
for(uint8_t i = 1; i < 5 - 1; i++) // {
{ // if(adc1_v[k] > adc1_v[k+1])
curadc1 = curadc1 + adc1_v[i]; // {
} // tem = adc1_v[k];
curadc1 = curadc1 /((float)(5 - 2));//去掉一个最大值和一个最小值求平均值 // adc1_v[k] = adc1_v[k+1];
// g_ptz.Voltage = curadc1; // adc1_v[k+1] = tem;
memset(adc1_v,0,sizeof(adc1_v)); // }
return curadc1; // }
// rt_kprintf("ADC Channel value: %f\n", curadc1); // }
// pdebug(DEBUG_LEVEL_INFO,"get ptz Voltage: %.3fV",g_ptz.Voltage); // for(uint8_t i = 1; i < LB_TIMES - 1; i++)
} // {
// curadc1 = curadc1 + adc1_v[i];
// }
// curadc1 = curadc1 /((float)(LB_TIMES - 2));//去掉一个最大值和一个最小值求平均值
// // g_ptz.Voltage = curadc1;
// memset(adc1_v, 0, sizeof(adc1_v));//adc1_v 快速清零
// curadc1_out = curadc1;
// }
// return curadc1_out;
} }
// //电流采集
// float ptz_Current_collect_adc1_task()
// {
// static float adc1_i[LB_TIMES];
// static float curadc0_out;
// static uint8_t adc0_num;
// int j,k;
// float tem;
// float curadc0;
// uint16_t value_I;
// adc_software_trigger_enable(TEST,ADC_ROUTINE_CHANNEL);
// // adc_software_trigger_enable(TEST,ADC_INSERTED_CHANNEL);
// // while(adc_flag_get(TEST, ADC_FLAG_EOC) == RESET); // 等待转换结束
// value_I = adc_routine_data_read(TEST); // 读取规则组数据寄存器
// // value_I = adc_inserted_data_read(TEST, CURRENT_ADC_CHANNEL); // 读取规则组数据寄存器
// adc1_i[adc0_num] = (((float)value_I / 4096.0 * 3.3)-3.3/2) / 0.132;//(float)value_I;//
// adc0_num ++;
// if(adc0_num >= LB_TIMES)
// {
// adc0_num = 0;
// for(j = 0; j < LB_TIMES-1; j++)//采样值由小到大排列
// {
// for(k = 0; k < LB_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_TIMES - 1; i++)
// {
// curadc0 = curadc0 + adc1_i[i];
// }
// curadc0 = curadc0 /((float)(LB_TIMES - 2));//去掉一个最大值和一个最小值求平均值
// memset(adc1_i, 0, sizeof(adc1_i));
// curadc0_out = curadc0;
// }
// return curadc0_out;
// }
void init_data_collect_module(void) void init_data_collect_module(void)
{ {
ADC_Init();//AD采集引脚初始化 adc_gpio_config();
// temp75_gpio_init();//温度传感器初始化 adc_config();
// creat_task_data_collect(); DMA_config();
} }

View File

@ -1,9 +1,24 @@
#ifndef __DRV_ADC_H_ #ifndef __DRV_ADC_H_
#define __DRV_ADC_H_ #define __DRV_ADC_H_
#define TEST ADC1
#define VOLTAGE_ADC_CHANNEL ADC_CHANNEL_12
#define CURRENT_ADC_CHANNEL ADC_CHANNEL_13
#define ADC_GPIO_PORT GPIOC
#define VOLTAGE_ADC_PIN GPIO_PIN_2
#define CURRENT_ADC_PIN GPIO_PIN_3
#define ADC_CHANNEL_NUM 2 // 规则组通道数量
#define LB_TIMES 5
void ADC_Init();
float ptz_Voltage_collect_adc1_task(); extern float curadc[ADC_CHANNEL_NUM];
// float ptz_Voltage_collect_adc1_task();
// float ptz_Current_collect_adc1_task();
float ptz_adc1_collect_task();
void adc_gpio_config(void);
void adc_config(void);
void init_data_collect_module(void); void init_data_collect_module(void);