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

合集下载

STM32多通道ADC采集详解(DMA模式和非DMA模式)

STM32多通道ADC采集详解(DMA模式和非DMA模式)

STM32多通道ADC采集详解(DMA模式和非DMA模式)在非DMA模式下,ADC采集的数据是通过CPU直接读取的,采集效率相对较低,但是编程相对简单。

首先,需要初始化ADC模块的工作模式(单通道、多通道等)和采样时间。

然后,使能ADC模块,并配置所需的通道和采样时间。

接着,设置采样序列,指定要采集的通道和相应的排列顺序。

在采集数据时,首先需要设置ADC转换模式和采样时间,然后开始转换,并等待转换完成。

转换完成后,通过读取ADC_DR寄存器可以获取转换结果。

如果需要采集多个通道的数据,可以通过设置ADCSQR中的SQx位来启动下一次转换。

在DMA模式下,ADC采集的数据是通过DMA控制器传输到指定的内存区域,采集效率较高,适合数据量较大的应用场景。

与非DMA模式相比,DMA模式下的配置需要额外设置DMA控制器的工作模式(单次传输、循环传输等)和传输数据的目的地地址。

在采集数据前,需要设置DMA传输的目的地地址,并使能DMA传输。

在开启ADC转换后,DMA控制器会根据设置的目的地地址来自动传输数据,无需CPU干预。

采集完成后,CPU可以通过检查DMA传输完成标志位来判断数据是否已传输完毕。

总结:
使用非DMA模式的ADC采集相对简单而容易上手,适用于数据量较小且对实时性要求不高的应用场景。

DMA模式下的ADC采集效率更高,适用于数据量较大且对实时性要求较高的应用场景。

无论是DMA模式还是非DMA模式,都需要根据具体的应用需求来选择合适的模式。

在使用DMA模式时,还需要注意合理设置DMA传输的目的地地址和传输模式,以充分发挥DMA的优势。

STM32单片机的ADC多通道采样

STM32单片机的ADC多通道采样
面给出《STM32库开发实战指南》上面配套的硬件电路图
如果设计电路图的话,可以参考这种思路。
我的收获
1引脚初始化的时候需要注意
每一个ADC通道都对应一个GPIO引脚,看图中的ADC123_IN10,表示
这个引脚(PC0)可以配置为ADC1的通道10,或者是ADC2的通道10,或
者是ADC3的通道10,这个地方非常重要,涉及到后面ADC初始化时函数
STM32单片机的ADC多通道采样
一单通道采样
参考资料:
《STM32库开发实战指南》
原理性质的东西还是少讲,因为上面那本书里面讲解的很详细了,直接来
看硬件电路图
这里使用的是3362电位器(10K),即用STM32来测量PB0和GND两
端的电压,这样的电路设计比较简单也容易理解,但是存在一定的弊端,下
的调用。
比如当我们使能ADC时,我们调用的函数是
ADC_Cmd();1
如果我们使用的是ADC1,那幺上面函数的写法就应该是
ADC_Cmd(ADC1,ENABLE);1
相应的如果是ADC2,那幺上面函数的写法就是
ADC_Cmd(ADC2,ENABLE);1
另外需要注意的是,我们这里的ADC使用了DMA,所以如果你使用的
是ADC1,那幺对应DMA就应该是DMA1的通道1
如果使用的是ADC2或者是ADC3就需要自己去查找手册,看看对应的
是哪个DMA的那个通道。
在后面上传的程序中可以看到DMA初始化的时候有这幺一条语句
DMA_Init(DMA1_Channel1);1
这就是初始化DMA1的通道1
相应的
DMA_Cmd(DMA1_Channel1,ENABLE);1
就是使能DMA1的通道1

STM32F0多路ADC采样中的BUG和解决方案

STM32F0多路ADC采样中的BUG和解决方案

STM32F0多路ADC采样中的BUG和解决方案在STM32F0系列中,多路ADC采样时可能会出现一些问题,下面是一些常见的BUG以及对应的解决方案:1.ADC转换结果误差较大:-原因:ADC的转换精度受到参考电压和时钟精度的影响,以及输入信号的干扰等。

-解决方案:-确保参考电压稳定,可以使用稳压器等电压源。

-降低输入信号的干扰,可以使用滤波电路。

-选择合适的采样率和分辨率,根据实际需求调整。

-使用校准功能对ADC进行校准,可以提高转换精度。

2.ADC采样速度不稳定:-原因:在多通道ADC采样时,切换通道可能会引入额外的时间延迟,导致采样速度不稳定。

-解决方案:-配置ADC转换模式为扫描模式,使得ADC可以按照一定的顺序进行多通道采样。

-调整通道切换速度,可以通过增加延时或者降低采样速率来解决。

3.ADC采样结果不准确或者不稳定:-原因:在多路ADC采样时,可能存在模拟输入信号的串扰或者共模干扰,导致采样结果不准确或者不稳定。

-解决方案:-选择合适的参考电压和可靠的电源地,以减少参考电压的波动或者输入信号的干扰。

-适当延长采样时间,可以通过增加采样周期来提高稳定性。

-使用信号调制技术,如差分信号采样、抗共模干扰技术等。

4.ADC采样中断丢失:-原因:在多通道ADC采样时,如果不及时处理中断,可能会导致中断丢失。

-解决方案:-配置合适的优先级分组和中断优先级,以确保ADC中断能够得到及时处理。

-在中断处理函数中尽量减少处理时间,避免长时间占用CPU。

5.ADC采样时CPU占用率过高:-原因:在ADC连续转换模式中,如果没有合适的采样间隔,可能会导致CPU占用率过高。

-解决方案:-合理配置ADC的采样频率和采样间隔,根据实际需求进行调整。

-使用DMA传输数据,减少CPU的负载,提高系统的稳定性和响应速度。

以上是一些常见的STM32F0多路ADC采样中可能出现的BUG以及对应的解决方案,根据实际情况进行调试和优化,可以提高ADC的准确性和稳定性。

STM32中AD采样的三种方法分析

STM32中AD采样的三种方法分析

STM32中AD采样的三种⽅法分析 在进⾏STM32F中AD采样的学习中,我们知道AD采样的⽅法有多种,按照逻辑程序处理有三种⽅式,⼀种是查询模式,⼀种是中断处理模式,⼀种是DMA模式。

三种⽅法按照处理复杂⽅法DMA模式处理模式效率最⾼,其次是中断处理模式,最差是查询模式,相信很多学者在学习AD采样程序时,很多例程采⽤DMA模式,在这⾥我针对三种程序进⾏分别分析。

1、AD采样查询模式 在AD采样查询模式中,我们需要注意的是IO⼝的初始化配置,这⾥我采⽤PA2作为模拟采集的引脚(AIN2)和串⼝3作为打印输出。

具体如下:建⽴⼀个USART3.C和USART3.H⽂件,其程序为: #include "usart3.h" #include "stdarg.h" u8 SendBuff[SENDBUFF_SIZE]; void USART3_Config(void) { //定义结构体 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; //开启外部时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE ); // USART3 GPIO config GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOAtiNG; GPIO_Init(GPIOB, &GPIO_InitStructure); //USART3 mode config USART_ART_BaudRate = 115200; USART_ART_WordLength = USART_WordLength_8b; USART_ART_StopBits = USART_StopBits_1; USART_ART_Parity = USART_Parity_No; USART_ART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_ART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART3, &USART_InitStructure); USART_Cmd(USART3, ENABLE); } 其次建⽴⼀个ADC.C和⼀个ADC.H⽂件,其中ADC.C中程序为: void ADC1_Init(void) { ADC1_GPIO_Config(); ADC1_Mode_Config(); } static void ADC1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; //开启外部时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA,ENABLE); //配置PA2引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //配置为模拟输⼊ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //调⽤库函数 GPIO_Init(GPIOA, &GPIO_InitStructure); } static void ADC1_Mode_Config(void) { //ADC1_ configuration ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独⽴ADC模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //禁⽌扫描模式 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使⽤外部触发转换 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //要转换的通道数⽬1 ADC_Init(ADC1,&ADC_InitStructure); //配置ADC时钟,为PCLK2的8分频,即9Mhz RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC1的通道2位55.5个采集周期 ADC_RegularChannelConfig(ADC1,ADC_Channel_2, 1, ADC_SampleTime_55Cycles5); ADC_Cmd(ADC1,ENABLE); //复位校准寄存器 ADC_ResetCalibration(ADC1); //等待校准寄存器复位完成 while(ADC_GetResetCalibrationStatus(ADC1)); //ADC校准 ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); //由于没有使⽤外部触发,所以使⽤软件触发ADC转换 ADC_SoftwareStartConvCmd(ADC1,ENABLE); } 然后在主函数main中其程序代码如下: int main(void) { USART3_Config(); ADC1_Init(); printf("输⼊ADC值"); while(1) { ADC_ConvertedValue = ADC_GetConversionValue(ADC1); ADC_ConvertedValueLocal =(float)ADC_ConvertedValue/4096*3.3; //读取ADC转换的值 printf("\r\n the current AD value = 0x%04X \r\n",ADC_ConvertedValue); printf("\r\n the current AD value = %f V \r\n",ADC_ConvertedValueLocal); Delay(0xFFFFEE); } } 这样采⽤查询的⽅法即可以采集ADC的电压值,⼀个值为16进制转换的值,⼀个是转换计算的值。

经典_STM32_ADC多通道采样的例子

经典_STM32_ADC多通道采样的例子

ADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待
ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地
DMA_InitStructure.DMA_BufferSize = N*M; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
RCC_DeInit(); //RCC 系统复位
RCC_HSEConfig(RCC_HSE_ON); //开启HSE
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE准备好

STM32三个ADC同步规则采样

STM32三个ADC同步规则采样

STM32三个ADC同步规则采样同步采样⼀般应⽤于交流信号中,是指多个ADC的采集时刻完全同步。

在电⼒测量领域,经常会遇到需要同步采样的情况,⽐如同步采样电压电流信号,计算其相位差。

阻抗分析时,也需要对输⼊输出信号进⾏同步采集,分析其相位差和幅度,计算阻抗。

1.Mode选择为三重同步规则模式。

2.使能DMA连续请求。

3.外部触发源选择TIM2触发事件。

配置完成后,打开ADC2和ADC3的配置,可以看到,Mode已经⾃动配置为三重同步规则模式,且外部触发源也已经隐藏⽆法选择,因为三重同步规则模式下,三个ADC必须使⽤同⼀个外部触发源。

同时ADC2和ADC3的DMA也不需要配置,使⽤同⼀个DMA。

ADC2配置如下:ADC配置完成后,打开TIM2定时器,⽤于触发ADC采样。

TIM2时钟选择内部时钟(84MHz),选择触发事件为Update Event,⽤于触发ADC。

配置其分频系数和计数周期如下,则ADC的采样率为84MHz÷(83+1) ÷(199+1)=5000Hz。

uint8_t DMA_Flag = 0;void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){DMA_Flag = 1;}HAL_ADC_Start(&hadc1);HAL_ADC_Start(&hadc2);HAL_ADC_Start(&hadc3);//启动ADCHAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*)adcbuf1,300);//启动同步规则模式及DMA,3个ADC,每次采样100个点*3 HAL_TIM_Base_Start(&htim2);//启动TIM2,⽤于触发ADC采样/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){if(DMA_Flag == 1)//AD转换完成标准{DMA_Flag = 0;HAL_TIM_Base_Stop(&htim2);HAL_ADCEx_MultiModeStop_DMA(&hadc1);HAL_ADC_Stop(&hadc1);HAL_ADC_Stop(&hadc2);HAL_ADC_Stop(&hadc3);//停⽌采样for(uint8_t i=0;i<100;i++)< span="">{sprintf(str,"$,%d,%d,%d",adcbuf1[i][0],adcbuf1[i][1],adcbuf1[i][2]);HAL_UART_Transmit(&huart1,(uint8_t*)str,strlen(str),100);//串⼝发送到上位机}HAL_ADC_Start(&hadc1);HAL_ADC_Start(&hadc2);HAL_ADC_Start(&hadc3);HAL_ADCEx_MultiModeStart_DMA(&hadc1,(uint32_t*)adcbuf1,300);HAL_TIM_Base_Start(&htim2);//重新启动采样}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */。

基于STM32单片机的多路数据采集系统设计

基于STM32单片机的多路数据采集系统设计

基于STM32单片机的多路数据采集系统设计概述:多路数据采集系统是一种用于采集和处理多种传感器信号的系统。

基于STM32单片机的多路数据采集系统具有低功耗、高精度、稳定可靠的特点,广泛应用于工业控制、环境监测和医疗设备等领域。

本文将介绍基于STM32单片机的多路数据采集系统的设计方案及实现方法。

设计方案:1.系统硬件设计:系统硬件由STM32单片机、多路模拟输入通道、数模转换器(ADC)和相关模拟电路组成。

其中,多路模拟输入通道可以通过模拟开关电路实现多通道选通;ADC负责将模拟信号转换为数字信号;STM32单片机负责控制和处理这些数字信号。

2.系统软件设计:系统软件可以采用裸机编程或者使用基于STM32的开发平台来进行开发。

其中,主要包括数据采集控制、数据转换、数据处理和数据存储等功能。

具体实现方法如下:-数据采集控制:配置STM32单片机的ADC模块,设置采集通道和相关参数,启动数据采集。

-数据转换:ADC将模拟信号转换为相应的数字量,并通过DMA等方式将数据传输到内存中。

-数据处理:根据实际需求对采集到的数据进行预处理,包括滤波、放大、校准等操作。

-数据存储:将处理后的数据存储到外部存储器(如SD卡)或者通过通信接口(如UART、USB)发送到上位机进行进一步处理和分析。

实现方法:1.硬件实现:按照设计方案,选择适应的STM32单片机、模拟开关电路和ADC芯片,完成硬件电路的设计和布局。

在设计时要注意信号的良好地线与电源隔离。

2.软件实现:(1)搭建开发环境:选择适合的开发板和开发软件(如Keil MDK),配置开发环境。

(2)编写初始化程序:初始化STM32单片机的GPIO口、ADC和DMA等模块,配置系统时钟和相关中断。

(3)编写数据采集程序:设置采集参数,例如采样频率、触发方式等。

通过ADC的DMA功能,实现数据的连续采集。

(4)编写数据处理程序:根据实际需求,对采集到的数据进行预处理,例如滤波、放大、校准等操作。

STM32-ADC结合DMA数据采样与软件滤波处理

STM32-ADC结合DMA数据采样与软件滤波处理

STM32 ADC结合DMA数据采样与软件滤波处理2012-03-17 23:53:05| 分类:STM32 | 标签:adc结合dma |字号大中小订阅本文原创于观海听涛,原作者所有,请注明出处。

作为一个偏向工控的芯片,ADC采样是一个十分重要的外设。

STM32集成三个12位精度18通道的部ADC,最高速度1微秒,结合DMA可以解放CPU进行更好的处理。

ADC接口上的其它逻辑功能包括:●同步的采样和保持●交叉的采样和保持●单次采样模拟看门狗功能允许非常精准地监视一路、多路或所有选中的通道,当被监视的信号超出预置的阀值时,将产生中断。

由标准定时器(TIMx)和高级控制定时器(TIM1和TIM8)产生的事件,可以分别部级联到ADC 的开始触发和注入触发,应用程序能使AD转换与时钟同步。

12位ADC是一种逐次逼近型模拟数字数字转换器。

它有多达18个通道,可测量16个外部和2个部信号源。

ADC的输入时钟不得超过14MHZ,它是由PCLK2经分频产生。

如果被ADC转换的模拟电压低于低阀值或高于高阀值,AWD模拟看门狗状态位被设置。

关于ADC采样与DMA关系,引用网上一段解释:STM32 的优点在哪里?除去宣传环节,细细分析。

STM32 时钟不算快,72MHZ,也不能扩展大容量的RAM FLASH,同样没有DSP 那样强大的指令集。

它的优势在哪里呢?---就在快速采集数据,快速处理上。

ARM 的特点就是方便。

这个快速采集,高性能的ADC 就是一个很好的体现,12 位精度,最快1uS 的转换速度,通常具备2 个以上独立的ADC 控制器,这意味着,STM32 可以同时对多个模拟量进行快速采集,这个特性不是一般的MCU具有的。

以上高性能的ADC,配合相对比较块的指令集和一些特色的算法支持,就构成了STM32 在电机控制上的强大特性。

好了,正题,怎末做一个简单的ADC,注意是简单的,ADC 是个复杂的问题,涉及硬件设计,电源质量,参考电压,信号预处理等等问题。

STM32利用DMA实现多通道ADC转换程序实例.docx

STM32利用DMA实现多通道ADC转换程序实例.docx

网上很多类似资料,总结就是要么给出不完整的一部分,要么就是没有标注说明之类的,鞋面我给大家贴出实用型的,包括如何配置DMA和ADC,如何采集数据,如何处理数据//系统时钟使用72MHZunsigned short AD_Value[5]={0};//定义成半字节数组void RCC_Config(void){ErrorStatus HSEStartUpStatus;//定义枚举型变量RCC_DeInit();RCC_HSEConfig(RCC_HSE_ON);HSEStartUpStatus = RCC_WaitForHSEStartUp();if(HSEStartUpStatus==SUCCESS){RCC_HCLKConfig(RCC_SYSCLK_Div1);RCC_PCLK2Config(RCC_HCLK_Div1);RCC_PCLK1Config(RCC_HCLK_Div2);FLASH_SetLatency(FLASH_Latency_2);FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);RCC_PLLCmd(ENABLE);while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);while(RCC_GetSYSCLKSource()!=0x08);}//---打开设备时钟---//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOF,ENABLE);//RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//开串口1和ADC1的时钟}void ADC_Start(void){DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动转换}void DMA_ADC_Config(void){ADC_InitTypeDef ADC_InitStructure;DMA_InitTypeDef DMA_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //设置成模拟输入GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_0);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //设置成模拟输入GPIO_Init(GPIOB, &GPIO_InitStructure);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//开ADC1的时钟RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //开DMA时钟RCC_ADCCLKConfig(RCC_PCLK2_Div8);//配置ADC时钟,为PCLK2的8分频,即9MHzDMA_DeInit(DMA1_Channel1);//ADC挂接在DMA的通道1上DMA_InitStructure.DMA_PeripheralBaseAddr = ADC_DR_ADDRESS; //DMA外设ADC基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地DMA_InitStructure.DMA_BufferSize = 5; //DMA通道的DMA缓存的大小系统用5个通道DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变即地址ADC1->DR不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增即数组AD_Value地址增加DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位,这里尤其注意因为选择的是半字节的,所以定义数组的时候也要定义成半字节数组,否则采集数据出乱,很多人是贴出资料来了,但是根本没有把这些注意点写明DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道x拥有高优先级DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x设置为非内存到内存传输DMA_Init(DMA1_Channel1, &DMA_InitStructure);//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);ADC_DeInit(ADC1);ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换//ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //注意不要使用持续转换模式,否则只要触发一次后续的转换就会永不停歇(除非CONT清0),这样第一次以后的ADC,就不是由TIM1_CC1来触发了ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_InitStructure.ADC_NbrOfChannel = 5; //顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 2, ADC_SampleTime_239Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 3, ADC_SampleTime_239Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_239Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5);ADC_ExternalTrigInjectedConvCmd(ADC1,DISABLE);ADC_DMACmd(ADC1, ENABLE); // 开启ADC的DMA支持(要实现DMA效用,还需独立配置DMA通道等参数)ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1ADC_ResetCalibration(ADC1);//复位校准寄存器while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待ADC_Start();}//数据采集处理void ADC_DateProcess(void){unsigned char i,k,h;unsigned int Buf=0;//递推先进先出原理ADCCollect.PVVoltageBuf[9]=get_ChannelVale(ADC_Channel_4)&0xfff;ADCCollect.BatteryVoltageBuf[9]=get_ChannelVale(ADC_Channel_5)&0xfff;ADCCollect.CirTem1Buf[9]=get_ChannelVale(ADC_Channel_6)&0xfff;ADCCollect.BatteryChargeCurrentBuf[9]=get_ChannelVale(ADC_Channel_7)&0xfff;ADCCollect.BatteryDisChargeCurrentBuf[9]=get_ChannelVale(ADC_Channel_8)&0xfff;for(i=0;i<9;i++){ADCCollect.PVVoltageBuf[i]=ADCCollect.PVVoltageBuf[1+i];ADCCollect.BatteryVoltageBuf[i]=ADCCollect.BatteryVoltageBuf[1+i];ADCCollect.CirTem1Buf[i]=ADCCollect.CirTem1Buf[1+i];ADCCollect.BatteryChargeCurrentBuf[i]=ADCCollect.BatteryChargeCurrentBuf[1+i];ADCCollect.BatteryDisChargeCurrentBuf[i]=ADCCollect.BatteryDisChargeCurrentBuf[1+i];}//排序for(k=0; k<9; k++ )//{for(h=0 ; h<9 - k ; h++)//{Buf=0;if(ADCCollect.PVVoltageBuf[h] > ADCCollect.PVVoltageBuf[h+1]){Buf = ADCCollect.PVVoltageBuf[h+1];ADCCollect.PVVoltageBuf[h+1] = ADCCollect.PVVoltageBuf[h];ADCCollect.PVVoltageBuf[h] = Buf;}Buf=0;if(ADCCollect.BatteryVoltageBuf[h] > ADCCollect.BatteryVoltageBuf[h+1]){Buf = ADCCollect.BatteryVoltageBuf[h+1];ADCCollect.BatteryVoltageBuf[h+1] = ADCCollect.BatteryVoltageBuf[h];ADCCollect.BatteryVoltageBuf[h] = Buf;}Buf=0;if(ADCCollect.CirTem1Buf[h] > ADCCollect.CirTem1Buf[h+1]){Buf = ADCCollect.CirTem1Buf[h+1];ADCCollect.CirTem1Buf[h+1] = ADCCollect.CirTem1Buf[h];ADCCollect.CirTem1Buf[h] = Buf;}Buf=0;if(ADCCollect.BatteryChargeCurrentBuf[h] > ADCCollect.BatteryChargeCurrentBuf[h+1]){Buf = ADCCollect.BatteryChargeCurrentBuf[h+1];ADCCollect.BatteryChargeCurrentBuf[h+1] = ADCCollect.BatteryChargeCurrentBuf[h];ADCCollect.BatteryChargeCurrentBuf[h] = Buf;}}}ADCCollect.CirTem1=0;ADCCollect.BatteryChargeCurrent=0;ADCCollect.BatteryDisChargeCurrent=0;ADCCollect.BatteryVoltage=0;ADCCollect.PVVoltage=0;//去掉最大值和最小值取平均值for(i=3;i<7;i++)//{ADCCollect.CirTem1+=ADCCollect.CirTem1Buf[i];ADCCollect.BatteryChargeCurrent+=ADCCollect.BatteryChargeCurrentBuf[i];ADCCollect.BatteryDisChargeCurrent+=ADCCollect.BatteryDisChargeCurrentBuf[i];ADCCollect.BatteryVoltage+=ADCCollect.BatteryVoltageBuf[i];ADCCollect.PVVoltage+=ADCCollect.PVVoltageBuf[i];}ADCCollect.CirTem1=ADCCollect.CirTem1/4;ADCCollect.BatteryChargeCurrent=ADCCollect.BatteryChargeCurrent/4; ADCCollect.BatteryDisChargeCurrent=ADCCollect.BatteryDisChargeCurrent/4; ADCCollect.BatteryVoltage=ADCCollect.BatteryVoltage/4;ADCCollect.PVVoltage=ADCCollect.PVVoltage/4;//充电电流ADCCollect.BatteryChargeCurrent=(ADCCollect.BatteryChargeCurrent*33)/4096; ADCCollect.BatteryChargeCurrent=(ADCCollect.BatteryChargeCurrent*30)/31;if(ADCCollect.BatteryChargeCurrent<0.2){ADCCollect.BatteryChargeCurrent=0;}//电池电压ADCCollect.BatteryVoltage=ADCCollect.BatteryVoltage*33/40960;ADCCollect.BatteryVoltage=ADCCollect.BatteryVoltage*3068/68;//放电电流ADCCollect.BatteryDisChargeCurrent=(ADCCollect.BatteryDisChargeCurrent*33)/4096; ADCCollect.BatteryDisChargeCurrent=(ADCCollect.BatteryDisChargeCurrent*30)/31;if(ADCCollect.BatteryDisChargeCurrent<0.2){ADCCollect.BatteryDisChargeCurrent=0;}//PV电压ADCCollect.PVVoltage=ADCCollect.PVVoltage*33/40960;ADCCollect.PVVoltage=ADCCollect.PVVoltage*3068/68;//温度ADCCollect.CirTem1=NTC_Temperature(ADCCollect.CirTem1);ADCCollect.CirTem1=ADCCollect.CirTem1/10;}科教兴国。

STM32 ADC DMA 使用心得

STM32 ADC DMA 使用心得

(二)ADC循环采集六路电压,使用DMA.这次实验真的很郁闷,对DMA的不了解让我深陷误区,明白之后,让我更加佩服DMA的强大。

误区就是:从实验的目标我们知道这次是用DMA把ADC转换的数据传送到内存中的一个数组里存起来,因为是采集6个通道,这里使能了ADC的扫描模式。

一旦启动ADC,就会按顺序转换SQRX里选中的通道,问题就是我一开始以为ADC与DMA并不会协调工做,也就是ADC自己转自己的,DMA自己传自己的,这样的话内存里的数组就不是我想要的了,后来着实的研究了很长时间,在群里的一位兄弟的提醒下,我才知道,可能我想的复杂了,也许就可以在ADC转一次,然后DMA把数据传一次,Ok,经过实验得知,这个想法是正确的。

好了,说了这么多废话,开始进入正题。

这里使用了ADC1的六个规则通道分别是:CH0、CH1、CH2、CH3、CH14、CH15,分别对应的引脚为PA0、PA1、PA2、PA3、PC4、PC5。

关于ADC的配置:启动了ADC1的扫描模式,还有连续转换模式,独立工作模式(只用1个ADC),因为用的了DMA,所以也要使能DMA位,使用外部触发(SWSTART),数据为右对齐。

还有SQRX等等就不说了,这里不需要ADC中断的。

中断在DMA里。

关于DMA的配置:因为ADC请求规定在DMA1的第一个通道,所以这里使用DMA_CH1,外设地址为ADC唯一的数据寄存器(u32)&ADC1->DR,存储器地址为(u32)SendBuff数组,这个数组可以存放6个元素。

这里还有使能传输完中断(TCIF),选择从外设读取,循环模式,外设地址非增量模式,存储器地址增量模式,外设数据宽度16位,存储器地址16位,非存储器到存储器模式。

关于DMA中断函数:当DMA传输完6次数据时,TCIF位自动置位,程序进入中断服务函数,首先先关闭ADC的连续转换,我们把数组的处理都放在了这里,处理完发送到串口,通过电脑的超级终端可以看到不停变化的6个引脚电压的数据。

STM32ADC多通道转换DMA模式与非DMA模式两种方法(HAL库)

STM32ADC多通道转换DMA模式与非DMA模式两种方法(HAL库)

STM32ADC多通道转换DMA模式与⾮DMA模式两种⽅法(HAL库)⼀、⾮DMA模式(转) 说明:这个是⾃⼰刚做的时候百度出来的,不是我⾃⼰做出来的,因为感觉有⽤就保存下来做学习⽤,原⽂链接:,下⾯第⼆部分我会补充⾃⼰的DMA模式的⽅法。

Stm32 ADC 的转换模式还是很灵活,很强⼤,模式种类很多,那么这也导致很多⼈使⽤的时候没细⼼研究参考⼿册的情况下容易混淆。

不知道该⽤哪种⽅式来实现⾃⼰想要的功能。

⽹上也可以搜到很多资料,但是⼤部分是针对之前⽼版本的标准库的。

昨天帮客户解决这个问题,正好做个总结:使⽤stm32cubeMX配置⽣成多通道采集的例⼦。

软件:STM32Cumebx MDK硬件:eemaker板(基于stm32F103c8的)在百度搜索ADC多通道采集,⼤部分的都是基于采⽤dma模式才实现的。

⽽我讲的使⽤⾮dma⽅法。

⾸先有⼏个概念要搞清楚: 扫描模式(想采集多通道必须开启):是⼀次对所选中的通道进⾏转换,⽐如开了ch0,ch1,ch4,ch5。

Ch0转换完以后就会⾃动转换通道0,1,4,5直到转换完。

但是这种连续性并不是不能被打断。

这就引⼊了间断模式,可以说是对扫描模式的⼀种补充。

它可以把0,1,4,5这四个通道进⾏分组。

可以分成0,1⼀组,4,5⼀组。

也可以每个通道配置为⼀组。

这样每⼀组转换之前都需要先触发⼀次。

Stm32 ADC的单次模式和连续模式。

这两中模式的概念是相对应的。

这⾥的单次模式并不是指⼀个通道。

假如你同时开了ch0,ch1,ch4,ch5这四个通道。

单次模式转换模式下会把这四个通道采集⼀边就停⽌了。

⽽连续模式就是这四个通道转换完以后再循环过来再从ch0开始。

另外还有规则组和注⼊组的概念,因为我这个例程只⽤到了规则组,就不多介绍这两个概念,想要弄清楚请⾃⾏查阅⼿册。

下⾯进⼊正题,配置stm32cubeMX。

先使能⼏个通道,我这⾥设置为0、1、4、5.然后就要配置ADC的参数: ⽬前经过我的测试,要想⽤⾮dma和中断模式只有这样配置可以正确进⾏多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组⼀个通道)。

STM32F103和STM32F401的ADC多通道采集DMA输出

STM32F103和STM32F401的ADC多通道采集DMA输出

STM32F103和STM32F401的ADC多通道采集DMA输出使⽤STM32F103和STM32F401CCU6对双轴摇杆(两个电压通道)进⾏ADC采样并通过DMA读取数值STM32 ADC(模数转换)⼯作模式单次转换模式In Single Conversion mode, the ADC does one conversion. This mode is started either by setting the ADON bit in the ADC_CR2 register (for a regular channel only) or by an external trigger (for a regular or injected channel), while the CONT bit is 0. Once the conversion of the selected channel is complete:If a regular channel was converted:– The converted data is stored in the 16-bit ADC_DR register– The EOC (End Of Conversion) flag is set– and an interrupt is generated if the EOCIE is set.If an injected channel was converted:– The converted data is stored in the 16-bit ADC_DRJ1 register– The JEOC (End Of Conversion Injected) flag is set– and an interrupt is generated if the JEOCIE bit is set.The ADC is then stopped.连续转换模式In continuous conversion mode, ADC starts another conversion as soon as it finishes one. This mode is started either by an external trigger or by setting the ADON bit in the ADC_CR2 register, while the CONT bit is 1. After each conversion:If a regular channel was converted:– The converted data is stored in the 16-bit ADC_DR register– The EOC (End Of Conversion) flag is set– An interrupt is generated if the EOCIE is set.If an injected channel was converted:– The converted data is stored in the 16-bit ADC_DRJ1 register– The JEOC (End Of Conversion Injected) flag is set– An interrupt is generated if the JEOCIE bit is set.扫描模式This mode is used to scan a group of analog channels. A single conversion is performed for each channel of the group. After each end of conversion, the next channel of the group is converted automatically. If the CONT bit is set, conversion does not stop at the last selected group channel but continues again from the first selected group channel.When using scan mode, DMA bit must be set and the direct memory access controller is used to transfer the converted data of regular group channels to SRAM after each update of the ADC_DR register. The injected channel converted data is always stored in theADC_JDRx registers.⾮连续模式This mode is enabled by setting the DISCEN bit in the ADC_CR1 register. It can be used to convert a short sequence of n conversions (n <=8) which is a part of the sequence of conversions selected in the ADC_SQRx registers. The value of n is specified by writing to the DISCNUM[2:0] bits in the ADC_CR1 register.When an external trigger occurs, it starts the next n conversions selected in the ADC_SQRx registers until all the conversions in the sequence are done. The total sequence length is defined by the L[3:0] bits in the ADC_SQR1 register.读取ADC结果的⼏种⽅式The Polling MethodIt’s the easiest way in code in order to perform an analog to digital conversion using the ADC on an analog input channel. However, it’s not an efficient way in all cases as it’s considered to be a blocking way of using the ADC. As in this way, we start the A/D conversion and wait for the ADC until it completes the conversion so the CPU can resume processing the main code.中断模式The interrupt method is an efficient way to do ADC conversion in a non-blocking manner, so the CPU can resume executing the main code routine until the ADC completes the conversion and fires an interrupt signal so the CPU can switch to the ISR context and save the conversion results for further processing.However, when you’re dealing with multiple channels in a circular mode or so, you’ll have periodic interrupts from the ADC that are too much for the CPU to handle. This will introduce jitter injection and interrupt latency and all sorts of timing issues to the system. This can be avoided by using DMA.DMA⽅式Lastly, the DMA method is the most efficient way of converting multiple ADC channels at very high rates and still transfers the results to the memory without CPU intervention which is so cool and time-saving technique.STM32F103C8T6的代码实现管脚与ADC的映射关系PA0:7 ADC1_IN0:7PB0 ADC1_IN8PB1 ADC1_IN9实现两个通道电压采集到DMA确定要采集的信号通道数量, 每个信号通道要保留的采样数, ⽐如下⾯的例⼦中是2个通道, 每个通道4个采样根据上⾯的数量得到ARRAYSIZE, 声明⽤于DMA的内存变量__IO uint16_t ADCConvertedValue[ARRAYSIZE]初始化时钟: ADC1, GPIOA, DMA1初始化GPIOA⽤于采集的两个pin初始化ADC1初始化DMA1代码#include <stdio.h>#include "timer.h"#include "usart.h"#define ARRAYSIZE 2*4__IO uint16_t ADCConvertedValue[ARRAYSIZE];void RCC_Configuration(void){/* ADCCLK = PCLK2/4 */RCC_ADCCLKConfig(RCC_PCLK2_Div4);/* Enable peripheral clocks ------------------------------------------------*//* Enable DMA1 clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* Enable ADC1 and GPIOC clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);}void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;/* Configure PA.00 (ADC Channel0) as analog input -------------------------*/GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOA, &GPIO_InitStructure);}int main(void){SystemInit();Systick_Init();USART_Configuration();/* System clocks configuration ---------------------------------------------*/RCC_Configuration();/* GPIO configuration ------------------------------------------------------*/GPIO_Configuration();/* ADC1 configuration ------------------------------------------------------*/ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//We will convert multiple channelsADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//right 12-bit data alignment in ADC data registerADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;// Set it to the number of channelsADC_InitStructure.ADC_NbrOfChannel = 2;ADC_Init(ADC1, &ADC_InitStructure);/* ADC1 regular channel0 configuration, rank decides the order in ADCConvertedValue, start from 1 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_41Cycles5);/* ADC1 regular channel1 configuration */ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_41Cycles5);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/* Enable ADC1 reset calibration register */ADC_ResetCalibration(ADC1);/* Check the end of ADC1 reset calibration register */while(ADC_GetResetCalibrationStatus(ADC1));/* Start ADC1 calibration */ADC_StartCalibration(ADC1);/* Check the end of ADC1 calibration */while(ADC_GetCalibrationStatus(ADC1));/* Start ADC1 Software Conversion */ADC_SoftwareStartConvCmd(ADC1, ENABLE);/* DMA1 channel1 configuration ----------------------------------------------*/DMA_InitTypeDef DMA_InitStructure;DMA_DeInit(DMA1_Channel1);// ADC1_DR_Address ((uint32_t)0x4001244C)DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(ADC1->DR);DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;/* Direction:DMA_DIR_PeripheralSRC:from peripheral,DMA_DIR_PeripheralDST:to peripheral*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;/* Specifies the buffer size, in data unit, of the specified Stream.The data unit is equal to the configuration set in DMA_PeripheralDataSizeor DMA_MemoryDataSize members depending in the transfer direction.Set it to the number of channels*/DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;// Specifies whether the memory address register should be incremented or notDMA_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;// Priority among DMA channelsDMA_InitStructure.DMA_Priority = DMA_Priority_High;// From Memory to MemoryDMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA1 channel1 */DMA_Cmd(DMA1_Channel1, ENABLE);while(1) {for (u8 i = 0; i < ARRAYSIZE; i++) {printf("%d ", *(ADCConvertedValue + i));}printf("\r\n");Systick_Delay_ms(500);}}void ADC1_IRQHandler(void){ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);ADC_SoftwareStartConvCmd(ADC1,ENABLE);}STM32F401CCU6的代码实现只有1个16通道ADC. One 12-bit analog-to-digital converter is embedded and shares up to 16 external channels, performing conversions in the single-shot or scan mode. In scan mode, automatic conversion is performed on a selected group of analog inputs. The ADC can be served by the DMA controller. An analog watchdog feature allows very precise monitoring of the converted voltage of one, some or all selected channels. An interrupt is generated when the converted voltage is outside the programmed thresholds.To synchronize A/D conversion and timers, the ADCs could be triggered by any of TIM1, TIM2, TIM3, TIM4 or TIM5 timer.管脚与ADC的映射关系PA0:7 ADC1_IN0:7PB0 ADC1_IN8PB1 ADC1_IN9PC0:5 ADC1_IN10:15因为F401CCU6的PC⼝只有PC13,PC14,PC15, 所以可以⽤的ADC只有ADC1_IN0 - IN9STM32F4的ADC1与DMA的映射根据, 这个系列的芯⽚中DMA1与DMA2各有8个Stream(Stream0 - Stream7), 分别对应着不同的外设, 其中ADC1对应的是DMA2的Stream0和Stream4, 在代码中必须使⽤这两个, 否则DMA不起作⽤实现两个通道电压采集到DMA的代码#include <stdio.h>#include "config.h"#include "led.h"#include "timer.h"#include "uart.h"#define ARRAYSIZE 2*4__IO uint16_t ADCConvertedValue[ARRAYSIZE];void RCC_Configuration(void){/* Enable ADCx, DMA and GPIO clocks ****************************************/RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE);}void GPIO_Configuration(void){/* Configure ADC1 Channel0,1 pin as analog input ******************************/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIOA, &GPIO_InitStructure);}int main(void){Systick_Init();USART1_Init();LED_Init();/* System clocks configuration ---------------------------------------------*/RCC_Configuration();/* GPIO configuration ------------------------------------------------------*/GPIO_Configuration();/* DMA2 Stream0 channel0 configuration **************************************/DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_Channel = DMA_Channel_0;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADCConvertedValue;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStructure.DMA_BufferSize = ARRAYSIZE;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_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init(DMA2_Stream0, &DMA_InitStructure);DMA_Cmd(DMA2_Stream0, ENABLE);/* ADC Common Init **********************************************************/ADC_CommonInitTypeDef ADC_CommonInitStructure;ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 预分频4分频, ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36MhzADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;// DMA使能 (DMA传输下要设置使能)ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //两个采样阶段之间的延迟x个时钟ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure);/* ADC1 Init ****************************************************************/ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;ADC_InitStructure.ADC_ScanConvMode = ENABLE;ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 2;ADC_Init(ADC1, &ADC_InitStructure);/* ADC1 regular channel0,1 configuration **************************************/ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_56Cycles);ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_56Cycles);/* Enable DMA request after last transfer (Single-ADC mode) */ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);ADC_SoftwareStartConv(ADC1);while(1) {LED_On();for (u8 i = 0; i < ARRAYSIZE; i++) {float a = (*(ADCConvertedValue + i) - 2048) * 512 /2048;printf("% 5d ", (int)a);}printf("\r\n");LED_Off();Systick_Delay_ms(200);}}参考这篇写得很详细可能有⽤的代码可能有⽤的代码 ContinuousConvMode可能有⽤的代码 ContinuousConvMode有⽤的代码 DMA, adc部分在main.c有⽤的代码 DMA, adc部分在main.c⽤stm32f103做的电容电感测试仪, 注⼊型, adc部分在main.cThis one is helpful这篇直接中断输出到串⼝STM32F2/F4/F7 DMA参考。

一文带你看懂Stm32定时器+ADC+DMA进行AD采样的实现

一文带你看懂Stm32定时器+ADC+DMA进行AD采样的实现

一文带你看懂Stm32定时器+ADC+DMA进行AD采样的实现此STM32单片机为STM32F103系列的STM32的ADC有DMA功能这都毋庸置疑,也是我们用的最多的!然而,如果我们要对一个信号(比如脉搏信号)进行定时采样(也就是隔一段时间,比如说2ms),有三种方法:1、使用定时器中断每隔一定时间进行ADC转换,这样每次都必须读ADC的数据寄存器,非常浪费时间!2、把ADC设置成连续转换模式,同时对应的DMA通道开启循环模式,这样ADC就一直在进行数据采集然后通过DMA把数据搬运至内存。

但是这样做的话还得加一个定时中断,用来定时读取内存中的数据!3、使用ADC的定时器触发ADC转换的功能,然后使用DMA进行数据的搬运!这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能,然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换完成中断,这样每次转换完成就会产生中断,我是采用第二种方法。

下面上代码:我这里使用的单通道//定时器初始化voidTIM2_ConfiguraTIon(void){TIM_TImeBaseInitTypeDefTIM_TimeBaseStructure;TIM_OCInitTypeDefTIM_OCInitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);TIM_TimeBaseStructure.TIM_Period=1999;//设置2ms一次TIM2比较的周期TIM_TimeBaseStructure.TIM_Prescaler=71;//系统主频72M,这里分频71,相当于1000K 的定时器2时钟TIM_TimeBaseStructure.TIM_ClockDivision=0x0;。

stm32 ADC多通道采样例程(HAL库)

stm32 ADC多通道采样例程(HAL库)

Stm32 基于HAL库ADC多通道采样例程1、用cubemx建立工程,cubemx 5.3.0版本,芯片型号:stm32f103zet6(1)开启外部高速时钟HSE,配置系统时钟为72M注意:ADC1时钟配置为9MHz(2)配置串口1,设置好波特率并开启串口中断2、启用ADC1 通道1,3,4,5,6注意要先设置好通道数量才能配置,各自ADC通道的参数。

Rank 是转换顺序,我们按1,2,3,4,5的顺序分别对应ADC1通道0,1,4,5,6。

多通道采样要开启扫描工作模式,在这里我们还有开启连续转换方式,连续转换是在ADC转换按照约定的转换顺序全部通道完成一次转换后,又自动启动下一次转换。

3、启用ADC转换DMA传输,多通道转换时要启用ADC的DMA传输,才能在相应的通道转换完成后,DMA自动去获取转换值。

中断方式没法在多通道采样时使用,因为在多通道扫描模式下,只有在最后一个通道转换结束时才会产生中断请求。

而ADC数据寄存器是共用的,这时候进入中断取值只能得到一个通道的数值。

4、到此,基础配置和ADC通道配置已经完成,接着我们设置工程名称和保存路径等就可以了,一般工程名和保存路径最好不要有中文,不然可能会出现一些意想不到的问题,在测试的过程中就遇到工程名或者保存路径中都用英文但是词组名称之间用空格隔开,在打开生成的工程文件后,向新建的分类文件夹中添加自己写的xxx.c文件,就导致keil软件卡死,不知道是keil软件还是cubemx的问题。

5、设置好工程名称和路径后就可以生成代码了,生成代码后我们选择打开工程。

接着我们开始编写代码(1)首先我们要修改main函数的一个错误,就是在初始化时要把MX_DMA_Init()函数放在MX_ADC1_Init()函数之前执行,cubemx生成代码时MX_DMA_Init()是在ADC初始化函数之后。

如果在后面则转换时打印输出的ADC值,大多数都为0,具体原因就不知道是怎么回事了,应该是cubemx这个版本还不太稳定。

stm32hal库获取adc多通道的值的函数

stm32hal库获取adc多通道的值的函数

stm32hal库获取adc多通道的值的函数一、前言在STM32开发中,ADC模块是一个常用的模块,可以用来获取外部模拟信号的值。

在某些应用场景下,需要同时获取多个通道的值。

本文将介绍如何使用STM32HAL库来获取ADC多通道的值。

二、函数介绍ADC_GetMultiChannelValue函数是本文要介绍的函数,它可以获取多个通道的ADC转换值。

该函数使用了DMA方式进行数据传输,可以大大提高数据传输效率。

三、函数原型以下是ADC_GetMultiChannelValue函数的原型:```void ADC_GetMultiChannelValue(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);```参数说明:- hadc:ADC句柄- pData:指向存储数据的缓冲区- Length:要转换的数据长度四、函数实现以下是ADC_GetMultiChannelValue函数的详细实现过程。

1. 开启DMA传输首先要开启DMA传输,在HAL_ADC_Start_DMA函数中设置DMA 句柄和缓冲区地址即可。

```HAL_ADC_Start_DMA(hadc, pData, Length);```2. 等待转换完成等待转换完成需要使用HAL_ADC_PollForConversion或者HAL_ADC_ConvCpltCallback回调函数。

这里我们使用回调函数来等待转换完成。

```void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {/* Conversion complete callback */}```3. 获取转换值在回调函数中,可以使用HAL_ADC_GetValue函数获取转换值。

由于我们要获取多个通道的值,所以需要在回调函数中进行多次转换。

```void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {static uint32_t index = 0;pData[index++] = HAL_ADC_GetValue(hadc);if (index == Length){/* All conversions are complete */}}```4. 关闭DMA传输最后需要关闭DMA传输,在转换完成后使用HAL_ADC_Stop_DMA 函数即可。

STM32—ADC多通道采集电压

STM32—ADC多通道采集电压

STM32—ADC多通道采集电压⽂章⽬录ADC详解前⾯的博客中详细介绍了STM32中ADC的相关信息,这篇博客是对ADC内容的⼀个总结提升,ADC的详细介绍:程序说明为了使这次代码阅读⽅便,博主没有在头⽂件中宏定义变量,都是直接采样库函数中的规定形参。

此次采⽤多通道采集电压,使⽤ADC1的通道10、11、12、13、14、15⼀共六个通道,采⽤DMA将转换结果传输⾄内存。

函数主体引脚配置引脚配置的时候,将所有引脚⼀次性配置好,过于简单,不作详细说明。

void ADC_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStruct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN ;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;GPIO_Init(GPIOC , &GPIO_InitStruct);}ADC和DMA配置此函数中主要配置了ADC的相关信息和DMA的信息。

uint16_t result[6]={0,0,0,0,0,0};void ADC_DMA_COnfig(void){ADC_InitTypeDef ADC_InitStructure;DMA_InitTypeDef DMA_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 复位DMA1的通道1 */DMA_DeInit(DMA1_Channel1);// 配置 DMA 初始化结构体// 外设基址为:ADC 数据寄存器地址DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( ADC1_BASE+0x4c);// 存储器地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)result;// 数据源来⾃外设DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;// 缓冲区⼤⼩,应该等于数据⽬的地的⼤⼩DMA_InitStructure.DMA_BufferSize = 6;// 外设寄存器只有⼀个,地址不⽤递增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;// 初始化DMADMA_Init(DMA1_Channel1, &DMA_InitStructure);// 使能 DMA 通道DMA_Cmd(DMA1_Channel1 , 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 = 6;// 初始化ADCADC_Init(ADC1, &ADC_InitStructure);// 配置ADC时钟为PCLK2的8分频,即9MHzRCC_ADCCLKConfig(RCC_PCLK2_Div8);// 配置ADC 通道的转换顺序和采样时间ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 5, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 6, ADC_SampleTime_55Cycles5);// 使能ADC DMA 请求ADC_DMACmd(ADC1, ENABLE);// 开启ADC ,并开始转换ADC_Cmd(ADC1, ENABLE);// 初始化ADC 校准寄存器ADC_ResetCalibration(ADC1);// 等待校准寄存器初始化完成while(ADC_GetResetCalibrationStatus(ADC1));// ADC开始校准ADC_StartCalibration(ADC1);// 等待校准完成while(ADC_GetCalibrationStatus(ADC1));// 由于没有采⽤外部触发,所以使⽤软件触发ADC转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);函数开头定义了ADC和DMA的结构体变量,并且打开了俩个外设的时钟(DMA挂载在AHB总线上)。

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

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

STM32ADC在DMA中断模式下多通道数据采集在DMA中断模式下进行多通道数据采集,需要进行以下步骤:1.初始化ADC模块:使用HAL库或者标准库,初始化ADC模块,设置采样时间、分辨率、触发源等参数。

同时,还需要配置ADC的多通道模式,选择需要采集的通道。

2.配置DMA:使用HAL库或者标准库,初始化DMA模块,设置DMA通道、数据传输方向、数据传输长度等参数。

3.设置中断回调函数:配置DMA传输完成后的中断回调函数,当DMA传输完成后会触发中断,在该中断中可以进行数据处理操作。

4.开始数据采集:启动ADC和DMA,开始进行数据采集。

下面是一个使用HAL库的示例代码,实现了三个通道的数据采集,每次采集10个数据点,采集完成后会触发中断进行数据处理:```c#include "stm32f4xx_hal.h"#define DATA_SIZE 10ADC_HandleTypeDef hadc1;DMA_HandleTypeDef hdma_adc1;uint16_t adc_data[DATA_SIZE * 3]; // 保存采集到的数据uint8_t current_channel = 0; // 当前采集的通道//ADCDMA中断回调函数void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) if (current_channel == 3)//数据采集完成,进行数据处理操作// 处理adc_data中已经采集到的数据// 重置current_channelcurrent_channel = 0;} else//继续采集下一个通道的数据current_channel++;HAL_ADC_Start_DMA(&hadc1, adc_data + DATA_SIZE * current_channel, DATA_SIZE);}int main(void)HAL_Init(;//初始化ADC模块__HAL_RCC_ADC1_CLK_ENABLE(;hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc1.Init.ExternalTrigConvEdge =ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.DMAContinuousRequests = ENABLE;hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc1.Init.NbrOfConversion = 3;hadc1.Init.ScanConvMode = ENABLE;HAL_ADC_Init(&hadc1);//配置ADC的通道顺序ADC_ChannelConfTypeDef sConfig;sConfig.Channel = ADC_CHANNEL_0;sConfig.Rank = 1;sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;HAL_ADC_ConfigChannel(&hadc1, &sConfig);sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = 2;HAL_ADC_ConfigChannel(&hadc1, &sConfig);sConfig.Channel = ADC_CHANNEL_2;sConfig.Rank = 3;HAL_ADC_ConfigChannel(&hadc1, &sConfig);//初始化DMA模块__HAL_RCC_DMA2_CLK_ENABLE(;hdma_adc1.Instance = DMA2_Stream0;hdma_adc1.Init.Channel = DMA_CHANNEL_0;hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_adc1.Init.Mode = DMA_CIRCULAR;hdma_adc1.Init.Priority = DMA_PRIORITY_LOW;HAL_DMA_Init(&hdma_adc1);//设置DMA中断回调函数HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);__HAL_DMA_ENABLE_IT(&hdma_adc1, DMA_IT_TC);//关联ADC和DMA__HAL_LINKDMA(&hadc1, DMA_Handle, hdma_adc1);//开始数据采集HAL_ADC_Start_DMA(&hadc1, adc_data, DATA_SIZE);while (1)//业务逻辑代码}//DMA中断处理函数void DMA2_Stream0_IRQHandler(void)HAL_DMA_IRQHandler(&hdma_adc1);```通过以上代码,就可以实现多通道的数据采集。

stm32 ADC多通道采样例程(HAL库)

stm32 ADC多通道采样例程(HAL库)

Stm32 基于HAL库ADC多通道采样例程1、用cubemx建立工程,cubemx 5.3.0版本,芯片型号:stm32f103zet6(1)开启外部高速时钟HSE,配置系统时钟为72M注意:ADC1时钟配置为9MHz(2)配置串口1,设置好波特率并开启串口中断2、启用ADC1 通道1,3,4,5,6注意要先设置好通道数量才能配置,各自ADC通道的参数。

Rank 是转换顺序,我们按1,2,3,4,5的顺序分别对应ADC1通道0,1,4,5,6。

多通道采样要开启扫描工作模式,在这里我们还有开启连续转换方式,连续转换是在ADC转换按照约定的转换顺序全部通道完成一次转换后,又自动启动下一次转换。

3、启用ADC转换DMA传输,多通道转换时要启用ADC的DMA传输,才能在相应的通道转换完成后,DMA自动去获取转换值。

中断方式没法在多通道采样时使用,因为在多通道扫描模式下,只有在最后一个通道转换结束时才会产生中断请求。

而ADC数据寄存器是共用的,这时候进入中断取值只能得到一个通道的数值。

4、到此,基础配置和ADC通道配置已经完成,接着我们设置工程名称和保存路径等就可以了,一般工程名和保存路径最好不要有中文,不然可能会出现一些意想不到的问题,在测试的过程中就遇到工程名或者保存路径中都用英文但是词组名称之间用空格隔开,在打开生成的工程文件后,向新建的分类文件夹中添加自己写的xxx.c文件,就导致keil软件卡死,不知道是keil软件还是cubemx的问题。

5、设置好工程名称和路径后就可以生成代码了,生成代码后我们选择打开工程。

接着我们开始编写代码(1)首先我们要修改main函数的一个错误,就是在初始化时要把MX_DMA_Init()函数放在MX_ADC1_Init()函数之前执行,cubemx生成代码时MX_DMA_Init()是在ADC初始化函数之后。

如果在后面则转换时打印输出的ADC值,大多数都为0,具体原因就不知道是怎么回事了,应该是cubemx这个版本还不太稳定。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

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

若有错误之处,希望读者指出,大家共同学习,一起进步!ADC.C文件vu16 AD_Value[N][M]; //[50][4]用来存放ADC转换结果,也是DMA的目标地址vu16 After_filter[M]; //用来存放求平均值之后的结果vu16 Vtemp_sensor[M]; //电压转换完成后的实际电压值//初始化ADC//这里我们仅以规则通道为例//我们默认将开启通道0~3void 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~3u16 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<N;count++){sum += AD_Value[count][i];}After_filter[i]=sum/N;sum=0;}for(i=0;i<4;i++){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,地址不变DisableDMA_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_CHxstm32f10x_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地址,内存地址,缓存大小)。

相关文档
最新文档