STM32 ADC 내부 온도센서 측정

김상인·2025년 4월 30일

이번 파트는 ADC실습으로 'analog input을 받기위한 센서가 없는데 어떻게 하는거지?'싶었는데, 보드 내에 온도센서가 내장되어있다고 한다. 그럼 바로 시작해보자!

늘 하던대로 프로젝트 생성 후, 내부클럭만을 사용하기 때문에 역시 HSE, LSE 비활성화 시켜준다. 그 다음 ADC1을 설정해주게 되는데 누른 후, Mode 리스트 중 Temperature Sensor Channel을 체크해준다.

그리고 계속 Analog to Digital 변환이 작동할 수 있도록 하단 parameter Settings -> ADC_Settings에서 Continuous Conversion Mode를 활성화 시킨다.

ADC_Regular_ConversionMode -> Rank -> Sampling Time을 13.5 Cycles로 변경한다. 여기서 샘플링 시간은 adc과정에서 전압을 잡아두는 시간이라고 하는데, 전압을 읽기위해 기다리는 시간이라고 이해하면 된다. 발생하는 전압을 붙잡아서 디지털값으로 변환하는데, 그렇다면 이 붙잡는 사이클이 길수록 느리지만 정확도가 높고 짧을수록 빠르지만 정확도가 낮은 값을 받는 것이다.

그럼 ADC를 활용하는 센서에 따라 개발자가 다르게 설정해줘야할텐데, 설정 기준이 센서마다 가이드가 있을까? 라는 궁금증이 생겨나서 ChatGPT에 물어봤다. 내부 센서는 잘 안쓸거같아서 외부센서 기준으로만 말하자면, 데이터 시트와 임피던스를 확인하거나 테스트를 통해서 적당한 사이클로 설정해야한다고 한다.

그 후 클럭 설정으로 넘어가면 팝업창이 뜨는데 클럭 설정에 문제가 있으면 뜨는 창이다. 자동으로 해결하고 싶으면 Yes를 클릭해 자동으로 해결하게 한다. 그러면 평소처럼 64MHz가 아닌 다른 값으로 설정되는 것을 확인할 수 있다. 책에서는 HCLK을 최대(64MHz)로 설정하고 PLLMul값을 16, ADC Prescaler를 8로 해준다.

여기서 에러나는 이유에 대해 딱히 설명이 나와있지않아 궁금해서 또 물어봤다. 그런데 설명이 뭔가 애매해서 다시 찾아봐야할 듯? 집요하게 물어보니 말을 바꿔서 답해준다.

초반에는 계속 64MHz의 클럭 주기와 사이클이 소수점을 야기해 어느정도의 정밀도 한계로 에러 발생한다, 하드웨어 시스템이 처리하지 못한다고 설명하다가, 제일 최근 답변에는 최소 요구 샘플링 시간에 미치지 못하기 때문이라고 한다. 후자가 좀 더 믿음직한 내용이다.

어쨌든 클럭 설정 후, 코드를 생성한다. main.c에서 MX_ADC1_Init() 함수를 정의하는 코드를 보면 ADC초기화 코드를 확인할 수 있다. 오른쪽 변수나 함수 등 리스트를 확인할 수 있어서, 궁금한 부분을 클릭하면 보다 쉽게 코드 파악할 수 있을 것이다.

우리는 ADC값을 눈으로 봐야하기 때문에 이전에 했던 printf에 대한 코드를 이 프로젝트에 적용시켜준다.
그리고 STM32 일부 디바이스는 리셋이나 전원이 켜진 후 ADC Self Calibration을 해줘야 정상적인 값을 읽을 수 있다고 한다. 이런 보정을 수행하는 코드를 추가해주도록 하자.

변환이 완료되길 기다리는 시간을 100ms로 하고, 이 ADC 결과값으로 온도값을 구하는 코드를 짤 것이다.
출력에서도 너무 빠른 반복 출력은 문제가 발생할 수 있어 추가로 뒤에 딜레이를 100ms 주었다.
데이터시트에서 온도값을 구하는 공식을 보면

Temperature (in °C) = ((V_SENSE - V_25) / Avg_Slope) + 25
  • V_SENSE: 현재 측정한 ADC 전압 값
  • V_25: 25℃일 때 온도센서 출력 전압 (보통 1.43V)
  • Avg_Slope: 센서 출력 전압의 평균 변화율 (보통 4.3 mV/°C)
  • 25: 기준 온도

이를 참고해서 상수값을 정의해주고 온도값을 구하는 코드를 작성한다. 그리고 시리얼 통신으로 출력값을 확인해주면 끝!

...
/* USER CODE BEGIN PV */
const float AVG_SLOPE = 4.3E-03;
const float V25 = 1.43;
const float ADC_TO_VOLT = 3.3 / 4096;
/* USER CODE END PV */
...
  uint16_t adc1;

  float vSense;
  float temp;

  while (1)
  {
	  HAL_ADC_PollForConversion(&hadc1, 100);
	  adc1 = HAL_ADC_GetValue(&hadc1);
	  //printf("ADC1_temperature: %d\n", adc1);

	  vSense = adc1 * ADC_TO_VOLT;
	  temp = (V25 - vSense) / AVG_SLOPE + 25.0;
	  printf("temperature: %d, %f\n", adc1, temp);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  HAL_Delay(100);
  }

온도센서가 어디에 달려있나 데이터시트랑 회로도를 확인하며 찾아봤는데 육안으로는 확인할 수 없는 곳에 있다고 한다. ADC1 해당 회로 주변에 배치되어있다고,, 오늘 실습 끝!

profile
이것저것 해보기

0개의 댓글