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

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

[复制链接]
STMCU小助手 发布时间:2022-1-22 21:58
STM32 ADC多通道转换
) R+ U% |8 y+ J2 y7 }5 E  r+ W描述:用ADC连续采集11路模拟信号,并由DMA传输到内存。ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ。在每次转换结束后,由DMA循环将转换的数据传输到内存中。ADC可以连续采集N次求平均值。最后通过串口传输出最后转换的结果。
; ^6 V$ Z& Q) J* i/ ~程序如下:
: B& n; O6 c! @) O3 }+ }5 X#i nclude "stm32f10x.h" //这个头文件包括STM32F10x所有外围寄存器、位、内存映射的定义
: n$ v( G- q. Z, l/ C#i nclude "eval.h" //头文件(包括串口、按键、LED的函数声明)
+ a9 x* K* A7 U. [) k#i nclude "SysTickDelay.h"* z# Z( A+ d# d8 {8 Y* ?9 A
#i nclude "UART_INTERFACE.h"
6 N. I" s  v$ ]/ r#i nclude <stdio.h>
+ S. j) D6 ^& j# |& j3 j" \( i+ a+ {1 H% |. Y9 p$ ], d; ~: {
#define N 50 //每通道采50次
0 U, V6 A$ v! @8 N* L- x#define M 12 //为12个通道* h4 R, D$ w' G

& n1 t: N0 O3 H6 mvu16 AD_Value[N][M]; //用来存放ADC转换结果,也是DMA的目标地址
/ ^% O5 I4 R5 }' Fvu16 After_filter[M]; //用来存放求平均值之后的结果, t6 r5 Z" s6 L* k. v
int i;
" H" |0 T4 V/ K% `8 T( Z# E8 c7 K6 d% v- n
7 a0 k1 j' h4 R6 o! h
void GPIO_Configuration(void)
7 I% z2 H0 J- G. A! U' `3 g! A{
! E! {  t. Q; n3 ?GPIO_InitTypeDef GPIO_InitStructure;# j5 i2 W5 b) S+ j" d5 a
( u9 v1 Y  Y& m+ O! t& u  N
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
5 P+ ^8 K5 Q2 X7 c8 a# hGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //因为USART1管脚是以复用的形式接到GPIO口上的,所以使用复用推挽式输出
# L% }) f4 r0 ]* n  a  G* uGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
. K8 E0 D2 K8 ^GPIO_Init(GPIOA, &GPIO_InitStructure);
! W4 J7 z0 X, Q+ r4 X) h# k+ L7 I
6 V% n" R7 [4 P% h! h, E' D4 x
% M3 \3 a5 W( h' D2 ZGPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;' G( C4 W4 B  V3 S( F3 {
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;4 ~# C/ u6 \. T+ ?
GPIO_Init(GPIOA, &GPIO_InitStructure);) C# G' N4 |# `. J
& M& b2 G5 V! J
( A. i" q. \5 @% E9 h
: J- I" |- h6 m
//PA0/1/2 作为模拟通道输入引脚. ~" F) [  t: v/ Y
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0| GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
& M/ K; e; N- r/ S0 {/ tGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
0 T9 J0 k! m' a8 BGPIO_Init(GPIOA, &GPIO_InitStructure);
# ]  e+ r3 A) I$ W$ x) Y! U  l. t& H5 C9 M- c, W
//PB0/1 作为模拟通道输入引脚; E4 @9 Z2 c4 b! u# \
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
/ I% y7 P  z- M  i2 h3 h2 l) V0 DGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚/ a0 q7 Q( @: {8 A) j
GPIO_Init(GPIOB, &GPIO_InitStructure);' B/ p' T; o. i/ E
$ m4 |( P; Z: \3 B
//PC0/1/2/3/4/5 作为模拟通道输入引脚1 `+ ]! Q7 u3 r+ K' B- j
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;1 u0 h/ o5 Y& B
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚8 `! Q8 k* c" T4 [
GPIO_Init(GPIOC, &GPIO_InitStructure);& N; b+ P! M8 i' _) Z3 ]
}- i# i/ Z+ m" j4 |5 _

, _- u# ]! L7 k* |( V1 O( ^}' x1 h4 z6 I6 o

: L4 s+ r; t! g# G/ m! e& x
, ]7 J- R" G* s1 ^void RCC_Configuration(void); H5 X/ ^7 G9 R8 \3 w) Y( u
{  ?/ n9 A* p& N) Z
ErrorStatus HSEStartUpStatus;
$ z# d9 v$ o) ]) n+ k
/ {9 c0 U, Q4 |9 W8 w% IRCC_DeInit(); //RCC 系统复位
# _8 e! k! p5 \6 U+ \. A% \. CRCC_HSEConfig(RCC_HSE_ON); //开启HSE% f4 ~! Z* E( a$ d/ ]
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待HSE准备好
  T6 u: n# w  Fif(HSEStartUpStatus == SUCCESS)5 @9 d+ v5 l% q
{5 h( l; Y( Q! R. z/ G; w0 o
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer3 ]1 ?  R. a; G) j
FLASH_SetLatency(FLASH_Latency_2); //Set 2 Latency cycles1 E/ z- L# d9 d: F
RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock = SYSCLK2 z) \9 z) I. X( M- @1 q  {
RCC_PCLK2Config(RCC_HCLK_Div1); //APB2 clock = HCLK- H9 y! ]' V3 A6 P6 C, i' J
RCC_PCLK1Config(RCC_HCLK_Div2); //APB1 clock = HCLK/2
' Z, _2 \& b3 g, c5 N3 A) X) gRCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHz0 H7 J! L6 `3 J# z$ |: h
RCC_PLLCmd(ENABLE); //Enable PLL
) G- _8 f# i5 S. l! S3 T$ {" ]while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLL is ready
! }) V$ Q+ K% R0 s% oRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source
" S8 g2 |8 i2 N5 t! c( Y1 ^while(RCC_GetSYSCLKSource() != 0x08); //Wait till PLL is used as system clock source+ Q! Q" V2 J. M& m

% f& B1 m5 w1 b( U( Q, y, yRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB) n  F$ P" ^4 `% x! \/ O! _4 I
| RCC_APB2Periph_GPIOC |RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO |RCC_APB2Periph_USART1, ENABLE ); //使能ADC1通道时钟,各个管脚时钟
2 _* q7 W+ h4 x& {* N* @% W6 b0 }9 W4 a. p6 f1 l& ^4 {
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //72M/6=12,ADC最大时间不能超过14M
. n) n& E, u8 b- U+ N/ J7 yRCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输3 Z! m/ Z6 K7 F2 v

$ _4 I) i$ p4 Z0 l9 a4 z1 W5 N. Z}
8 x  \# m6 k  K* S* H! Y; E+ R9 b}
8 t2 a3 d, g! \- C9 k7 |3 {7 a7 r4 e1 ^( \/ e1 K6 w& d7 P3 \% u- G- [
9 F1 W2 ?5 E) |7 T& {" ^
void ADC1_Configuration(void)
) @) R; ]/ i9 q% U5 D# k{
: n  Z- [  B6 {* H' b9 QADC_InitTypeDef ADC_InitStructure;
8 z' J8 L% e' }! x6 }7 r; c/ G1 w( ?7 j
ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值
) B4 W, [2 `# M- \9 V& b
! v, \' |& k8 L! T
3 E0 V3 N6 [7 ]# |' zADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式6 w) d9 x5 D) s0 {1 o
ADC_InitStructure.ADC_ScanConvMode =ENABLE; //模数转换工作在扫描模式
! g) i; t  i! [) UADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在连续转换模式8 p5 k4 |& |1 K8 E5 I
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发转换关闭
" h& K7 y4 n/ e. U& SADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
6 [( [% k$ W# a4 bADC_InitStructure.ADC_NbrOfChannel = M; //顺序进行规则转换的ADC通道的数目
: o. [; E! p- \. W3 I' z9 J2 YADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器5 X; T9 r, i* E
/ `- o- D# ^% k/ ^6 \9 r% Z/ a# f
) O* K/ ]. Q" E8 Z0 u
//设置指定ADC的规则组通道,设置它们的转化顺序和采样时间6 w0 I2 u7 t7 |# F0 I: c- Y/ W
//ADC1,ADC通道x,规则采样顺序值为y,采样时间为239.5周期
+ K8 ]8 H* V- h5 Z; K6 A) ~ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );; l" M1 h) _2 w6 h) [% f
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
3 Y+ t0 s' l* _/ [ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );  C) F1 M5 K4 j: L2 Y
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );( w6 f5 {4 F- |- |4 N8 x8 q* b) n
ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 5, ADC_SampleTime_239Cycles5 );
1 ~3 t) y' g, W( Z; c& I* vADC_RegularChannelConfig(ADC1, ADC_Channel_9, 6, ADC_SampleTime_239Cycles5 );
% ~% _5 `+ F% ?8 lADC_RegularChannelConfig(ADC1, ADC_Channel_10, 7, ADC_SampleTime_239Cycles5 );- s2 I/ ], `7 x: o% _
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 8, ADC_SampleTime_239Cycles5 );* k9 [* F5 {3 w
ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 9, ADC_SampleTime_239Cycles5 );
+ `" A  z# S& I6 V& z8 d1 OADC_RegularChannelConfig(ADC1, ADC_Channel_13, 10, ADC_SampleTime_239Cycles5 );1 ?1 a- n0 S2 [* z/ p+ S- Q5 ~
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 11, ADC_SampleTime_239Cycles5 );
+ R, u4 V. p! rADC_RegularChannelConfig(ADC1, ADC_Channel_15, 12, ADC_SampleTime_239Cycles5 );
, s  i8 `0 E* ]8 g1 m, c& B. p! h
// 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道等参数)
( z! a4 {# x' Y$ f8 l7 EADC_DMACmd(ADC1, ENABLE);
6 n: k! e# v  e3 U9 C- D; E2 k3 c# n. x

; S1 S* {& n2 |& {7 Q+ CADC_Cmd(ADC1, ENABLE); //使能指定的ADC14 Z/ M' ^1 s5 m! h* \- ]" n

! G5 W. Z- A  ~" d, V: o# i3 t( B4 bADC_ResetCalibration(ADC1); //复位指定的ADC1的校准寄存器; I- J0 G1 S) q- x, j: B/ _# A) y

4 M8 p. j! [3 K: b. I' u) |while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1复位校准寄存器的状态,设置状态则等待
+ j' y# R9 z, L5 x% v4 t! n& K. P/ G

* u$ C) U' G* U% ?) NADC_StartCalibration(ADC1); //开始指定ADC1的校准状态, @1 N% L1 @4 M  \2 Q

7 J6 {4 Q1 @: j3 A) q9 L. T, ^% wwhile(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待
7 o+ V# W2 i* f5 K' S  j9 F( j) ?5 I; `/ U1 I; {  g- s  O& N$ ^$ T, g+ j

, e* Q6 W/ o5 W8 a- v1 C' U* Q}
4 A2 u, G5 |6 K5 g+ P1 {
2 f& |" |; L! g- J) X6 o3 R+ m/ \- V$ b7 E
void DMA_Configuration(void)
( N3 I: d8 O: w( `/ i{; v  D. e2 I! z* P) @" A/ `

1 y9 l9 v+ ~; P, A6 ^: }DMA_InitTypeDef DMA_InitStructure;/ p0 O" B4 Y( |' c$ R* Q
DMA_DeInit(DMA1_Channel1); //将DMA的通道1寄存器重设为缺省值
' I+ Y: |0 Q5 o5 j! O0 dDMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR; //DMA外设ADC基地址9 G  R+ ^. P8 Z2 x2 j( _  C
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value; //DMA内存基地址$ G: o) P2 Q; ^/ @3 S4 M6 k2 R" |
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //内存作为数据传输的目的地
6 D9 M" {2 [, p7 ~$ h8 FDMA_InitStructure.DMA_BufferSize = N*M; //DMA通道的DMA缓存的大小3 z. v2 r! |! \) R% J( A$ e0 }& T
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
& V7 @; {7 b/ `; u7 F) EDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增6 ^9 v+ p1 u1 J( v3 w
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
4 B$ M& ]: f: W) c! EDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
+ R# h0 \' @5 H# }7 M( WDMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式% u& b9 C2 B: m# |
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级! ]7 g+ ^8 N* K2 L+ {4 v
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
* j* w# S4 K6 U8 \& QDMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
6 U5 S. j( x5 ~: h5 v+ w7 x, s0 s" B" k$ n, o2 j
}7 L9 }/ G1 J2 M: n: K" W! U

5 {5 R, h% P* l- f; [8 S
+ ?! I1 I9 x! u. O. q//配置所有外设
* @9 U# W- v; xvoid Init_All_Periph(void)
9 O: Q. Q. U! e) l% Q{
9 u" Y2 f0 |' ]+ T$ U: T4 l5 ]) W
RCC_Configuration();
) T  D  d. G; G7 a0 Q, y, ^; h& q
4 x; h/ A6 z9 V& u( }2 P" R( Z( ZGPIO_Configuration();+ H0 m1 ~4 }; b1 I" g" k

0 ^0 v$ d2 D+ kADC1_Configuration();
9 j9 B1 X9 W  y9 D8 Y0 }. \: _! q8 }3 g! p
DMA_Configuration();
" d# [# l8 `  P5 a* B+ O0 y6 @. K. d" P
//USART1_Configuration();
9 @6 d1 n# w, tUSART_Configuration(9600);1 K, Z. J/ z% ]0 A, H# J; i

/ ?. ^8 @! x' M+ M0 M- W/ _9 s- P: _2 Q
}7 Q, G1 `1 n5 R" S2 r" y. |8 |; l

. d( U" Z- x8 f/ ?% g) {  `# n/ w/ q3 |: U0 T! S$ U

' `& F. y. f$ b! K8 a5 Du16 GetVolt(u16 advalue)! K- e0 a2 n: D: _/ v- [
8 o1 t/ c, ?8 G# |: w
{
$ [+ ~' X! J( s& O5 W: V! C: N: z( S2 }2 Q6 b7 A8 A( w( Q' {, ]
return (u16)(advalue * 330 / 4096); //求的结果扩大了100倍,方便下面求出小数
  x" ?* @6 w7 r( R4 Z6 f. Y  I8 B, \8 ?5 \3 B+ {$ p, ]  g) u9 e
}, c3 Y/ d4 C: a6 W. V/ G: e! b
! m+ @& H' k1 u# n
' z6 l, ~! j: f# l: Q
0 m+ \9 t% D+ a# _; r: K
# x8 t3 ]/ ^+ r. H* z
void filter(void)
" n  Y* Q2 N! Z8 b! i' @1 ?4 D4 `{4 o* B9 u9 f+ b  Y( `6 H9 \9 Y
int sum = 0;! ?" N' B* m& h1 O  U  f% M
u8 count;
9 j  B7 P: r! L3 f) qfor(i=0;i<12;i++)
4 A% C5 ~5 s1 X- `# G( G  I' d
3 |" P9 P5 @  X6 ^$ T+ J{
* W: |( z$ w% F. {4 H
; f* ?! U5 V" J' c! h0 L$ U1 s+ kfor ( count=0;count<N;count++)4 @) U( Q3 {/ r3 Y' `( q* Y! L
/ A$ Q6 r# n$ A! d$ T; r
{4 e. V! ]4 N: J2 S! z# e+ Y
# W8 B  g# b4 n1 N
sum += AD_Value[count];5 A# v& e+ r$ e, g% C" ^2 Q7 f

; W3 t5 k$ q$ B8 U" z}0 }8 R) @. K* Z4 V2 P: y

0 g. |% j+ D5 I5 a+ l4 |& gAfter_filter=sum/N;7 m! ~  g4 V0 K  o" T
: o  n3 e/ ^0 G; _
sum=0;
# J4 R' V& h) d$ G8 j}: A5 @+ {  l( e' I) J: ]

7 |/ U. p  p+ G* ~! d4 S}$ e# K7 m7 _! Q6 |6 G
! \- Y1 a( d* `8 H0 ]
8 p3 I  u) {$ Y; O

: A0 S5 x/ N- a8 ?8 s( X
( M' {; N5 M; I/ Bint main(void)' t0 a5 c2 m& d  T" e5 }
{
" L; @* L8 F2 O" H7 \
% e+ s/ K5 ~: ]9 d2 j5 Yu16 value[M];+ X# `% J" s5 T3 O$ r

1 s& O/ f7 x5 t+ a3 hinit_All_Periph();7 p) q2 v, D4 j7 H4 |) t
SysTick_Initaize();! N! u0 i$ ^8 S/ m) @% n

, l) z0 c$ t7 b6 f
4 [) F' k) F* E0 VADC_SoftwareStartConvCmd(ADC1, ENABLE);+ z: c9 a" X$ |: L
DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道2 g8 q2 k8 |( T$ G
while(1)
8 X, m' `$ `9 s/ Y{
8 Y& N9 ~: |' D- u8 t5 ]- _7 gwhile(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待传输完成否则第一位数据容易丢失/ u" N' T* d5 P) ?* Z+ O( n+ y

; l4 w# G  |: Z' Rfilter();
% `1 P" s# ~1 Rfor(i=0;i<12;i++)
3 o- n: O$ k7 o" q2 b{
7 @2 W, R1 ]  r; @value= GetVolt(After_filter);  ~2 H' P2 K' O& h0 S; r
$ @: A7 f" [2 y% q2 V+ e. n/ r! H
printf("value[%d]:\t%d.%dv\n",i,value/100,value0) ;- G0 h2 a1 ~& [/ C2 K
delay_ms(100);4 A6 j1 |# j, j" b* T
}7 ^9 O7 P& v9 J0 \
}
4 X8 u1 G. P) V/ O5 ^7 q9 t' g% C0 t5 d% e; f% M& p* J4 d8 J0 K
}
8 o+ [2 t" h3 W2 i/ i6 S+ g总结
" i. H# m" o# j  j8 M! S! C4 K该程序中的两个宏定义,M和N,分别代表有多少个通道,每个通道转换多少次,可以修改其值。
- I5 Q: z1 E& ~- q" [! `曾出现的问题:配置时钟时要知道外部晶振是多少,以便准确配置时钟。将转换值由二进制转换为十进制时,要先扩大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 手机版