内部温度传感器简介测量的温度位置 内部温度传感器集成在芯片中,测量的是芯片的温度。
1 ^- C H) r5 q/ l 如何测量对应位置的温度?
2 q- ^5 M3 k6 f. L
! g; ]3 ^! @7 q; _$ a
温度传感器与ADC1_CH16相连,另外ADC1_CH17是与内部参照电压VREF+相连,因此我们可以通过ADC1的第16路通道测量芯片温度实时对应的电压转换得来的数字量,也可以通过ADC1的第17路通道测量内部参照电压对应的数字量。 6 m* w6 |4 P9 C3 O* g0 m
" b% n" L8 X5 E9 U
我们知道STM32的ADC转换DATA是12Bits的,因此输入电压(小于3.3V大于0V)ADC转换为数字量的值为“大于0小于4096”。
" e B; V" [% a+ R2 `7 @$ R
5 t d% N& e0 e& [& f
我们由“T-V关系图”,“V的数字量”和“ADC量程”,可以得知“此时的温度”。 , i6 s9 d2 d/ n
; a2 b1 V o8 q4 S, ~* [
内部传感器配置注意事项
3 n3 M. [6 u4 c$ z, j0 u- N+ S( m/ W3 s9 E# q
① 读取内部温度传感器数据的周期应大于17.1us; ② 内部温度传感器的温度测量误差约为1.5℃,因此内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温 度,应该使用一个外置的温度传感器。
6 l- Y k* r4 z( X7 w; T
K7 S1 L3 a; h( a3 o w1 U0 y# ^! [
内部温度传感器配置流程
. s7 s" f8 T4 O: j
: w5 Y4 N5 ^ m, `) }所属函数位置 | 执行步骤 | 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次读取的数据进行取平均值处理 | 温度与电压数字量之间的转换函数 | 用温度与电压数字量之间的对应关系进行转换 |
. q0 j- ^# O* C3 v5 ^6 q内部温度传感器实验代码解析ADC初始化代码0 m; o4 Y" R8 ?
+ l: ^* @0 o: n1 Y
5 k* J$ I8 k3 D$ x/ l- void ADC_InitConfig()
1 A9 [0 a2 M8 C' t$ ~ - {
' Q5 o& E) Y& a A' c - ADC_InitTypeDef ADC_InitStructure; : E9 U0 z- e) H" M
-
/ C3 d" I; s1 c! ^ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
* Q& q! I. I! i1 p4 ] - 1 L+ L O4 Y/ ?9 G/ K! N: }7 _; q$ r
- ADC_DeInit(ADC1);
' H, N T& d0 d5 r y9 c* ], ` - RCC_ADCCLKConfig(RCC_PCLK2_Div6); . M# ~ w. _5 y; @8 ]* L
- ; D6 j( a* ^3 _5 G& x
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; * g; [) M. k- w' t
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; , j9 v$ N4 ~. Y' R% Q7 A
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 7 I1 s' N4 P B( M4 y' B
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; $ N c+ [" T" q" A" v' u( }8 l
- ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度 / r$ v, ?5 n- y/ ~3 }" v4 r
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; , [# p$ n7 ?! I) D/ l
- ADC_Init(ADC1,&ADC_InitStructure); % e$ x, K9 g6 }. }& `2 K, p
-
' v" I. q- A. p' Q& E - ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器
. G# V) i! M. ~5 m -
( _! w, P7 d% B& `* L; w4 G* ~' n - ADC_Cmd(ADC1,ENABLE); // 使能ADC1 . |2 y$ E& ^4 A. z' P L# n
-
$ u& f; ?% {' Q5 p L1 u6 z/ [ - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 ! | X: H" i% V) H& E, B6 c
- while(ADC_GetResetCalibrationStatus(ADC1)); ( s' {% B. U; E- K& |1 Z. s9 o
-
- r# V% C' O8 g6 R# \- `6 L5 Y9 K - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
0 V3 S' a5 @1 Z5 m - while(ADC_GetCalibrationStatus(ADC1)); , S! [* b6 H. |5 b; [3 c: o
- 8 J( B% q* o5 \+ D: V
- delay_init(); 3 D- B; L* u2 R! N
- }
复制代码
! @. s- {& r" q& k$ }* w我们应该注意到:ADC1_CH16连接着内部温度传感器,不用初始化具体的GPIO口引脚,只需要将寄存器的相应位使能即可:
% w+ p3 b3 u0 w r, h, x
" R! }1 L7 N7 ~, l+ n" x+ l
我们有些同学在用如下“等待”代码的时候有些疑问: " G4 l2 C3 v4 Q( C
- . L6 Z9 J1 l. d4 q) z$ I' y
- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 1 Y3 ?; A$ T* k5 {
- while(ADC_GetResetCalibrationStatus(ADC1)); + Y7 c( v% U! Z3 {6 [8 Z% F# F
-
- ~. W L# z$ O# l2 [ - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
0 B' w, i9 }( f+ ` - while(ADC_GetCalibrationStatus(ADC1));
复制代码 / k! @0 @+ h1 x! p, G
我们用while循环为ADC外设提供执行任务所需的等待时间,但是我们一对比如下while代码,就有点懵了: 6 |5 d1 D t7 q4 ?" Y( q
- + @& R5 X! u+ ]2 i5 O
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 + r. I; l. _% o2 ]
-
! g5 _) J1 z) N0 b( d, E! A - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码
1 D+ Y2 O0 ?+ `( q; ] @9 B9 k! M1 O& v" O% y/ s J
3 C' R. K- c5 I' S ~& _2 }6 ^在while循环中,应该“取非”?这个是个让人不解的问题。 我们此时应该看寄存器,看寄存器中位与状态的对应关系: ADC1复位校准功能与ADC1执行校准功能分别对应“ADC控制寄存器 2(ADC_CR2)”对应的如下两个位:
* {1 b# h% _& k% Z6 |' }/ \& ~
) j& i4 `7 G z0 ^! L
2 u: E+ p0 }2 X! O
我们看到上图,可以得到如下结论:
: P+ E( ]- B5 ]7 z' N3 a: R
功能 | 状态 | 位标志 | 检验ADC校准功能复位状态(完成/进行中) | 复位执行中 | 1(SET) | 复位完成(复位指令执行完毕) | 0(RESET) | 检验执行ADC校准功能的状态(完成/进行中) | 正在开始执行ADC校准功能 | 1(SET) | ADC校准功能执行完毕 | 0(RESET) | * }. x0 w: A4 j7 ?; O* S
此外,ADC_SR状态寄存器中的标志位EOC位代表着“ADC转换工作是否结束”:
功能 | 状态 | 位标志 | 查看ADC转换是否结束 | ADC转换结束 | 1(SET) | ADC转换完成 | 0(RESET) | ' v5 Q* Y6 b; a
DC转换函数
0 D4 I1 a2 J- Y. H6 X: w
- d! C, r2 D I% C; I
, w, c' |3 p+ h/ r2 i! u _" U- u16 ADC_GetValue()
8 M* ^! \ Y7 _) f# l: t - {
% C; |" W! b% p6 ^9 O - ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期
5 r( {3 @8 I: H# Z* g% Y -
8 g! h, l. y8 I; c - ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
% y6 c* J! [) \2 w) }8 a -
- `9 F; X2 V; V - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 : S4 P) }( W1 C0 s7 F) ]0 u+ w
- & U: q( U' ~& b$ `
- return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 2 I5 ?) Z6 N5 U
- }
复制代码 4 W! D& t! R6 d
$ s% ^ u4 w& u4 }' }5 j
注意:我们一定要在读取ADC通道转换值得函数中去执行: / @: J$ g! ^% a- {; I" H( ]7 s
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 8 x* m- U& A: H" F4 Q- ]
- 3 {" j$ b" s/ `
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 1 n3 Y1 o) v V+ H$ t. w6 V
我们初始化时只想初始化ADCx设备的属性,而函数“ADC_SoftwareStartConvCmd”得功能是根据ADCx各个引脚的属性启动ADCx外设进行转换操作。显然,初始化时不应进行获取转换值得操作。 " E4 E7 t8 v. Y2 T
9 b' x* x, g( } 多次读取取平均函数) H9 \2 } B2 y1 y! _
2 {9 p$ A5 Q. i
) x% S" ^* \9 {8 [" [- //获取通道ch的转换值 # w/ B1 J8 D" w) L
- //取times次,然后平均
. H0 Y% m* k2 _! B/ s - u16 T_Get_Adc_Average(u8 ch,u8 times)
) Q* l1 `- F1 ~7 E - {
7 z6 o D, r0 N8 s5 h7 |3 G - u32 temp_val=0; 2 }' I, Q4 B, |
- u8 t;
! O+ u% B, q& o, k; W- m* E& K) q - for(t=0;t<times;t++) 0 k" }0 T% x" q- V
- { t2 `; l7 _5 O8 E- H. f) x
- temp_val+=T_Get_Adc(ch);
7 H6 N Y$ ^" z2 I$ n# m$ ~ - delay_ms(5);
: l* {; Y* i$ t% f - } a0 ^8 k/ N/ b. ^
- return temp_val/times;
0 v/ g: r" H$ q - }
复制代码
( n5 I# u$ g+ X L- x
& Q; {$ C* H/ `6 V5 g: P% VADC转换的数字量转换为所需温度的函数
- z% _! ^! ^: ]+ A# C9 r4 `) @6 U4 w
/ B$ p- r4 M: V0 J7 k) w+ Z" \" L/ I! f+ S* B5 X
- " y' B2 T. d8 M+ d5 M* ^0 l6 `" c
- //得到温度值
- `+ e" o B' U8 n6 p3 ^6 h - //返回值:温度值(扩大了100倍,单位:℃.) 9 x( I; \. U. c5 Q
- short Get_Temprate(void) //获取内部温度传感器温度值 v" q! ^% L8 `4 m
- {
7 {; u: j! Y" U, @6 e, l5 Y - u32 adcx;
# V5 ~4 ]8 c6 M% P/ T- f a - short result; 3 @+ k( `# g/ ^4 ]- |- @
- double temperate; " X8 s0 m B- H
- adcx=T_Get_Adc_Average(ADC_Channel_16,20); //读取通道16,20次取平均
7 X8 ]- H! Y; X4 ^; v, _ - temperate=(float)adcx*(3.3/4096); //电压值 : J4 j* g" B$ a/ w [ H: k6 b
- temperate=(1.43-temperate)/0.0043+25; //转换为温度值
+ F3 j5 N6 f, C$ o/ I5 j+ }% v! c - result=temperate*=100; //扩大100倍.
) W' v$ h9 v9 D. E* o - return result;
4 @+ l& t# ~7 _# D+ S( o- V - }9 T6 T; O' d0 C" v
-
复制代码 8 Y' v4 u- k( C: s# S, v1 e
+ e# v; |* m; V; R0 P8 g% P4 n
9 [4 k- F" `$ y7 u% g总体代码示例TempSensor.c+ s9 L: y3 u+ U# E5 \
; k0 M9 Y7 f2 D% M
3 J5 N/ z# _/ K& t; o6 U0 i* |- #include "TempSensor.h"
9 q* a2 {9 E& ]! j: ^6 U - #include "stm32f10x.h" 7 |8 A4 U, r! i0 Q. n* f2 S% C# U
- #include "delay.h" 9 j! { N: N/ Z1 R) a
- * f: J1 v) q' @/ B5 \' T, ]2 w
- void ADC_InitConfig() . s& l5 g, ]* f& u
- { ( Q0 d- B: H1 h4 N% l
- ADC_InitTypeDef ADC_InitStructure; ! k6 K4 [3 a) j$ ?* p. r! K% H
-
3 A2 H( c* l( i8 Z' L4 V - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 6 R6 c% b" s4 U6 J9 k# f
-
1 `# U2 r" W5 v2 _. B7 p) [- z - ADC_DeInit(ADC1); + _- j' J1 f7 ~. U- U3 P3 y
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);
& X' X: w3 s- I: F4 ^1 |7 G0 y -
: P) l+ J( e2 J l2 i6 J - ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; ' r k' F9 S% `5 L
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; ' P/ a' t( s) ]3 g: r/ Y+ K
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; % Y! \$ y1 b& u/ R" k6 o& U8 M
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 9 g' r9 U. O6 \& _
- ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度
) V7 [! u: P3 S0 A7 W# o - ADC_InitStructure.ADC_ScanConvMode = DISABLE;
t, e: z/ ^' l8 z# C - ADC_Init(ADC1,&ADC_InitStructure);
7 a) J* m6 @" R- f2 ^ -
$ z/ _+ z3 A/ G$ A3 s4 r - ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器
0 U3 ^& a& r2 N* I -
+ d' A" Y# t3 k0 a - ADC_Cmd(ADC1,ENABLE); // 使能ADC1 6 t0 N2 r5 } q; y. h
-
& N7 g) a# L2 J _ |4 B - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 5 ~: G$ Q0 ^# n
- while(ADC_GetResetCalibrationStatus(ADC1)); 1 V# ^, O5 p& V3 T3 V
- , D3 Z& f* ^: C1 I, u6 \8 D
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 / k8 [) \2 |; w6 b3 ~' `7 f. |9 M$ c
- while(ADC_GetCalibrationStatus(ADC1)); 3 \7 ~9 p! ]( v, @8 s& p% V
-
7 I- _* K* S% T. y( M% w4 D3 m - delay_init();
: h- ] m+ ~. ^6 S- y - }
2 q0 a1 q: P- X$ Z+ x( @ - ; o% N4 P' n# Y! F1 {, ^0 }
- u16 ADC_GetValue()
' a; \7 t4 y& }3 p- K' H) J - { , d" d* H* U2 w+ [( F, d
- ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期 5 E7 n. `, X. w8 \3 {7 K
- 8 k! z7 F; K0 B8 C, D; W& X
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
* h. U$ {6 H6 \7 n# r& j: u -
: W; l! H* D6 E* X1 ]7 S) g - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
" n/ s3 k! l) N7 t. S8 W( W -
+ g* p! K9 s3 x6 x - return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
2 a+ P3 B# B) h7 l1 v - }
$ I) b E* v, y+ W -
/ l. [4 h# U8 ^2 ^* h, \ - u16 ADC_GetAverageValue()
8 c# y; L$ p4 Y- J1 ]3 d0 w. d - { 9 D0 O. x) v$ o+ e! w: I+ G
- u8 i = 0;
! @' x: z6 A& W* `. L1 u - u16 temp = 0; T# h9 J P) w# Y
- 4 k6 b3 ^7 g* F3 \
- for(;i<5;i++)
u1 L8 ^+ l j/ Y - {
]/ o* _( D3 }/ W - temp += ADC_GetValue(); 2 y1 J6 T5 e6 x, s9 W
- delay_ms(5);
8 V9 M- [3 e) t' ~& P4 R - } ) s+ h, V @, F" l- r
- return temp/5;
$ O3 _4 k X0 N - }
8 ~8 T- M5 c8 s6 }2 ` - " _% J$ g. _* ?" u) ]
- u16 DigitalValueConversion() / K% {( X5 e; a6 n
- { * q% {5 M( _8 C0 z: F" H
- float temp = ADC_GetAverageValue(); * z: ` U4 a2 ?4 |* |$ i
- return ((1.43-3.3*(temp/4096))/0.043+25)*100;
# N& G/ W& j- d% [+ L9 m. @ - }
复制代码 1 y7 @# b7 H, U" x/ l/ ^. K# x
. c* c9 @/ j+ T- m: w0 [5 _TempSensor.h
! r5 h+ O4 F$ a$ Z# T" s$ s% \3 t# K' y( a; F
- 5 \8 d. o+ o7 E- X
- #ifndef _TEMPSENSOR_H % f0 q! b/ i, t* R4 p
- #define _TEMPSENSOR_H
& X/ l' O6 x+ o! q -
. L3 g0 L4 z0 [+ ?: t4 e9 h2 U - #include "sys.h"
% s$ P1 L* m" w* ~ N# z0 ? -
8 w1 v& e. n( S4 A' W$ Y2 v g - void ADC_InitConfig();
8 f( _, s9 q" f# q, Z - u16 ADC_GetValue(); % o/ g! j7 t5 W2 [
- u16 ADC_GetAverageValue();
7 [3 t; j! N* I; \ - u16 DigitalValueConversion();
8 u1 G' l$ G) D3 M( |3 r- T; J -
* m7 h) h5 |+ n0 ~4 x - #endif
复制代码
, `- T) ^7 N V: V6 C' H
Y1 d2 M( ]1 W0 `: e$ h, D# ]! fMain.c: i! @+ S+ A3 f/ i' z
7 l5 J& m% ~ ^3 k! k- #include "TempSensor.h" ' S- D. U4 q! o( \" u( B! ~& ~2 y
- #include "stm32f10x.h"
O' v3 _7 Z# H' B$ T - #include "usart.h" * y6 X3 T6 P0 E+ y
- #include "delay.h"
# U% p- r% G! f" O4 _ - #include "lcd.h" % S; G. G% T2 ^- r* ~/ R% L, h b
-
4 c' e/ v) }- z, u - int main()
! |1 ^# |/ Q1 J! p - {
' a% S( v4 d T* C - u16 temp = 0;
4 `! H: g! G b& u: T' C' j -
+ v% H' h) h0 q) f2 T. I8 a7 s - ADC_InitConfig();
/ Y8 z/ T# ^, j& ?0 e% [ - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Z* |2 z- G3 V' p - uart_init(115200);
, J" k/ i8 T. G# E. t - delay_init();
( R: G! _: k1 l, F. X& t6 ^ - LCD_Init(); 8 l7 a, N2 I7 e2 b1 i( V
- LCD_Clear(BLUE);
, p& l! {9 Q x) e) R -
0 K" L% `" y, \! q+ ?8 F - temp = DigitalValueConversion();
4 @* h' a! X8 q& Q c - 3 X. g3 j; a" ]: c9 a
- POINT_COLOR=RED;//设置字体为红色
+ S. d6 N0 l" {4 z/ s3 |' H" a - LCD_ShowString(30,50,200,16,16,"WarShip STM32");
$ b6 V/ g& T6 h' L: K1 y - LCD_ShowString(30,70,200,16,16,"Temperature TEST"); 7 }' L- m& e; \4 G' G
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
- g! s( L5 e+ `! E - LCD_ShowString(30,110,200,16,16,"2015/1/14"); ' K5 c( D2 @3 [2 q8 f/ c/ B$ P/ b
- LCD_ShowString(30,140,200,16,16,"TEMPERATE: 00.00C");
# C3 v$ f- Z" t) m -
, \0 L1 T/ O: @. k; x - while(1) 3 j8 _4 o$ s% a& d# t
- { 6 E$ T' r2 y9 T; p
- temp = DigitalValueConversion(); 2 b3 A. N1 t5 F g% Q
- LCD_ShowNum(30+11*8,140,temp/100,2,16);
' x% e+ r; t& q - LCD_ShowNum(30+14*8,140,temp%100,2,16);
3 t8 Z8 @" T( ` k - delay_ms(150); \; c, v" C, C5 r, f; \
- } ) u; s! _0 m% w) T* o
- }
复制代码
) j% S: f9 z8 O2 l$ S 2 L7 c0 a! ~9 [# z) @) }
程序运行结果: _ ~; S+ {7 l! w1 X* F
4 I! S! W# A4 L4 c& s* Z
& t' Q: M4 L& X* B; L, [& R/ y
R8 h3 d7 K3 l2 F M/ T" n' k
. J% c' P4 K/ Z S& a3 L' ^ |