diff --git a/.vscode/settings.json b/.vscode/settings.json index 83d2b82..dd889a0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -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" } } \ No newline at end of file diff --git a/applications/main/main.c b/applications/main/main.c index 8747a20..e1f8b9f 100644 --- a/applications/main/main.c +++ b/applications/main/main.c @@ -37,10 +37,11 @@ OF SUCH DAMAGE. #include "rtthread.h" #include "rtservice.h" #include // 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; } \ No newline at end of file diff --git a/drivers/adc.md b/drivers/adc.md new file mode 100644 index 0000000..7f72fa0 --- /dev/null +++ b/drivers/adc.md @@ -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[规则组
常规任务队列] + A2[注入组
高优先级任务队列] +end + +subgraph B[执行策略(How)] + B1[操作模式
单次/连续/扫描/间断] +end + +subgraph C[结果收集(What to do)] + direction LR + C1[数据转移方式
查询/中断/DMA] +end + +D[原始模拟信号] --> A +A -- 任务列表 --> B +B -- 执行转换 --> C +C -- 获取结果 --> E[数字转换结果] + +B -.->|执行策略同时
应用于两个组| A1 +B -.->|执行策略同时
应用于两个组| A2 + +C1 -->|读取规则组
需及时处理| A1 +C1 -->|读取注入组
有专用寄存器| 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/中断):定义了结果数据的处理方式。 + +三者协同工作,共同构成了一个高效、可靠且响应及时的数据采集系统。 diff --git a/drivers/drv_adc.c b/drivers/drv_adc.c index f718ee5..c489a6e 100644 --- a/drivers/drv_adc.c +++ b/drivers/drv_adc.c @@ -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(); } diff --git a/drivers/drv_adc.h b/drivers/drv_adc.h index 00b2e15..73ff474 100644 --- a/drivers/drv_adc.h +++ b/drivers/drv_adc.h @@ -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);