STM32多通道ADC的DMA方式采集

硬件:STM32F103C8T6
软件:KEIL MDK 5.23
固件库:STM32F1标准外设库。
调试软件:XCOM串口调试助手

stm32有多达16个通道,常用的采样方法有两种,一是分时采集每个通道的数据,用查询或者中断的方式采集完一个通道的数据,将通道设置为下一个,依次采集,这种方法思路简单,但是效率不高,适合初学者。二是利用DMA功能采集多个规则通道的数据,。

本文使用代码主要基于野火bsp库修改。

bsp_adc.h

#ifndef __ADC_H
#define __ADC_H#include "stm32f10x.h"// 注意:用作ADC采集的IO必须没有复用,否则采集电压会有影响
#define Vref    3300.0
/********************ADC1输入通道(引脚)配置**************************/
#define    ADC_APBxClock_FUN             RCC_APB2PeriphClockCmd
#define    ADC_CLK                       RCC_APB2Periph_ADC1#define    ADC_GPIO_APBxClock_FUN        RCC_APB2PeriphClockCmd#define    ADC_GPIO_CLK1                 RCC_APB2Periph_GPIOA
#define    ADC_PORT1                     GPIOA#define    ADC_GPIO_CLK2                 RCC_APB2Periph_GPIOB
#define    ADC_PORT2                     GPIOB#define    ADC_GPIO_CLK3                 RCC_APB2Periph_GPIOC
#define    ADC_PORT3                     GPIOC// 转换通道个数
#define    NOFCHANEL                     16#define    ADC_PIN1                      GPIO_Pin_0
#define    ADC_CHANNEL1                  ADC_Channel_0#define    ADC_PIN2                      GPIO_Pin_1
#define    ADC_CHANNEL2                  ADC_Channel_1#define    ADC_PIN3                      GPIO_Pin_2
#define    ADC_CHANNEL3                  ADC_Channel_2#define    ADC_PIN4                      GPIO_Pin_3
#define    ADC_CHANNEL4                  ADC_Channel_3#define    ADC_PIN5                      GPIO_Pin_4
#define    ADC_CHANNEL5                  ADC_Channel_4#define    ADC_PIN6                      GPIO_Pin_5
#define    ADC_CHANNEL6                  ADC_Channel_5#define    ADC_PIN7                      GPIO_Pin_6
#define    ADC_CHANNEL7                  ADC_Channel_6#define    ADC_PIN8                      GPIO_Pin_7
#define    ADC_CHANNEL8                  ADC_Channel_7#define    ADC_PIN9                      GPIO_Pin_0
#define    ADC_CHANNEL9                  ADC_Channel_8#define    ADC_PIN10                     GPIO_Pin_1
#define    ADC_CHANNEL10                 ADC_Channel_9#define    ADC_PIN11                     GPIO_Pin_0
#define    ADC_CHANNEL11                 ADC_Channel_10#define    ADC_PIN12                     GPIO_Pin_1
#define    ADC_CHANNEL12                 ADC_Channel_11#define    ADC_PIN13                     GPIO_Pin_2
#define    ADC_CHANNEL13                 ADC_Channel_12#define    ADC_PIN14                     GPIO_Pin_3
#define    ADC_CHANNEL14                 ADC_Channel_13#define    ADC_PIN15                     GPIO_Pin_4
#define    ADC_CHANNEL15                 ADC_Channel_14#define    ADC_PIN16                     GPIO_Pin_5
#define    ADC_CHANNEL16                 ADC_Channel_15// ADC1 对应 DMA1通道1,ADC3对应DMA2通道5,ADC2没有DMA功能
#define    ADC_x                         ADC1
#define    ADC_DMA_CHANNEL               DMA1_Channel1
#define    ADC_DMA_CLK                   RCC_AHBPeriph_DMA1/**************************函数声明********************************/
void ADCx_Init(void);//adc初始化
void filter(int in[5],int N);//平滑滤波
void get_adc(void);#endif /* __ADC_H */

bsp_adc.c

#include "bsp_adc.h"
#include <stdio.h>
#include <math.h>
#include "usart.h"    extern int adc[NOFCHANEL];
int out[5];
__IO uint16_t ADC_ConvertedValue[NOFCHANEL]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};/*** @brief  ADC GPIO 初始化* @param  无* @retval 无*/
static void ADCx_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;// 打开 ADC IO端口时钟ADC_GPIO_APBxClock_FUN (ADC_GPIO_CLK1, ENABLE );// 配置 ADC IO 引脚模式----------AGPIO_InitStructure.GPIO_Pin =     ADC_PIN1|ADC_PIN2|ADC_PIN3|ADC_PIN4|ADC_PIN5|ADC_PIN6|ADC_PIN7|ADC_PIN8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 初始化 ADC IOGPIO_Init(ADC_PORT1, &GPIO_InitStructure);   // 打开 ADC IO端口时钟----------BADC_GPIO_APBxClock_FUN (ADC_GPIO_CLK2, ENABLE );// 配置 ADC IO 引脚模式GPIO_InitStructure.GPIO_Pin =  ADC_PIN9|ADC_PIN10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 初始化 ADC IOGPIO_Init(ADC_PORT2, &GPIO_InitStructure);    // 打开 ADC IO端口时钟----------CADC_GPIO_APBxClock_FUN (ADC_GPIO_CLK3, ENABLE );// 配置 ADC IO 引脚模式GPIO_InitStructure.GPIO_Pin =  ADC_PIN11|ADC_PIN12|ADC_PIN13|ADC_PIN14|ADC_PIN15|ADC_PIN16;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;// 初始化 ADC IOGPIO_Init(ADC_PORT3, &GPIO_InitStructure);
}/*** @brief  配置ADC工作模式* @param  无* @retval 无*/
static void ADCx_Mode_Config(void)
{DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;// 打开DMA时钟RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);// 打开ADC时钟ADC_APBxClock_FUN (ADC_CLK, ENABLE);// 复位DMA控制器DMA_DeInit(ADC_DMA_CHANNEL);// 配置 DMA 初始化结构体// 外设基址为:ADC 数据寄存器地址DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADC_x->DR ) );// 存储器地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ADC_ConvertedValue;// 数据源来自外设DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// 缓冲区大小,应该等于数据目的地的大小DMA_InitStructure.DMA_BufferSize = NOFCHANEL;// 外设寄存器只有一个,地址不用递增DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// 存储器地址递增DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 外设数据大小为半字,即两个字节DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;// 内存数据大小也为半字,跟外设数据大小相同DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;// 循环传输模式DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响DMA_InitStructure.DMA_Priority = DMA_Priority_High;// 禁止存储器到存储器模式,因为是从外设到存储器DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;// 初始化DMADMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);// 使能 DMA 通道DMA_Cmd(ADC_DMA_CHANNEL , ENABLE);// ADC 模式配置// 只使用一个ADC,属于单模式ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;// 扫描模式ADC_InitStructure.ADC_ScanConvMode = ENABLE ; // 连续转换模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;// 不用外部触发转换,软件开启即可ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;// 转换结果右对齐ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// 转换通道个数ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL;    // 初始化ADCADC_Init(ADC_x, &ADC_InitStructure);// 配置ADC时钟N狿CLK2的8分频,即9MHzRCC_ADCCLKConfig(RCC_PCLK2_Div8); // 配置ADC 通道的转换顺序和采样时间ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL1 ,  1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL2 ,  2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL3 ,  3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL4 ,  4, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL5 ,  5, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL6 ,  6, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL7 ,  7, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL8 ,  8, ADC_SampleTime_55Cycles5);    ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL9 ,  9, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL10, 10, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL11, 11, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL12, 12, ADC_SampleTime_55Cycles5);    ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL13, 13, ADC_SampleTime_55Cycles5);   ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL14, 14, ADC_SampleTime_55Cycles5);   ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL15, 15, ADC_SampleTime_55Cycles5);   ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL16, 16, ADC_SampleTime_55Cycles5);   // 使能ADC DMA 请求ADC_DMACmd(ADC_x, ENABLE);// 开启ADC ,并开始转换ADC_Cmd(ADC_x, ENABLE);// 初始化ADC 校准寄存器  ADC_ResetCalibration(ADC_x);// 等待校准寄存器初始化完成while(ADC_GetResetCalibrationStatus(ADC_x));// ADC开始校准ADC_StartCalibration(ADC_x);// 等待校准完成while(ADC_GetCalibrationStatus(ADC_x));// 由于没有采用外部触发,所以使用软件触发ADC转换 ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}/*** @brief  ADC初始化* @param  无* @retval 无*/
void ADCx_Init(void)
{ADCx_GPIO_Config();ADCx_Mode_Config();
}/**********************************
**平滑滤波
***********************************/
void filter(int in[5],int N)
{int i;if(N < 5){for(i=0; i<=N-1; i++)out[i]= in[i];}else{out[0]= (69.0* in[0]+ 4.0* in[1]- 6.0* in[2]+ 4.0* in[3]- in[4])/ 70.0;out[1]= (2.0* in[0]+ 27.0* in[1]+ 12.0* in[2]- 8.0* in[3]+ 2.0* in[4])/ 35.0;for(i= 2; i<= N- 3; i++){out[i]= (-3.0* (in[i- 2]+ in[i+ 2])+ 12.0* (in[i- 1]+ in[i+ 1])+17.0 *in[i] )/ 35.0;}out[N-2]= (2.0* in[N - 5] - 8.0 * in[N - 4] + 12.0 * in[N - 3] + 27.0 * in[N - 2] + 2.0 * in[N - 1]) / 35.0;out[N-1]= (-in[N- 5]+ 4.0* in[N- 4]- 6.0* in[N- 3]+ 4.0* in[N - 2] + 69.0 * in[N - 1]) / 70.0;}
}/***************************
**获取adc
****************************/
void get_adc(void)
{int i,j,k,a[NOFCHANEL][5],c[5];for(j=0; j<5; j++){for(i=0; i<5; i++){for(k=0; k<NOFCHANEL; k++){adc[k] =(float) ADC_ConvertedValue[k]/4096*Vref;a[k][i]=adc[k];}}for(k=0;k<NOFCHANEL;k++){for(i=0;i<5;i++){c[i]=a[k][i];}filter(c,5);adc[k]= (out[0]+out[1]+out[2]+out[3]+out[4])/5;a[k][j]=adc[k];}}for(k=0;k<NOFCHANEL;k++){for(i=0;i<5;i++){c[i]=a[k][i];}filter(c,5);adc[k]= (out[0]+out[1]+out[2]+out[3]+out[4])/5;}}

main.c

/* Include ---------------------------- *///引用文件参考正点原子例程
#include "delay.h"
#include "sys.h"
#include "usart.h"
/* Include 2 -------------------------- */
#include "bsp_adc.h"
/* Sets of ADCx ----------------------- */
#define Vref 3300.0
int adc[NOFCHANEL];
/* Main ------------------------------- */
int main(void)
{   delay_init();            //延时函数初始化  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2ADCx_Init();while(1){get_adc();printf("\r\n-----\r\nA%d A%d A%d A%d\r\nA%d A%d A%d A%d\r\nA%d A%d A%d A%d\r\nA%d A%d A%d A%d\r\n\r\n-----\r\n",adc[0],adc[1],adc[2],adc[3],adc[4],adc[5],adc[6],adc[7],adc[8],adc[9],adc[10],adc[11],adc[12],adc[13],adc[14],adc[15]);delay_ms(1000);}
}
/*  === END === */

参考文章

[1] tpos_YU. stm32的DMA+ADC多通道数据采集
[2] 发呆健将. STM32 多通道ADC采集详解(DMA模式和非DMA模式)
[3] 夜风~. STM32——多通道ADC的DMA方式采集方法

【STM32】ADC的DMA方式采集(16通道)相关推荐

  1. STM32——多通道ADC的DMA方式采集方法

    前言: 最近在调试STM32F205芯片ADC多通道DMA方式采集数据,总结下STM32多通道ADC的DMA方式采集的使用方法. 硬件平台:STM32F205 软件平台:keil v5 函数库:标准库 ...

  2. 嵌入式作业STM32采用串口DMA方式发送数据

    目录 前言 要求 一.DMA的基本介绍 DMA的基本定义 DMA的主要特征 STM32F411x系列芯片DMA控制器 二.通过CubeMX配置项目 1.创建项目 2.选择芯片STM32F103C8T6 ...

  3. STM32F1与STM32CubeIDE快速入门-ADC通过DMA方式与PWM实现调光器

    DMA 方法是以非常高的速率转换多个 ADC 通道的最有效方法,并且仍然将结果传输到内存而无需 CPU 干预,这是一种非常酷且省时的技术. 本次实例将实现ADC以DMA方式采样,并转换成PWM输出,从 ...

  4. STM32—ADC和DMA的应用之电流检测(第二部分:电流检测电路与数据处理)

    文章目录 前言 一.电流检测原理 1.霍尔效应 2.CC6902电流传感器 二.电流检测电路 三.数据处理 前言 前一部分介绍了如何配置ADC和DMA,这一部分介绍在硬件部分如何实现电流检测以及检测到 ...

  5. STM32采用串口DMA方式实现发送数据

    文章目录 一.实验工具 二.DMA介绍 三.配置工程 1.新建工程 2.引脚配置 3.设置RCC 4.设置串口 5.DMA设置 6.时钟源设置 7.项目文件设置 8.创建代码 四.Keil中修改代码 ...

  6. 关于RS485通讯中使用STM32串口以DMA方式发送数据丢失字节的问题

    1.开发平台 计算机操作系统:WIN7 64位: 开发环境:Keil MDK 5.14: MCU:STM32F407ZET6: STM32F4xx固件库:STM32F4xx_DSP_StdPeriph ...

  7. STM32内部参考电压+DMA精准采集电池电压

    最近项目又遇到了电池电压采集,锂电池的电压范围是4.2到2.8一般,当锂电池低于3.3V时,单片机供电电压会小于3.3V,那么电池电压参考计算4096就不能对应3.3,所以必须采用内部参考电压.(我项 ...

  8. STM32使用PWM+DMA方式驱动WS2812灯珠

    一. 关于WS2812 WS2812 内部集成了处理芯片和3颗不同颜色的led灯(红,绿,蓝),通过单总线协议分别控制三个灯的亮度强弱,达到全彩的效果. WS2812B Datasheet 二. WS ...

  9. STM32使用串口DMA方式发送数据

    1.cubemx设置 1.1基本设置 1.2 打开DMA和中断 2.代码实现 HAL_UART_Transmit_DMA(&huart1,(uint8_t*)str,strlen(str)); ...

  10. 1--STM32 ADC1与ADC2 16通道DMA采集笔记

    最近在搞ADC,网上还是很多资源的, 以下为参考链接: 1.对STM32 ADC单次转换模式 连续转换模式 扫描模式的理解: https://www.cnblogs.com/zhanghankui/p ...

最新文章

  1. php 求数组组合数,php实现求数组全排列,元素所有组合的方法
  2. ML之HMM:HMM算法相关论文、关键步骤、测试代码配图集合
  3. 使用mvc模式读取服务器上的文件,关于C#:如何使用asp.net MVC应用程序从服务器上的网络路径读取...
  4. 利用自定义分页技术提高数据库性能
  5. Linux System Account SSH Weak Password Detection Automatic By System API
  6. 【Java】计算1!+2!+.....+20!的值
  7. java jpanel 叠加_java – 如何在JPanel上叠加,调整大小和居中组件?
  8. [转]Linux下显示硬件信息--lshw
  9. Nginx安装使用及与tomcat实现负载均衡
  10. MATLAB compatloose,麻烦帮忙看下这个视频
  11. elementui回到顶部Backtop
  12. JavaWeb基础教程
  13. SpringBoot-缓存Ehcache的使用
  14. 华为鸿蒙操作系统国美通讯,国美通讯(600898)03月06日14:30大单揭秘
  15. 机器人导航,人工势场法的地图导航规划
  16. js,JQ 图片转换base64 base64转换为file对象,blob对象
  17. adb 指令集说明详解[非常详细]
  18. 大数据服务平台---接口自动化
  19. spring-狂神学习笔记-联系我获取md文档
  20. 高速刹车失灵,特斯拉回应女子坐车顶维权

热门文章

  1. 微信小程序之订阅消息
  2. 0/0型极限等于多少_两个重要极限的一点理解(下)
  3. 爬虫实例之豆瓣高分电影
  4. Calibre转换电子书格式
  5. 0ctf-2017-babyheap图解
  6. 这些好玩的 GitHub 项目,你知道几个?
  7. 蓝色音箱改装电源_创新便携/无线音箱排行榜,创新便携/无线音箱十大排名推荐...
  8. ALS算法的基本思想
  9. [原]极域电子教室3个没被发现的bug(V6 2007)
  10. v4l2loopback -- 源码分析