超详细的STM32讲解——AD单通道与多通道转换(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的优势。
stm32f2 adc dma 原理
一、STM32F2系列概述STM32F2系列是STMicroelectronics公司推出的一款高性能、低功耗的32位微控制器,广泛应用于工业控制、汽车电子、消费类电子等领域。
该系列微控制器集成了丰富的外设资源和丰富的接口,具有较高的运算性能和低功耗特性。
其中,ADC(模拟数值转换器)和DMA (直接内存访问)是STM32F2系列微控制器中的重要外设和功能模块,本文将重点介绍STM32F2系列中ADC和DMA的原理和应用。
二、ADC原理及工作流程1. ADC简介ADC,全称为Analog-to-Digital Converter,即模拟数值转换器,是一种将模拟信号转换为数字信号的器件。
在STM32F2系列微控制器中,ADC模块可以将外部模拟电压信号转换为数字化的数据,以便微控制器进行处理和分析。
2. ADC工作原理ADC模块通过取样保持电路对外部模拟信号进行采样,然后经过模数转换器(ADC Converter)将模拟信号转换为数字信号。
在STM32F2系列微控制器中,ADC模块使用的是SAR(Successive Approximation Register)型ADC,其工作原理是通过比较器、取样保持电路和逐次逼近寄存器等部件实现模拟信号的快速准确转换。
3. ADC工作流程(1)初始化ADC模块,设置转换参数和数据格式等;(2)配置ADC通道、采样周期和转换模式;(3)启动ADC转换,对外部模拟信号进行采样和转换;(4)获取转换结果,进行数据处理和分析。
三、DMA原理及应用1. DMA简介DMA,全称为Direct Memory Access,即直接内存访问,是一种数据传输方式,它可以在不需要CPU干预的情况下,实现内存之间或外设和内存之间的高速数据传输。
2. DMA工作原理DMA核心是DMA控制器,它可以控制外设和内存之间的数据传输。
在STM32F2系列微控制器中,DMA控制器具有多通道、多优先级和循环缓冲等特性,可以实现灵活高效的数据传输。
STM32双ADC多路通道采样DMA传输单通道模拟看门狗设置
STM32双ADC多路通道采样DMA传输单通道模拟看门狗设置vu32 ADCConvertedValue[TimsOfSample][NbrOfChannel];void DMA_Config(){DMA_InitTypeDef DMA_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);NVIC_Config( DMA1_Channel1_IRQn,0,1);DMA_DeInit(DMA1_Channel1);DMA_InitStructure.DMA_BufferSize=DMABuffSize;//⼀次中断传输数据的个数,数据单位与外设或内存单位⼤⼩相同DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设作为数据传输来源DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//内存到内存传输关闭DMA_InitStructure.DMA_MemoryBaseAddr=(u32)ADCConvertedValue;//存储器地址,实际就是⼀个内部的SRAM变量DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;//内存数据⼤⼩与外设数据⼤⼩相同,为32位DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内存地址递增DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//循环模式⽤于处理循环缓冲区和连续的数据传输(如ADC的扫描模式)。
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&ADC1->DR;//外设基地址:ADC数据寄存器地址DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;//外设数据⼤⼩为32位DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址固定DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先级⾼,只使⽤⼀个DMA时,优先级设置不影响DMA_Init(DMA1_Channel1,&DMA_InitStructure);//DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);DMA_Cmd(DMA1_Channel1,ENABLE);}void ADC_DualModeConfig(){ADC_InitTypeDef ADC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2,ENABLE);RCC_ADCCLKConfig(RCC_PCLK2_Div6);//ADC采样时钟分频,确保ADC的时钟不超过14MHzGPIO_Config( GPIOA,RCC_APB2Periph_GPIOA,GPIO_Mode_AIN,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);NVIC_Config( ADC1_2_IRQn,0,0);DMA_Config();ADC_DeInit(ADC1);ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据对齐⽅式右对齐ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;//同步规则模式ADC_InitStructure.ADC_NbrOfChannel=NbrOfChannel;//规则序列的长度ADC_InitStructure.ADC_ScanConvMode=ENABLE;//模数转换⼯作在扫描模式ADC_Init(ADC1,&ADC_InitStructure);ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_28Cycles5);ADC_RegularChannelConfig(ADC1,ADC_Channel_7,2,ADC_SampleTime_28Cycles5);ADC_RegularChannelConfig(ADC1,ADC_Channel_1,3,ADC_SampleTime_28Cycles5);ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;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 = NbrOfChannel;ADC_Init(ADC2, &ADC_InitStructure);ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 1, ADC_SampleTime_28Cycles5); ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 2, ADC_SampleTime_28Cycles5); ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 3, ADC_SampleTime_28Cycles5); ADC_ExternalTrigConvCmd(ADC2, ENABLE);ADC_AnalogWatchdogThresholdsConfig(ADC2,0xBA3, 0x000);ADC_AnalogWatchdogSingleChannelConfig(ADC2, ADC_Channel_6);ADC_AnalogWatchdogCmd(ADC2, ADC_AnalogWatchdog_SingleRegEnable);ADC_ITConfig(ADC2, ADC_IT_AWD, ENABLE);ADC_DMACmd(ADC1,ENABLE);ADC_Cmd(ADC1,ENABLE);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));ADC_SoftwareStartConvCmd(ADC1, ENABLE);while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));DMA_ClearFlag(DMA1_FLAG_TC1);}。
介绍如何通过意法的STM32 MCU实现用DMA完成多通道的AD采样功能
介绍如何通过意法的STM32 MCU实现用DMA完成多通道的AD采样功
能
在嵌入式产品中有时候需要实现对外部的模拟量进行采样处理和记录,而这就需要使用到ADC功能,将外部的模拟量转换成数字量。
而在复杂的嵌入式产品中,往往需要使用多路AD采样,例如在智能家居产品,电池电量检测,热敏温度传感器,烟雾传感器,气敏传感器等都是可以使用ADC来实现采样的。
在本文章,将会介绍如何通过意法的STM32 MCU实现用DMA完成多通道的AD采样功能。
什么叫ADC
ADC即模拟数字转换器(英语:Analog-to-digital converter)是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。
一个模拟数字转换器可以提供信号用于测量。
与之相对的设备成为数字模拟转换器。
影响AD采样的因素有哪些
分辨率
分辨率指的是ADC的位数,例如STM32F103MCU的内部ADC的分辨率是12位,那么它所采样的结果就在0-4096之间。
最小采样单位值
根据基准电压和参考电压的不同,其值也是不同的,例如在基准电压为3.3V,参考电压最低为0V,最高为3.3V,采样分辨率位12位的嵌入式系统中,则ADC的最小量程单位则为:3.3V/4096 = 0.00080566。
量程
在无负电压的嵌入式系统中,量程范围0-基准电压。
电源噪音
电源质量直接影响了AD采样的正确性和稳定性,如果条件满足,建议使用线性稳压源,若是使用开关电源的话,需要在VDDA模拟电源输入和参考电压输入接一个线性稳压管,同时要注意减小PCB板布局走线中结电容对采样电路的影响。
STM32之ADC单次转换模式和连续转换模式
STM32之ADC单次转换模式和连续转换模式⼀、背景在STM32中的AD的单通道采样中可以设置成单次转换模式和连续转换模式,如何理解这两个转换模式的区别,通过程序⼜是怎样实现的?⼆、正⽂⾸先理解单次转换模式,即ADC进⾏单次转换(单样本)的单通道X(参见图1。
)并停⽌转换完成后。
连续转换模式,即ADC在常规信道转换中连续地、⽆限地转换单信道,如下图所⽰。
在STM32的ADC库函数中主要由 ADC_InitStructure.ADC_ScanConvMode = DISABLE; 来决定AD采集⼯作在单次转换模式(DISABLE)或者是连续转换模式(ENABLE)。
⽽我在程序中是设置单次转换模式,按照单次转换模式的理解应该只转换⼀次,但运⾏主程序后却⼀直可以采集出数据。
//设置指定ADC的规则组通道,⼀个序列,采样时间ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束return ADC_GetConversionValue(ADC1); //返回最近⼀次ADC1规则组的转换结果经过看数据⼿册ADC的寄存器如下所⽰,发现主程序每次循环后AD采集都会进⾏开始转换通道的开启,即这个函数ADC_SoftwareStartConvCmd(ADC1, ENABLE); 所以是采集结束后循环⼀次之后⼜开始采集。
当我把这个函数ADC_SoftwareStartConvCmd(ADC1, ENABLE); 放到ADC的初始化中就到发现只采集⼀次。
另外,当我把这个函数ADC_SoftwareStartConvCmd(ADC1, ENABLE); 放到ADC的初始化中,并且把AD采集⼯作模式更改为连续转换模式,即是ADC_InitStructure.ADC_ContinuousConvMode =ENABLE;可在主程序中看到AD⼀直是连续采集的。
STM32-ADC多通道转换实例
STM32-ADC多通道转换实例以下是为大家整理的sTm32-ADc多通道转换实例的相关范文,本文关键词为sTm32,ADc,通道,转换,实例,描述,ADc,连续,采,您可以从右上方搜索框检索更多相关文章,如果您觉得有用,请继续关注我们并推荐给您的好友,您可以在教育文库中查看更多范文。
描述:用ADc连续采集11路模拟信号,并由DmA传输到内存。
ADc配置为扫描并且连续转换模式,ADc的时钟配置为12mhZ。
在每次转换结束后,由DmA循环将转换的数据传输到内存中。
ADc可以连续采集n次求平均值。
最后通过串口传输出最后转换的结果。
程序如下:#include\//这个头文件包括sTm32F10x所有外围寄存器、位、内存映射的定义#include\//头文件(包括串口、按键、LeD的函数声明)#include\#include\#include#definen50//每通道采50次#definem12//为12个通道vu16AD_Value[n][m];//用来存放ADc转换结果,也是DmA的目标地址vu16After_filter[m];//用来存放求平均值之后的结果inti;/*gpIo管脚的配置选用ADc的通道01289101112131415,分别对应的管脚为pA0pA1pA2pb0pb1pc0pc1pc2pc3pc4pc5串口使用usART1其中Tx为pA9,Rx为pA10*/voidgpIo_configuration(void){gpIo_InitTypeDefgpIo_Initstructure;/*configureusART1Tx(pA.09)asalternatefunctionpush-pull*/gpIo_Initstru cture.gpIo_pin=gpIo_pin_9;gpIo_Initstructure.gpIo_mode=gpIo_mode_AF_pp;//因为usART1管脚是以复用的形式接到gpIo口上的,所以使用复用推挽式输出gpIo_Initstructure.gpIo_speed=gpIo_speed_50mhz;gpIo_Init(gpIoA,/*configureusART1Rx(pA.10)asinputfloating*/gpIo_Initstructure.gpIo_pin=gpIo_pin_10;gpIo_Initstructure.gpIo_mode=gpIo_mode_In_FLoATIng;gpIo_Init(gpIoA, //pA0/1/2作为模拟通道输入引脚gpIo_Initstructure.gpIo_pin=gpIo_pin_0|gpIo_pin_1|gpIo_pin_2|gpIo_p in_3;gpIo_Initstructure.gpIo_mode=gpIo_mode_AIn;//模拟输入引脚gpIo_Init(gpIoA,//pb0/1作为模拟通道输入引脚gpIo_Initstructure.gpIo_pin=gpIo_pin_0|gpIo_pin_1;gpIo_Initstructure.g pIo_mode=gpIo_mode_AIn;//模拟输入引脚gpIo_Init(gpIob,//pc0/1/2/3/4/5作为模拟通道输入引脚gpIo_Initstructure.gpIo_pin=gpIo_pin_0|gpIo_pin_1|gpIo_pin_2|gpIo_p in_3|gpIo_pin_4|gpIo_pin_5;gpIo_Initstructure.gpIo_mode=gpIo_mode _AIn;//模拟输入引脚gpIo_Init(gpIoc,}}/*配置系统时钟,使能各外设时钟*/voidRcc_configuration(void){errorstatushsestartupstatus;Rcc_DeInit();//Rcc系统复位Rcc_hseconfig(Rcc_hse_on);//开启hse hsestartupstatus=Rcc_waitForhsestartup();//等待hse准备好if(hsestartupstatus==success){FLAsh_prefetchbuffercmd(FLAsh_prefetchbuffer_enable);//enableprefetchbufferFLAsh_setLatency(FLAsh_Latency_2);//set2LatencycyclesRcc_hcLKconfig( Rcc_sYscLK_Div1);//Ahbclock=sYscLKRcc_pcLK2config(Rcc_hcLK_Div1);// Apb2clock=hcLKRcc_pcLK1config(Rcc_hcLK_Div2);//Apb1clock=hcLK/2Rc c_pLLconfig(Rcc_pLLsource_hse_Div1,Rcc_pLLmul_6);//pLLcLK=12mhz*6 =72mhzRcc_pLLcmd(enAbLe);//enablepLLwhile(Rcc_getFlagstatus(Rcc_FLAg_pLLRDY)==ReseT);//waittillpLLisready Rcc_sYscLKconfig(Rcc_sYscLKsource_pLLcLK);//selectpLLassystemclocksourcewhile(Rcc_getsYscLKsource()!=0x08);//waittillpLLisusedassystemclocksou rce/*使能各个外设时钟*/Rcc_Apb2periphclockcmd(Rcc_Apb2periph_gpIoA|Rcc_Apb2periph_gpI ob|Rcc_Apb2periph_gpIoc|Rcc_Apb2periph_ADc1|Rcc_Apb2periph_AFIo| Rcc_Apb2periph_usART1,enAbLe);//使能ADc1通道时钟,各个管脚时钟/*configureADccLKsuchasADccLK=pcLK2/6*/Rcc_ADccLKconfig(Rcc_pcLK2_Div6);//72m/6=12,ADc最大时间不能超过14mRcc_Ahbperiphclockcmd(Rcc_Ahbperiph_DmA1,enAbLe);//使能DmA传输}}/*配置ADc1*/voidADc1_configuration(void){ADc_InitTypeDefADc_Initstructure;ADc_DeInit(ADc1);//将外设ADc1的全部寄存器重设为缺省值/*ADc1configuration------------------------------------------------------*/ADc_Initstructure.ADc_mode=ADc_mode_Independent;//ADc工作模式:ADc1和ADc2工作在独立模式式ADc_Initstructure.ADc_continuousconvmode=enAbLe;=//模数转换工作在连续转换模式ADc_Initstructure.ADc_externalTrigconv//外部触发转换关闭齐ADc_Initstructure.ADc_nbrofchannel=m;//顺序进行规则转换的ADc通道的数目ADc_Initstructure.ADc_scanconvmode=enAbLe;//模数转换工作在扫描模ADc_externalTrigconv_none;ADc_Initstructure.ADc_DataAlign=ADc_DataAlign_Right;//ADc数据右对ADc_Init(ADc1,//根据ADc_Initstruct中指定的参数初始化外设ADcx的寄存器/*ADc1regularchannel11configuration*///设置指定ADc的规则组通道,设置它们的转化顺序和采样时间//ADc1,ADc通道x,规则采样顺序值为y,采样时间为239.5周期ADc_Regularchannelconfig(ADc1,ADc_channel_0,1,ADc_sampleTime_23 9cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_1,2,ADc_sampleTime_23 9cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_2,3,ADc_sampl eTime_239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_3,4,A Dc_sampleTime_239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_8,5,ADc_sampleTime_23 9cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_9,6,ADc_sampl eTime_239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_10,7, ADc_sampleTime_239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_11,8,ADc_sampleTime_239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_12,9,ADc_sampleTime_2 39cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_13,10,ADc_sampleTime_ 239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_14,11,ADc_sampleTime_ 239cycles5);ADc_Regularchannelconfig(ADc1,ADc_channel_15,12,ADc_sampleTime_ 239cycles5);//开启ADc的DmA支持(要实现DmA功能,还需独立配置DmA 通道等参数)ADc_DmAcmd(ADc1,enAbLe);/*enableADc1*/ADc_cmd(ADc1,enAbLe);//使能指定的ADc1/*enableADc1resetcalibarationregister*/ADc_Resetcalibration(ADc1);//复位指定的ADc1的校准寄存器/*checktheendofADc1resetcalibrationregister*/while(ADc_getResetcalibrationstatus(ADc1));//获取ADc1复位校准寄存器的状态,设置状态则等待/*startADc1calibaration*/ADc_startcalibration(ADc1);//开始指定ADc1的校准状态/*checktheendofADc1calibration*/while(ADc_getcalibrationstatus(ADc1));//获取指定ADc1的校准程序,设置状态则等待}/*配置DmA*/voidDmA_configuration(void){/*ADc1DmA1channelconfig*/DmA_InitTypeDefDmA_Initstructure;DmA_DeInit(DmA1_channel1);//将DmA的通道1寄存器重设为缺省值DmA_Initstructure.DmA_peripheralbaseAddr=(u32)//DmA外设ADc基地址DmA_Initstructure.DmA_memorybaseAddr=(u32)//DmA内存DmA_Initstructure.DmA_DIR=DmA_DIR_peripheralsRc;//内存作为数据传DmA_Initstructure.DmA_buffersize=n*m;//DmA通道的DmA缓存的大小DmA_Initstructure.DmA_peripheralInc=DmA_peripheralInc_Disable;//外设DmA_Initstructure.DmA_memoryInc=DmA_memoryInc_enable;//内存地址基地址输的目的地地址寄存器不变寄存器递增DmA_Initstructure.DmA_peripheralDatasize=DmA_peripheralDatasize_h alfword;//数据宽度为16位DmA_Initstructure.DmA_memoryDatasize=DmA_memoryDatasize_halfw ord;//数据宽度为16位式DmA_Initstructure.DmA_priority=DmA_priority_high;//DmA通道x 拥有高DmA_Initstructure.DmA_m2m=DmA_m2m_Disable;//DmA通道x没有设DmA_Init(DmA1_channel1,//根据DmA_Initstruct中优先级置为内存到内存传输指定的参数初始化DmA的通道DmA_Initstructure.DmA_mode=DmA_mode_circular;//工作在循环缓存模以下是为大家整理的sTm32-ADc多通道转换实例(2)的相关范文,本文关键词为sTm32,ADc,通道,转换,实例,描述,ADc,连续,采,您可以从右上方搜索框检索更多相关文章,如果您觉得有用,请继续关注我们并推荐给您的好友,您可以在教育文库中查看更多范文。
STM32 AD DMA
{
//先初始化IO口
RCC->APB2ENR|=1<<2; //使能PORTA口时钟
RCC->APB2ENR|=1<<4; //使能PORTC口时钟
GPIOA->CRL&=0XFFFF0000; //PA0 1 2 3 anolog输入
ADC1->CR2&=~(1<<11); //右对齐
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1|=5<<20; //6个转换在规则序列
ADC1->SQR3 = 0X00000000;
ADC1->SQR3|= 0X1EE18820;
ADC1->SMPR1|=7<<12; //通道14 239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2|=7<<9; //通道3 239.5周期,提高采样时间可以提高精确度
ADC1->SMPR2|=7<<6; //通道2 239.5周期,提高采样时间可以提高精确度
RCC->CFGR&=~(3<<14); //分频因子清零
//SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
//否则将导致ADC准确度下降!
RCC->CFGR|=2<<14;
ADC1->CR1&=0XF0FFFF; //工作模式清零
DMA_CHx->CCR|=0<<14; //非存储器到存储器模式
stm32相关笔记——ADC部分
stm32相关笔记——ADC部分我们在学习⼀门技术的时候,应该对它的理论部分有所了解,然后才能在实践中进⼀步加深理解,进⽽掌握。
对于stm32来说,我认为学习的时候应该先仔细阅读相关的参考⼿册,然后再动⼿实践,这样才能理解得更加透彻,掌握得更加牢固!今天记录⼀下我学习stm32的ADC部分的了解。
1.介绍⼩结:stm32的ADC有18个通道(16个外部通道+2个内部通道),有单次、连续、扫描和间断四种模式,ADC的结果可以左对齐和右对齐的⽅式存储在16位的数据寄存器中(⼀般我们都是使⽤右对齐的⽅式)2、特征3、框图框图应该是最重要的部分了,理解了框图,对这个外设的理解就⽐较透彻了。
①模拟⾄数字转换器中有两个通道,⼀个是注⼊通道,⼀个是规则通道,对应的转换结果也是存储到注⼊通道数据寄存器和规则通道数据寄存器中(都是16位的);②注⼊通道数据寄存器有4个,规则通道数据寄存器只有1个,规则通道最多可以转化16个通道的数据,⽽结果都是存储在⼀个规则通道数据寄存器中,为了避免数据丢失,可以采⽤DMA搬运数据,提⾼效率。
③触发注⼊通道开始转化的外部触发信号有8种,如图所⽰,其中TIM8_CH4及其重映射只存在于⼤容量的产品中。
④类似于注⼊通道,触发规则通道的外部触发信号也有8种,如图所⽰,其中TIM8_TRGO及其重映射也只存在于⼤容量产品中。
⑤以上的两点只针对ADC1和ADC2,ADC3的触发信号有所不同,如图所⽰:⑥转换的过程如图,ADCx_IN0~ADCx_IN15共16个外部通道,通过GPIO端⼝将模拟量传达到模拟⾄数字转化器中的注⼊通道或者规则通道,另外还有两个内部通道温度传感器和V REFINT,同样也可以将模拟量传送到模拟⾄数字转化器中的注⼊通道或者规则通道,注⼊通道最多可以转换4个通道的模拟量,转换结果存储到注⼊通道数据寄存器中,转换完成后会产⽣JEOC标志位,规则通道最多可以转换16个通道,转换结果存储到规则通道数据寄存器中,转换完成后会产⽣EOC标志位。
STM32超详细的讲解——AD单通道与多通道转换(DMA)
第三章AD转换本章的内容分两部分,第一是AD的单通道转换,第二是AD的多通道转换。
首先先将单通道转换。
STM32中自带的AD最大的转换频率是14MHZ,共有16个转换通道,每个转ADC123_IN10表明PC0管脚可以作为AD1,AD2,AD3的第10通道。
下面我们将PC0配置成AD1的通道10为例进行讲解。
3.1首先我们应将PC0设置成模拟输入:#include "adc.h"/*为何定义ADC1_DR_Address 为((u32)0x40012400+0x4c),因为存放AD转换结果的寄存器的地址就是0x4001244c*/#define ADC1_DR_Address ((u32)0x40012400+0x4c)/*定义变量ADC_ConvertedValue,放AD1通道10转换的数据*/__IO uint16_t ADC_ConvertedValue;static void ADC1_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable ADC1 and GPIOC clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 |RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOC, &GPIO_InitStructure);}3.2设置完端口后下一步当然是对AD进行初始化:这里需要补充一个知识点DMA,DMA就相当与CPU的一个秘书,他的作用就是帮CPU减轻负担的。
说的再具体点就是帮CPU来转移数据的。
我们都知道,AD每次转换结束后会将转换的结果放到一个固定的寄存器里,以往我们如果想将该寄存器中的值赋给某一变量时会用到赋值语句,如果不用DMA,则赋值语句便要CPU来完成,CPU本来就要忙着处理其他事情,现在还要来解决赋值语句这么简单的问题,肯到会蛋疼。
野火STM32ADC(DMA模式)实验详细分析
69.* 输出 :无
70.* 调用 :内部调用
71.*/
72.static void ADC1_Mode_Config(void)
73.{
74.ADC_InitTypeDef ADC_InitStructure; //定义 ADC 结构体
75.DMA_InitTypeDef DMA_InitStructure; //定义 DMA 结构体
volatile作为指令关键字确保本条指令不会因编译器的优化而省略且要求每次直接读值
野火STM32ADC(DMA模式)实验详细分析
发现ADC(DMA模式)实验 啊,DMA 那里地方,讲解不是太详细。按照野火教程上,USART 的DMA 方式实验,没有讲。 所以还有些模糊,今天对照野火的ADC 程序,然后对照库函数,做了个详细的备注.这里只注释adc.c 函数的内容。 新手上路,喜欢搞得详细一些,分享给 和我一样的新手。 哈哈。。。
102.ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //开启连续转换模式,即不停地进行ADC转换
103.ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不使用外部触发启动
127.
128./* 开启 ADC校准 */
129.ADC_StartCalibration(ADC1);
130./* 等待校准完成*/
131.while(ADC_GetCalibrationStatus(ADC1));
132.
133./* 由于没有采用外部触发,所以使用软件触发ADC转换 */
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;}科教兴国。
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和中断模式只有这样配置可以正确进⾏多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组⼀个通道)。
一文带你看懂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配置详解
STM32单片机的ADC配置详解一、ADC定义将模拟量转换为数字量的过程称为模式(A/D)转换,完成这一转换的工具就是模数转换器(简称ADC),用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。
例如:把芯片的引脚上的电压读出来,把芯片集成的上的温度传感器的温度读出来!二、ADC要点1-独立模式-单通道-中断读取①、初始化ADC用到的GPIO;②、设置ADC的工作参数并初始化;③、配置ADC时钟;④、设置ADC转换通道顺序及采样时间;⑤、配置使能ADC转换完成中断,在中断内读取转换完的数据;⑥、使能ADC;⑦使能软件触发ADC转换。
三、ADC内容1)ADC数量:STM32有3个ADC,每个ADC最多有16个外部通道,ADC1和ADC2都有16个外部通道,而ADC3随CPU引脚的不同通道数也不同,一般都有8个外部通道。
2)ADC精度:ADC为12位,即模拟电压经过ADC转换后是一个12位的数字量;一般情况下ADC的输入电压范围是:0~3.3V,因此最小精度为:3.3/2^12,当数字量为X时,则有模拟量Y = (3.3 / 2^12)*X。
3)电压输入范围:ADC 输入范围为:VREF- ≤VIN ≤VREF+。
由VREF- 、VREF+ 、VDDA 、VSSA 、这四个外部引脚决定。
一般把VSSA 和VREF- 接地,把VREF+ 和VDDA 接3V3,得到ADC的输入电压范围为:0~3.3V。
4)输入通道:ADC的信号输入就是通过通道来实现的,信号通过通道输入到单片机中,单片机经过转换后,将模拟信号输出为数字信号;STM32F103的ADC多达18个通道,在F103ZET6中ADC1的通道16连接到了芯片内部的温度传感器,Vrefint (内部参照电压)连接到了通道17,ADC2 的模拟通道16 和17 连接到了内部的VSS(地)。
外部的16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4 路。
stm32CubeMx实现单通道ADCDMA采集
stm32CubeMx实现单通道ADCDMA采集今天要做的是ADC单通道DMA采集实验MCU : STM32F429开发⼯具:STM32CubeMx 版本号 5.0.0实验⽬的:实现ADC1 13通道 DMA采集⼀:简介 ⾸先,我们来看⼀下STM32F4XX参考⼿册⾥关于该芯⽚的ADC功能介绍⼆:STM32CubeMx 配置配置RCC配置时钟,硬件使⽤了25MHz⽆源晶振配置ADC数据对齐⽅式为右对齐使能连续转换模式,DMA连续请求设置采样次数为 3个周期配置 DMAMode设置为Circular模式,数据宽度设置为Half Word 2个字节配置Project Manager设置好之后,点击GENERATE CODE ⽣成代码定义变量__IO uint16_t ADC_ConvertedValue[20];__IO float ADC_Volt;启动DMA数据传输HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_ConvertedValue[0], 20);读取ADC数据unsigned int i = 0, ADC_Value = 0;for(i = 0; i < 20; ++i){ ADC_Value += ADC_ConvertedValue[i];}ADC_Value = ADC_Value / 20;printf("ADC Value %d\r\n",ADC_Value);printf("vol %f\r\n", ADC_Value * 3.3 / 4096);三:实验结果串⼝输出结果四:实验中遇到的问题 1最后⼀个参数⼀开始的时候写1,程序就出现了阻塞的现象。
我分析可能是因为DMA选择的是Circular模式,会⼀直产⽣中断,从⽽使得CPU都被中断抢占了,因此将数据传输长度改为了20,每次对20个数据进⾏求均值计算,然后测试没有问题。
STM32中AD转换概念解释与操作方法
STM32中AD转换概念解释与操作方法STM32AD转换AD转换模式主要有单次,多次,间断模式。
单通道单次·、连续转换:单次转换模式只转换一次,无论规则组还是注入组里所选择的通道转换完成,ADC置位EOC或JEOC后,如果使能了相应的中断,ADC就停止。
软件、外部事件再触发,ADC才进行下一次转换。
而连续模式则不需要软件、外部事件的触发自动进行下次转换。
因此单通道的单次、连续转换模式主要针对某单一输入通道进行转换。
应用举例:ADC输入通道2输入,通道采集时间71.5clk软件触发,触发间隔0.5ms,产生中断。
多通道的单次、连续转换:上面谈到某单一通道可进行单次、连续转换,如果规则组或者注入组里的转换序列长度大于1,ADC又是如何进行转换的呢?ADC提供了通道扫描功能。
当使能了该功能后,同一组上一通道转换结束后,将自动启动同组的下一通道进行转换。
单次转换模式中,同一组的最后一通道转换结束后,ADC将停止,直到下次触发;连续转换模式中,ADC将从该组的第一转换序列开始,周而复始。
因此该方式下,如果通道配置成规则组,建议采用DMA方式,让CPU 自动在每次数据转换结束后,通知DMA进行数据拷贝,减少软件的复杂度。
应用举例:ADC输入通道0、2、3、4,按照0、2、3、4进行转换,采样间隔71.5clk,采用DMA传输方式,单通道采样次数10次。
间断模式主要是对多通道转换序列组合的补充。
间断长度为n(n < 8),数值n由ADC_CR1寄存器的DISCNUM[2:0]设置。
它由外部事件触发转换。
每次触发N个通道被转换。
例如某规则通道序列为0、2、3、5、7、8、9,其中n为3,,那么转换顺序如下:第一次触发:通道0、2、3被转换;第二次触发:通道5、7、8被转换;第三次触发:通道9被转换;第四次触发:0、2、3被转换。
stm32的ADC之规则组和注入组STM32加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换。
(完整版)STM32学习之:DMA详解.doc
STM32 学习之: DMA 详解JawSoW个人分类:STM32DMA部分我用到的相,当然,可能是新西,我用不到它的复功能吧。
下面用答的形式表达我的思路。
DMA有什么用?直接存器存取用来提供在外和存器之或者存器和存器之的高速数据。
无 CPU的干,通 DMA数据可以快速地移。
就省了 CPU的源来做其他操作。
有多少个DMA源?有两个 DMA控制器, DMA1有 7 个通道, DMA2有 5 个通道。
数据从什么地方送到什么地方?外到 SRAM(I2C/UART 等取数据并送入SRAM);SRAM的两个区域之;外到外(ADC取数据后送到TIM1 控制其生不同的PWM占空比);SRAM到外( SRAM中先保存的数据送入DAC生各种波形);⋯⋯有一些目前搞不清楚的。
DMA可以多少数据?的 DMA的概念是用于大批量数据的,但是我理解,在STM32中,它的概念被展了,也更多的候快速是其用的重点。
数据可以从1~ 65535 个。
直接存器存取( Direct Memory Access ,DMA)是算机科学中的一种内存技。
它允某些内部的硬体子系(外),可以独立地直接写系存器,而不需道 CPU。
在同等程度的 CPU担下, DMA是一种快速的数据送方式。
它允不同速度的硬件装置来沟通,而不需要依于 CPU的大量中断求。
【摘自 Wikipedia 】在越来越多的片机采用DMA技,提供外和存器之或者存器之的高速数据。
当CPU 初始化个作,作本身是由DMA 控制器来行和完成。
STM32就有一个DMA控制器,它有7 个通道,每个通道专门用来管理一个或多个外设对存储器访问的请求,还有一个仲裁器来协调各个DMA请求的优先权。
DMA 控制器和Cortex-M3 核共享系统数据总线执行直接存储器数据传输。
当CPU和DMA同时访问相同的目标(RAM 或外设总线仲裁器执行循环调度,以保证) 时, DMA请求可能会停止CPU 访问系统总线达若干个周期,CPU 至少可以得到一半的系统总线( 存储器或外设) 带宽。
STM32 ADC_DMA
STM32 ADC多通道转换描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。
ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。
在每次转换结束后,由DMA循环将转换的数据传输到内存中。
ADC可以连续采集N次求平均值。
最后通过串口传输出最后转换的结果。
程序如下:#i nclude "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义#i nclude "eval.h" //头文件(包括串口、按键、LED的函数声明)#i nclude "SysTickDelay.h"#i nclude "UART_INTERFACE.h"#i nclude <stdio.h>#define N 50 //每通道采50次#define M 12 //为12个通道vu16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址vu16 After_filter[M]; //用来存放求平均值之后的结果int i;void GPIO_Configuration(void){GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //因为USART1管脚是以复用的形式接到GPIO口上的,所以使用复用推挽式输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);//PA0/1/2 作为模拟通道输入引脚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);//PB0/1 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOB, &GPIO_InitStructure);//PC0/1/2/3/4/5 作为模拟通道输入引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚GPIO_Init(GPIOC, &GPIO_InitStructure);}}void RCC_Configuration(void){ErrorStatus HSEStartUpStatus;RCC_DeInit(); //RCC 系统复位RCC_HSEConfig(RCC_HSE_ON); //开启HSEHSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE准备好if(HSEStartUpStatus == SUCCESS){FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch BufferFLASH_SetLatency(FLASH_Latency_2); //Set 2 Latency cyclesRCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock = SYSCLKRCC_PCLK2Config(RCC_HCLK_Div1); //APB2 clock = HCLKRCC_PCLK1Config(RCC_HCLK_Div2); //APB1 clock = HCLK/2RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHzRCC_PLLCmd(ENABLE); //Enable PLLwhile(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLL is readyRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source while(RCC_GetSYSCLKSource() != 0x08); //Wait till PLL is used as system clock sourceRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE ); //使能ADC1通道时钟,各个管脚时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14MRCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输}}void ADC1_Configuration(void){ADC_InitTypeDef ADC_InitStructure;ADC_DeInit(ADC1); //将外设ADC1 的全部寄存器重设为缺省值ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式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数据右对齐ADC_InitStructure.ADC_NbrOfChannel = M; //顺序进行规则转换的ADC通道的数目ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间//ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 6, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 7, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 8, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 11, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 12, ADC_SampleTime_239Cycles5 );// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)ADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1ADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待}void DMA_Configuration(void){DMA_InitTypeDef DMA_InitStructure;DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_V alue; //DMA内存基地址DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地DMA_InitStructure.DMA_BufferSize = N*M; //DMA通道的DMA缓存的大小DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增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_InitStruct中指定的参数初始化DMA的通道}//配置所有外设void Init_All_Periph(void){RCC_Configuration();GPIO_Configuration();ADC1_Configuration();DMA_Configuration();//USART1_Configuration();USART_Configuration(9600);}u16 GetVolt(u16 advalue){return (u16)(advalue * 330 / 4096); //求的结果扩大了100倍,方便下面求出小数}void filter(void){int sum = 0;u8 count;for(i=0;i<12;i++){for ( count=0;count<N;count++){sum += AD_Value[count][i];}After_filter[i]=sum/N;sum=0;}}int main(void){u16 value[M];init_All_Periph();SysTick_Initaize();ADC_SoftwareStartConvCmd(ADC1, ENABLE);DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道while(1){while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待传输完成否则第一位数据容易丢失filter();for(i=0;i<12;i++){value[i]= GetV olt(After_filter[i]);printf("value[%d]:\t%d.%dv\n",i,value[i]/100,value[i]0) ;delay_ms(100);}}}总结该程序中的两个宏定义,M和N,分别代表有多少个通道,每个通道转换多少次,可以修改其值。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第三章AD转换本章的内容分两部分,第一是AD的单通道转换,第二是AD的多通道转换。
首先先将单通道转换。
STM32中自带的AD最大的转换频率是14MHZ,共有16个转换通道,每个转ADC123_IN10表明PC0管脚可以作为AD1,AD2,AD3的第10通道。
下面我们将PC0配置成AD1的通道10为例进行讲解。
3.1首先我们应将PC0设置成模拟输入:#include "adc.h"/*为何定义ADC1_DR_Address 为((u32)0x40012400+0x4c),因为存放AD转换结果的寄存器的地址就是0x4001244c*/#define ADC1_DR_Address ((u32)0x40012400+0x4c)/*定义变量ADC_ConvertedValue,放AD1通道10转换的数据*/__IO uint16_t ADC_ConvertedValue;static void ADC1_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable ADC1 and GPIOC clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 |RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOC, &GPIO_InitStructure);}3.2设置完端口后下一步当然是对AD进行初始化:这里需要补充一个知识点DMA,DMA就相当与CPU的一个秘书,他的作用就是帮CPU减轻负担的。
说的再具体点就是帮CPU来转移数据的。
我们都知道,AD每次转换结束后会将转换的结果放到一个固定的寄存器里,以往我们如果想将该寄存器中的值赋给某一变量时会用到赋值语句,如果不用DMA,则赋值语句便要CPU来完成,CPU本来就要忙着处理其他事情,现在还要来解决赋值语句这么简单的问题,肯到会蛋疼。
所以需要DMA这个秘书来帮他解决这个问题。
由于DMA只是个秘书,所以比较笨,你只有把任务交代清楚了她才能很好的完成任务。
那么怎样来给DMA吩咐任务呢,聪明的人肯定想到了,那当然是“DMA_Init(DMA1_Channel1, &DMA_InitStructure)”这个函数啦。
下面就来一步步的来给DMA交代任务。
/* 函数名:ADC1_Mode_Config* 描述:配置ADC1的工作模式为MDA模式* 输入: 无* 输出:无* 调用:内部调用*/static void ADC1_Mode_Config(void){DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;/* 将与DMA有关的寄存器设我初始值*/DMA_DeInit(DMA1_Channel1);/*定义DMA外设基地址, 这里的ADC1_DR_Address 是用户自己定义的,即为存放转换结果的寄存器,他的作用就是告诉DMA取数就到ADC1_DR_Address 这里来取。
*/DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address;/*定义内存基地址,即告诉DMA要将从AD中取来的数放到ADC_ConvertedValue中*/DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&ADC_ConvertedValue;/*定义AD外设作为数据传输的来源,即告诉DMA是将AD中的数据取出放到内存中,不能反过来*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;/*指定DMA通道的DMA缓存的大小,即告诉DMA开辟几个内存空间,由于我们只取通道10的AD数据所以只需开辟一个内存空间*/DMA_InitStructure.DMA_BufferSize = 1;/*设定寄存器地址固定,即告诉DMA,只从固定的一个地方取数*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/*设定内存地址固定,即每次DMA,,只将数搬到固定的内存中*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/*设定外设数据宽度,即告诉DMA要取的数的大小*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;/*设定内存的的宽度*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;/*设定DMA工作再循环缓存模式,即告诉DMA要不停的搬运,不能偷懒*/ DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;/*设定DMA选定的通道软件优先级*/DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA channel1,CPU有好几个DMA秘书,现在只用DMA1_Channel1这个秘书*/DMA_Cmd(DMA1_Channel1, ENABLE);/*设置ADC工作在独立模式*/ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;/*规定AD转换工作在单次模式,即对一个通道采样*/ADC_InitStructure.ADC_ScanConvMode = DISABLE ;/*设定AD转化在连续模式*/ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;/*不使用外部促发转换*/ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;/*采集的数据在寄存器中以右对齐的方式存放*/ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;/*设定要转换的AD通道数目*/ADC_InitStructure.ADC_NbrOfChannel = 1;ADC_Init(ADC1, &ADC_InitStructure);/*配置ADC时钟,为PCLK2的8分频,即9MHz*/RCC_ADCCLKConfig(RCC_PCLK2_Div8);/*配置ADC1的通道11为55.5个采样周期*/ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/*复位校准寄存器*/ADC_ResetCalibration(ADC1);/*等待校准寄存器复位完成*/while(ADC_GetResetCalibrationStatus(ADC1));/* ADC校准*/ADC_StartCalibration(ADC1);/* 等待校准完成*/while(ADC_GetCalibrationStatus(ADC1));/* 由于没有采用外部触发,所以使用软件触发ADC转换*/ADC_SoftwareStartConvCmd(ADC1, ENABLE);}配置完以上的程序,那么AD每转换一次,DMA都会将转换结果搬到变量ADC_ConvertedValue中,而不需用每次都用赋值语句来取值AD转换的值。
第二部分:AD多路采样#include "adc.h"#define ADC1_DR_Address ((u32)0x40012400+0x4c)/*定义数组变量ADC_ConvertedValue[2],分别放AD1通道10和11转换的数据*/__IO uint16_t ADC_ConvertedValue[2];/** 函数名:ADC1_GPIO_Config* 描述:使能ADC1和DMA1的时钟,设置PC0,PC1为模拟输入* 输入: 无* 输出:无* 调用:内部调用*/static void ADC1_GPIO_Config(void){GPIO_InitTypeDef GPIO_InitStructure;/* Enable DMA clock */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* Enable ADC1 and GPIOC clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC,ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_Init(GPIOC, &GPIO_InitStructure);}/* 函数名:ADC1_Mode_Config* 描述:配置ADC1的工作模式为MDA模式* 输入: 无* 输出:无* 调用:内部调用*/static void ADC1_Mode_Config(void){DMA_InitTypeDef DMA_InitStructure;ADC_InitTypeDef ADC_InitStructure;/* DMA channel1 configuration */DMA_DeInit(DMA1_Channel1);/*定义DMA外设基地址,即为存放转换结果的寄存器*/DMA_InitStructure.DMA_PeripheralBaseAddr =ADC1_DR_Address;/*定义内存基地址*/DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&ADC_ConvertedValue;/*定义AD外设作为数据传输的来源*/DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;/*指定DMA通道的DMA缓存的大小,即需要开辟几个内存空间,本实验有两个转换通道,所以开辟两个*/DMA_InitStructure.DMA_BufferSize = 2;/*设定寄存器地址固定*/DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;/*设定内存地址递加,即每次DMA都是将该外设寄存器中的值传到两个内存空间中*/DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;/*设定外设数据宽度*/DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;/*设定内存的的宽度*/DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;/*设定DMA工作再循环缓存模式*/DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;/*设定DMA选定的通道软件优先级*/DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA1_Channel1, &DMA_InitStructure);/* Enable DMA channel1 */DMA_Cmd(DMA1_Channel1, ENABLE);/*设置ADC工作在独立模式*/ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;/*规定AD转换工作在扫描模式,即对多个通道采样*/ ADC_InitStructure.ADC_ScanConvMode = ENABLE ;/*设定AD转化在连续模式*/ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;/*不使用外部促发转换*/ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;/*采集的数据在寄存器中以右对齐的方式存放*/ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;/*设定要转换的AD通道数目*/ADC_InitStructure.ADC_NbrOfChannel = 2;ADC_Init(ADC1, &ADC_InitStructure);/*配置ADC时钟,为PCLK2的8分频,即9MHz*/RCC_ADCCLKConfig(RCC_PCLK2_Div8);/*配置ADC1的通道10和11的转换先后顺序以及采样时间为为55.5个采样周期*/ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);/* Enable ADC1 DMA */ADC_DMACmd(ADC1, ENABLE);/* Enable ADC1 */ADC_Cmd(ADC1, ENABLE);/*复位校准寄存器*/ADC_ResetCalibration(ADC1);/*等待校准寄存器复位完成*/while(ADC_GetResetCalibrationStatus(ADC1));/* ADC校准*/ADC_StartCalibration(ADC1);/* 等待校准完成*/while(ADC_GetCalibrationStatus(ADC1));/* 由于没有采用外部触发,所以使用软件触发ADC转换*/ADC_SoftwareStartConvCmd(ADC1, ENABLE);}!!!!!单通道采样与多通道采样的不同点都在第二段程序中用红色标出来了,注意比较。