简介
前一段时间正好买了两个10K, B值3450的NTC电阻, 打算用来测量硬盘的温度, 正好可以使用星允派的ADC功能来对数据进行计算并且得到正确的温度.

板子上大多数的ADC PIN都被占用了, 引出的只有C口的几个PIN,如上图中我圈起来的. 因此可以使用上述的PIN作为ADC的输入.

如上图所示ADC1, 通道13. 由于需要串口输出, 所以最好再配置一下串口. 否则没办法来查看ADC的值.

生成Project, 这里需要注意的一点是在Clion中如果使用printf的话浮点数默认是没办法输出的. 我们需要配置工程下的 CMakeLists.txt. 在文件的最下面增加上以下代码.
set(LINKER_FLAGS "-u _printf_float")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LINKER_FLAGS}")
然后重写IO putchart用于printf输出
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
根据串联的10K分压电阻,采用接地法即 3.3 -> 10K电阻(接ADC引脚) 接NTC -> 地, 通过厂家提供的B值进行计算即可得到正确的温度
float temp_trans(uint16_t adc_value)
{
float Vref = 3.3f;
float R_fixed = 10000.0f;
float T0 = 298.15f; // 25°C in Kelvin
float B = 3435.0f;
float R0 = 10000.0f; // NTC 25°C 电阻
float Ka = 273.15f;
float Vout = ((float)adc_value / 4095.0f) * Vref;
float R_ntc = R_fixed * (Vout / (Vref - Vout));
float tempK = 1.0f / (1.0f / T0 + log(R_ntc / R0) / B);
float tempC = tempK - Ka;
return tempC;
}
接线图

完整的代码
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
#include <math.h>
extern ADC_HandleTypeDef hadc1;
void SystemClock_Config(void);
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
float temp_trans(uint16_t adc_value)
{
float Vref = 3.3f;
float R_fixed = 10000.0f;
float T0 = 298.15f; // 25°C in Kelvin
float B = 3435.0f;
float R0 = 10000.0f; // NTC 25°C 电阻
float Ka = 273.15f;
float Vout = ((float)adc_value / 4095.0f) * Vref;
// 使用正确的分压公式推导
float R_ntc = R_fixed * (Vout / (Vref - Vout));
float tempK = 1.0f / (1.0f / T0 + log(R_ntc / R0) / B);
float tempC = tempK - Ka;
return tempC;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_ADC1_Init();
MX_USART1_UART_Init();
while (1) {
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
uint32_t adcValue = HAL_ADC_GetValue(&hadc1);
float tempC = temp_trans(adcValue);
printf("ADC: %lu, Temp: %.2f °C\r\n", adcValue, tempC);
HAL_Delay(1000);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
效果如下

😄 还可以这样玩