你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32学习笔记1(ADC多通道采样)

[复制链接]
STMCU小助手 发布时间:2022-1-22 21:58
STM32 ADC多通道转换
0 h/ w2 }# \  T9 A7 H) G% M描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。在每次转换结束后,由DMA循环将转换的数据传输到内存中。ADC可以连续采集N次求平均值。最后通过串口传输出最后转换的结果。# S3 K7 N# i. j' [2 z7 B% P2 V
程序如下:! @9 q6 t+ C' V6 d
#i nclude "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义
1 e+ @1 {5 c  l) J; g# h8 M#i nclude "eval.h" //头文件(包括串口、按键、LED的函数声明)
8 J7 L, E( [1 J) c#i nclude "SysTickDelay.h"6 x2 I7 M. N& s; g2 Q8 D3 ^. W3 V/ x
#i nclude "UART_INTERFACE.h"! ~( k6 a5 w# ]; x9 V. l, ^
#i nclude <stdio.h>$ @  ]+ D6 o! ?
6 h5 i0 h- u* D0 n! Y* ^' Q& `* J
#define N 50 //每通道采50次" }+ b7 r/ P3 O" J# C$ y- F$ X
#define M 12 //为12个通道) A/ b& i8 b7 L9 i
; ~! e# x: l& D
vu16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址
8 L4 C  i7 u4 j4 o- ivu16 After_filter[M]; //用来存放求平均值之后的结果) V' k" `# h# P7 d6 O
int i;
* I  R0 h4 V" \5 W7 `
% \, A2 D5 P3 L# i/ C& l1 l- g' m! s- _
void GPIO_Configuration(void)6 Q9 C$ N3 t) A. x- D
{: U& g- j9 G/ n0 ?" t& l" A. M* e, G
GPIO_InitTypeDef GPIO_InitStructure;) B7 q, w5 P0 t: A3 I
* ^3 P( }; C- r9 `( g/ u
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
8 B0 V  M! v9 H, W1 u( kGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //因为USART1管脚是以复用的形式接到GPIO口上的,所以使用复用推挽式输出
3 M- ?) O# X: k' f" ~GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;* P$ \8 |9 @: L+ R2 W* q
GPIO_Init(GPIOA, &GPIO_InitStructure);) p2 K) \6 G, d1 \$ G

6 |. i) b: q$ `9 N3 C3 P' ~% ?5 h+ o, D7 S9 C; \# e8 U, ?
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
0 u0 L/ z- y: h: R! M7 VGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
0 o6 G4 u0 _/ L& fGPIO_Init(GPIOA, &GPIO_InitStructure);% ~. G/ Z: g! ~; g  P" _$ x

  X' e7 ?5 ~2 r& f+ O& B- g1 k/ n+ G+ Z$ h' v% w
! K, B" e9 L/ D( E$ Q) S
//PA0/1/2 作为模拟通道输入引脚
+ s* l" _0 e/ |( QGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
3 K, z: ~/ @+ |3 r. B) GGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
! N& h+ `* r: S- \3 B+ b. o; OGPIO_Init(GPIOA, &GPIO_InitStructure);' v* k" g  X  F6 f, _% u: D+ V

0 U* `4 o7 X! o//PB0/1 作为模拟通道输入引脚
0 a. l; n! {: j! H. dGPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
2 w+ g3 u* h: c4 eGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚! t; [5 X- `8 f: s, H- ^% t
GPIO_Init(GPIOB, &GPIO_InitStructure);
1 S) E6 J5 I  {: J2 R4 V2 l. N4 i7 S+ r0 l/ ?9 D& O
//PC0/1/2/3/4/5 作为模拟通道输入引脚5 c* ^8 Q9 d7 u/ J9 v8 C4 B! ^- ]
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;2 r8 E$ R. D2 d1 w  _. [
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
1 ?' N! G6 X/ |! ~& }5 YGPIO_Init(GPIOC, &GPIO_InitStructure);
- y: s  h& B% b# |  u}8 ]. L; C# O# l

  m( h* h' ], [}/ e# Z& s9 A2 J" o
8 h) a) I/ O) ~6 Y' J  ]( ~7 e

' ]& O, J2 @! e3 u: Y& Kvoid RCC_Configuration(void)& P$ E2 L9 B1 s; d# |
{
! P+ ?" p! M+ ~ErrorStatus HSEStartUpStatus;
$ `& i0 z- ~. K
1 k, Y+ ?  W, WRCC_DeInit(); //RCC 系统复位
8 c( I! _* [8 s8 i" S( Y/ PRCC_HSEConfig(RCC_HSE_ON); //开启HSE7 n' d5 v: c. B8 f* f) M
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE准备好
9 I' P$ Y/ C3 ^8 h4 {" fif(HSEStartUpStatus == SUCCESS)
6 Q/ c7 A, X& j5 e" _- ~# M{; P/ ~  [8 t3 H, y& u
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
( G$ c* {+ y' Q! o& SFLASH_SetLatency(FLASH_Latency_2); //Set 2 Latency cycles2 I( g/ _) c3 w. u( K# b
RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock = SYSCLK; R- N, e! g0 \# b' L
RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 clock = HCLK, _$ m3 h/ N  M3 Y- C; x: a# r# X
RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 clock = HCLK/2
2 w& d" r0 c2 eRCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHz; f, `( Z. J3 S# t9 K. d6 e
RCC_PLLCmd(ENABLE); //Enable PLL, }. d) m! d& t) x: {
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLL is ready! D2 ]% x- j+ C& r# y5 t# q& f  F
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source
% A$ `( H- \- x- m; h( F& q* N1 Rwhile(RCC_GetSYSCLKSource() != 0x08); //Wait till PLL is used as system clock source
/ r8 |$ o; Y; M, q$ q0 Z5 V8 N: L+ W5 X8 o
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB
  k$ J' J; W+ {1 y/ h| RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE ); //使能ADC1通道时钟,各个管脚时钟1 ?( j# `* C( \  J# J3 E  H

+ I! w/ a4 Y2 qRCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M
9 P  `. v: I; ARCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输: s! g& w5 A2 \0 V4 q: k* y
5 ?+ {. ?- |* q* ~4 Z
}
* h% U8 q/ W% ~) g1 L( l4 f, Z}$ \) P7 o; N& U
* X0 q; M8 k0 z& a" X

% y& v" ], ]$ E: r# `+ R* h7 |1 Cvoid ADC1_Configuration(void)
3 x, k  C2 u5 e, P# J# Q; h{
0 Q4 ?, n) e4 UADC_InitTypeDef ADC_InitStructure;# T2 I1 l  a& J- O: G. e' A

+ `- a: f/ R6 @. r# w7 ~/ OADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值( Y1 s' A" t# Z
( s2 g9 a- d2 r1 r/ E4 ]* Q5 G

% P4 ^; I9 G* `! X9 SADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
) D) h( F$ m" u& }ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式
" U" C' J0 a, G' G/ s! DADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式
: U& Y: \) C5 p% ^) {" VADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发转换关闭' J% s4 ~- h" \% m/ ?* t( S
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐0 u4 U; x  a% R
ADC_InitStructure.ADC_NbrOfChannel = M; //顺序进行规则转换的ADC通道的数目
6 d  ]; c* f6 g+ i4 OADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
! G6 n8 g1 f7 l$ K# t- P8 R; `8 ~
2 z7 H' x. e4 E
//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间, x3 s$ _; w5 [) g: m$ O/ l
//ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期9 @) S' O; B& _; F; h
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );
) ~; U8 R! N; H- I( Z8 x6 V+ tADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
! m& }; t3 O2 ]' T% W& kADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
* T/ [! h7 y8 S1 x) Y3 JADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );
: y9 ?( G9 O! P( y' QADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5 );0 q! d! G8 @1 V1 ?
ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 6, ADC_SampleTime_239Cycles5 );& x1 _. B8 _: u" I
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 7, ADC_SampleTime_239Cycles5 );! _- E7 d; o+ Q- x# w3 V1 F7 O5 |
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 8, ADC_SampleTime_239Cycles5 );9 c8 k; p' s: \+ j( R
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_239Cycles5 );
" Q5 f8 e3 K5 }. l* E$ XADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_239Cycles5 );
3 i% [3 _0 A, G; P6 H3 G8 z4 uADC_RegularChannelConfig(ADC1, ADC_Channel_14, 11, ADC_SampleTime_239Cycles5 );0 {9 J* D/ l2 x7 r0 r
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 12, ADC_SampleTime_239Cycles5 );9 \- T* ^9 H/ y/ P3 ?

$ A5 p0 s; w$ _: F/ ?- R$ H( k// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)5 z6 F% J$ m& O  X0 m9 p* t# P" E2 b
ADC_DMACmd(ADC1, ENABLE);* S( M" P9 u. R+ W- Y
) }( I* D3 p. f5 V

8 o/ T- ?; D2 P) n! M3 sADC_Cmd(ADC1, ENABLE); //使能指定的ADC1, l  H! {; ~8 I; }( S6 e# n9 h
4 V$ d8 x3 R3 H5 L+ S! z
ADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器
* g4 s7 n$ R" z: M) ^" c- f( p" Y) L# Y' g% s9 v8 w
while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待: B6 r7 o; I& h/ T) [1 `6 m& g

; V" e8 E# Y) J$ N; c8 o1 ]
2 |# X- T: u8 p" K! e# c/ ZADC_StartCalibration(ADC1); //开始指定ADC1的校准状态
% G7 [, W5 t- m- ^0 m) B' `; ?9 O* i5 C9 R  b: G8 d
while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待# I0 o- t% G" L. ?
. r& w2 b4 `# g1 k0 t; H" d* W

; |& r( _! W5 l# ?: A8 A- Y}# Y( P3 Q; D  [9 a, R6 x8 V. ~
/ @( O( ?& S8 s8 ^  K8 `

1 m7 z5 V( Q! i+ Y" Nvoid DMA_Configuration(void)9 e, \, ~3 \  ], f. b
{$ l# Q* c: v1 ^- P! D1 v

* N$ G+ T$ E  D9 U( e3 ]DMA_InitTypeDef DMA_InitStructure;% V- o  |- x$ }9 M; S# V* B
DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值5 f1 y8 F: Z) i1 Y9 U6 P1 L: N
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址# t: N% X! Z) _7 w; n$ y" T) N
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //DMA内存基地址& j" U( `! @: @: }9 U4 \
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地
: R) z% B# k( D% q1 a/ \$ ZDMA_InitStructure.DMA_BufferSize = N*M; //DMA通道的DMA缓存的大小
, C4 b3 N& N5 m1 D9 sDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
) s  y4 c0 a7 W5 f1 h4 [7 E/ I% F. VDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增$ j0 ^' q, w5 a. b# c" v3 D" X7 o
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位3 B' `# X* d! N' s+ l5 f
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
0 E6 k, j4 j4 g/ tDMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式4 o+ K& [! p+ g
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级, }; L8 x9 a8 K% q9 m
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
9 a2 I& o7 v" w& j8 K) S! cDMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道! F; n& g5 D2 H  }+ X
) `$ [+ o1 {9 m
}( o- V  Z( C6 R
0 f/ @" L: n$ [! _& X4 z: P3 d

. u$ s, ^0 i. }. W, s//配置所有外设* _4 x4 b3 C, s5 L. Y/ g
void Init_All_Periph(void)+ E8 H9 [# S: z' r4 W
{. Z% c; m: \: }1 F
4 s, W# f# K" y8 r5 n
RCC_Configuration();3 A; C6 m0 Y/ r% d

3 |& J: \. Q: o1 [  B9 ^2 i% SGPIO_Configuration();
( y7 O  @5 n3 x5 N& U; B$ A$ N$ s
; \3 o# o' R" ^6 hADC1_Configuration();
- \! }" M3 r# k6 @% g0 D4 S$ h# F5 p( @' @( b; v1 G  H
DMA_Configuration();0 e8 y8 G) [( X; T2 {2 ?, R, L
& M' O4 Z  T# y$ E4 M1 a# l
//USART1_Configuration();
! A. X' |  @% N- p3 d5 ]USART_Configuration(9600);' H6 G3 g" X$ f1 H1 x5 ]- a( [
$ g# R) u1 Q9 `7 ^
% s( M& Y, B) s
}
3 i8 ?" M, |- q8 [+ r0 y. X- ^' R
! I( ], o5 W( [3 C3 ~! o' [- y+ x- J% A
9 S+ _0 b7 f+ N
u16 GetVolt(u16 advalue)  z. E) B1 H9 y6 [% p
6 M3 I8 z; D- {4 V6 L7 _
{
( G$ l5 b" H3 e0 d0 ?% s
4 J0 Y) E" z& T3 ]& Ereturn (u16)(advalue * 330 / 4096); //求的结果扩大了100倍,方便下面求出小数
+ Z2 E0 A; ^/ Q* R& `+ B- A2 h
* G! n1 \6 d+ |: a}
  W6 V4 Y% ]5 s% O% T
" Y+ o+ W2 H' N0 w  D" A3 `9 E) t/ v, `) v2 U6 d" ]- E" e
+ l) t4 {1 ~6 @3 _3 y5 e: _% B
  Q) {/ T" C! O3 i. p1 d
void filter(void)
/ j( e* B4 h2 A- h! P- C{
7 N; S8 X1 B8 `8 fint sum = 0;, @% X+ c( w$ s6 y
u8 count;9 v+ C7 F  g: M
for(i=0;i<12;i++)
4 i$ l" P- S9 ~* a( _7 b
- W' G1 F/ t* y: Z3 `/ Q{
0 D6 w3 ]2 i/ W' i3 H( a7 m( R
5 S" m/ d, r; }for ( count=0;count<N;count++)
; L. v3 w) R/ ~( s
; ?# e0 X( _, m2 O$ V) @# T( B4 U/ V: h+ U{
3 \/ {6 V1 ^  l+ g0 K: f8 `- z: }
sum += AD_Value[count];
  D; p8 C1 {: L% d, z; j  a" X. M# [$ m/ M( p
}! }. C9 e; D" d+ Y* }# ]6 s6 l4 h

$ }; m7 n$ E+ v5 sAfter_filter=sum/N;
1 n  V1 y: M+ u8 b- w
% u3 g( n8 U- K. c' G; gsum=0;2 M7 I) G2 l7 ^, Z" x
}( N! D/ _# J0 U

, o3 z! C! y8 o4 e}) \  z* c* r% h2 n

" o6 z% y6 X( L0 \, k, Z: e  z7 n" G- E0 ]% L- i1 E( z( v
, i4 r4 I! D+ ]3 q8 s5 B2 O( I
" V# U! s& S1 z6 j9 h7 U/ P
int main(void)
& Q/ U" r/ r- j9 q{
2 L" P9 Z7 Z8 M! w; ]& M/ M
) O" M: Q% ]3 |% K9 Y/ `6 g$ ru16 value[M];
- K" b& k$ Z" L3 k% E
  h$ I, B+ v+ o/ o/ p* S5 Cinit_All_Periph();
3 T' C) N/ k: e  L, Q4 E5 LSysTick_Initaize();( X+ Z; o  m8 F( C8 {

( ?7 U8 m3 [# u2 q" }7 N
, s% @5 z8 L2 BADC_SoftwareStartConvCmd(ADC1, ENABLE);9 ]# w4 S4 S0 M! U3 |/ U6 O
DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道
% r* R) E, ~  l. [1 _8 I2 X$ Lwhile(1)! W- \5 I( g5 ]9 S7 L# A
{
4 [6 E4 L* a* N* f- Awhile(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待传输完成否则第一位数据容易丢失0 D% X+ D1 C* i' j# w

9 F$ B4 }' C: n/ y: v4 u: T7 Zfilter();. J- B6 `, N& U3 w' ]0 E% Y3 N
for(i=0;i<12;i++)+ `6 t6 c& V* D, n8 R& N
{
/ K. V3 x) D# Uvalue= GetVolt(After_filter);- S$ r0 J4 y% ?

; I; u0 F+ x2 fprintf("value[%d]:\t%d.%dv\n",i,value/100,value0) ;
, s: b5 w$ M0 @- |7 cdelay_ms(100);! ^* g+ `# F2 R' d: i
}
; `9 N' A3 h+ H6 k! z) s; ?}. s1 c5 Y# E, O$ r1 c) f
9 J. ?4 e* |% ~; {+ B' n2 y2 }
}
. Z. ~! P8 j5 a6 D, G+ k  e+ i总结
: P' `5 G, d9 `/ w) W该程序中的两个宏定义,M和N,分别代表有多少个通道,每个通道转换多少次,可以修改其值。& p! ]$ Q$ ^+ d& y
曾出现的问题:配置时钟时要知道外部晶振是多少,以便准确配置时钟。将转换值由二进制转换为十进制时,要先扩大100倍,方便显示小数。最后串口输出时在 printf语句之前加这句代码,防止输出的第一位数据丢失:while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
赞 收藏 评论0 发布时间:2022-1-22 21:58

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版