基于HAL库,实现最简单ADC采集。
" C5 R+ c( f# n第一步,使用CubeMX配置时钟。, i! m: D) e* B5 ?0 `
* N$ J+ t" u# d2 ?; u( `' A: K2 ~3 }" H
然后是adc的配置:
# b5 P/ n" L. i# \
# S3 y! t) o9 G7 t w
* @: o6 o& }! p- J( j* {* ^. {6 p( @2 c# M
将,稍微修改一下风格,并手写头文件和源文件。! J3 X4 Y1 c" q% J: U1 Y
7 ~2 r+ \6 |8 A% Padc.h很简单,就不说了。
. e, A* }; }* S3 }8 r' U! j [. ~9 P' T) h" n3 K/ U$ @
- #ifndef __ADC_H
6 O- I+ f# X/ [- c - #define __ADC_H
* J% v7 p6 A5 d x" _/ x - #include "sys.h"4 g: a6 ~7 l) p7 v/ N9 O$ y
- . r/ u u! P- d8 h8 \& {8 A
- void MY_ADC_Init(void); //ADC通道初始化; |9 _* Q P9 ` O) _1 d
- u16 Get_Adc(void); //获得某个通道值
$ R6 p* `. K$ q1 ? - #endif
复制代码
( I( q( W) Q+ f- e/ d# M其中,MY_ADC_Init和HAL_ADC_MspInit的内容完全是根据CubeMX生成的代码写的,就改了一个变量名字。Get_Adc则简单了,当我们需要获取adc的值的时候,先HAL_ADC_Start启动ADC,然后HAL_ADC_PollForConversion等待转换完成,最后HAL_ADC_GetValue返回结果。
# l3 @! f4 L7 ~. b- ? Z$ z' k6 X3 B& ^1 }
- #include "adc.h"
9 ^' |* ^% E% x' j! k - #include "delay.h"
$ ^3 `2 h+ C; d3 S K' ~ - 0 k) }/ `$ v( J! M" f! Y# j
T. t/ N! K4 e- ADC_HandleTypeDef ADC1_Handler; //ADC句柄
+ O- P/ C7 {8 \" q0 h/ g - ADC_ChannelConfTypeDef ADC1_ChanConf; //ADC通道配置句柄3 f/ s# k' u& f2 ^1 D
. {( l" n% @9 R
0 x% t1 D2 I* u) M- J, X- //初始化ADC
+ a9 [) _( j+ q) t, b8 @ - void MY_ADC_Init(void)! O2 ]# S# G9 X3 K" x1 {8 V2 _
- {% A: j$ o% t; F! b. a0 m4 Y
- ADC1_Handler.Instance = ADC1;, A* M- _ X( [+ }# {
- ADC1_Handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //4分频,ADCCLK=PCLK2/4=108/4=27MHZ
9 m3 D( l9 s3 W+ @6 s - ADC1_Handler.Init.Resolution = ADC_RESOLUTION_12B; //12位模式0 H9 r) p2 u9 m+ K/ }8 ]1 L2 m
- ADC1_Handler.Init.ScanConvMode = DISABLE; //非扫描模式4 M K' D1 p i$ G+ @' V
- ADC1_Handler.Init.ContinuousConvMode = DISABLE; //关闭连续转换
/ N. {, }+ F6 x! D7 U - ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; //禁止不连续采样模式# f! @8 t8 {9 b2 [9 D
- ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //使用软件触发
( t. p5 @( [ A1 U2 w - ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //软件触发% F: q( |. F- \
- ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //右对齐
- u0 ]3 ^- I4 } - ADC1_Handler.Init.NbrOfConversion = 1; //1个转换在规则序列中 也就是只转换规则序列1* z6 ]6 P& s2 L
- ADC1_Handler.Init.NbrOfDiscConversion = 0; //不连续采样通道数为0
$ ?, T, \5 O' w( c# P! q2 j - ADC1_Handler.Init.DMAContinuousRequests = DISABLE; //关闭DMA请求
* X- Q( S7 y# N& j - ADC1_Handler.Init.EOCSelection = DISABLE; //关闭EOC中断
, w/ C7 c) U$ M. f Y) I! B1 Q - HAL_ADC_Init(&ADC1_Handler); //初始化* M# M+ m" w0 }
- % {! o$ a1 Y. O7 k+ |; |. T/ D
- ADC1_ChanConf.Channel = ADC_CHANNEL_5; //通道5 PA5! m8 t8 n( U3 G9 z; y N
- ADC1_ChanConf.Rank = 1; //1个序列6 I; }, U- Z; B9 R Q
- ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间+ k1 {) q, @8 O* Z/ B$ V( v; u
- ADC1_ChanConf.Offset = 0;
) ^, ?( e2 ~8 S D2 P( T& X1 I$ s - HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); //通道配置
1 Z$ b1 [: L/ n. M9 X- B - 1 w9 D# }4 B9 k i4 L; ^
- }
8 q. j1 z/ ` Y7 w E - 2 t" G& z* F: @( C: X, r% @0 y
- //ADC底层驱动,引脚配置,时钟使能
! F0 w5 ~* m3 U ]& x7 L; v! ? - //此函数会被HAL_ADC_Init()调用
# v4 _ I5 I, o: y' Q& f, w* G - //hadc:ADC句柄
- S4 `' r9 y0 h, w9 U3 O9 N - void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)$ o5 H) B9 \4 A+ v& z# ^& o
- {
. w" ]0 R( h# _: H - GPIO_InitTypeDef GPIO_Initure;9 S+ a2 R; [# T) F5 P3 V
- __HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟8 @+ l* z5 S: R8 s" q' G) M
- __HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
- |3 X5 m. ~. u; Q9 I: K4 I - ! d! Z- H5 a) j
- GPIO_Initure.Pin = GPIO_PIN_5; //PA5
0 `/ H1 U5 w8 Y3 O - GPIO_Initure.Mode = GPIO_MODE_ANALOG; //模拟
! I4 W7 M8 `1 g% T' S - GPIO_Initure.Pull = GPIO_NOPULL; //不带上下拉4 [ N5 {- Z; j) Z- I9 [- B+ \% J
- HAL_GPIO_Init(GPIOA, &GPIO_Initure);
; G$ O% N4 `( q/ s) ?/ {1 C! C+ t - }
9 L" x, U: p$ g3 h7 L
* Z! [' g A5 B0 ]+ z, Q- //获得ADC值
0 F0 i5 D' m! g( O0 }* p% Q3 K - //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16$ s- I2 ]2 G" O6 t/ I
- //返回值:转换结果
% w% d( }0 X- f3 e - u16 Get_Adc()3 M2 P4 C& V; L
- {7 T- n9 X$ C* [$ Y0 [# `' g) [# j( [. ?
- HAL_ADC_Start(&ADC1_Handler); //开启ADC
; t5 a; `8 b, E. B, T4 l - HAL_ADC_PollForConversion(&ADC1_Handler, 10); //轮询转换
# ^4 c7 q& W0 M) i0 o2 o: _ - return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
' j1 l% t, T; b1 T" D7 O, j. Z8 m - }
复制代码 + U4 \; i+ w+ F7 ]" n1 v% a0 D
main.c中,主函数初始化之后,直接读取adc的值,并打印。
7 f D9 \0 K5 Y( R3 L5 h$ h% J+ g" K
- #include "sys.h"7 I% \7 c* @ Y2 ^ f3 C- s
- #include "delay.h"
% e+ l9 Z2 j& v/ i1 Z) m- s - #include "usart.h"
; K5 J2 S% [% m; n) k - #include "adc.h"
k' i$ Z* |3 i& R; i( u
1 Q4 z/ e8 W! p0 i8 H! z, {- int main(void)
% m; q1 l9 p& s - {8 x- Y9 d/ F: z/ E2 u8 b* \
- u16 adcx;* G5 ^- j3 w, c9 H5 Q ^
- Cache_Enable(); //打开L1-Cache# g9 _* u, ~7 j: H1 d( _; V7 P3 s# A
- HAL_Init(); //初始化HAL库
; S6 n/ n& X+ U) w5 u - Stm32_Clock_Init(432, 8, 2, 9); //设置时钟,216Mhz! t u+ P. {" O
- delay_init(216); //延时初始化
/ Y! O8 c7 e" C4 B% }" G+ } - uart_init(115200); //串口初始化
' a/ J$ I3 S- l: c! o1 A, W7 E8 g4 r - MY_ADC_Init(); //初始化ADC1通道5* h5 W: X" x Y% L# m
-
: l+ w, r2 F: n B2 A6 a" E) q/ p! } - while (1)4 Z; w7 e3 r! l. I6 D* j; y
- {7 L) f: F$ t1 u* d) a4 d
- adcx = Get_Adc(); //获取通道5的转换值,20次取平均$ L3 E; z+ j2 E3 n
- printf("%d\r\n", adcx);
' ^) W& R7 x$ b* e) {& l - delay_ms(250);
$ M: v; Y4 w- K( _ - }
# T. e. z+ N7 h0 D - }
复制代码 . c# u) g+ g8 n& n! B
如果需要对多个通道进行轮询读取,可以稍微修改一下函数Get_Adc,在每次读取之前设置一下需要转换的通道:
' K& F1 B) K6 }2 Y6 ~, a
( J5 ^) F3 R: G+ |6 h- //获得ADC值; ~0 S) Y) ?/ q) v2 L* U ?
- //ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
) `8 I! ]7 n, q/ ~5 L+ g& h% b - //返回值:转换结果
7 L7 n2 e( I# P- g7 m# Q# x+ z - u16 Get_Adc(u32 ch)
4 T G" N( f) _5 ^; M7 a* W4 T4 G - {
$ J/ B2 e! t2 Z. G - ADC_ChannelConfTypeDef ADC1_ChanConf;8 }. u, G/ n* _, E1 j, V
# n2 O5 L) }; R4 ~9 u" H+ o- ADC1_ChanConf.Channel=ch; //通道
' w: D& F' S; \4 v0 ?/ L& r" Y - ADC1_ChanConf.Rank=1; //1个序列
9 p. k+ w) j0 L6 @( r; J( i4 M - ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间) h* O* o- r; L# J3 B6 [
- ADC1_ChanConf.Offset=0; ' c4 L+ N; N2 `7 b8 M
- HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf); //通道配置3 _9 O, Z; j/ O/ v2 h
- 4 E* l7 u1 _' {
- HAL_ADC_Start(&ADC1_Handler); //开启ADC6 @0 }5 E4 n6 f4 F
-
7 E- K! k) h4 {# Y0 V - HAL_ADC_PollForConversion(&ADC1_Handler,10); //轮询转换" f2 k4 p/ `0 U, @1 o2 |# ~
8 e& i7 `# H; G4 Z/ V- y$ s% ^: c- return (u16)HAL_ADC_GetValue(&ADC1_Handler); //返回最近一次ADC1规则组的转换结果
z' S+ p8 M& M: V- P$ j% D7 w - }
8 G5 w8 `1 z; X% `4 a
复制代码
, e6 W# I6 [0 v0 \' U; b4 U6 u
; |* A2 J8 W9 D
! m3 i& X L4 q% |0 S" I* _ |