背景
由于项目临时需要温度数据,又不想改动硬件了,反正对温度精度要求不算太高,索性就用MCU片上温度传感器的温度,来替代了。这里自己根据网上帖子做了一些测试用例尝试测温,但是,效果都不理想。发现ST官方提供了一个例程《AN3964应用笔记STM32L1x 温度传感器应用举例》。这个测试例程比较老了,使用固件库开发,对我来说,我用STM32CubeMX或者STM32CubeIDE开发了,都是基于HAL库,所以面临一定的移植工作。本文实现了该应用笔记的解析,同时实现了STM32CubeMX+Keil uVision5的代码移植。这里提供移植过程中的所有文档,希望加速面临同样问题的小伙伴的开发进度。
AN3964测温过程简介
这里也可以参考原始文档。本文也做点简单介绍,主要是提醒关键信息。
温度测量和数据处理
温度传感器的输出在芯片内部连至 STM32L1x 中 ADC (模数转换器)的通道 16
(ADC_IN16), ADC 通道用于采样和转换温度传感器的输出电压。必须进一步处理原始
ADC 数据,以便用标准温度单位显示温度 (摄氏度、华氏度、开氏温度)。
ADC 参考电压 (VDDA = VREF+)连至 STM32L1xxDISCOVERY 板的 3 V VDD 电源。若不
知道 VDD 的精确值,则与使用电池工作的应用一样,必须对它测量以得到正确的总体 ADC
转换范围 (见下节的详细信息)。
电池供电设备上的温度测量
若器件直接用电池供电,则微控制器的供电电压会有变化。若 ADC 参考电压连至 VDDA,即
低引脚数封装器件的连接方式, ADC 转换的值会随电池电压漂移。需要知道供电电压以补偿
该电压漂移。可使用芯片的内部电压参考 (VREFINT)来确定实际供电电压 (VDDA)。
ADC_IN17 内部参考输入上的 ADC 采样值 (Val_VREFINT)可由下式表示:
精确的芯片内部参考电压 (VREFINT)由 ADC 单独采样,在制造过程期间,将每个器件的
对应转换值 (Val_VREFINT_CAL)储存于受保护的存储区,其地址为产品数据手册中规定的
VREFINT_CAL。内部参考电压校准数据为 12 位的无符号数 (右对齐,存储于 2 个字节
中),由用于参考的 STM32L1x ADC 获取
工厂测量的校准数据总体精度为 ± 5 mV (若需更详细信息,请参考数据手册)。
我们可使用上式确定实际的 VDDA 电压,如下所示:
Val_VREFINT = = VREFINT × 212 ⁄ VREF+ VREFINT × 4096 V ⁄ DDA
V
VREF_MEAS = = VREF+ 3V 0.01V ±
V
DDA = 3 Val_V × REFINT_CAL ⁄ Val_VREFINT
当采样温度传感器数据 ValTS_bat 时, ADC 量程会参考前面步骤中确定的实际 VDDA 值。因
为温度传感器工厂校准数据是在 ADC 量程设为 3 V 时获得的,所以我们需要归一化
ValTS_bat,以得到 ADC 量程为 3 V 时应获得的温度传感器数据 (ValTS)。可使用下式归
一化 ValTS_bat:
若 ADC 参考为 3 V 供电 (STM32L1 Discovery 的情况),则不需要这样归一化,可直接使
用采样温度数据确定温度,如第 2.2.1 章节:温度传感器校准中所述。
应用程序示例说明
每 2 秒,应用从温度传感器电压获取 16 个采样。使用四分均值算法,对 ADC 原始数据滤波、平均,以降低电源系统的噪声。将结果重新计算为标准的温度测量单位下的数值 (在本例中为 °C)。ADC 原始数据或当前温度值每 2 秒更新一次 LCD 显示,单位为摄氏度。用户可通过按用户按钮在两种温度数据表示之间切换。为演示 STM32L1x 超低功耗微控制器的低功耗能力,在温度传感器数据测量间歇期, CPU切换至停止模式, RTC (实时时钟)唤醒设为 2 秒。 ADC 数据获取和数据传输由直接存储器访问 (DMA)管理在此阶段 CPU 处于低功耗睡眠模式。仅在初始化阶段和数据处理期间, CPU 才处于运行模式,其频率为 16 MHz (基于 HSI 振荡器时钟)。
原始工程修改测试
原始工程是适配STM32L152,同时采用的固件库,我项目的板子使用的是STM32L151同时也没有LCD,想要测试该例程,需要进行更改。
这里只是提示更改过程的主要步骤,具体参考工程代码
设置lcd相关的代码不参与编译,同时修改main.c中相关的调用函数。
原来工程使用的MCU休眠和按键,这里都不需要,所以注释并添加相关代码,实现工程能够正常运行到STM32L151,其中添加延时代码如下
//__WFI();
//Delay(2000);
T_StartupTimeDelay = 100000;
while (T_StartupTimeDelay--);
工程实际运行的结果如下:从下图可以看出测量的室温为30°,也算准确。
移植STM32CubeMX+Keil uVision5
上述工程对我来说,用途不大,只能用来演示。最终使用到项目上还得完成STM32CubeMX+Keil uVision5移植。这里主要难点是对ADC的配置,可以参考如下配置:
Main函数主要代码中
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
printf(" ** TEMPERATURE SENSOR EXAMPLE ** \r\n");
/* Test user or factory temperature sensor calibration value */
if ( testFactoryCalibData() == SUCCESS ) {
getFactoryTSCalibData(&calibdata);
printf(" ** getFactoryTSCalibData ** \r\n");
}
else if ( testUserCalibData() == SUCCESS ) {
calibdata = *USER_CALIB_DATA;
printf(" ** testUserCalibData ** \r\n");
}
else {
/* User calibration or factory calibration TS data are not available */
calibdata.TS_CAL_1 = DEFAULT_COLD_VAL;
calibdata.TS_CAL_2 = DEFAULT_HOT_VAL;
writeCalibData(&calibdata);
calibdata = *USER_CALIB_DATA;
printf(" ** writeCalibData ** \r\n");
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (HAL_ADC_Start_DMA(&hadc,
(uint32_t *)ADC_ConvertedValueBuff,
ADC_CONV_BUFF_SIZE
) != HAL_OK)
{
Error_Handler();
}
HAL_Delay(2000);
// Process mesured Temperature data - calculate average temperature value in
processTempData();
printf("temperature_C = %d\r\n", temperature_C);
}
/* USER CODE END 3 */
}
测试结果截图如下:
调试过程问题
调试过程中发现温度一直不稳定,并且不准确偏差太大,都偏差都80°左右,经过详细的对比排查,发现最后四个通道的ADC采样周期设置不准确,修改后,回复正常。
这里也可以用手按住MCU,可以看到温度会又有缓慢上升现象。
本文使用资源下载路径
STM32L1x片上温度传感器采用ADC及工厂校准数据提升测量温度精度,移植固件库代码,同时实现了CubeMX+KeiluV资源-CSDN文库