STM32 시리즈 ADC 실습하기 - Nucleo-G071RB
안녕하세요.
이전 글에서 ADC와 DAC에 이론에 대해서 간략하게 확인해 보았습니다. 이번에는 ADC를 폴링과 인터럽트모드로 사용하는 방법에 대해서 알아보겠습니다.
1. ADC 프로젝트
1) 프로젝트 생성
이전 내용에서 프로젝트 생성하는 방법을 읽었다는 전제로 간단하게 진행하도록 하겠습니다.
새로운 STM32 프로젝트를 생성하고 가지고 있는 평가보드를 선택합니다. 원하는 프로젝트 이름으로 입력하고 생성합니다.
이전과 동일하게 System Core의 RCC와 RTC 등 기본 설정을 해줍니다.
2) ADC 설정 (폴링, Polling)
사용할 ADC 핀을 선택합니다. 여기서는 A0(PA0) 핀을 통해 ADC 기능을 테스트해 보겠습니다.
PA0핀 설정을 ADC1_IN0로 선택합니다. 그리고 나머지 설정은 기본값으로 합니다.
ADC 해상도(Resolution)는 12bit로 되어 있습니다. 기본 설정을 완료했다면, 저장해서 자동으로 코드생성을 합니다.
2. 하드웨어 연결
가변저항 혹은 파워서플라이 장비가 없다는 가정하에 ADC 값의 최대, 최소 값을 확인해 보기 위해서 A0(IN0) 핀에 3.3V 전압 혹은 GND를 연결해서 테스트를 합니다.
핀을 옮겨서 끼우다 보면 쇼트나 다른 곳에 끼울 있으므로 주의해야 합니다.
3. ADC 소스 코드
ADC 변환 값을 저장하고 uart로 출력하기 위해서 변수 2개를 만듭니다.
/* USER CODE BEGIN PV */
char uart_buf[30];
int adc_value;
/* USER CODE END PV */
while 문안에 ADC 변환 시작함수를 넣어줍니다.
ADC 변환이 완료될 때까지 대기하는 함수 HAL_ADC_PollForConversion()를 추가합니다. 첫 번째 인자는 ADC 핸들러 주소값이고, 두 번째 인자는 변환 완료를 기다리는 최대시간(ms)입니다.
지정한 시간 내에 변환이 완료되지 않으면 타임아웃(HAL_TIMEOUT) 반환하거나 오류를 반환(HAL_ERROR)합니다. 여기서는 사용하지 않았지만, 정상일 경우 HAL_OK를 반환합니다.
변환이 잘 되었다면 ADC 값을 HAL_ADC_GetValue() 함수를 통해 가져옵니다. 그 후 값을 문자열로 변환해서 uart로 출력합니다.
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
adc_value = HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
memset(uart_buf, 0, 30);
sprintf(uart_buf, "adc_value : %d\r\n", adc_value);
HAL_UART_Transmit(&huart2, uart_buf, sizeof(uart_buf)-1, 1000 );
HAL_Delay(500);
/* USER CODE END WHILE */
4. ADC 폴링(Polling) 모드로 실행 결과
테스트하기 위해서 A0핀에 3.3V 전압과 GND를 연결해서 최댓값과 최솟값을 확인합니다.
5. ADC 인터럽트 모드, Interrupt mode) 설정
기존에 방식과 크게 다르지 않고 설정하는 것과 사용하는 함수에 변화가 있습니다.
1) 설정
Analog -> ADC 탭으로 이동합니다. NVIC 활성화를 체크합니다.
저장하면 필요한 코드를 자동 생성합니다.
2) 소스코드 작성
위(3번)에서 폴링모드로 작업했던 main 부분의 소스코드는 주석(//) 처리하거나 삭제합니다.
인터럽트로 설정했고, HAL_Driver의 stm32g0xx_hal_adc.c 파일을 보면 ADC 값이 변환되었을 때 발생하는 콜백함수(HAL_ADC_ConvCpltCallback)를 확인할 수 있습니다.
여기서 HAL_ADC_ConvCpltCallback함수를 재정의 해서 사용하면 됩니다. main 함수 USER CODE BEGIN 0 주석 아래 코드를 작성합니다.
인터럽트 부분에서 uart나 기타 처리를 할 수도 있지만, 인터럽트 내부에서는 최소한의 처리를 하는 것이 유리하기 때문에 변환된 값만 전역변수로 이동하는 코드를 추가합니다.
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
adc_value = HAL_ADC_GetValue(&hadc1);
}
/* USER CODE END 0 */
while 문에서 ADC 변환값을 uart로 출력합니다.
처음 HAL_ADC_Start_IT() 위치는 초기화하는 곳 등 다른 곳에 추가해도 됩니다.
그러나 ADC 변환 이후에 다시 호출해 주어야 변환 완료한 인터럽트가 발생해서 갱신된 값을 확인할 수 있습니다.
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_ADC_Start_IT(&hadc1);
HAL_Delay(500);
memset(uart_buf, 0, 30);
sprintf(uart_buf, "adc_value_it : %d\r\n", adc_value);
HAL_UART_Transmit(&huart2, uart_buf, sizeof(uart_buf)-1, 1000 );
/* USER CODE END WHILE *
6. ADC 인터럽트 모드로 실행 결과
폴링모드 테스트와 같이 A0핀에 3.3V 전압과 GND를 연결해서 최댓값과 최솟값을 확인합니다.
위의 내용은 ADC 값을 얻어 오는 단순한 방법을 알아보았습니다.
ADC 다채널 스캔, DMA 기능 연동 등 다양한 기능이 남아 있으므로 확인해 보는 것도 좋은 실습이 될 것입니다.
감사합니다.
<참고 자료>
1. 임베디드 콘트롤러 기초 7차시 - STEP 교육과정