内部温度传感器简介测量的温度位置 内部温度传感器集成在芯片中,测量的是芯片的温度。
8 l% _% E" J. k2 ]9 r 如何测量对应位置的温度?3 m& |4 o% E! a7 ~9 E1 y9 B
+ A3 R! \3 Y4 F
温度传感器与ADC1_CH16相连,另外ADC1_CH17是与内部参照电压VREF+相连,因此我们可以通过ADC1的第16路通道测量芯片温度实时对应的电压转换得来的数字量,也可以通过ADC1的第17路通道测量内部参照电压对应的数字量。 4 K, `3 a: I$ x [! {
+ B8 u5 y6 v& p. b) f
我们知道STM32的ADC转换DATA是12Bits的,因此输入电压(小于3.3V大于0V)ADC转换为数字量的值为“大于0小于4096”。 4 [& s6 d4 W7 L+ ^2 B$ I. ~* z5 M' y
* a2 f8 G; B/ d/ p; u; B
我们由“T-V关系图”,“V的数字量”和“ADC量程”,可以得知“此时的温度”。 + ~$ [# I C9 o0 |( {
# N/ `/ J2 p$ I
内部传感器配置注意事项0 q( G$ f) q5 b8 n$ k
3 h7 u5 p2 k% {! X* ?1 B/ y- N
① 读取内部温度传感器数据的周期应大于17.1us; ② 内部温度传感器的温度测量误差约为1.5℃,因此内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温 度,应该使用一个外置的温度传感器。
, E0 d" Z, i. x1 W# e, c
' ~$ N4 a. _' S5 o 内部温度传感器配置流程! S& l( b! G4 W9 t- ^, Q
8 X3 _/ C6 W- z, W" x8 @0 T所属函数位置 | 执行步骤 | ADCx的初始化函数 | 使能相应总线上(APB1或者APB2)ADCx与GPIOx的外设时钟 | 配置GPIOx口中ADCx对应的引脚为模拟输入模式(ADC外设对应的GPIO模式) | 将ADCx复位为缺省值(就是将ADCx的所有设过的属性全部重设为默认值) | 设置ADCx时钟分频 | 将ADCx的校准寄存器恢复为默认值(此时应用对应的标志位来判断此步过程是否完成,如果完成再执行下一步) | 将ADCx的校准寄存器初始化,开始校准(此时应用对应的标志位来判断此步过程是否完成,如果完成再执行下一步) | 使能ADC1_CH16对应的内部温度传感器 | 使能ADCx外设 | ADCx_CHy通道数值读取函数 | 配置ADCx_CHy(ADCx对应的y通道)的转换序号与转换周期 | 启动ADCx_CHy继续转换(此时应用对应标志位判断ADCx外设所有通道是否转换完成) | 读取ADCx_CHy通道的数字量的值 | ADCx_CHy通道读取的数据的后期处理函数 | 对n次读取的数据进行取平均值处理 | 温度与电压数字量之间的转换函数 | 用温度与电压数字量之间的对应关系进行转换 | $ Y3 h/ _# q3 l5 E1 t2 p
内部温度传感器实验代码解析ADC初始化代码
! o3 R- V+ l( x/ E/ T1 H$ m8 X2 x+ a* C8 g$ M* k9 V
- % `' F6 {5 _0 Y6 J: n- @/ K
- void ADC_InitConfig() F8 ]- U/ j( Z |- p! V @: O
- { + j8 e6 H7 C5 C( L
- ADC_InitTypeDef ADC_InitStructure; ( \2 B3 l6 w! {) t2 }
- 7 l+ T. }, n( g2 t' m' J2 \
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
, l- i3 X' P7 G$ a' D; x0 P -
2 N( T9 l* d: G$ ~0 l - ADC_DeInit(ADC1); ) m, u1 B% z8 R
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); 6 R, o9 M( }8 w
- - O8 `/ P# C$ @& _$ A0 J4 z
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; 8 K! x4 @% z- Y4 ^
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
. `7 T1 }9 b8 \5 R- Z - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
; b1 t1 U# k" m s6 p - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
" i# C8 a: ?$ U - ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度 # a2 H% P7 A1 J" w `8 N- w+ B1 v! M6 Z" u
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; ) h2 Q1 T* v* n. {8 y1 E
- ADC_Init(ADC1,&ADC_InitStructure);
1 e( [: d B6 }! v* h. P$ P& g7 T -
" q- p9 t& p' ]# J- a8 y& C. G - ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器 1 c2 g& ]" l; Z1 ~2 o# w
-
, Q: u4 }* q9 ] - ADC_Cmd(ADC1,ENABLE); // 使能ADC1 \, B3 R- P3 S% c
-
C2 j3 T. T9 b4 m5 V - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 ) }: [/ f: C+ x8 z, ]) n* K
- while(ADC_GetResetCalibrationStatus(ADC1));
$ s" |7 c4 h+ N( k5 D7 [, n - 4 q9 J8 q4 r% R5 R
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
4 t" s X6 ^* X( ?4 e - while(ADC_GetCalibrationStatus(ADC1)); + ?" W9 \; D) g5 K9 p* @9 \1 `& i
- 9 Y% Y" w0 q/ d& r! f, w8 T$ [
- delay_init();
, I( Z5 [* C4 s' d4 U) u1 `9 M/ _ - }
复制代码 7 J8 h2 c, U& f4 J
我们应该注意到:ADC1_CH16连接着内部温度传感器,不用初始化具体的GPIO口引脚,只需要将寄存器的相应位使能即可:
! M9 n4 L L, W0 G, H0 ^
2 y; s [* f' H0 b
我们有些同学在用如下“等待”代码的时候有些疑问:
4 |! p" R; C/ l. D: ~
3 W8 l; n' J. Y2 K- N& @- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 / P. Z% j& V& t* {) O* q. S* b
- while(ADC_GetResetCalibrationStatus(ADC1)); 1 k# Z% W, j! l# J5 x$ E: V
- & {1 t' x9 B6 k; M, A: R$ g
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
( q! I. e+ x3 S1 {4 ` - while(ADC_GetCalibrationStatus(ADC1));
复制代码 7 W# `0 G6 A9 f. I! }3 K! ?
我们用while循环为ADC外设提供执行任务所需的等待时间,但是我们一对比如下while代码,就有点懵了:
4 b6 u2 o3 f1 z8 M+ A- ?% o
- 3 x/ t5 s+ ?0 x1 R4 v
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 & T8 n, U6 I h) ?# t9 u3 w
-
" [5 f4 [; z. o( @ - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 ; c" L1 D; C/ V( W1 K i8 M
# _2 l8 A- B) Y( b) |
0 v' _2 E T! q0 K* | A
在while循环中,应该“取非”?这个是个让人不解的问题。 我们此时应该看寄存器,看寄存器中位与状态的对应关系: ADC1复位校准功能与ADC1执行校准功能分别对应“ADC控制寄存器 2(ADC_CR2)”对应的如下两个位:
) S0 O! c* B1 |2 A; m- P6 u
' i/ I3 x% m. U" X4 `
) p W8 I% D* _( b9 C
我们看到上图,可以得到如下结论: ( M [$ y2 y% ~" F. `' Z% m$ C
功能 | 状态 | 位标志 | 检验ADC校准功能复位状态(完成/进行中) | 复位执行中 | 1(SET) | 复位完成(复位指令执行完毕) | 0(RESET) | 检验执行ADC校准功能的状态(完成/进行中) | 正在开始执行ADC校准功能 | 1(SET) | ADC校准功能执行完毕 | 0(RESET) |
% n4 o' @! u2 P& N* ^) q' ~此外,ADC_SR状态寄存器中的标志位EOC位代表着“ADC转换工作是否结束”:
功能 | 状态 | 位标志 | 查看ADC转换是否结束 | ADC转换结束 | 1(SET) | ADC转换完成 | 0(RESET) |
8 Z% x0 O/ ?: w5 A, O+ B) cDC转换函数
8 B% k# F+ B7 q1 D4 |( B
8 Z. N" L! R" v
8 M$ X) k7 L" K% p; v5 p9 h- u16 ADC_GetValue()
: U( _- b- ~5 z. w - { : B3 p* y& q3 D% _% {9 l! b
- ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期
1 b4 K! t l" {: R -
1 D+ k3 o& P( H- `+ B- w5 V - ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
5 O+ q0 {! S4 G" s- X - ( f v Z/ j7 L! O: h b8 i
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 * W, i6 a$ S7 ?2 \! v
-
( q" {% e+ O$ {: ?/ Q - return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 6 A+ o; W% M6 L0 _0 U3 l2 p) H) b0 @
- }
复制代码
! ]9 x. v) {7 _* h; T( s, v' a1 m7 u9 a% G5 c3 K2 g0 [; X
注意:我们一定要在读取ADC通道转换值得函数中去执行:
3 L k) O% }: q$ b/ @
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
C9 h: j2 M) n5 g) X) w2 n -
) b4 S$ r6 }1 \8 l9 } - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 : g- J( N7 B$ Q6 |% [- v
我们初始化时只想初始化ADCx设备的属性,而函数“ADC_SoftwareStartConvCmd”得功能是根据ADCx各个引脚的属性启动ADCx外设进行转换操作。显然,初始化时不应进行获取转换值得操作。 " \- {9 Y J0 y0 y
2 e$ K+ F M* Y, |' n. z' k
多次读取取平均函数+ ]+ a1 I S) O3 P
% l! b' {# K' ?$ M; Q& ^
- ! h' V* }; o4 L" W
- //获取通道ch的转换值
r9 @9 ^ t5 v5 t# s - //取times次,然后平均
! e% |1 J) @5 \% F - u16 T_Get_Adc_Average(u8 ch,u8 times)
/ S: G* l) R* m) h o2 Q - { ) j: j+ u' W3 ~- T# C
- u32 temp_val=0; + H1 a$ ]4 k x1 q% D
- u8 t; 1 D1 G; g7 _9 Q" s1 \3 `: K
- for(t=0;t<times;t++)
8 [, c/ b& N( y4 { `7 |. R- h - {
5 \* a' Y8 _/ |3 \- S2 E. D - temp_val+=T_Get_Adc(ch);
& g% ?7 ~ h( w7 P! q7 o" z$ }5 E - delay_ms(5);
3 P d% p i6 g& R - } ) d: E# u, @5 w" @
- return temp_val/times; 8 R( ^! H4 r) x7 n
- }
复制代码
4 }4 ]6 I2 ^; U2 G3 A 4 n. j1 g e w/ T% S! [
ADC转换的数字量转换为所需温度的函数
5 k# }& }5 F% ]3 P* n' Y1 ^) h' z* H, H( o7 ]
, M/ F: R \# t; c- T- 9 U9 a; [- Y. g0 H
- //得到温度值
8 w7 Q) K; E" B: k+ O& \: k" M - //返回值:温度值(扩大了100倍,单位:℃.) : T- j/ l" Y' {! N
- short Get_Temprate(void) //获取内部温度传感器温度值
7 S/ w( w w/ V. M. e1 k" C - { - E8 R1 H- w& c3 J
- u32 adcx;
: x& F" | D, A) M6 ?3 c) c' V - short result;
% i0 g1 C: w$ G - double temperate; : m3 d2 z5 d: j* Z( f% p7 ^
- adcx=T_Get_Adc_Average(ADC_Channel_16,20); //读取通道16,20次取平均 6 G3 S. {6 ?+ }0 \- f
- temperate=(float)adcx*(3.3/4096); //电压值
- h# ]2 ?+ v" u3 i" R. T3 x - temperate=(1.43-temperate)/0.0043+25; //转换为温度值 ; Z3 M1 Q, t" Y+ @& H( l% }
- result=temperate*=100; //扩大100倍.
- f1 f9 l2 | l) u& e9 f - return result; & N, `. @) u3 C
- } }! I# b8 I: T/ j8 l0 A5 l/ P- |1 l+ `
-
复制代码 ( R" M% a b5 k2 ]& i
5 ^+ l+ g9 r( B. W( }% B; G' p5 Q
8 O0 ]& {1 [% g# ]3 p/ v8 \
总体代码示例TempSensor.c& W$ Q! r+ G" m; U
1 S& W" [) R4 t7 e/ i: Q: \- S0 w. [' W3 Q6 f1 w" O
- #include "TempSensor.h" + c" V0 `2 o: ~5 r
- #include "stm32f10x.h"
$ e+ l8 L3 S5 B7 Y' h - #include "delay.h"
7 Z; y5 T2 x/ n* N" E4 k6 h -
; S! C9 D2 J8 K1 n" ` - void ADC_InitConfig() " {, \/ Z8 T& u+ F. y
- { 9 H% Z8 I/ v, ~
- ADC_InitTypeDef ADC_InitStructure;
. T4 t- [5 v* D" u2 x0 w \ -
% g. s* H1 i3 u1 O. I! p4 A - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 8 N$ @; F' v# N# K6 U, T
-
0 j9 o! ?' \# _0 @9 t - ADC_DeInit(ADC1); 6 R: `; z Z4 }7 J, L' d
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); 6 U2 t7 g, `/ R& Q; Q
- ( W) E- _7 e+ \4 _
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
8 Q6 ~6 ~4 S) K- C* Q - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; ) r% B( L3 c) m f" ]: F
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ' n9 o* z- O, N* f0 f3 o. F; x5 L; ^
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
( S; O* J4 _, U+ { - ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度
: X2 O6 Y: D4 t# ^* ~/ J - ADC_InitStructure.ADC_ScanConvMode = DISABLE; ; k; ?3 z$ ?' t( u0 I
- ADC_Init(ADC1,&ADC_InitStructure); " ?: g" ~5 W" W4 r+ A
- 8 n$ Y3 e6 o9 {
- ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器
- u9 o) l- @( x; A' d, Q3 ~- i - / N3 S, p9 K" @8 `
- ADC_Cmd(ADC1,ENABLE); // 使能ADC1
8 f, P% j1 r( O; S0 ~2 P. S -
' j$ t6 c0 ^+ r" ]1 x. v& c - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位
# J% V/ x1 Z+ w' c. [ - while(ADC_GetResetCalibrationStatus(ADC1)); ( P7 W$ y9 `7 F; h M' Z
- % _ u, {# `/ H; W
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
# }4 i' z) E" R8 ^ - while(ADC_GetCalibrationStatus(ADC1)); ' f. @( K" b: u+ I# f
- E* `& w' {8 g, `# d, |- m- D9 N
- delay_init();
+ w3 S) V1 b! B' @ - } 4 ~4 I5 Z, w) P# I7 t" |7 N6 I
-
. p& {+ t; u& b, M( J9 N2 ^ - u16 ADC_GetValue()
* Z: r0 C" I$ \+ X+ p - { : c1 ^" U1 @! Y9 }
- ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期
1 Q; z( n& V+ u" w - 2 D0 ?2 A2 @- U1 r' z+ `4 w. q N
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
3 k! }" T3 O5 E' e" z; h6 Y -
. ~1 B0 ?* e" X- r! p, C - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 7 ~# X: u% H4 s7 e
- ~# d, a% x# @( ~3 Z" m7 D
- return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 1 C' ]0 Z9 j4 v& S7 K1 L! S+ Q
- } ( w$ _. y5 b# `. ?
- 6 ~4 s2 Q' N( T3 a2 M
- u16 ADC_GetAverageValue()
4 R2 `0 ]$ K: z( O% [ - { ( s" T; E. d z. P, g9 Q
- u8 i = 0; , [/ b6 f4 Z0 Q- G
- u16 temp = 0;
7 h& D E. A! ` -
5 z, r: D1 i/ } a& f - for(;i<5;i++)
2 d( _$ Z' D; w$ i - { ' A" i4 u8 H1 o/ f
- temp += ADC_GetValue();
% B" V7 l- R; @- ~% ]( b2 ] - delay_ms(5);
. X. a- Z) i' | - } 1 B9 e. A9 x2 Y# ?4 I' Z# o
- return temp/5; 8 Q* P, e2 L l, r
- } , d; D% N+ i8 c" I) h
- ; k* g& z" j9 Y/ A
- u16 DigitalValueConversion() ) F1 |3 d" k7 y, H, ?, _
- { & f# T( k# S4 `. o% T
- float temp = ADC_GetAverageValue(); 2 @6 _0 y: Q. t& S& g
- return ((1.43-3.3*(temp/4096))/0.043+25)*100; ' E, a. g# i" E+ _% l6 D& \5 r
- }
复制代码
5 t; ~7 T1 P( q x$ N
. L, M! [, G8 ~+ Z: H( s* e$ PTempSensor.h' F4 J2 A/ S# [& _3 q) a' K" ~
; X# Z0 [9 t: i6 k
i; ]+ v/ M9 C8 H9 I- #ifndef _TEMPSENSOR_H 1 I4 B% u7 W) M$ x7 G
- #define _TEMPSENSOR_H 4 o) R# L7 g7 \/ [6 [9 f6 S
-
0 a4 a/ i4 U: ~ - #include "sys.h"
8 \" W& I H1 S/ v4 Q - 3 U4 P, W; B" j! H% }0 ~/ z/ @3 [
- void ADC_InitConfig(); * P# V3 ]( D; L n
- u16 ADC_GetValue();
' k5 j# U' D8 ~; S - u16 ADC_GetAverageValue(); . E- A8 r* P( d; k
- u16 DigitalValueConversion(); 1 ]8 C6 K8 b! i4 C0 K: a
- * r$ F2 l% j5 S, Z3 {) B0 O
- #endif
复制代码 # J$ B# N7 C% J1 d7 I) ^. z
3 {0 {! y& a7 R0 hMain.c8 P. j. d) Y- p0 Z5 o
1 J7 K" N) T" l0 V" R; \- #include "TempSensor.h"
8 J7 A8 {% g9 d$ V( } - #include "stm32f10x.h" 6 N5 j K5 y% l) |7 D9 h. t
- #include "usart.h"
, t1 w( }2 i2 a+ ~# Z4 `0 p; l- p - #include "delay.h" ; c7 x9 v. m2 w7 N& S- M
- #include "lcd.h" x0 z- t) |: E( F" C# ^
- 0 g! _4 L$ q8 s2 u
- int main() 7 X; R/ T* u& ]
- { J2 q3 d# C1 p/ h) q Z
- u16 temp = 0;
+ @6 o! X' r6 s+ \( k8 d0 K3 Q - 9 n0 l/ o `; L) d b! S/ X
- ADC_InitConfig(); ( t: o6 C0 h) T# \
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
7 R. I2 H" L% B, z0 y9 H - uart_init(115200);
" B2 }/ G5 L& r6 I, D - delay_init();
: N6 Q/ Y5 {% o$ b5 ~ - LCD_Init();
) \3 R* q" U9 [, g - LCD_Clear(BLUE); 3 `" R/ m9 E. ]" y3 J* w
-
& m1 R' {% `/ F; D- h1 G- h) P - temp = DigitalValueConversion();
) D2 B/ u0 y8 v7 l. D: x1 W -
0 N( E. O' G: u: p& ]" K - POINT_COLOR=RED;//设置字体为红色 % b7 c' C$ l. {% f* ^
- LCD_ShowString(30,50,200,16,16,"WarShip STM32");
* Q+ Q. f: t1 [2 U2 Q3 i6 u - LCD_ShowString(30,70,200,16,16,"Temperature TEST"); 9 a; ~+ @- ?2 q* l6 j
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); / y# ]/ j$ D- B( L I7 j( k9 K
- LCD_ShowString(30,110,200,16,16,"2015/1/14");
& T( ?! T( q) p8 E2 w& [0 E - LCD_ShowString(30,140,200,16,16,"TEMPERATE: 00.00C");
! l- w, S! `. R: Q) i - . W0 m, r5 z E8 E0 O/ j3 j6 a5 b' y
- while(1)
3 o/ z2 K4 }5 Z - {
% _$ f: i$ m$ a- a1 W- w3 F( h) a - temp = DigitalValueConversion();
0 L; Y# N- j" Y) @* W: f$ I! V* S& ^ - LCD_ShowNum(30+11*8,140,temp/100,2,16);
1 u* O8 F4 _' k; Z6 w" W - LCD_ShowNum(30+14*8,140,temp%100,2,16); # O7 I# Z5 c5 |6 m3 Y
- delay_ms(150); ! W: z5 D, t1 P' N2 Z i. R! X! b
- } ! h( C" R: k+ O& M2 g4 N6 P$ @5 \
- }
复制代码 ) m. k6 P. v; x6 L( E( ?
- `1 X5 b6 K, |
程序运行结果
" \ W; }) S# ]$ R4 o K9 r- }8 q
8 l, o( N1 w( A" o
! M) Q* h6 e! f( @ r
1 i3 t. }/ l: s8 B8 `+ N* } |