|
内部温度传感器简介测量的温度位置 内部温度传感器集成在芯片中,测量的是芯片的温度。 0 M( \% H0 v& ]2 d% e9 \
如何测量对应位置的温度?
0 Z* `: i3 W' H4 Y0 [( s( f
- | i# d" b+ I+ Y& N
温度传感器与ADC1_CH16相连,另外ADC1_CH17是与内部参照电压VREF+相连,因此我们可以通过ADC1的第16路通道测量芯片温度实时对应的电压转换得来的数字量,也可以通过ADC1的第17路通道测量内部参照电压对应的数字量。 " i/ @9 d8 c7 j( H* I' Z
5 b5 W& Q7 B6 s
我们知道STM32的ADC转换DATA是12Bits的,因此输入电压(小于3.3V大于0V)ADC转换为数字量的值为“大于0小于4096”。
( ^$ e' i# C! i2 y2 B1 O
" _2 |2 e% F9 V0 V 我们由“T-V关系图”,“V的数字量”和“ADC量程”,可以得知“此时的温度”。
9 D. y$ {2 W- Z7 i

( e0 _+ B- b# d9 F. q9 W
内部传感器配置注意事项
$ V& y3 R/ L% u# Z' W- T+ v2 R6 V) q
① 读取内部温度传感器数据的周期应大于17.1us; ② 内部温度传感器的温度测量误差约为1.5℃,因此内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温 度,应该使用一个外置的温度传感器。 " K+ ^- O* p1 b# _4 C2 _% G+ w
6 d3 K. [5 l: B/ S8 r1 S
内部温度传感器配置流程
+ \* s) K! Q: J6 y; ~! Y" Z- O& W& `: ?, x
所属函数位置 | 执行步骤 | 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次读取的数据进行取平均值处理 | 温度与电压数字量之间的转换函数 | 用温度与电压数字量之间的对应关系进行转换 |
9 w; M0 x8 {7 c# w2 W% K内部温度传感器实验代码解析ADC初始化代码6 d! Y6 M6 i9 N
1 r: j; Y4 ~: W6 v! R- 0 R/ _4 T/ ], E
- void ADC_InitConfig() ' q8 w# i; s" p$ }% {! K- W5 w
- { / B- O) ]6 _5 g: ?: d" S
- ADC_InitTypeDef ADC_InitStructure;
" Q3 |: s9 m; n8 n! Q+ Y -
9 u7 X' s4 y# ?3 o$ w1 ] [ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
2 ` G* b1 [( s% R: V1 ? - 8 E+ C& R" f5 @9 S; Y1 g6 y _
- ADC_DeInit(ADC1); % z) P/ s) K- k# |4 u
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);
& {$ e2 P4 I+ Y: d; E& x! p' C" o -
0 x# G# ]) Z$ |; k9 ~% U - ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
4 u8 t2 y9 S+ Z/ N! { - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; I8 u9 D7 l" v8 R$ F+ w# \) a
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
6 U4 b3 C% n Z - ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 3 ^2 ]0 q3 e$ n) k
- ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度 3 N: Q' p( c. v% x' y" d
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; / G* g l" ^, U. c5 a* Q' i9 v6 {
- ADC_Init(ADC1,&ADC_InitStructure); ( v/ H; I' r9 i
-
% i% d# |6 t7 a5 D3 G. ` - ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器 ) V3 W% k# ~8 X; o
-
, D$ Y/ J* i0 k* x4 ~( W I - ADC_Cmd(ADC1,ENABLE); // 使能ADC1
% J |0 S! O: G! \) s -
( U7 {5 j8 `1 C2 A- q. g# N* l& K p - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 & j5 ?" H+ |2 {3 z' u
- while(ADC_GetResetCalibrationStatus(ADC1)); ) I4 e" Y* H# c9 G
-
% a' u' W" j6 p( f4 @* ~) H0 s - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 1 r0 |( E9 D) n) X3 G7 ~. T
- while(ADC_GetCalibrationStatus(ADC1)); 3 H7 _8 h. a2 T( X) J) o5 F! o
-
' ^; i: z+ K6 X9 G$ p - delay_init();
0 M& f5 U5 s1 j3 ~* W& s - }
复制代码 . N, i' g% l, F
我们应该注意到:ADC1_CH16连接着内部温度传感器,不用初始化具体的GPIO口引脚,只需要将寄存器的相应位使能即可:
4 w; }6 q1 [# y: p! ]2 Z
1 t1 N" x2 e, A+ D3 u( O
我们有些同学在用如下“等待”代码的时候有些疑问: / \# }9 f& {- r \. ^& t9 B9 ~9 r
- 8 m; {9 c8 ~6 P: |
- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 3 p- E) I! q4 P/ I0 a7 O! `
- while(ADC_GetResetCalibrationStatus(ADC1)); 2 E) c4 O4 C8 V& |
- % F7 ]* y. X5 r' Q1 j
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能
! X- G# b; L1 x) P. Z9 V - while(ADC_GetCalibrationStatus(ADC1));
复制代码
- i5 y( ?. I9 M+ P7 o! k0 H* x我们用while循环为ADC外设提供执行任务所需的等待时间,但是我们一对比如下while代码,就有点懵了: 9 x+ _, I U" U9 T
- 9 @6 m/ M- _% e0 p
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 8 I. Y& U7 j7 N* {/ f# C7 _
- ; Z8 L7 Q8 |4 i5 T! m
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 j7 W5 ^) J# b( T3 a1 e! S
! \8 t7 A" M3 @& V/ ]2 k7 e
3 _$ A$ Y7 G! A+ K+ R# x# Z0 C- g
在while循环中,应该“取非”?这个是个让人不解的问题。 我们此时应该看寄存器,看寄存器中位与状态的对应关系: ADC1复位校准功能与ADC1执行校准功能分别对应“ADC控制寄存器 2(ADC_CR2)”对应的如下两个位: 3 U0 G. O5 X' c. E
/ w! e: q. V" E% {) D
4 _) h2 M! U3 n7 v4 f9 W
我们看到上图,可以得到如下结论: ; b$ w( [2 t8 Y& P9 p5 S* ~) K
功能 | 状态 | 位标志 | 检验ADC校准功能复位状态(完成/进行中) | 复位执行中 | 1(SET) | 复位完成(复位指令执行完毕) | 0(RESET) | 检验执行ADC校准功能的状态(完成/进行中) | 正在开始执行ADC校准功能 | 1(SET) | ADC校准功能执行完毕 | 0(RESET) | - v9 d$ ^" ]) s4 j
此外,ADC_SR状态寄存器中的标志位EOC位代表着“ADC转换工作是否结束”:
功能 | 状态 | 位标志 | 查看ADC转换是否结束 | ADC转换结束 | 1(SET) | ADC转换完成 | 0(RESET) |
5 V% W6 R4 ^* c) ^1 QDC转换函数' B' Y1 C) C: S8 O7 e y9 }
: X) b$ J V' f" B) X1 i0 ~
2 i2 ~ [+ T+ }, r. C- u16 ADC_GetValue() I7 S0 N) d5 N% s. F- h D
- {
: G6 k8 z% ~3 H7 R; J$ ~9 [: { - ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期 : a0 d6 T, t3 z0 J9 v
-
E; C2 x" r; L2 q# N8 q( J( I - ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 0 j* U% D" a$ i/ n# K& H0 }
-
: z3 k: P+ z# d" n5 o+ y - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
$ s; m+ U" @4 t - 2 {6 d; o4 N4 R/ z# n T
- return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
8 F' ]0 ]" h& |, h* [0 a - }
复制代码
1 W0 F7 S+ b9 Y. k" F
2 N3 y" n) E, S3 A+ C; c8 v
注意:我们一定要在读取ADC通道转换值得函数中去执行: 5 T9 v$ _! G% n
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 ) B6 Z2 i& F( ]7 z
- & H6 C! m7 T1 P% q+ u1 Y
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 0 a+ M2 f: t8 b. t! O E5 D% Y) p
我们初始化时只想初始化ADCx设备的属性,而函数“ADC_SoftwareStartConvCmd”得功能是根据ADCx各个引脚的属性启动ADCx外设进行转换操作。显然,初始化时不应进行获取转换值得操作。 + b$ T5 E4 g+ Z7 x1 p( c
9 N4 \" D6 J) F4 \5 P* [3 I# w 多次读取取平均函数7 v$ D9 n3 Q4 N V! d# d
9 ]! T: A( z9 A+ L7 ~! A" x
, H. ?) N+ H' _, p- //获取通道ch的转换值 + Q+ g1 x& k% |; M
- //取times次,然后平均 $ e0 G; E: v/ h. s0 w1 m
- u16 T_Get_Adc_Average(u8 ch,u8 times) 1 \ v& N* j) S
- { ) L2 a, R0 D) C
- u32 temp_val=0;
& ~4 T# d7 {9 U$ g) g - u8 t;
/ B$ J0 @, O; Q& h - for(t=0;t<times;t++) 4 E5 V/ H5 i3 b* g' H1 U7 ?
- {
: J b- y5 A# k3 q$ C+ {0 \ - temp_val+=T_Get_Adc(ch); * G8 L6 _+ N: s8 o/ A
- delay_ms(5); / O8 x% U1 U2 e7 c2 v! |: d1 R2 s# C1 l
- }
: X# p5 N4 x4 O- ? x* I - return temp_val/times;
3 {: B2 r7 p; m* o( Q# {+ W k - }
复制代码
0 }4 z* Y) [& z) B: W 6 Q5 c1 A& B! ^& t8 }* t
ADC转换的数字量转换为所需温度的函数0 j# o* _; k5 u6 {# u8 [. V
/ x7 w& q9 z* s- A1 ^# b
. d4 [4 Y' p1 i/ k6 B" X; D
- / o2 d: w; o0 E( u8 a" }
- //得到温度值 / W' ]. s" h# n+ s( |" Z, Q4 g/ r
- //返回值:温度值(扩大了100倍,单位:℃.) 9 b7 c$ r; a6 G6 K9 I
- short Get_Temprate(void) //获取内部温度传感器温度值 , ?' b; M3 k1 u D
- { 4 s* C: x- B$ J
- u32 adcx; ( {! Y' j, |5 F- \2 P1 O X
- short result; 6 i# ~+ A- G7 a9 k8 X P; \ I
- double temperate; 2 t6 v9 U6 O% R1 O1 {# @0 R
- adcx=T_Get_Adc_Average(ADC_Channel_16,20); //读取通道16,20次取平均 ; ?- h: Q; q5 K9 W- y
- temperate=(float)adcx*(3.3/4096); //电压值 , m! @7 ^$ M3 ` w; L
- temperate=(1.43-temperate)/0.0043+25; //转换为温度值 5 m2 ~( t; H, a) X6 F, T( r
- result=temperate*=100; //扩大100倍. ' b. G; a1 p) Q/ H' W5 Y1 D% C D
- return result;
* e8 n% T# r( P2 ~7 c3 { - }
% Z9 u! ~" G4 M- |4 h -
复制代码 3 i9 H9 `( G8 s. q+ V y! h
; ~1 S1 e& Y" ?
7 H" Q4 F7 u. p6 q3 r$ ?
总体代码示例TempSensor.c2 Z' ~+ ^- p8 h; U; K, s5 P
4 g3 w1 f) }3 M' m3 n
' G* `' {% |3 m4 u( h- #include "TempSensor.h"
, \3 d2 [/ z* |5 p, U - #include "stm32f10x.h" , _- k0 p6 b1 D
- #include "delay.h" & k# S; ?+ {5 I7 E1 V
- + `$ n6 x% Y3 G
- void ADC_InitConfig()
/ b6 ^3 H8 H1 U' d, m5 L - { + e: n+ H* C9 e2 }9 H& x
- ADC_InitTypeDef ADC_InitStructure;
! O% i. U9 ]: e- S6 q+ s% ?/ M# k - 8 g( y, _. N* @$ K9 V
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 4 H4 j0 Z% k f
- . r; \* ~/ ^/ ?) J3 o9 f$ K
- ADC_DeInit(ADC1);
# W( M. Y5 n: h: V% s5 E# T - RCC_ADCCLKConfig(RCC_PCLK2_Div6);
8 A$ `) s7 k8 H. n9 n - 0 S0 P8 d: E+ L
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
6 l) l+ B, }8 ]$ E5 a - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; & y. M4 B+ |& g4 a" T+ q/ O, } A$ C
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; . M- I) y. U9 T
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
, i* Y* u/ o( u6 h; A j/ j - ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度
! `4 w( v4 i% g! f/ y6 m0 ]; a* | - ADC_InitStructure.ADC_ScanConvMode = DISABLE;
; {. W$ J A9 d - ADC_Init(ADC1,&ADC_InitStructure);
# c/ S$ j- }* r6 } - 2 Z4 H8 f' w4 r) c) K, q7 O5 j; d p
- ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器
' L$ L# c, }; I* m" U$ G -
* M8 W6 m0 e+ `. m* W- } - ADC_Cmd(ADC1,ENABLE); // 使能ADC1
. _, L& d( K0 @! @ -
9 e8 b; z) h8 a4 m" c/ U. w% j) d - ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 , I+ R H+ L- S# S0 [* \
- while(ADC_GetResetCalibrationStatus(ADC1));
; N9 _( ^6 k: G1 @ -
: ~: r! c7 H$ ~8 |+ Q% ] v+ ~/ j - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 4 }+ Z2 E1 L, k# z8 f
- while(ADC_GetCalibrationStatus(ADC1)); 3 p+ {2 P* w+ K2 b3 H
-
. K! G5 X: V# @4 C - delay_init(); , Q/ V3 Y! ^3 }, E' D
- } 1 d4 R# h9 F. d$ B( u
-
4 ?# B; Z( r# h1 u& J: g - u16 ADC_GetValue() 6 }3 Z6 ^! M8 ?
- { + X) J( n' P, @2 Q U$ J) q% d
- ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期
" Q* w; E) z4 b( y -
( R. d$ C' V0 r& ~# S9 w6 l - ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
, u5 ]/ O- [) t* ^9 M - 1 U. j2 a' i; o: Y! }
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 $ b S5 [; y3 a9 E2 P* y/ f& Q
-
2 t t+ p! k0 g( H1 C) B - return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
5 i( [1 n# H+ R% S M - }
( {3 ?% ?# o7 V- n. } - 2 j& \/ L& v1 {( J
- u16 ADC_GetAverageValue() + D6 }2 |$ q5 T/ T6 V4 E
- { ( C! ~: I# S& n: {$ h2 v- `' K, f
- u8 i = 0;
( ^+ b' Z, Z9 Y5 C: G - u16 temp = 0;
9 D2 ]0 |+ j& N6 a. Y - . ^7 `+ w. ?# q [$ V0 Q5 O
- for(;i<5;i++) $ r. R* Y% \! t$ A" j
- {
, k" |! c4 [1 e7 h& s9 N - temp += ADC_GetValue();
6 C5 u, J5 o* Q3 `* T K1 N8 S - delay_ms(5); % L; ?! m5 [8 N9 L' l3 |# H
- } * ^& Y; X3 i& h; i( ?, E
- return temp/5; 9 h% \5 B" g/ r" K/ o' H
- }
' p d" Y( T! S3 V0 ? - 5 Z5 Z3 L4 u" A9 J" g
- u16 DigitalValueConversion()
6 x' {0 h9 m2 H/ M5 \ - {
( Z( p: \9 y8 t+ S4 t1 F - float temp = ADC_GetAverageValue();
7 K7 r% X g9 f6 F - return ((1.43-3.3*(temp/4096))/0.043+25)*100;
" f; r q. d5 F6 l K7 b/ C - }
复制代码 B7 j0 s, ^8 ~
0 m, w0 l6 @8 T( X8 v8 T* ]4 J! ~TempSensor.h( T( q# l3 Z- E% q: F
A/ j7 d Q' s# a3 x) a- G P) f) K p* C1 d8 s
- #ifndef _TEMPSENSOR_H 1 Y% T0 {8 F! y6 O
- #define _TEMPSENSOR_H % H$ O0 J" ?8 ]
- F" a/ b6 c) N s, r( z
- #include "sys.h" $ s' o. O* ~1 S( f" K5 v
-
7 f! \/ d% H1 D1 u - void ADC_InitConfig();
* f+ j# A3 P+ N% Q% @& ~0 w - u16 ADC_GetValue();
7 ]+ |4 u7 Y4 G8 n* v( r - u16 ADC_GetAverageValue();
3 `1 q9 ?% E; r Q0 C* Q - u16 DigitalValueConversion(); " E; m: D- T. e- m
- / K7 F( Y% |; v. h0 C- u
- #endif
复制代码
# y+ o8 _8 a8 o. @. `- T5 d8 g
, d2 \) r2 z4 c! ~7 I9 DMain.c
! i& e6 \6 C! ~* a8 d" J# G1 n7 c$ [9 d: P
- #include "TempSensor.h" / x# D B; A( H% E+ ^1 y
- #include "stm32f10x.h" 1 N) F$ q. @. p- u9 o1 i
- #include "usart.h" # G* q: @4 } ~% b: E
- #include "delay.h" 8 J. h8 Q6 w$ E, f3 g$ Q: {: D4 b
- #include "lcd.h"
; ]1 L/ r, R, b( A -
1 h9 D1 b6 C2 x4 K) t7 m. C - int main() . l( I7 J$ \ n5 M+ R9 o
- {
G# J8 g: v) P D$ l; m - u16 temp = 0; 2 t) J8 k* r- |9 ~# b: o
-
3 w: U: }" S. [ - ADC_InitConfig();
' [8 [8 [8 D. l0 i) J - NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 3 K( z0 s/ {4 z% C6 F
- uart_init(115200); / }8 E w9 z0 q e
- delay_init();
. h) z/ ]1 f/ _ - LCD_Init(); _3 D! t) f3 C) p
- LCD_Clear(BLUE); 2 o2 F% \. {- {) | w) U$ ~
- - F6 E2 x/ h8 |% h0 ]1 t. u
- temp = DigitalValueConversion();
1 ~3 ~" d7 \3 N& u+ \" t! z* a - 1 b( g' g) k/ L3 ?1 j
- POINT_COLOR=RED;//设置字体为红色
8 ~. C9 k" l |0 u - LCD_ShowString(30,50,200,16,16,"WarShip STM32");
& B" I" l A$ ?0 `$ p - LCD_ShowString(30,70,200,16,16,"Temperature TEST"); 0 J$ V/ m$ W6 A( D! ^& ~: H2 b, I& u
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK"); / | [; R4 U9 D" P) ?7 V
- LCD_ShowString(30,110,200,16,16,"2015/1/14");
' m! y$ K! \* Y2 m7 `* s$ m8 T - LCD_ShowString(30,140,200,16,16,"TEMPERATE: 00.00C");
# v( y3 x1 F9 ?6 R -
; a, |2 u: j( U5 B0 p# b; u; {8 C - while(1)
2 p) f$ R% u! n( y, w - {
; Q. g9 e: q! g$ ]% k! }/ e* b - temp = DigitalValueConversion();
7 f% a8 z5 o. L2 r0 `7 X - LCD_ShowNum(30+11*8,140,temp/100,2,16);
' e# m1 t' K% `* U6 I - LCD_ShowNum(30+14*8,140,temp%100,2,16); ; V+ {# M* c7 o3 z. q
- delay_ms(150);
& z% i* E, y* A4 l" m - }
# d2 ] V/ M5 ?+ J$ m6 _ - }
复制代码
0 a5 @9 Y* N% g( M5 ? ; X" m5 K4 {( t* P+ |1 e Z
程序运行结果" i, S& l/ h2 c* y/ R
9 ^( U) Y/ N; U! o9 `4 L7 q. c7 ?, ]1 _8 r: N/ y% P
8 z- K( c, N' e: Q9 B
2 K _0 y$ C/ o/ @ |