STM32F4 内部温度传感器(Internal Temperature Sensor)

STM32F4系列MCU内置有温度传感器,用于采集片内温度,其绑定在ADC1的IN18通道,CubeMX中显示为"Temperature sensor channel"。

ADC配置

ADC的结构体hadc1配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  • ClockPrescaler:预分频系数,默认为PCLK2 / 4,此例为90 / 4 = 22.5MHz
  • Resolution:ADC分辨率,可选有 12 位、10 位、8 位和 6 位。分辨率越高,转换数据精度越高,转换时间也越长;反之分辨率越低,转换数据精度越低,转换时间也越
    短。
  • ScanConvMode:是否使用扫描。多通道启用,单通道禁用。
  • ContinuousConvMode:启用为自动连续转换,禁用为单次转换。如果设置为单次转换,那么每次转换后都要人工介入才能开启新的转换
  • DiscontinuousConvMode:配置是否使用不连续的采样模式。该参数只有在ScanConvMode启用,且ContinuousConvMode关闭的情况下才有效
  • ExternalTrigConv:外部触发方式选择。若为软件触发则外部触发会关闭。
  • ExternalTrigConvEdge:外部触发极性选择(禁止触发检测、上升沿检测、下降沿检测或均可)
  • DataAlign:数据对齐方式,默认右对齐
  • NbrOfConversion:常规转换通道数目,范围1~16
  • DMAContinuousRequests:指定DMA请求是否以一次性模式执行(达到转换次数时DMA传输停止)或在连续模式下执行(DMA传输无限制,无论转换数量如何)。在连续模式下执行时,DMA必须配置在循环(Circular)模式,否则DMA传输缓冲区被填满时将发生溢出。
  • EOCSelection:指定转换结束后是否产生EOS中断或事件参数

STM32F429的ADC总转换时间可以通过下式计算:

Tconversion=Tsampling+12×TadcT_{conversion} = T_{sampling} + 12 \times T_{adc}

对于每个ADC通道,采样时间可以通过ADC_SMPR1(用于通道10-18)或ADC_SMPR2(用于通道0-9)寄存器的相应位来配置。例如,通道0的采样时间是通过ADC_SMPR2的SMPR2[2:0]位设置。采样时间也可在adc.c中用代码定义,通常默认为3个ADC周期(SMP=000),可获得最快的采样速度:

1
2
3
4
5
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.
*/
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;

12个周期由ADC输入时钟ADC_CLK决定,其由APB2( 即PCLK2)分频产生,在ClockPrescaler中可修改。

若采样时间为3个ADC周期,则ADC转换总时间为15个ADC周期,APB2时钟频率为90MHz,PCLK2/4分频后为22.5MHz,那么转换时间就是0.6667us。

DMA配置

启用DMA2,ADC1转换后的原始数据存储到16位缓冲区Rx_Buf中。由于ADC分辨率为12位,即采回的数据为12位,正好能够被16位缓冲区存下,便于后续观察和管理内存中的采样值。如果用32位缓冲区,一个区域会存两个采样值,不方便查看和后续的转换。

采样

ADC直接采样会存在跳变或抖动,通常需要进行一定的软件滤波,最常见的方法是简单平均法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
@ brief:ADC采样并取平均
@ param:times:平均次数
@ return:计算得到的平均值
*/
uint16_t adc1_get_average_value(uint8_t times)
{
uint16_t temp_value = 0;
uint8_t t;

/* ADC 配置在单次模式,每次采样都需要手动重启ADC服务 */
HAL_ADC_Start_DMA(&hadc1, (uint32_t *) Rx_Buf, Rx_Buf_Size); //强制转换Rx_Buf为32位以满足形参限制

/* 采样值取平均 */
for (t = 0; t < times; t++)
{
temp_value = temp_value + HAL_ADC_GetValue(&hadc1);
HAL_Delay(5);
}

/* 返回平均值 */
return temp_value / times;
}

因分辨率为12位,ADC每次采样返回的数值即为12位无符号整型(十进制0~4095)。DMA将会传输每一次的采样值至缓冲区,为了能够更好的查看每一次返回的数值,该例程事先将缓冲区定义成了uint16_t类型,这样缓冲区数组的每一个单元正好能够存下一个采样值。在调用ADC采样函数时,只需要将其声明为uint32_t类型指针,这样DMA会按4个字节(32位)来传输数据。DMA本身并不关心传输的采样值到底是几位的,他只会读取4个字节的数据然后传递至内存,因此,每两个 uint16_t 数据(即 2 个采样值)会合并成一个 uint32_t,在内存中形成连续的数据块。

以此类推,如果采样值为8位(uint8_t),那么DMA每次将会打包4个采样值为一个uint32_t数值传回同样定义为uint8_t的缓冲区然后解包,缓冲区中的每个单元都显示一个采样值。

然后进行温度的读取。温度传感器换算公式为(单位为摄氏度):

T=((VsenseV25)/AvgSlope)+25T = ((V_{sense}-V_{25})/AvgSlope) + 25

式中参数取典型值,有V25=0.76V_{25}=0.76AvgSlope=2.5mv/AvgSlope = 2.5mv/℃
采集温度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
@ brief:采集温度
@ param:NULL
@ return:温度值(short)
*/
double read_temperature(void)
{
uint16_t adc_value;
double temperature; //返回温度为双精度值

adc_value = adc1_get_average_value(10);

temperature = ((float)adc_value * 3.3 / 4096.0 - 0.76) / 0.0025 + 25.0;

return temperature;
}

main.c

1
2
3
4
5
6
ic_temp = read_temperature();

uint8_t txbuf[15];
sprintf(txbuf, "temp is: %.2f\n", ic_temp); //转换为字符串

HAL_UART_Transmit(&huart1, (uint8_t *)txbuf, strlen(txbuf), 0xFFFF); //串口轮询发送温度值

结果

上位机接收

内存监视结果


STM32F4 内部温度传感器(Internal Temperature Sensor)
http://akichen891.github.io/2024/12/04/STM32内部温度传感器采集/
作者
Aki Chen
发布于
2024年12月4日
更新于
2024年12月5日
许可协议