stm32的示波器ADC_DMA

本文介绍了如何使用STM32的ADC和DMA功能进行高速数据采集,建议采用DMA缓存256或512点的方式,以提高采集效率。代码示例展示了ADC和DMA的配置,包括GPIO初始化、ADC与DMA的设置、TIM3的配置等,以实现基于TIM3触发的ADC转换和DMA传输。同时,提供了获取内部温度传感器数据的函数。
摘要由CSDN通过智能技术生成

建议

  • 在使用STM32内置ADC作为示波器的ADC采集时候,请使用DMA的配置,并且一次性采集的数据位数要多一点,比如DMA的缓存为256个点或者512个点。下面不废话直接上主要代码。

代码:

此处为ADC和DMA的配置代码

/*---------------------------------------------------------
---------------------------------------------------------*/
#include "stm32f10x.h"
#include "adc.h"
//#include "oscilloscope.h"
//#include "ucos_ii.h"
//#include "tft_api.h"
/*-----------------------------------------
		    	声明变量
------------------------------------------*/
//extern WaveType WaveInfo;
//extern WaveMode WaveCtrl;
u16	i;
u16 ADCV1[SAMPDEPTH];
u16 ADCV2[SAMPDEPTH];
volatile u32 ADCConvertedValue[SAMPDEPTH];//AD转换缓冲区,占用RAM 0.8KB	ADC1对应低16位,ADC2对应高16位
//uint32_t	ADCConvertedValue[SAMPDEPTH];
/*-----------------------------------------
		    	ADC1端口初始化
------------------------------------------*/
void ADC1_GPIO_Init(void)
{
	GPIO_InitTypeDef IO_Init;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2|RCC_APB2Periph_GPIOA,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置 ADC 分频因子6,	2M/6=12,ADC 最大时间不能超过 14M
	//C1模拟输入
	IO_Init.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4;
	IO_Init.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA,&IO_Init);
}

/* #define ADC1_DR_Address ((unsigned int)0x40012400+0x4c) */
/* unsigned short int ADC1_DMA_Value; */
/*--------------------------------------------------
 函数说明:配置ADC1完成AD采集,是本示波器最核心的部分.
 配置方案:ADC1由TIM3提供的触发事件进行触发AD转换,控
 		  制TIM3的速率就可以完成采样率的改变.同时采
		  用DMA完成数据传输,注入通道1完成内部温度传
		  感器AD采集. 
--------------------------------------------------*/
void ADC1_Mode_Config(void)
{
	//配置DMA
	DMA_InitTypeDef DMA_csh;
	ADC_InitTypeDef ADC_csh;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
/*
DMA_MemoryDataSize_Byte            数据宽度为 8 位 
DMA_MemoryDataSize_HalfWord        数据宽度为 16 位 
DMA_MemoryDataSize_Word            数据宽度为32 位
*/

	DMA_DeInit(DMA1_Channel1);  					   //DMA复位,通道1
	DMA_csh.DMA_PeripheralBaseAddr = ADC1_DR_Address;  //ADC1地址
//	DMA_csh.DMA_MemoryBaseAddr = (unsigned int)ADCConvertedValue;  //内存地址
	DMA_csh.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;  //内存地址
	DMA_csh.DMA_DIR = DMA_DIR_PeripheralSRC;  
	DMA_csh.DMA_BufferSize = SAMPDEPTH;  			  		//缓冲大小为采样深度我此处是512
	DMA_csh.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址固定
	DMA_csh.DMA_MemoryInc = DMA_MemoryInc_Enable; 			//内存地址自增
	DMA_csh.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;  //32位
	DMA_csh.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;			//32位
	DMA_csh.DMA_Mode = DMA_Mode_Circular;  					//循环传输
	DMA_csh.DMA_Priority = DMA_Priority_High;  				//DMA优先级高
	DMA_csh.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1,&DMA_csh);  						//写入DMA1配置参数
	DMA_Cmd(DMA1_Channel1,ENABLE);	   						//使能DMA1通道1
	DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);			//使能DMA CH1中断

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	//配置TIM3工作在18MHz,为AD提供触发
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); 
	TIM_TimeBaseStructure.TIM_Period = 1;          
	TIM_TimeBaseStructure.TIM_Prescaler = 29; 	//工作在18M,每格最大值时,不至于溢出      
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;    
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //使用TIM3事件更新作为ADC触发
	
	//配置ADC1
	/*
	ADC_Mode_Independent            ADC1 和ADC2 工作在独立模式 
ADC_Mode_RegInjecSimult         ADC1 和ADC2 工作在同步规则和同步注入模式 
ADC_Mode_RegSimult_AlterTrig    ADC1 和ADC2 工作在同步规则模式和交替触发模式 
ADC_Mode_InjecSimult_FastInterl ADC1 和ADC2 工作在同步规则模式和快速交替模式 
ADC_Mode_InjecSimult_SlowInterl ADC1 和ADC2 工作在同步注入模式和慢速交替模式 
ADC_Mode_InjecSimult             ADC1 和ADC2 工作在同步注入模式 
ADC_Mode_RegSimult              ADC1 和ADC2 工作在同步规则模式 
ADC_Mode_FastInterl                ADC1 和ADC2 工作在快速交替模式 
ADC_Mode_SlowInterl               ADC1 和ADC2 工作在慢速交替模式 
ADC_Mode_AlterTrig                  ADC1 和ADC2 工作在交替触发模式
	*/
	ADC_csh.ADC_Mode = ADC_Mode_RegSimult;  		//ADC1 和ADC2 工作在同步规则模式
  ADC_csh.ADC_ScanConvMode = DISABLE;   			//关闭扫描模式
	ADC_csh.ADC_ContinuousConvMode = DISABLE;  		//连续AD转换开启
	ADC_csh.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;  //由TIM3提供的触发事件进行触发AD转换
	ADC_csh.ADC_DataAlign = ADC_DataAlign_Right; 	//数据右对齐
	ADC_csh.ADC_NbrOfChannel = 1;  					//要转换的通道数目1
	ADC_Init(ADC1,&ADC_csh);   						//写入ADC1配置参数
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_239Cycles5);//采样速率1M
//	ADC_DMACmd(ADC1,ENABLE); 						//使能ADC1 DMA
	ADC_ExternalTrigConvCmd(ADC1,ENABLE);			//打开ADC1外部触发	
	/******配置ADC2**********/
	ADC_csh.ADC_Mode = ADC_Mode_RegSimult;  		//双通道同时采样
	ADC_csh.ADC_ScanConvMode = DISABLE;   			//关闭扫描模式
	ADC_csh.ADC_ContinuousConvMode = DISABLE;  		//连续AD转换开启
	ADC_csh.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //软件触发转换
	ADC_csh.ADC_DataAlign = ADC_DataAlign_Right; 	//数据右对齐
	ADC_csh.ADC_NbrOfChannel = 1;  					//要转换的通道数目1
	ADC_Init(ADC2,&ADC_csh);   						//写入ADC1配置参数
	ADC_RegularChannelConfig(ADC2,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);//采样速率1M
	ADC_ExternalTrigConvCmd(ADC2,ENABLE);			//打开ADC1外部触发    
	/*******************/
/*	ADC_InjectedChannelConfig(ADC1,ADC_Channel_16,1,ADC_SampleTime_239Cycles5);	 //配置ADC1通道16为注入通道1
	ADC_ExternalTrigInjectedConvConfig(ADC1,ADC_ExternalTrigInjecConv_None);	 //软件触发注入通道的转换
	ADC_TempSensorVrefintCmd(ENABLE);											 //使能温度传感器
*/
	ADC_DMACmd(ADC1,ENABLE); 						//使能ADC1 DMA
	ADC_Cmd(ADC1,ENABLE); 							//使能ADC1
	ADC_ResetCalibration(ADC1);	  					//复位校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1));     //等待校准寄存器复位完成
	ADC_StartCalibration(ADC1);	  					//开始校准
	while(ADC_GetCalibrationStatus(ADC1)); 			//等待校准完成
	
	ADC_Cmd(ADC2,ENABLE); 
	ADC_ResetCalibration(ADC2);	  					//复位校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC2));     //等待校准寄存器复位完成
	ADC_StartCalibration(ADC2);	  					//开始校准
	while(ADC_GetCalibrationStatus(ADC2)); 			//等待校准完成
	
	TIM_Cmd(TIM3,ENABLE);		//使能 TIM3
}
/*-----------------------------------------
 函数说明:通过注入通道1转换内部温度传感器
 		  AD值,读取10次有效数据取平均返回 
------------------------------------------*/
u16 GetTempSensor(void)   
{ 
	u16 temp=0,i,k=0;
	for(i=0; i<10; )
	{
		ADC_SoftwareStartInjectedConvCmd(ADC1,ENABLE);	//软件触发注入通道的转换
		k = (0x6EE - ADC_GetInjectedConversionValue(ADC1,ADC_InjectedChannel_1)) / 0x05 + 25;
		if(k>0 && k<100)
		{
			temp += k;
			i++;
		}
	}
	temp /= 10;
	return temp;	     
}
/*-----------------------------------------
 函数说明:ADC1初始化 
------------------------------------------*/
void ADC1_Init(void)
{
	ADC1_GPIO_Init();
	ADC1_Mode_Config();
}
/*-----------------------------------------
 函数说明:ADC传输DMA通道1中断服务程序
 		  DMA把AD值传输到缓冲区完成后关闭定
		  时器3(作为触发AD转换的定时器)同时
		  置更新完成标志位为1,开定时器3在应
		  用中开启. 
------------------------------------------*/
void DMA1_Channel1_IRQHandler()
{
//      OSIntNesting++;  
      DMA_ClearFlag(DMA1_FLAG_TC1);	//清除DMA传输完成中断
      TIM_Cmd(TIM3,DISABLE);		//关闭TIM3
//      WaveCtrl.UpdatTrue = 1;		//已经完成一次波形FIFO,可以批量读出数据
 //     OSIntExit();
	for(i=0;i<SAMPDEPTH;i++)
  {
	 ADCV2[i]=ADCConvertedValue[i]>>16;
	 ADCV1[i]=ADCConvertedValue[i] & 0xFFFF;
  }
  TIM_Cmd(TIM3,ENABLE);		//使能 TIM3
}
/*-----------------------------------------
 函数说明:擦除AD缓冲区 
------------------------------------------*/
void Earse_AD_FIFO(void)
{
	uint32_t i;
 	for(i=0; i<SAMPDEPTH; i++)
	{
		ADCConvertedValue[i] = 0;
	}	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值