IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 【STM32】ADC的DMA方式采集(16通道) -> 正文阅读

[嵌入式]【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 引脚模式----------A
	GPIO_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 IO
	GPIO_Init(ADC_PORT1, &GPIO_InitStructure);	

  // 打开 ADC IO端口时钟----------B
	ADC_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 IO
	GPIO_Init(ADC_PORT2, &GPIO_InitStructure);	
	
	// 打开 ADC IO端口时钟----------C
	ADC_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 IO
	GPIO_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;
	
	// 初始化DMA
	DMA_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;	
		
	// 初始化ADC
	ADC_Init(ADC_x, &ADC_InitStructure);
	
	// 配置ADC时钟N狿CLK2的8分频,即9MHz
	RCC_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);// 设置中断优先级分组2
    ADCx_Init();
 
	while(1)
	{
		get_adc();
		
		printf("\r\n-----\r\n
				A%d A%d A%d A%d\r\n
				A%d A%d A%d A%d\r\n
				A%d A%d A%d A%d\r\n
				A%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方式采集方法

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:20:04  更:2022-05-07 11:20:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/30 1:09:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码