stm32 ADC 简介stm32的ADC是 12位逐次逼近型 模拟数字转换器;它包括18个通道,可以用来测量16个外部通道和2个内部通道.ADC转换的结果存放在16位数据寄存器(ADC规则数据寄存器,ADC_DR 和 ADC注入数据寄存器,ADC_JDCx)中,这个数据寄存器可以设置对齐方式为左对齐或右对齐. ADC通道与GPIO对应表(图片来自整点原子STM32F1开发指南库函数版本)5 q, P' W# s$ L5 j) N( j
5 q. |3 u+ `! X) D, u7 |2 I. C4 {
6 w, v1 m. _: k% U6 l" y 规则通道组和注入通道组注入通道可打断规则通道的转换
所谓规则通道组和注入通道组其实应该就是通道的分组吧,按照OOP的思想来理解,通道组是一个基类,注入通道组和规则通道组派生自通道组这个基类,通道组这个基类中包含了一个保存各个通道的数组. 为什么要对通道进行分组呢,这个有待深究,以后再说. ADC相关的寄存器3 [. V S" V) j$ ?. q& T
ADC_CR1
" ?. |( s7 c, `$ M! s/ ]% ^3 z各个位描述如下图:
" m# V! {' v8 F. f$ Y' T8 t3 o8 r: M, M7 ?
0 s' m* a& W) c' R# J0 B! F
- scan位:
+ @; G( P/ r7 G# z! X/ @% V) i设置扫描模式,1为使用扫描模式,0则关闭.扫描模式下,有ADC_SQRx或ADC_JSQRx寄存器选中的通道被转换,此时如果设置了EOCIE或JEOCIE,则只有在最后一个通道转换完毕后才会产生EOC或JEOC中断 - DUALMOD位:
! m, r# m5 W! O/ p! S) o设置ADC的操作模式,详细的看下面的来自<<stm32中文参考手册>>截图
* d4 p! w) ]+ V+ ^
/ `4 {( C& m2 J& k, c( I9 m! C
% c) s- b. P2 _$ C8 e" a7 t
ADC_CR25 G/ Y6 T" s; C9 b
各个位描述如下图:
2 q2 u0 O: g1 F K# E
- ADON位:用于开关AD转换器
- CONT位:用于设置是否进行连续转换,使用单次转换CONT位必须设置为0.
- EXTSEL[2:0]:用于选择启动规则转换组转换的外部事件: i* U; L$ T) h0 G, s- q
6 G1 J) h0 f1 y8 P如果需要使用软件触发,就将这三个位设置为 111
' U+ g, }- d% z9 Z |4 | ADC采样事件寄存器(ADC_SMPR1和ADC_SMPR2)/ j& @9 T6 A k/ {" R! g
各个位描述如下图:
- u6 ~) G3 |* e. ~, M K这两个寄存器用来设置通道0~17的采样时间,每个通道要占3位.
% G0 H4 T, m* w* r J) V
+ N8 [9 C% K4 ^* Q, k9 ]+ v
对于每个要转换的通道,采样时间尽量长一点,以获得较高的准确度,但是会降低ADC的转换速率.ADC的转换时间可以由以下公式计算: Tconv = 采样时间 + 12.5周期
ADC规则序列寄存器(ADC_SQR1~3)这几个寄存器功能都差不多,不一一详细说明了.
8 c1 P, L2 U n2 [0 E: ^! C3 B
- L[3:0]:用于存储规则序列的长度
; a3 N* q& E( a4 k7 n6 D2 X ADC数据寄存器(ADC_DR)这个没什么好说的,用来存放AD转换后的结果 要注意可以通过ADC_CR2的ALIGN位设置这个寄存器是左对齐还是右对齐 ADC状态寄存器(ADC_SR)没啥好说的,保存了各种状态,看图吧. , f9 l/ K$ r* x
4 s4 {$ g! H4 _( D- L% v5 H
通过库函数配置ADC1通道1进行AD转换查看手册可以知道ADC1通道1对应着PA1,如下图' |8 h0 ^& s; _+ m0 L

2 R) _9 V( E" V' J3 g
) Q: G5 |+ C) J4 p2 d9 @ k& F% | v& H$ M) g7 k
1.外设使能 - STM32F103ZET6的ADC通道1在PA1上所以我们先要使能 PORTA的时钟 和 ADC1时钟,然后设置 PA1为模拟输入.
; t/ N, _$ C. B; T7 |: a7 u
3 Z" C; G/ G1 {" t
2.复位ADC1,同时设置ADC1的分频因子 - 开启了ADC1的时钟后,要复位ADC1,将ADC1的全部寄存器重设位缺省值,然后通过RCC_CFGR设置ADC1的分频因子,并且分频因子要确保ADC1的时钟不超过14MHz!
O' w( ]# l2 T+ \; u( T. Y//ADC复位 ADC_DeInit();( w( }; {9 t4 _; ?1 ~& J/ c% j
RCC_ADCCLKConfig(RCC_PCLK2_DIV6); //设置分配因子的库函数" Z6 O# c3 ~9 ]2 `9 D
5 {' m% M1 \8 z9 h1 T2 L
3.初始化ADC1参数,设置ADC1的工作模式以及规则序列的相关信息.
; w( s' ^! n1 `3 R: @void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);// ADC初始化 # U; a& l' g+ L1 O/ T& x+ T
4.使能ADC并校准0 f4 R8 ^8 T# F8 y
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState); //使能指定的ADC
. C, p6 F6 u+ g1 }( ~; L) L/ e9 h/ Zvoid ADC_ResetCalibration(ADC_TypeDef* ADCx);//复位校准1 p5 v2 ~8 c, J& Y7 P1 B% k: v
while(ADC_GetResetCalibrationStatus(ADCx));//等待复位校准结束. R) i- z) Z& E* i
void ADC_StartCalibration(ADC_TypeDef* ADCx);//执行ADC校准! H0 ], ?$ q7 I* ^4 C! R
while(ADC_GetCalibrationStatus(ADCx));//等待AD校准结束 6 x# Q, Y# a5 |& F+ x) f4 M
5.设置规则序列1里面的通道,读取ADC的值6 ] R; D+ g4 P' x2 }6 x7 z# A
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime); //设置规则序列通道以及采样周期. Y. T& l4 o0 p
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);//允许软件开启ADC转换4 X) f. k; U2 [( v! U0 e
while(!ADC_GetFlagStatus(ADCx,ADC_FLAG_EOC));//等待转换结束
% Q8 q2 ]! n! r/ _, D( K2 Tuint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);//获取转 换结果数据
0 o9 r; K& O8 d7 r: F! G- zMDK5中实现代码配置stm32f103库函数编程环境,我用的是正点原子的那一套,不多记录了; ADC1_Init() 函数 void ADC1_Init(void)ADC_GetConvValue() u16 ADC_GetConvValue(u8 channel)ADC_GetAverageConvValue() u16 ADC_GetAverageConvValue(u8 channel,u8 times)ADC_SampleValue2ReadableValue() double ADC_SampleValue2ReadableValue(u16 sampleValue)main.c文件代码 main.c在main.c中使用的 USART_WriteLine(const char*str,...)函数 是我自己封装的串口函数,也可以使用正点原子 System文件夹 下提供的printf()函数; $ ~* l. g4 w- n+ a
总结库函数配置ADC的步骤1.使能需要用到的GPIO 和 ADC的时钟;! o" v" p8 V; t' W/ W8 B
2.配置ADC的时钟分频:
" R3 ~! X! H7 V: jvoid RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
3 y9 G3 [* g5 @4 k) Q0 M1 s) N2.配置IO口,输入模式为 GPIO_Mode_AIN,模拟输入模式;
7 }5 V8 a* G: u8 O& b! |3.调用 ADC_DeInit(); 对ADC进行复位;
% V- [% L, h% m; l1 }4.调用 ADC_Init();初始化ADC
2 \2 M0 r8 e4 h* G4 i5.调用 ADC_Cmd(ADCx,ENABLE);,使能ADC1 \9 m6 X9 ^% y0 N4 g" l/ h1 d a3 I
6.校准ADC:
7 [0 V* u8 U7 v- n. NADC_ResetCalibration(ADC1); //复位校准 while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准完成 ADC_StartCalibration(ADC1); //ACD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待ADC校准完成 H4 T, U* Q6 A! S
7.获取AD转换的结果 + g6 g" o! x* x9 T& E) j
3 P* P( |1 u9 ^$ w3 {% a |