STM32F767多通道ADC采集+DMA传输

一、ADC简介

TM32F767xx系列有3个ADC,这些ADC可以独立使用,也可以使用双重/三重模式(提高采样率)。STM32F767的ADC是12位逐次逼近型的模拟数字转换器。它有19个通道,可测量16个外部源、2个内部源和Vbat通道的信号。我使用的是STM32F767IGT6

1、ADC采样频率

不要让ADC的时钟超过36M,否则将导致结果准确度下降。STM32F767的ADC最大工作频率是36Mhz,而ADC时钟(ADCCLK)来自APB2,APB2频率一般是108Mhz,我们设置ADCPRE=01,即4分频,这样得到ADCCLK频率为27Mhz

2、ADC转换时间

ADC的转换时间: 总转换时间(Tcovn)=采样时间+12个周期
例如,当ADCCLK=27Mhz的时候,并设置3个周期的采样时间,则得到:Tcovn=3+12=15个周期=0.55us。
stm32f767的采样时间周期可以在stm32f7xx_hal_adc.h中选择,可以选择3~480个周期的采样时间。如下图所示:
在这里插入图片描述

3、ADC寄存器

ADC里面用到的寄存器有很多,常用的有以下几个,具体使用方法就不一一介绍了
在这里插入图片描述

4、ADC引脚与外部通道对应关系

在这里插入图片描述

二、DMA简介

DMA 全称Direct Memory Access,即直接存储器访问。
DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。
DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

STM32最多有2个DMA控制器,2个DMA控制器总共有16个数据流(每个控制器8个)。每个DMA控制器都用于管理一个或者多个外设的存储器访问请求。

三、代码配置

1、ADC、DMA初始化配置

我将它们都配置在了adc.c文件中,代码如下所示:

			#include "adc.h"
			#include "delay.h"
			#include "usart.h"
			#include "sdram.h"
			#include "led.h"
			#include "lcd.h"
			
			#define M 8 //定义M
			#define N 4
			u16  value[N][M];
			uint32_t ADC_ConvertedValueRead[4];
			uint32_t ADC_ConvertedValue[4];
			
			ADC_HandleTypeDef  ADC1_Handler;       //ADC句柄
			DMA_HandleTypeDef  ADC1TxDMA_Handler;      //DMA句柄
			
			
			//初始化ADC
			void MY_ADC_Init(void)
			{ 
			     ADC_ChannelConfTypeDef ADC1_ChanConf;
					
				//GPIO初始化
				GPIO_InitTypeDef GPIO_Initure;
			    __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
			    __HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
				__HAL_RCC_GPIOC_CLK_ENABLE();           //开启GPIOC时钟
				
			    GPIO_Initure.Pin=GPIO_PIN_5|GPIO_PIN_7;            //PA5
			    GPIO_Initure.Mode=GPIO_MODE_ANALOG;     //模拟
			    GPIO_Initure.Pull=GPIO_NOPULL;          //不带上下拉
			    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
				
				GPIO_Initure.Pin=GPIO_PIN_4|GPIO_PIN_5;     //|GPIO_PIN_5;            
			    GPIO_Initure.Mode=GPIO_MODE_ANALOG;     //模拟
			    GPIO_Initure.Pull=GPIO_NOPULL;          //不带上下拉
			    HAL_GPIO_Init(GPIOC,&GPIO_Initure);
			
				//ADC1功能配置
				ADC1_Handler.Instance=ADC1;
			    ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4;   //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
			    ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B;             //12位模式
			    ADC1_Handler.Init.DataAlign=ADC_DATAALIGN_RIGHT;             //右对齐
			    ADC1_Handler.Init.ScanConvMode=ENABLE;                       //扫描模式,扫描模式用于多通道采集
			    ADC1_Handler.Init.EOCSelection=DISABLE;                      //关闭EOC中断
			    ADC1_Handler.Init.ContinuousConvMode=ENABLE;                //开启连续转换模式,即不停地进行ADC转换	
			    ADC1_Handler.Init.NbrOfConversion=4;                         //规则序列中有4个转换
			    ADC1_Handler.Init.DiscontinuousConvMode=DISABLE;             //禁止不连续采样模式
			    ADC1_Handler.Init.NbrOfDiscConversion=0;                     //不连续采样通道数为0	
			    ADC1_Handler.Init.ExternalTrigConv=ADC_SOFTWARE_START;       //软件触发
			    ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
			    ADC1_Handler.Init.DMAContinuousRequests=ENABLE;             //开启DMA请求
			    
				ADC1_Handler.DMA_Handle=&ADC1TxDMA_Handler;
			
			     HAL_ADC_Init(&ADC1_Handler);                                 //初始化 
				
			//采样通道、顺序配置	
			    ADC1_ChanConf.Channel=ADC_CHANNEL_7;                         //通道
			    ADC1_ChanConf.Rank=1;                                        //序列
			    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES;         //采样时间
			    ADC1_ChanConf.Offset=0;                 
			    HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);        //通道配置
				
				ADC1_ChanConf.Channel=ADC_CHANNEL_14;                         //通道
			    ADC1_ChanConf.Rank=2;                                        //序列
			    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES;         //采样时间
			    ADC1_ChanConf.Offset=0;                 
			    HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);        //通道配置
				
				ADC1_ChanConf.Channel=ADC_CHANNEL_15;                         //通道
			    ADC1_ChanConf.Rank=3;                                        //序列
			    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES;         //采样时间
			    ADC1_ChanConf.Offset=0;                 
			    HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);        //通道配置
				
				ADC1_ChanConf.Channel=ADC_CHANNEL_5;                         //通道
			    ADC1_ChanConf.Rank=4;                                        //序列
			    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES;         //采样时间
			    ADC1_ChanConf.Offset=0;                 
			    HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);        //通道配置
					
			}
			
			//初始化DMA
			void DMA_Config(void)
			{
				__HAL_RCC_DMA2_CLK_ENABLE(); 	//DMA2时钟使能
			
				ADC1TxDMA_Handler.Instance=DMA2_Stream0;                            //数据流选择
			    ADC1TxDMA_Handler.Init.Channel=DMA_CHANNEL_0;                      //通道选择
			    ADC1TxDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;             //外设到存储器
			    ADC1TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
			    ADC1TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //存储器增量模式
			    ADC1TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_WORD;    //外设数据长度:32位
			    ADC1TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_WORD;       //存储器数据长度:32位
			    ADC1TxDMA_Handler.Init.Mode=DMA_CIRCULAR;                            //外设流控模式  循环模式
			    ADC1TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;               //中等优先级
			    ADC1TxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              
			    ADC1TxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      
			    ADC1TxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                 //存储器突发单次传输
			    ADC1TxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;              //外设突发单次传输
				
				ADC1TxDMA_Handler.XferCpltCallback = HAL_DMA_IRQHandler;
			      
			    HAL_DMA_DeInit(&ADC1TxDMA_Handler); 
			    HAL_DMA_Init(&ADC1TxDMA_Handler);
			   
			   __HAL_LINKDMA(&ADC1_Handler,DMA_Handle,ADC1TxDMA_Handler);    //将DMA与ADC1联系起来(发送DMA)
				
			   HAL_NVIC_SetPriority(DMA2_Stream0_IRQn,0,0);
			   HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
				
			}
			
			void DMA2_Stream0_IRQHandler(void)
			{
					HAL_DMA_IRQHandler(&ADC1TxDMA_Handler);
			}
			
			
			
			//采样函数
			void task_adc(void)
			{    
				int i;	
			     HAL_ADC_Start_DMA(&ADC1_Handler,&ADC_ConvertedValueRead[0],4);  
			      for(i=0; i<M; i++)
			        { 
						delay_us(10);
						
						value[0][i] = (u16)(ADC_ConvertedValue[0]&0xFFF ); //获取ADC的值
						value[1][i] = (u16)(ADC_ConvertedValue[1]&0xFFF);  //获取ADC的值
						value[2][i] = (u16)(ADC_ConvertedValue[2]&0xFFF); 
						value[3][i] = (u16)(ADC_ConvertedValue[3]&0xFFF);
					
			//              printf("\r\n 编号%d  \t 编号%d  \t AD值: %d\r\n", 0,i,  value[0][i]);
			//			  printf("\r\n 编号%d  \t 编号%d  \t AD值: %d\r\n", 1,i,  value[1][i]); 
			//			  printf("\r\n 编号%d  \t 编号%d  \t AD值: %d\r\n", 2,i,  value[2][i]);
			//			  printf("\r\n 编号%d  \t 编号%d  \t AD值: %d\r\n", 3,i,  value[3][i]); 
						 
			            LCD_ShowxNum(134,130,value[0][i],4,16,0);    //显示ADCC采样后的原始值
				        LCD_ShowxNum(134,150,value[1][i],4,16,0);    //显示ADCC采样后的原始值
			            LCD_ShowxNum(134,170,value[2][i],4,16,0);    //显示ADCC采样后的原始值
			             LCD_ShowxNum(134,190,value[3][i],4,16,0);    //显示ADCC采样后的原始值	
			
			//			delay_us(50);
			        }
					 HAL_ADC_Stop_DMA(&ADC1_Handler);      //传输完成以后关闭串口DMA
			
			}
			
			/**
			  * 函数功能: ADC转换完成回调函数
			  * 输入参数: hadc:ADC外设设备句柄
			  * 返 回 值: 无
			  * 说    明: 读取ADC转化结果时,一定要关闭Cache,否则数组中的数据为空,即关闭Cache后读取数据,读完在打开。
										此函数在 void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc) 中调用
			  */
			void  HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) 
			{
				uint32_t i;
				SCB_DisableDCache();
				
				for(i=0;i<4;i++)
				 {
					 ADC_ConvertedValue[i] = ADC_ConvertedValueRead[i];
				 }
				
				SCB_EnableDCache();	
			}

注意 :STM32767在使用时一定要注意Cache的问题

2、adc.h文件的配置

		#ifndef __ADC_H
		#define __ADC_H
		#include "sys.h"
		
		/********* 扩展变量 **********/
		extern ADC_HandleTypeDef ADC1_Handler;      //ADC句柄
		extern DMA_HandleTypeDef  ADC1TxDMA_Handler;      //DMA句柄
		
		/********* 函数声明**********/
		void MY_ADC_Init(void); 				//ADC通道初始化
		void DMA_Config(void);
		void task_adc(void);
		
		#endif 

3、main.c文件配置

	#include "sys.h"
	#include "delay.h"
	#include "usart.h"
	#include "led.h"
	#include "key.h"
	#include "lcd.h"
	#include "sdram.h"
	#include "adc.h"
	
	extern uint32_t ADC_ConvertedValueRead[4];
	
	int main(void)
	{
		Cache_Enable();                 //打开L1-Cache
	    HAL_Init();				        //初始化HAL库
	    Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 
	    delay_init(216);                //延时初始化
		uart_init(115200);		        //串口初始化
	    LED_Init();                     //初始化LED
	    KEY_Init();                     //初始化按键
	    SDRAM_Init();                   //初始化SDRAM
	    LCD_Init();                     //LCD初始化
	    
		MY_ADC_Init();                  //初始化ADC1
		DMA_Config();
	   
	    POINT_COLOR=RED; 
		LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");	
		LCD_ShowString(30,70,200,16,16,"ADC TEST");	
		LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
		LCD_ShowString(30,110,200,16,16,"2019/4/18");	  
		POINT_COLOR=BLUE;//设置字体为蓝色
		LCD_ShowString(30,130,200,16,16,"ADC1_PA7_VAL:");
	    LCD_ShowString(30,150,200,16,16,"ADC1_PC4_VAL:");
	    LCD_ShowString(30,170,200,16,16,"ADC1_PC5_VAL:");
	    LCD_ShowString(30,190,200,16,16,"ADC1_PA5_VAL:");	
	
		printf("采样开始\r\n ");
		task_adc();
		printf("采样结束\r\n ");
	
		while(1);
		      	
	}

以上代码我亲测有效,当然,如果有什么问题,欢迎交流讨论。

  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
STM32F103是一款具有多通道ADC、TIM、DMA和FFT功能的微控制器。 首先,多通道ADC允许我们同时采集多个不同通道的模拟信号。这对于需要同时监测多个传感器或信号源的应用非常有用。通过配置ADC的多个通道,并设置相应的采样速率和分辨率,可以轻松实现高效的数据采集。 其次,TIM(定时器)模块允许我们生成精确的时间基准。在实时系统和定时器应用中,我们可以配置TIM来实现各种定时和计时功能。通过设置预分频器、计数器和比较器,我们可以准确地生成周期性的、定时的或脉冲宽度可变的信号。这对于控制和调度其他外设非常有用。 接下来,DMA(直接内存访问)控制器允许我们实现高速数据传输,而不需要CPU的干预。通过配置DMA通道并定义源和目标的地址、传输长度和传输方向,我们可以实现高效的数据传输操作。这对于处理大量数据、高速数据流或实时响应的应用非常有用。 最后,FFT(快速傅里叶变换)是一种用于信号处理和频谱分析的重要算法。通过使用STM32F103的FFT库,我们可以对采集到的模拟信号进行频谱分析,以提取信号的频率和幅度特征。这对于音频处理、通信系统、传感器数据分析等应用非常有用。 之,STM32F103的多通道ADC、TIM、DMA和FFT功能为我们提供了丰富的数据采集、定时、数据传输和信号处理能力,使得我们可以设计出高度灵活、高效的嵌入式系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值