[STM32G4] STM32G431KBU3芯片内部温度读取的实例代码

[复制链接]
 楼主| dffzh 发表于 2025-5-22 17:09 | 显示全部楼层 |阅读模式
本帖最后由 dffzh 于 2025-6-4 17:24 编辑

#申请原创#
@21小跑堂

我们有时候会利用MCU芯片内部的温度传感器来读取MCU温度,并用此温度数据来做一些应用功能,比如参数随温度动态调整,监控MCU芯片温度或者线性调整温度偏移等功能。这篇文章作者就带大家看一下如何读取STM32的STM32G431KBU3芯片的内部温度数据。通过整个读取过程的操作,以后大家遇到其他芯片,也可以按这个步骤进行尝试。
1、先看手册
我们先来看下芯片数据手册,找到与内部温度传感器相关的章节介绍,主要如下:
温度数据一般来源于模拟信号,那肯定是用ADC模块,所以我们先确认绑定了ADC外设的哪个通道,这个时候就需要打开数据手册或者用户手册来查看:

28462682ee9462580f.png
从用户手册可以看出,内部温度传感器是绑定了ADC1的16通道和ADC5的4通道。
再来看看对温度传感器的说明,读取流程和计算方法:
91794682ee951a2668.png
46217682ee956d6a32.png
58367682ee95d8317e.png
如果公式里面有一些常量参数值,也要看下如何读取出来:
28625682ee969ec768.png
83949682ee96f13b02.png
79532682ee9754faa9.png
2、再写代码
知道怎么读取芯片的温度传感器数据和计算方法后,接下来就可以编写代码调试了。
代码主要涉及ADC初始化配置和温度读取两个方面。
其中读取芯片内部温度传感器的ADC通道对应的宏是:
2040068400fad5b329.png
ADC初始化配置接口为MX_ADC_Init,代码如下:
  1. void MX_ADC_Init(void)
  2. {

  3.   /* USER CODE BEGIN ADC1_Init 0 */

  4.   /* USER CODE END ADC1_Init 0 */

  5.   ADC_MultiModeTypeDef multimode = {0};
  6.   ADC_ChannelConfTypeDef sConfig = {0};

  7.   /* USER CODE BEGIN ADC1_Init 1 */

  8.   /* USER CODE END ADC1_Init 1 */

  9.   /** Common config
  10.   */
  11.   hadc1.Instance = ADC1;
  12.   hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
  13.   hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  14.   hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  15.   hadc1.Init.GainCompensation = 0;
  16.   hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  17.   hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  18.   hadc1.Init.LowPowerAutoWait = DISABLE;
  19.   hadc1.Init.ContinuousConvMode = DISABLE;
  20.   hadc1.Init.NbrOfConversion = 1;
  21.   hadc1.Init.DiscontinuousConvMode = DISABLE;
  22.   hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  23.   hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  24.   hadc1.Init.DMAContinuousRequests = DISABLE;
  25.   hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  26.   hadc1.Init.OversamplingMode = DISABLE;
  27.   if (HAL_ADC_Init(&hadc1) != HAL_OK)
  28.   {
  29.     Error_Handler();
  30.   }

  31.   /** Configure the ADC multi-mode
  32.   */
  33.   multimode.Mode = ADC_MODE_INDEPENDENT;
  34.   if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  35.   {
  36.     Error_Handler();
  37.   }

  38.   /** Configure Regular Channel
  39.   */
  40.   sConfig.Channel = ADC_CHANNEL_TEMPSENSOR_ADC1;
  41.   sConfig.Rank = ADC_REGULAR_RANK_1;
  42.   sConfig.SamplingTime = ADC_SAMPLETIME_92CYCLES_5;
  43.   sConfig.SingleDiff = ADC_SINGLE_ENDED;
  44.   sConfig.OffsetNumber = ADC_OFFSET_NONE;
  45.   sConfig.Offset = 0;
  46.   if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  47.   {
  48.     Error_Handler();
  49.   }
  50.   /* USER CODE BEGIN ADC1_Init 2 */

  51.   /* USER CODE END ADC1_Init 2 */
  52. }
读取出厂校准点参数的代码如下:
  1. uint8_t TS_CAL1_TEMP = 30;
  2. uint8_t TS_CAL2_TEMP = 130;
  3. uint16_t TS_CAL1 = 0;
  4. uint16_t TS_CAL2 = 0;
  5. //存储校准参数的地址
  6. #define TS_CAL1_ADDR   0x1FFF75A8
  7. #define TS_CAL2_ADDR   0x1FFF75CA

  8. //从地址里读取所存的数据
  9. uint8_t read_from_flash(uint32_t addr)
  10. {
  11.         return *(uint8_t*)addr;
  12. }
  13. void read_g4_temp_cal(void)
  14. {
  15.         uint8_t ts_cal_value_1 = 0;
  16.         uint8_t ts_cal_value_2 = 0;

  17.         HAL_FLASH_Unlock();

  18.         ts_cal_value_1 = read_from_flash(TS_CAL1_ADDR);
  19.         ts_cal_value_2 = read_from_flash(TS_CAL1_ADDR+1);
  20.         TS_CAL1 = ts_cal_value_1 | (ts_cal_value_2 << 8);

  21.         ts_cal_value_1 = read_from_flash(TS_CAL2_ADDR);
  22.         ts_cal_value_2 = read_from_flash(TS_CAL2_ADDR+1);
  23.         TS_CAL2 = ts_cal_value_1 | (ts_cal_value_2 << 8);

  24.         HAL_FLASH_Lock();
  25. }

读取并转换温度的代码如下:
  1. void read_g4_temperature(void)
  2. {
  3.         uint16_t adc_value = 0;

  4.         //1.read adc value
  5.         HAL_ADC_Start(&hadc1);
  6.         HAL_ADC_PollForConversion(&hadc1, 100);
  7.         while(!HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC));
  8.         adc_value = HAL_ADC_GetValue(&hadc1);
  9.         AD_Value = adc_value *3.3/3;
  10.         //2.calculate actual temperature
  11.         g4_temp = ((TS_CAL2_TEMP - TS_CAL1_TEMP)*(AD_Value - TS_CAL1)/(TS_CAL2 - TS_CAL1)) + 30;
  12.         //3. test
  13.         //*ADC_PartStruct[0].Objects.objChannelValue = g4_temp;
  14.         sCh1Value = g4_temp;
  15.         //HAL_Delay(500);
  16. }

3、最后测试验证
代码写好并且编译通过后,就是上板验证看看能不能成功读取温度。在Keil里使用jlink仿真器进行调试,全速运行后,看指示温度(单位为摄氏度)的全局变量的值从开始的21慢慢上升到27: 47825682ee9af4ba34.png
又升到了29: 6328682ee9b85a1eb.png
从以上的仿真验证结果可以看出,读取MCU芯片内部温度传感器的代码和数据基本上是准确的。
不过这里没有考虑到精度问题,如果是对温度精度要求不高的场景,可以使用MCU内部温度作为数据源,如果是对温度精度要求比较高的场景,比如要保留几位小数点等,最好是先确认下你所用的MCU的内部温度传感器的精度,但是一般情况下建议直接使用外置的温度传感器,比如PT100或者热电偶之类的。

以上通过读取STM32G431KBU3芯片的内部温度数据,给大家提供了一种读取MCU芯片内部温度的基本方法,可以作为温度测试的一种参考。

83434682ee9923a587.png

评论

[url=home.php?mod=space&uid=760190]@21小跑堂[/url] :本地文档查看是有超过800字的(算上代码),我又增加了文字描述,请原创审核哦!  发表于 2025-6-4 17:22
感谢大佬分享本文未满800字不予审核  发表于 2025-6-4 16:47
gaonaiweng 发表于 2025-5-31 18:14 | 显示全部楼层
重点看温度计算公式和校准参数
 楼主| dffzh 发表于 2025-6-4 09:22 | 显示全部楼层
gaonaiweng 发表于 2025-5-31 18:14
重点看温度计算公式和校准参数

是的呢。
EchoInEons 发表于 2025-6-14 18:44 | 显示全部楼层
看下初始化校准,是否需要标定还是每次出场的时候标定一次即可?
 楼主| dffzh 发表于 2025-6-16 08:50 | 显示全部楼层
EchoInEons 发表于 2025-6-14 18:44
看下初始化校准,是否需要标定还是每次出场的时候标定一次即可?

如果对温度测量要求不高,初始化校准一次即可了。
cooldog123pp 发表于 2025-6-25 08:15 | 显示全部楼层
重点看温度计算公式和校准参数,是每次开机都需要校准吗?
 楼主| dffzh 发表于 2025-6-25 08:41 | 显示全部楼层
cooldog123pp 发表于 2025-6-25 08:15
重点看温度计算公式和校准参数,是每次开机都需要校准吗?

如果对温度测量要求不高,初始化校准一次即可,如果对精度要求高,可以定期校准一次。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

109

主题

1164

帖子

22

粉丝
快速回复 在线客服 返回列表 返回顶部