单次转换+扫描;规则组
This commit is contained in:
parent
a47c59a1d3
commit
bb4fca415b
|
@ -2,6 +2,8 @@
|
|||
"files.associations": {
|
||||
"stdio.h": "c",
|
||||
"drv_usart.h": "c",
|
||||
"rtservice.h": "c"
|
||||
"rtservice.h": "c",
|
||||
"gd32f4xx_adc.h": "c",
|
||||
"drv_adc.h": "c"
|
||||
}
|
||||
}
|
|
@ -37,10 +37,11 @@ OF SUCH DAMAGE.
|
|||
#include "rtthread.h"
|
||||
#include "rtservice.h"
|
||||
#include <stdio.h> // FILE 类是一个结构体,在 stdio.h 头文件中
|
||||
#include "drv_adc.h"
|
||||
|
||||
float voltage = 7.7;
|
||||
uint8_t num = 0;
|
||||
|
||||
float voltage;
|
||||
float current;
|
||||
float current_origin;
|
||||
|
||||
/*!
|
||||
\brief main function
|
||||
|
@ -57,11 +58,12 @@ int main(void)
|
|||
// 进入主循环或启动其他任务
|
||||
while (1)
|
||||
{
|
||||
voltage = ptz_Voltage_collect_adc1_task();
|
||||
num++;
|
||||
rt_thread_mdelay(1000);
|
||||
// voltage = ptz_Voltage_collect_adc1_task();
|
||||
// current = ptz_Current_collect_adc1_task();
|
||||
ptz_adc1_collect_task();
|
||||
|
||||
current_origin = current*0.132 + 3.3/2;
|
||||
rt_thread_mdelay(500);
|
||||
// 主循环代码...
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
GD32F4系列搭载了高性能的12位逐次逼近型(SAR)ADC,提供了非常灵活和强大的数据采集功能。其采集方式可以从**操作模式**和**数据转移方式**两个维度来理解。
|
||||
|
||||
### 一、按操作模式划分
|
||||
|
||||
操作模式决定了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/中断):定义了结果数据的处理方式。
|
||||
|
||||
三者协同工作,共同构成了一个高效、可靠且响应及时的数据采集系统。
|
|
@ -2,90 +2,240 @@
|
|||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include "gd32f4xx.h"
|
||||
#include "gd32f4xx_adc.h"
|
||||
#include "gd32f4xx_dma.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);
|
||||
//引脚复用,PC2——电压ADC1-CH12,PC3——电流ADC1-CH13
|
||||
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);
|
||||
|
||||
/* 启用ADC0时钟 */
|
||||
rcu_periph_clock_enable(RCU_ADC1);
|
||||
//总线时钟20分频=6MHZ
|
||||
adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
|
||||
/***********************************************/
|
||||
|
||||
|
||||
//对齐方式 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);
|
||||
/* 配置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);
|
||||
}
|
||||
|
||||
//电压采集
|
||||
float ptz_Voltage_collect_adc1_task()
|
||||
void adc_config(void)
|
||||
{
|
||||
static float adc1_v[5];
|
||||
static unsigned char adc1_num;
|
||||
int j,k;
|
||||
float tem;
|
||||
float curadc1;
|
||||
uint16_t value_V;
|
||||
//软件触发使能
|
||||
adc_software_trigger_enable(ADC1,ADC_INSERTED_CHANNEL);
|
||||
value_V = ADC_IDATA1(ADC1);
|
||||
/* ########## ADC 基础配置 ########## */
|
||||
// 复位ADC配置(可选,但建议初始化时做一次)
|
||||
adc_deinit();
|
||||
|
||||
adc1_v[adc1_num] = (float)value_V / 4096.0 * 11 *3.3;//(float)value_V;//
|
||||
adc1_num++;
|
||||
if(adc1_num >= 5)
|
||||
{
|
||||
adc1_num = 0;
|
||||
for(j = 0; j < 5-1; j++)//采样值由小到大排列
|
||||
{
|
||||
for(k = 0; k < 5-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 < 5 - 1; i++)
|
||||
{
|
||||
curadc1 = curadc1 + adc1_v[i];
|
||||
}
|
||||
curadc1 = curadc1 /((float)(5 - 2));//去掉一个最大值和一个最小值求平均值
|
||||
// g_ptz.Voltage = curadc1;
|
||||
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);
|
||||
}
|
||||
// 配置数据对齐方式为右对齐
|
||||
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_software_trigger_enable(TEST, ADC_ROUTINE_CHANNEL);
|
||||
}
|
||||
|
||||
static void DMA_config()
|
||||
{
|
||||
uint32_t dmax = DMA1;
|
||||
uint32_t dmax_rcu = RCU_DMA1;
|
||||
uint32_t dmax_ch = DMA_CH0;
|
||||
uint32_t damx_sub = DMA_SUBPERI0;
|
||||
uint32_t dmax_dirction = DMA_PERIPH_TO_MEMORY;
|
||||
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(TEST, ADC_ROUTINE_CHANNEL);
|
||||
// adc_software_trigger_enable(TEST, ADC_INSERTED_CHANNEL);
|
||||
|
||||
// while(adc_flag_get(TEST, ADC_FLAG_EOC) == RESET); // 等待转换结束
|
||||
// value_V = adc_routine_data_read(TEST); // 读取规则组数据寄存器
|
||||
// value_V = adc_inserted_data_read(TEST, VOLTAGE_ADC_CHANNEL); // 读取规则组数据寄存器
|
||||
|
||||
// ... 后面的中位值平均滤波处理保持不变 ...
|
||||
// *11,硬件需要
|
||||
// adc1_v[adc1_num] = (float)value_V / 4096.0 * 3.3; // 间接测量,11倍分压/放大
|
||||
|
||||
// ...
|
||||
|
||||
// adc1_num++;
|
||||
// if(adc1_num >= LB_TIMES)
|
||||
// {
|
||||
// adc1_num = 0;
|
||||
// for(j = 0; j < LB_TIMES-1; j++)//采样值由小到大排列
|
||||
// {
|
||||
// for(k = 0; k < LB_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_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)
|
||||
{
|
||||
ADC_Init();//AD采集引脚初始化
|
||||
// temp75_gpio_init();//温度传感器初始化
|
||||
// creat_task_data_collect();
|
||||
adc_gpio_config();
|
||||
adc_config();
|
||||
DMA_config();
|
||||
}
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
#ifndef __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);
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue