STM32 ADC在DMA中断模式下多通道数据采集

更新时间:2023-12-24 16:15:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

本程序实现STM32 DMA中断模式下ADC多通道数据采集,并经过简单的均值滤波,亲测可用。

若有错误之处,希望读者指出,大家共同学习,一起进步!

ADC.C文件

vu16 AD_Value[N][M]; //[50][4]用来存放ADC转换结果,也是DMA的目标地址 vu16 After_filter[M]; //用来存放求平均值之后的结果 vu16 Vtemp_sensor[M]; //电压转换完成后的实际电压值 //初始化ADC

//这里我们仅以规则通道为例 //我们默认将开启通道0~3 void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1, ENABLE ); //使能ADC1通道时钟 /* Configure ADCCLK such as ADCCLK = PCLK2/6 */ RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M //PA0/1/2/3 作为模拟通道输入引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure);

//模拟输入引脚

ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值 /* ADC1 configuration ------------------------------------------------------*/

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE;//扫描模式,各个通道均扫描完后EOC才置位 DISABLE; //模数转换工作在单通道模式 ADC_InitStructure.ADC_ContinuousConvMode =ENABLE; //ENABLE连续转换模式 DISABLE模数转换工作在单次转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = M; //1; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 //为了能够正确配置每一个ADC通道,在调用ADC_Init()之后,必须调用

ADC_ChannelConfig()

//来配置每个所使用通道的转换次序和采样时间

ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_1,2,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_2,3,ADC_SampleTime_55Cycles5); ADC_RegularChannelConfig(ADC1,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);

// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数) ADC_DMACmd(ADC1, ENABLE);

ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1,ADC开始工作

/* Enable ADC1 reset calibaration register */

ADC_ResetCalibration(ADC1); //重置指定的ADC1的校准寄存器 /* Check the end of ADC1 reset calibration register */

while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1重置校准寄存器的状态,设置状态则等待 /* Start ADC1 calibaration */ ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态 /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待 /* Start ADC1 Software Conversion */ //下面函数不可缺少 ********** ADC_SoftwareStartConvCmd(ADC1, ENABLE); 功能 }

//使能指定的ADC1的软件转换启动

//获得ADC值 //ch:通道值 0~3

u16 Get_Adc(u8 ch) {

//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间 //ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,规则采样顺序值为1,采样时间为239.5周期 //ADC1->CR2|=1<<22; //启动规则转换通道 /* Start ADC1 Software Conversion */ ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 //while(!(ADC1->SR&1<<1));//等待转换结束 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果

}

/***************************************** ADC滤波函数

*********************************************/ void filter(void) {

int sum = 0; u8 count,i; for(i=0;i<4;i++) { for ( count=0;count

Vtemp_sensor[i]= After_filter[i]* 330 / 4096; } }

Adc.h文件

#define N 50 //每通道采50次 #define M 4 //为12个通道

void Adc_Init(void); u16 Get_Adc(u8 ch);

void Show_Adc(u8 channel_n); void filter(void); //ADC滤波函数

DMA.C文件

DMA_InitTypeDef DMA_InitStructure;

u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度 //DMA1的各通道配置

//这里的传输形式是固定的,这点要根据不同的情况来修改 //从存储器->外设模式/8位数据宽度/存储器增量模式 //DMA_CHx:DMA通道CHx //cpar:外设地址 //cmar:存储器地址 //cndtr:数据传输量

void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr) {

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输时钟

DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值 DMA1_MEM_LEN=cndtr; DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址 DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//DST; //外设作为数据传输的目的地 DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增Enable,地址不变Disable DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//Word 一个字 //DMA外设ADC基地址,数据宽度为8位 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //半个字_HalfWord;一字节_Byte; //DMA内存基地址,数据宽度为8位 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式开启,Buffer写满后,自动回到初始地址开始传输 //工作在正常缓存模式DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到

内存传输 DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器 }

//下面两个函数不可缺少 ********** DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道

DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //使能DMA传输完成中断

Dma.h文件

void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);//配置DMA1_CHx

stm32f10x_it.c文件

/**************************************************************

STM32 DMA中断函数

***************************************************************/ void DMA1_Channel1_IRQHandler(void) {

if(DMA_GetITStatus(DMA1_IT_TC1) != RESET) {

filter();//ADC滤波函数

DMA_ClearITPendingBit(DMA1_IT_TC1); } }

主函数调用

#define ADC1_DR_Address ((u32)0x4001244c) //ADC数据寄存器地址

extern vu16 AD_Value[N][M];//主函数和子函数公用同一变量时使用 extern vu16 After_filter[M]; //用来存放求平均值之后的结果

extern vu16 Vtemp_sensor[M]; //电压转换完成后的实际电压值

MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)&AD_Value,N*M);//DMA初始化,(DMA的通道1,外设ADC地址,内存地址,缓存大小)

本文来源:https://www.bwwdw.com/article/nzu5.html

Top