内部温度传感器简介测量的温度位置 内部温度传感器集成在芯片中,测量的是芯片的温度。 / u3 I P9 P8 S: S1 ^
如何测量对应位置的温度?
# a, ?1 i, K9 V" }0 N, Z
( S% a& l# o4 }
温度传感器与ADC1_CH16相连,另外ADC1_CH17是与内部参照电压VREF+相连,因此我们可以通过ADC1的第16路通道测量芯片温度实时对应的电压转换得来的数字量,也可以通过ADC1的第17路通道测量内部参照电压对应的数字量。
! s9 ^4 S& a$ _& B/ @) u0 n
# x# |/ I- Z- ?3 `, N* _8 {
我们知道STM32的ADC转换DATA是12Bits的,因此输入电压(小于3.3V大于0V)ADC转换为数字量的值为“大于0小于4096”。 * \' M4 M( L; A- g, R5 n) p
! N. ~) S2 l1 B6 y1 ^
我们由“T-V关系图”,“V的数字量”和“ADC量程”,可以得知“此时的温度”。
% R$ M+ f2 Z0 E$ J' a
1 D9 @ P5 v! T# _ H/ x
内部传感器配置注意事项
1 E# T5 N- w) @& o
/ Q, j7 g# C& K# m% Y" ^① 读取内部温度传感器数据的周期应大于17.1us; ② 内部温度传感器的温度测量误差约为1.5℃,因此内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温 度,应该使用一个外置的温度传感器。 & D& D* t( Z9 g3 j
* z2 f. a0 y% e8 Z0 i
内部温度传感器配置流程( B5 k: z( W/ K4 f/ v) ~
/ M. D. F Q8 W7 s0 [所属函数位置 | 执行步骤 | 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次读取的数据进行取平均值处理 | 温度与电压数字量之间的转换函数 | 用温度与电压数字量之间的对应关系进行转换 | 7 z! \' H2 \' u8 ]
内部温度传感器实验代码解析ADC初始化代码
: h7 T/ f$ j; M D
8 E8 b/ W4 I! S3 Y7 s- " ]6 m( M- o) j/ Z2 J0 _6 s6 R" k* _
- void ADC_InitConfig()
1 ]' e, R" |8 \! C" w - { * \1 }( T; L) E1 Y' O1 @
- ADC_InitTypeDef ADC_InitStructure; i8 N( Z2 s$ R: }/ C- h' u+ f o
-
5 y' z) ]3 P# k - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE); 6 z& t) _% |- G u
-
; D, g) a; v, a9 l) a - ADC_DeInit(ADC1); + [" s @' a3 m
- RCC_ADCCLKConfig(RCC_PCLK2_Div6);
# ~3 X9 D* n. K1 H - ! |/ `: d f Z' I
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
, v. {. V( D; C5 k - ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
3 x# n& n, O: k7 k# d q4 { - ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ( {1 M' x! O6 g, L
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 3 F' g6 \: M$ J R: ~/ F
- ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度
V* o- z( n% u! `0 J* y( E - ADC_InitStructure.ADC_ScanConvMode = DISABLE; % l8 f7 ~# S6 J5 \- o! |& g0 J
- ADC_Init(ADC1,&ADC_InitStructure);
: A* P2 }# t F+ X% ^ - ( `' Y- W. c0 e: S/ q
- ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器 , Q" _- v7 n0 W! Q
- 6 [5 g6 Z% p% `
- ADC_Cmd(ADC1,ENABLE); // 使能ADC1 " L/ n, ^( T3 b5 f8 C# h" W
- * `) E H. l* u% r. H. g8 y4 ?
- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位
[6 d5 V( g) G: X$ j0 e- l - while(ADC_GetResetCalibrationStatus(ADC1));
; [, E& C& L/ c- F$ I# M; C - ! J# r* A" K8 g: Z+ Y! k6 d5 G: |
- ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 3 b0 J1 O9 b$ h/ d. R5 \
- while(ADC_GetCalibrationStatus(ADC1));
3 B [) k7 W O2 A - + a1 @- {' g5 z9 F9 ]6 e) ^
- delay_init(); ) `+ ~% C; [0 b
- }
复制代码
m* \& d/ d$ X+ l. c7 `" R0 f) `我们应该注意到:ADC1_CH16连接着内部温度传感器,不用初始化具体的GPIO口引脚,只需要将寄存器的相应位使能即可:
4 |3 z! E' ?( L& p R- x9 J; ]
1 P; m# e) `4 G% k+ K1 w& f q
我们有些同学在用如下“等待”代码的时候有些疑问: * g' V3 \+ [8 g F
5 k% P5 f; Y7 Q# _4 f- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位
* V/ u0 Z4 _4 s- I C; ~- K - while(ADC_GetResetCalibrationStatus(ADC1));
# M: o+ c" N7 `+ j4 ?# Z$ f0 H& s: C -
b! f& G7 f, @ - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 + w, L! b3 t8 t: E
- while(ADC_GetCalibrationStatus(ADC1));
复制代码 4 X1 T w! ?$ w: _0 m% F" l
我们用while循环为ADC外设提供执行任务所需的等待时间,但是我们一对比如下while代码,就有点懵了: ! ?& g# g- x8 i/ M' L! U. B
- # @6 k9 e5 s0 S# f
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
& G! T# W- v p7 l4 o -
3 c0 q1 X% P$ p# a3 [/ z: {' s! e( X - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 & ^2 N/ Q) R( O% X6 l
& }% @8 z1 h" Z1 _* m
2 X1 p$ t8 v! M2 O$ a6 _
在while循环中,应该“取非”?这个是个让人不解的问题。 我们此时应该看寄存器,看寄存器中位与状态的对应关系: ADC1复位校准功能与ADC1执行校准功能分别对应“ADC控制寄存器 2(ADC_CR2)”对应的如下两个位:
% S" J: @- j& o& F9 I. s6 Z& x
" T, m8 I/ L4 d8 _$ @+ Z, M; {$ ^+ c6 z% `* _7 J9 ~1 v* ` K) Q
我们看到上图,可以得到如下结论: ' Z0 x- Y8 u% V3 E6 ~
功能 | 状态 | 位标志 | 检验ADC校准功能复位状态(完成/进行中) | 复位执行中 | 1(SET) | 复位完成(复位指令执行完毕) | 0(RESET) | 检验执行ADC校准功能的状态(完成/进行中) | 正在开始执行ADC校准功能 | 1(SET) | ADC校准功能执行完毕 | 0(RESET) | 3 A$ G8 X2 d- t! K/ D* W8 E5 Q
此外,ADC_SR状态寄存器中的标志位EOC位代表着“ADC转换工作是否结束”:
功能 | 状态 | 位标志 | 查看ADC转换是否结束 | ADC转换结束 | 1(SET) | ADC转换完成 | 0(RESET) |
2 F0 H- i% `: n8 T1 |DC转换函数 o' T0 F) L* V5 c5 M
% x4 _$ `3 T/ Y7 ?: T" F
! R n; M+ F5 k. _* H5 z# j7 u- u16 ADC_GetValue()
2 o* V$ Z4 `( ~/ g$ B1 h - { A. i: e% T5 J6 W# C
- ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期 8 ~- s2 W$ o7 z/ Z7 v' J
- # o2 h V2 B3 j4 N% s) O
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 / M3 y% a( s J
- $ j2 E& \9 E' `$ q3 A9 t3 c/ \
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
2 c% _4 o. a3 x1 v' A -
" Y9 o/ S! h- v! n* I - return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
! f. s# i6 M; d! D* b' I( |! D - }
复制代码 ) w4 t" V/ k2 C: }2 c; E
- m+ v5 t$ f8 ?% z8 j7 D1 K; k
注意:我们一定要在读取ADC通道转换值得函数中去执行: ( Y9 t) D4 M! g) o/ _% ^7 b: W" N8 ~( x
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
2 v0 ]( y; [- G3 \- m - # }, u/ s. A6 a% P o/ N/ e( l
- while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
复制代码 # e9 l% w- q6 n, e7 g; a
我们初始化时只想初始化ADCx设备的属性,而函数“ADC_SoftwareStartConvCmd”得功能是根据ADCx各个引脚的属性启动ADCx外设进行转换操作。显然,初始化时不应进行获取转换值得操作。 # e+ z. |5 m3 ^1 h
I/ ?1 `0 {; w/ Y$ d- c* s5 J 多次读取取平均函数 p9 {: l! L9 q$ M: l& _
8 |" @( H! _; ^1 |+ R/ i$ H
. c6 J! l' s% R- l4 r1 r- //获取通道ch的转换值
, t7 l! p, W( f/ h/ i* Y. j - //取times次,然后平均
2 _) M* ^! D1 L, ~# O; _ - u16 T_Get_Adc_Average(u8 ch,u8 times) ! F0 l+ v0 q* P6 @/ A( ^
- {
2 i# J5 _" h" q, O - u32 temp_val=0; 0 v9 d7 ]$ x* l# ^
- u8 t;
0 b2 k$ d/ W( e8 C3 a/ b0 |) @, M - for(t=0;t<times;t++)
3 X. m7 j2 q/ F7 X- j+ e; Y - {
( H% j$ }. g( _3 b) k7 J - temp_val+=T_Get_Adc(ch);
# {2 A H4 s% y. Q, v% W. g - delay_ms(5);
2 {- d" y4 a' W1 { - }
S; x9 Y: \# L8 y1 B' _ - return temp_val/times;
0 R! f% ~8 w2 t. u0 b) ]/ B - }
复制代码
4 Q( V) v) Q* I( H, _: I/ ] j; c
0 U! W8 }+ V' G8 f z" V( l) @ADC转换的数字量转换为所需温度的函数
i( K7 F1 g, Q# H9 q' u6 c$ Y3 m+ Z& O
5 F) n9 a, g3 ?3 s/ b3 B: |/ J+ o: n0 _! z4 R4 ?; j- b3 X
: b& d( t* d! F) Z' {0 B, C" R- //得到温度值
3 G- G- F/ j4 S& I2 B. x/ v - //返回值:温度值(扩大了100倍,单位:℃.)
) |, X( n2 M( H% U9 u. W - short Get_Temprate(void) //获取内部温度传感器温度值
z7 R h L4 U* u5 ^* x/ e4 `8 j0 u - { : | O2 r: ?* }7 \( t2 m, X& |
- u32 adcx; 5 h$ H1 n$ y1 N+ O' M
- short result;
0 n2 G: y0 t) h# b& x, S - double temperate; , K# N7 X# X- l R9 y9 c7 d2 u
- adcx=T_Get_Adc_Average(ADC_Channel_16,20); //读取通道16,20次取平均
, Y6 Q/ z: @9 j: R" U0 q( ] - temperate=(float)adcx*(3.3/4096); //电压值 - P, W% y \* q+ `
- temperate=(1.43-temperate)/0.0043+25; //转换为温度值 7 X9 u* _) L% g4 y8 z4 \
- result=temperate*=100; //扩大100倍.
+ `( o8 K# d# A1 n; X B8 _% y - return result;
7 }" [1 P0 o% `. d o' q5 P - }% {9 h( D5 m; U) K6 x+ v& U
-
复制代码 % ~' Z/ g. v7 O4 X g
2 a6 h3 M& M% O8 _" @
: H% A7 _1 j- D! Q% V/ q4 \
总体代码示例TempSensor.c
. m4 G" ~! X+ ^. I8 ^% G3 D" S6 C/ C$ B5 J( B" T6 M
+ R! `! O ~" G& d4 C! V- #include "TempSensor.h" V; N3 i9 z* m i5 \+ T* T) Z
- #include "stm32f10x.h" * b5 T C( { m. p- i
- #include "delay.h"
" z; s% s! q- J5 H -
8 I5 Y( e4 F! r, W- j$ m# z" { - void ADC_InitConfig()
6 M; i- U6 r3 e4 ~$ o7 b - { 5 y; ?+ \& p6 i0 U$ m
- ADC_InitTypeDef ADC_InitStructure;
. h+ u" U- m- ^' X$ P7 T- O -
6 H& S- E; U# z5 @$ N8 a n - RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
+ R1 l/ \3 y& |$ q; b% P - . H% s' p1 {1 v" q' D9 R% A
- ADC_DeInit(ADC1);
- g, d# W( E: l/ L - RCC_ADCCLKConfig(RCC_PCLK2_Div6); 3 h3 @; N+ i2 w1 P# P' d
- % ?+ L) m" a2 |/ j6 P7 _9 T; f; X! O
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; / S' q" z- N. M% j; G, p
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left; ) L( s& j$ D% i1 F: U6 g2 u
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 7 |! z8 p* q' X
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
7 c2 _' | |' M4 g$ ~ - ADC_InitStructure.ADC_NbrOfChannel = 1; // 定义规则通道的长度 $ {1 j* f) d1 F7 ]( O
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; 8 F3 H: C; P# F$ r5 y! A& ~9 N
- ADC_Init(ADC1,&ADC_InitStructure);
; j# ], h6 N: M; Q% W8 i -
( z4 O! K4 c% n8 s - ADC_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器 ! W4 I9 o4 Q1 d- c' \
-
X, X* ]$ i4 F9 L/ G; U" A; ^ - ADC_Cmd(ADC1,ENABLE); // 使能ADC1
, R1 _2 f2 U- _) }, X7 j: [ - . d3 V# t/ g h% J
- ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位 9 S3 ~5 ~8 k( \
- while(ADC_GetResetCalibrationStatus(ADC1)); Q& \7 e% p4 y5 N* P% K
-
+ N, e" a0 W U) a - ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能 ( j4 Z9 `4 {% \; x. P8 d( q
- while(ADC_GetCalibrationStatus(ADC1)); ' g3 i) o, D5 g/ I) [! V0 ^+ H
-
0 w' u% b) S( ~) X# C7 B - delay_init(); 4 q& d/ r/ v* v4 G; x+ k
- }
5 V% A! o9 b& c; O) |+ j- z6 m' B - % j9 n% I8 I+ l
- u16 ADC_GetValue()
, j% u: h& R$ J# y, w2 U; ` - {
% d" a, A4 @2 z ?/ U - ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道3,第一个转换,采样时间为239.5周期 0 }. U7 j: N$ ~4 Q# f- }$ g, h
- # S8 [( c. [ A! Q k# P5 a7 J
- ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 / U! Z% }/ V1 `3 Z0 u
-
. z' ]9 C2 m8 h d - while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
+ z- N8 ^' u& e* A3 G# } -
1 Y% T; d. f, }. t0 a( A% R - return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
5 r4 ^* X2 [: e# @1 \. D - } ) B |3 \0 x+ G+ m
-
; p1 ]7 c% l. [0 L" _) } - u16 ADC_GetAverageValue() $ L: E0 H* O9 P; |
- {
/ s# I8 d7 b9 w, ^7 l: k6 Y - u8 i = 0; 0 h- \# r. _5 Z) C. U* r0 Z
- u16 temp = 0;
7 ~( C3 q) q( }/ H6 n -
! g! v: M& m* R4 A% Z% f+ \; ?) Q - for(;i<5;i++)
0 {# P- ^- }5 M& t9 I" x - {
* K: `& S0 z0 l; P( w% W - temp += ADC_GetValue();
2 {+ Q" O1 a4 ~+ A+ T; K6 c% v% a - delay_ms(5); " g8 E+ w; Z$ `* ?$ L- e9 p6 A3 A
- } 9 a) i+ k' Q6 ~9 f7 y2 h
- return temp/5;
7 m0 s W. x# L3 a0 r/ s4 P: ~ J - }
: V! g0 K J- g) I- x$ o* d$ u - $ _# \$ a2 |; G8 U
- u16 DigitalValueConversion() % F! d) h/ x' n1 Q( F
- {
0 c5 T/ f5 j4 L. C - float temp = ADC_GetAverageValue(); X& W* s: Y+ G, Z7 M
- return ((1.43-3.3*(temp/4096))/0.043+25)*100; ; }* K% h5 h8 Q& ^8 @' Q
- }
复制代码
% b* \, K) M" L' n! L
( m4 m5 U! Z/ sTempSensor.h3 K4 G L% H$ T- ?! h' O, [
7 P- y+ C" b8 V0 A- 6 K5 X O# d# I" J0 t: {
- #ifndef _TEMPSENSOR_H
# a: Y0 u- I- `9 G - #define _TEMPSENSOR_H
' Z, ?8 {2 V' t. z2 P -
) r9 ?$ c; b9 ~2 v& w9 ^ - #include "sys.h" % o& }5 Q3 m: @: u" M% q
- - @5 t; }$ P$ q: e
- void ADC_InitConfig();
) B( z( |& f4 { - u16 ADC_GetValue(); 1 B; T; y0 N* g; }
- u16 ADC_GetAverageValue();
, |, z2 x4 n6 |3 i6 \$ Z+ s - u16 DigitalValueConversion(); 1 R2 |8 H! e2 T3 a: o6 H
-
9 z- q" J2 _. f- n" M* j# b% g5 I - #endif
复制代码 ) F. z( O3 ~, g& ~
5 ]; X) A7 _+ s% p+ Y* ~Main.c: ~% L2 ?' N. @ G& M
: X: W* z6 w& e* w1 d- #include "TempSensor.h"
9 z2 u" Y9 i8 Z' R: O9 y - #include "stm32f10x.h"
9 U- w# ?( g# b+ P" [2 a+ d7 h - #include "usart.h" ( j n- ]# g2 s2 S
- #include "delay.h"
* b, X" G) o5 ^) \& G9 L, V - #include "lcd.h"
' @2 v1 X; \0 f. W4 c( ~* J -
: y2 l# D9 c I2 d - int main() 1 O& R5 ?" i, C) h9 \2 n F
- {
- V s8 [8 r; `, d - u16 temp = 0;
9 I2 s& n" ?! {4 n* o' q -
1 j% W; V' T- O% y [ - ADC_InitConfig(); ) I, F6 F% x+ e. N
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
+ k1 s4 `7 E5 H* t1 `1 T% F - uart_init(115200); 6 o8 l: q0 \4 G: U2 z3 [
- delay_init();
5 a5 S3 @" V1 X7 N/ C2 T - LCD_Init(); 4 _! j; D F+ [& @' M; F
- LCD_Clear(BLUE); * h: v4 \3 i* T& T: u
-
# x4 X8 a- t+ k - temp = DigitalValueConversion(); 9 v ~3 G! y% I+ E" M9 {; t
- n6 K( B: H/ G0 |
- POINT_COLOR=RED;//设置字体为红色 / @8 |, q8 e6 h$ o. |
- LCD_ShowString(30,50,200,16,16,"WarShip STM32");
7 c. j1 z; W; K/ i7 ^) Q: U' j& ] - LCD_ShowString(30,70,200,16,16,"Temperature TEST"); % H# {9 [) ~$ E$ I
- LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
; C2 |) H4 a7 o2 {! F4 W - LCD_ShowString(30,110,200,16,16,"2015/1/14"); # N: R) Y& w! a9 @: j$ r A
- LCD_ShowString(30,140,200,16,16,"TEMPERATE: 00.00C"); - C$ Z. Y( H7 C3 F$ S
-
) B. p! e& l" v7 v% ]2 _9 t4 l - while(1) $ A0 C. ^) Q9 o, x. N# ~
- { 4 ^9 Z, i! H) X
- temp = DigitalValueConversion(); ; [8 Y/ U, V% `- X5 ?
- LCD_ShowNum(30+11*8,140,temp/100,2,16); 2 k4 M# R+ e( g9 [
- LCD_ShowNum(30+14*8,140,temp%100,2,16); ! C9 G x! x) r0 j0 E, [; i
- delay_ms(150);
$ ]) r' Z7 ^) I }7 K - }
~9 d, \0 J4 g+ w1 d - }
复制代码 , f% T* U1 d% _2 T" n1 v( P
0 w( T$ I) I$ F6 G, \程序运行结果9 K9 O# y% M$ F7 F
/ J) E/ Y+ S) u3 r. {/ g) m9 y
* U1 ]- }! l2 G5 Y' F* Z( r8 ?* a
2 [ L7 T1 m9 C8 @" Q
% o* n/ \& I. B# P, Z
|