|
STM32 ADC多通道转换 描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。在每次转换结束后,由DMA循环将转换的数据传输到内存中。ADC可以连续采集N次求平均值。最后通过串口传输出最后转换的结果。 程序如下:$ |- \; r) A) h7 _+ y: |6 F6 p$ q #include "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义! V8 C( Q* ], K1 i8 H+ Z #include "eval.h" //头文件(包括串口、按键、LED的函数声明) #include "SysTickDelay.h" 4 S& O$ b. A3 c, F #include "UART_INTERFACE.h" #include ) g5 J9 }4 a/ N #define N 50 //每通道采50次 #define M 12 //为12个通道1 t8 u1 R, S' `1 P' S" E vu16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址 vu16 After_filter[M]; //用来存放求平均值之后的结果 int i; 0 r$ I% d- x1 z$ o; V, e9 O& y% r ! Q B7 Z( D, R$ s8 Y0 O# t( V, v /*GPIO管脚的配置 选用ADC的通道0 1 2 8 9 10 11 12 13 14 15,分别对应的管脚为PA0 PA1 PA2 PB0 PB1 PC0 PC1 PC2 PC3 PC4 PC5/ Z4 B t w9 ^" C7 d" L- ? 串口使用USART1其中TX为PA9,RX为PA10 */9 o+ z9 h3 W3 k/ `$ R void GPIO_Configuration(void)( ~# d" |$ z! |5 J* W { GPIO_InitTypeDef GPIO_InitStructure; /* Configure USART1 Tx (PA.09) as alternate function push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;0 ^3 D/ j- x% ^' f GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //因为USART1管脚是以复用的形式接到GPIO口上的,所以使用复用推挽式输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;$ F' {& L0 U7 ~( j p$ P; x GPIO_Init(GPIOA, &GPIO_InitStructure); 7 {" L# R. {5 A6 i, N2 D /* Configure USART1 Rx (PA.10) as input floating */8 x% p4 ?6 s5 y GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;: k9 D0 ?! o2 O ~+ d% g GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;! t' c* x/ Z. Q/ c G. `- Y GPIO_Init(GPIOA, &GPIO_InitStructure);5 M! V" b6 ]7 ~ 3 X7 Z P/ o: ]4 N u //PA0/1/2 作为模拟通道输入引脚 4 m3 M7 y/ `' u# W- ]* Z( _! y GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚2 V, b2 y3 L8 @% M4 V- v K GPIO_Init(GPIOA, &GPIO_InitStructure); % H6 o7 O& C0 E h a- K1 o" B. X //PB0/1 作为模拟通道输入引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;6 _# Z' A4 y8 V# |6 I GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 GPIO_Init(GPIOB, &GPIO_InitStructure);3 T1 B3 p5 \+ Y( \9 h0 }0 a: I0 A$ q# h //PC0/1/2/3/4/5 作为模拟通道输入引脚 . i" R2 a5 r; X. N) p2 I6 y 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);3 K' l0 M3 b' H# l, N p }( ]" l0 a+ D# s8 M# c. e. c! B } ! }: ^8 ~, X0 M' g /*配置系统时钟,使能各外设时钟*/ void RCC_Configuration(void) {0 _/ c ~7 p' D ErrorStatus HSEStartUpStatus; RCC_DeInit(); //RCC 系统复位7 e# F, I* Q$ Z( i RCC_HSEConfig(RCC_HSE_ON); //开启HSE, ?$ h; [5 ?7 s s% n$ N HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE准备好+ W4 G) w* `6 M8 b6 ^3 L if(HSEStartUpStatus == SUCCESS)$ \( I) P9 \/ n D {! o: N" r* r! Y: L% g FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer4 P8 ^* ? o( k q, ~4 I% L J FLASH_SetLatency(FLASH_Latency_2); //Set 2 Latency cycles RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock = SYSCLK RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 clock = HCLK |* o2 `% D9 s, N RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 clock = HCLK/2; }6 s4 ^3 `3 X E9 @ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHz RCC_PLLCmd(ENABLE); //Enable PLL while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLL is ready RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source while(RCC_GetSYSCLKSource() != 0x08); //Wait till PLL is used as system clock source /*使能各个外设时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB# @9 r' X' h" C& W0 k4 J | RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE ); //使能ADC1通道时钟,各个管脚时钟3 s& W/ `& [8 D1 r/ k /* Configure ADCCLK such as ADCCLK = PCLK2/6 */ 0 l. w2 R( c6 C/ p& M1 V2 J RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M2 c% n+ r" X* J0 E RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输8 Q$ e; P0 v+ h7 | , A% E, u7 P/ ~8 r3 u6 J } }1 l3 G9 j* s; [* R& K: X$ g* P /*配置ADC1*/- i- @7 ^. ^* @6 u! [ void ADC1_Configuration(void)! j0 ^4 q: @ B: p6 W+ U {, j- \& e8 @! F2 F ADC_InitTypeDef ADC_InitStructure;# S+ d* V: ^& {) w. u% Z& h ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值/ \# H2 K# m2 ^0 g2 r. e1 | /* ADC1 configuration ------------------------------------------------------*/ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式% `; P, e ]# k# U1 ~ ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式) ?& L v& a/ x) \" d+ L& R. p4 Q ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发转换关闭- ^. C, @7 j& O' _8 ]/ p. Z ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐6 ^8 p6 ~( e, V- Q) r7 X6 l) P ADC_InitStructure.ADC_NbrOfChannel = M; //顺序进行规则转换的ADC通道的数目) x8 N1 F5 d3 r) b6 Q ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器; f( h& j2 ^4 [3 i$ P) O# D" N# ` /* ADC1 regular channel11 configuration */ 1 {: {# z; g" l //设置指定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 ); & M7 _5 B1 i6 F% X3 F1 U1 w ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5 ); 7 d1 ~3 B- c8 F" ~' H( D: E 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 );% a! i2 {% Z' A9 K' V' L ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_239Cycles5 );+ m' a& s* y+ @7 I: P ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 11, ADC_SampleTime_239Cycles5 ); ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 12, ADC_SampleTime_239Cycles5 ); % }, E1 H @) w5 |4 o+ M' D // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数) ADC_DMACmd(ADC1, ENABLE); /* Enable ADC1 */+ I, Y, _% |. T2 e5 Y. m9 { ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1) x# t7 Y) z* e! r /* Enable ADC1 reset calibaration register */ 8 \. P9 e/ h5 ~ e0 u. _9 Y ADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器 /* Check the end of ADC1 reset calibration register */ while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待 * z* C- @: @8 m. N+ e /* Start ADC1 calibaration */5 K! [" J: t$ t* h ADC_StartCalibration(ADC1); //开始指定ADC1的校准状态/ l" C7 R- `. K /* Check the end of ADC1 calibration */ while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待' y' a( [7 ^! _8 J & @+ u* S# _: s, i% _ T }1 t+ Y3 p, }; F# ?9 b /*配置DMA*/ void DMA_Configuration(void) { /* ADC1 DMA1 Channel Config */ DMA_InitTypeDef DMA_InitStructure;$ s2 G! y0 |* a* V/ k DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值 DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址* Q5 r) O! b* t* i DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //DMA内存基地址9 R+ _( n; O1 v* w& n0 x( ` 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位5 g( A* q' j" r DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位0 B% j4 G9 q" P R. r8 q/ V7 ` DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式( @0 t. w2 G0 w, h% d; J; \' X DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级 ' _& e+ v8 I; S8 K$ K DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输 DMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道/ k Z/ |! S* h" W) ~5 z ) D! y1 f1 y, p1 \6 F: X7 o } //配置所有外设 void Init_All_Periph(void) { Q: `: W" q" H' Q' @' K$ | ( p) K9 O/ `* L2 v RCC_Configuration(); + m: k) m0 C; t& L GPIO_Configuration();. A. c$ z: t1 H2 U& o9 g5 D ADC1_Configuration();5 \( }& k4 v% U! b! a, P DMA_Configuration();' \) a1 h# O# o7 ~. \4 d5 @7 M : k" w% c) K. y8 H //USART1_Configuration(); USART_Configuration(9600); 5 r4 y( _: r9 @7 ~3 S! Z$ X S 1 a- I5 L0 U% |3 O0 b3 V } # x. E0 ?, t( T$ V: @6 T6 O9 k! |2 y /*获取ADC的值,将二进制换算为十进制*/ u16 GetVolt(u16 advalue) & i2 z6 U! } R$ y1 @ C {- X) I' r9 d5 U0 j return (u16)(advalue * 330 / 4096); //求的结果扩大了100倍,方便下面求出小数/ \4 x0 q, V' A. f } y) f/ ~% n& P, {( U# m ; V0 T- Y. Y# p3 M /*求平均值函数*/ void filter(void)4 R( F& T/ _- A. X {0 P3 g/ x& p1 u E int sum = 0; u8 count; ( k @1 ^! \' a: X for(i=0;i |
微信公众号
手机版