【STM32】ADC的DMA方式采集(16通道)
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通道)相关推荐
- STM32——多通道ADC的DMA方式采集方法
前言: 最近在调试STM32F205芯片ADC多通道DMA方式采集数据,总结下STM32多通道ADC的DMA方式采集的使用方法. 硬件平台:STM32F205 软件平台:keil v5 函数库:标准库 ...
- 嵌入式作业STM32采用串口DMA方式发送数据
目录 前言 要求 一.DMA的基本介绍 DMA的基本定义 DMA的主要特征 STM32F411x系列芯片DMA控制器 二.通过CubeMX配置项目 1.创建项目 2.选择芯片STM32F103C8T6 ...
- STM32F1与STM32CubeIDE快速入门-ADC通过DMA方式与PWM实现调光器
DMA 方法是以非常高的速率转换多个 ADC 通道的最有效方法,并且仍然将结果传输到内存而无需 CPU 干预,这是一种非常酷且省时的技术. 本次实例将实现ADC以DMA方式采样,并转换成PWM输出,从 ...
- STM32—ADC和DMA的应用之电流检测(第二部分:电流检测电路与数据处理)
文章目录 前言 一.电流检测原理 1.霍尔效应 2.CC6902电流传感器 二.电流检测电路 三.数据处理 前言 前一部分介绍了如何配置ADC和DMA,这一部分介绍在硬件部分如何实现电流检测以及检测到 ...
- STM32采用串口DMA方式实现发送数据
文章目录 一.实验工具 二.DMA介绍 三.配置工程 1.新建工程 2.引脚配置 3.设置RCC 4.设置串口 5.DMA设置 6.时钟源设置 7.项目文件设置 8.创建代码 四.Keil中修改代码 ...
- 关于RS485通讯中使用STM32串口以DMA方式发送数据丢失字节的问题
1.开发平台 计算机操作系统:WIN7 64位: 开发环境:Keil MDK 5.14: MCU:STM32F407ZET6: STM32F4xx固件库:STM32F4xx_DSP_StdPeriph ...
- STM32内部参考电压+DMA精准采集电池电压
最近项目又遇到了电池电压采集,锂电池的电压范围是4.2到2.8一般,当锂电池低于3.3V时,单片机供电电压会小于3.3V,那么电池电压参考计算4096就不能对应3.3,所以必须采用内部参考电压.(我项 ...
- STM32使用PWM+DMA方式驱动WS2812灯珠
一. 关于WS2812 WS2812 内部集成了处理芯片和3颗不同颜色的led灯(红,绿,蓝),通过单总线协议分别控制三个灯的亮度强弱,达到全彩的效果. WS2812B Datasheet 二. WS ...
- STM32使用串口DMA方式发送数据
1.cubemx设置 1.1基本设置 1.2 打开DMA和中断 2.代码实现 HAL_UART_Transmit_DMA(&huart1,(uint8_t*)str,strlen(str)); ...
- 1--STM32 ADC1与ADC2 16通道DMA采集笔记
最近在搞ADC,网上还是很多资源的, 以下为参考链接: 1.对STM32 ADC单次转换模式 连续转换模式 扫描模式的理解: https://www.cnblogs.com/zhanghankui/p ...
最新文章
- php 求数组组合数,php实现求数组全排列,元素所有组合的方法
- ML之HMM:HMM算法相关论文、关键步骤、测试代码配图集合
- 使用mvc模式读取服务器上的文件,关于C#:如何使用asp.net MVC应用程序从服务器上的网络路径读取...
- 利用自定义分页技术提高数据库性能
- Linux System Account SSH Weak Password Detection Automatic By System API
- 【Java】计算1!+2!+.....+20!的值
- java jpanel 叠加_java – 如何在JPanel上叠加,调整大小和居中组件?
- [转]Linux下显示硬件信息--lshw
- Nginx安装使用及与tomcat实现负载均衡
- MATLAB compatloose,麻烦帮忙看下这个视频
- elementui回到顶部Backtop
- JavaWeb基础教程
- SpringBoot-缓存Ehcache的使用
- 华为鸿蒙操作系统国美通讯,国美通讯(600898)03月06日14:30大单揭秘
- 机器人导航,人工势场法的地图导航规划
- js,JQ 图片转换base64 base64转换为file对象,blob对象
- adb 指令集说明详解[非常详细]
- 大数据服务平台---接口自动化
- spring-狂神学习笔记-联系我获取md文档
- 高速刹车失灵,特斯拉回应女子坐车顶维权