|
记录一下STM32的ADC编程方法! 前面已经学习了DMA,知道如何使用DMA去减小CPU的负担,这里的ADC转换也来使用DMA---这个也是STM32的ADC转换最常见的方式。
6 q2 r' N& r$ u' V. k---第一步是---了解STM32的ADC对应的GPIO口----如下图---不用记住,可以查询,我是将它剪下来粘贴到书本的相应章节----! # z6 k8 R: z2 c( u
% H. v# ~0 w! ^ X4 z/ Z
/ @: _9 o1 s. ?) r# j, G
---第二步是---配置相应ADC转换的GPIO口----这里使用PC0--PC1 - static void ADC1_GPIO_Config(void)
# H4 A6 S1 o" t: }$ t - {
3 j( O1 c3 L1 x o. Y# m - GPIO_InitTypeDef GPIO_InitStructure;0 o% Y4 ]* ?2 L0 J
2 ?2 Z6 c* I- E; F# o9 r q/ u( Z- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开DMA1的时钟5 |- g# I T% U+ U' R1 P- ~
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);5 r' W5 n. [$ ] c8 c, a2 ^
- 4 g5 @8 h5 b# W. J; W; f8 ~
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 |GPIO_Pin_1;; |3 l) ~: Q6 C0 W8 \
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入6 Q$ p; }- x! _& \! K( L- K& T" I9 Q
- GPIO_Init(GPIOC, &GPIO_InitStructure);+ l e9 O$ U, \! b7 M
- }
复制代码 6 q6 w1 ~& s% X
---第三步是---配置ADC的DMA----配置ADC通道等--- - <div align="left">#define ADC1_DR_Address ((u32)0x40012400+0x4c) //外设地址
5 V& U# P; A, W# A( l4 \9 x; n* I - __IO uint16_t ADC_ConvertedValue[2]; //内存数组</div>* d# A/ O* }( C. M- G, o& j# A
- <div align="left">static void ADC1_Mode_Config(void)
. u, M) |) g+ `1 g( R: S8 n% ?* L g# @ - {
" n) z2 A& s6 U1 g5 b6 f - DMA_InitTypeDef DMA_InitStructure;
! R2 }6 A4 ~ T2 a9 O1 s0 N% @ - ADC_InitTypeDef ADC_InitStructure;
3 g+ h" i7 ?4 A: I" k
. t: X4 Q/ U6 j2 V9 Q! _; F5 K' B- DMA_DeInit(DMA1_Channel1);
; J( h4 G. `& J4 @# o3 Y) l - //---------------ADC的DMA配置--------------------
1 e- z, \9 A( ~1 P9 |: f - DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC1地址---代表ADC1保存转换值的寄存器; f. d0 B) y; V( n3 b$ r2 z
- DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue; //内存地址---用来保存DMA传输过来的ADC转换值----后面直接使用的变量地址. \+ l& b% d" F n
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设为数据源
9 W, o& h6 C0 k# Y' [% @; K5 r" g5 K0 e - DMA_InitStructure.DMA_BufferSize = 2; //传输总数据---2通道需要传输2个数据
7 b' u. Y8 N9 ]& S4 n9 a* Y3 H - DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址固定
, |& w) `% z# A# d - DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增---总体表示始终从外设ADC1地址处取值---依次保存到连续的两个内存变量中---- z% x, x) q+ |$ P3 p7 @
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设传输数据单元---半字16位# v. p! e' ]# v
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存传输数据单元---半字16位
' K' x5 a% |$ L4 h& F/ L4 j0 V* s - DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式---2个数据依次循环接收从外设ADC1传输过来的ADC值---/ k1 Q/ S, a6 d+ l7 O6 J
- DMA_InitStructure.DMA_Priority = DMA_Priority_High; //高优先级8 y. P3 Y2 p9 A
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //禁止内存传内存
, P# E4 h% ^% N1 _ - DMA_Init(DMA1_Channel1, &DMA_InitStructure);/ n, H: ?3 j% B& [5 S" X+ f( V
- 7 j2 P3 s8 f4 w* Y
- DMA_Cmd(DMA1_Channel1, ENABLE); //再次打开DMA1
2 ]% V- G0 ^3 k( J. m) N3 q3 f6 g - . U% ?3 Z: S# E$ m; |( m
- //------------ADC模式配置------------------------3 |% Z# u. \7 Y# R, Q
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式----还有很多模式---这个比较常见8 I4 S8 \" \, c8 G! L1 ?
- ADC_InitStructure.ADC_ScanConvMode = ENABLE ; //扫描模式---采集多通道使用----本程序采集2通道---所以扫描模式% b, E) G) R, s C3 |- `$ P4 w7 ^
- ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换模式---不难理解---就是不停地采集---一次接一次
/ K ]) N! L! G - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发转换---触发分为外部触发---比如中断与定时器。软件触发---后面有专用函数/ y- y9 V, v/ i
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集的数据右对齐---方便计算
6 W; i6 v* z g# s7 w7 J' c+ W3 o# R - ADC_InitStructure.ADC_NbrOfChannel = 2; //总共需要转换的通道个数---这里2个
0 O8 T, J/ f2 e; c0 l - ADC_Init(ADC1, &ADC_InitStructure);* a3 L+ ?8 v( F% {. Z! T/ I2 [
- / I5 |: p: v2 R* u# F
- RCC_ADCCLKConfig(RCC_PCLK2_Div8); //配置ADC转换时钟---PCLK2的8分频
- \9 ?7 C/ t7 k0 E B0 ?7 C - //下面这个函数比较重要----配置ADC的通道与采样周期---前面说的PC0与PC1对应的ADC通道分别是--10与11。采集周期也有几种。
) ^! u7 W0 H1 y% k - ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);
$ v h4 R+ T: w' M: c% N; i: @ G - ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5);+ E- G q& i6 f% c+ ]4 V6 X
- 4 E. o! q+ Z8 E
- ADC_DMACmd(ADC1, ENABLE); //打开DMA1的ADC18 U2 j* `9 R1 C" W- G) l3 E6 x7 V
- ADC_Cmd(ADC1, ENABLE); //打开ADC1* e5 r) Z' L7 k7 N7 [
- 7 g6 T3 W% G! T! c) Y" C
- ADC_ResetCalibration(ADC1); //复位校准寄存器7 {7 V8 b% }7 a% a, e5 {
- while(ADC_GetResetCalibrationStatus(ADC1)); //等待校准寄存器复位完成! }5 Z) R9 t8 F1 x- O3 X
% d* g' `: n. A; ^3 h/ l- ADC_StartCalibration(ADC1); //ADC校准( g8 }5 W* y2 H" ]) S
- while(ADC_GetCalibrationStatus(ADC1)); //校准完成
6 k, K/ r: W. r. b; v" T8 Q
1 S k( o& Q3 w( B5 @/ j2 z5 ]( q- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发转换- T6 l9 s/ Y3 V2 D0 r
- }</div>
复制代码
% U; M; u5 ^$ w; V; Q3 g---第四部分是---在硬件上使用了一个通道切换芯片----CD4052----由PC2---PC3控制通道的选择CD4052切换控制GPIO配置---- - void GPIO_Config(void)8 ]/ `. ?4 B8 V6 a4 B l. m
- {
8 a4 S/ W. H1 \& j - GPIO_InitTypeDef GPIO_InitStructure;+ K0 l$ i. E- f' D- ~' f
- 6 S% i! {3 N) G8 D
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
+ B& }" y# P. f1 V - ' H) |, i G9 B
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;6 x" T0 g" w2 \# \' _* Q% c
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推完输出2 u; N: n- ~+ c' n) N9 ]
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;, x! a) r+ Y/ [1 W: \
- GPIO_Init(GPIOC, &GPIO_InitStructure);' E+ {5 e; u0 M# C0 w2 W6 x. I
- }
复制代码
4 X' K( ?5 D- K---第五部分是---主函数----- - <div align="left">extern __IO uint16_t ADC_ConvertedValue[2]; //声明外部变量1 p5 _) S' `" R% f
- uint16_t My_ADC[2]; //求平均值</div><div align="left">int main(void)
2 g/ P3 ^# F0 \7 E$ ?6 b: r- B - {
7 g! [% m% m8 F' ^% ~( B0 U+ v - u8 i,led=0x01;
# t1 O9 N% z% h- u) N - % i$ ^6 u: k' \" z6 Y; ?2 p
- USART1_Config();</div><div align="left">0 J! L6 [- q) x
- ADC1_GPIO_Config();0 C. X& S+ \' y, ~; [
- ADC1_Mode_Config();</div><div align="left">+ k6 d, z5 b8 a0 ]0 o( Y7 X
- while (1): R' M* o) i0 Z5 X9 m8 f
- {
3 N6 L' q* ]4 _# l7 y8 b) j e - My_ADC[0]=0;/ D# ]: B; e& ^, z' |+ \
- My_ADC[1]=0;
1 w- C" U8 w& h5 X( {
, q5 B, Y( l; b% v4 _ z) d5 o- : K" [# Y$ D. z% H% O. i6 o
- for(i=0;i<10;i++) . [" R5 t. j! B" K) U
- {) u* R. n# [2 B* u7 g5 o
- My_ADC[0]+=ADC_ConvertedValue[0];
3 |5 I# g. @' S& E - My_ADC[1]+=ADC_ConvertedValue[1];
0 X6 u# Y: Z$ B C" R - }- U+ l' e+ a/ `4 b6 E4 W. P
- My_ADC[0]=My_ADC[0]/10; //采集10次求平均值& e9 ] ` C, ^$ s, z
- My_ADC[1]=My_ADC[1]/10;6 A3 C7 F" R4 ?, Z
w: v7 o2 L j0 t3 t1 c. x; P* ~- ADC_ConvertedValueLocal =(float) My_ADC[0]/4096*3.3; //转换为电压值! n% t) n+ A* O9 ?4 {! ^% i% b
- ) m& F5 @. K7 ?5 l4 { e
- printf("\r\n The current AD---0 value = 0x%04X \n", My_ADC[0]); - S, p4 @0 V$ x8 f
- printf("The current AD---0 value = %f V \n",ADC_ConvertedValueLocal); 1 u. ^6 v; g5 e9 ?* w1 }
- & F+ b* T" j! H" ~, _, A
- ADC_ConvertedValueLocal =(float) My_ADC[1]/4096*3.3; % E4 C* j* t6 R! r0 s% f
' e+ ]+ k X4 z+ y4 _- printf("The current AD---1 value = 0x%04X \n", My_ADC[1]); # ^, }) a* i9 r0 o f9 ^5 z
- printf("The current AD---1 value = %f V \n",ADC_ConvertedValueLocal); 3 I& h# W7 T* C3 W: x$ I; w# E
- }- T. _+ V6 G7 N: C- D
- }</div>
复制代码 & a& U1 A: u4 H; w& v) B9 b3 Q
|