STM32F767多通道ADC采集+DMA传输

文章目录

  • 一、ADC简介
    • 1、ADC采样频率
    • 2、ADC转换时间
    • 3、ADC寄存器
    • 4、ADC引脚与外部通道对应关系
  • 二、DMA简介
  • 三、代码配置
    • 1、ADC、DMA初始化配置
    • 2、adc.h文件的配置
    • 3、main.c文件配置

一、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个周期的采样时间。如下图所示:
STM32F767多通道ADC采集+DMA传输_第1张图片

3、ADC寄存器

ADC里面用到的寄存器有很多,常用的有以下几个,具体使用方法就不一一介绍了
STM32F767多通道ADC采集+DMA传输_第2张图片

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

STM32F767多通道ADC采集+DMA传输_第3张图片

二、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

注意 :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);
		      	
	}

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

你可能感兴趣的:(STM32)