임베디드를 좋아하는 조금 특이한 개발자?

[STM32] 인터럽트를 이용한 echo UART 통신 본문

Embedded/STM32

[STM32] 인터럽트를 이용한 echo UART 통신

Gordon_ 2024. 9. 13. 07:39

1. STM32의 UART 통신의 문제점

   STM32의 가장 큰 문제점은 아두이노에 비해 UART를 사용하기 매우 힘들기에 배우기 힘들어 한다고 생각한다. 내가 경험한 바로 크게 2가지 정도 UART를 사용하는데 힘들어하는 점은 다음과 같다.

 

1.1. 수신하려는 데이터 길이가 고정

  많은 사람들이 STM32를 다루기전에 아두이노를 먼저 사용한 경험이 있는 사람이 대부분일 것이다. 아두이노에서는 굳이 데이터의 길이를 알지 않아도 자동적으로 처리해주기에 개발하는데 매우 편리하다. 하지만, STM32의 경우 데이터를 송수신 하는 경우 데이터의 길이를 미리 알아야 송수신이 가능하다. 특히, 데이터의 길이가 가변적인 경우( ex. 명령어를 보내는 경우) 매우 난감하다.

 

1.2.  인터럽트가 도중 멈추는 경우

   MCU를 프로그래밍 하는 경우, 외부 하드웨어의 이벤트를 처리하기 위해 인터럽트를 사용한다.(버튼, 데이터 수신 등) 그러므로 UART 통신에서 데이터를 수신하기 위해서 인터럽트를 통해 수신된 데이터를 처리하려고 하지만 STM32의 경우 인터럽트가 도중에 멈추는 현상이 발생한다. 내가 생각하기에 Overrun 현상이 발생한다고 생각한다.


2. 문제점 해결 방안

2.1. 데이터를 1Byte씩 수신 및 통신 제어 문자(ETX 등) 사용

  데이터를 1Byte씩 수신하고 제어 문자를 사용하여 데이터를 구분하여 가번적인 길이를 처리 하는 방법을 사용할 수 있다.

 

2.2. Queue를 통한 데이터 수신

  인터럽트가 도중에 멈추는 문제를 해결하기 위해서는 수신되는 데이터를 인터럽트에서 수신한 후, 해당 데이터에 대한 처리는 main함수에서 처리하는 것이다. 수신된 데이터를 main 함수에서 처리하기 위해 Queue를 사용하여 Main 함수에서 수신된 데이터의 유무를 확인 하는 방법을 사용할 것이다.

 

대략적인 데이터 처리 흐름


3. STM32 CubeMX 설정

3.1. UART 통신 설정

UART 통신에 대한 설정

 

UART 인터럽트 설정


4. main.c를 C++로 빌드하기 위한 설정

Queue를 C언어로 직접 구현하여도 되지만, C++ 라이브러리에서 제공하는 Queue를 사용하기 위해 C++로 변환하는 과정을 거쳤다.

main.c 확장자를 cpp로 변경
C++로 빌드하기 위한 CMake 파일 설정

 


5. UART 수신 인터럽트 Callback 함수 작성

5.1. UART 수신 인터럽트 활성화

UART 수신 인터럽트 활성화 코드 작성

 
__HAL_UART_ENABLE_IT(&huart3,UART_IT_RXNE);

 

5.2. UART 수신 Callback 함수 선언

main.h 헤더 파일에 UART 수신 데이터를 처리하기 위한 Callback 함수를 선언한다.

UART 수신 인터럽트 함수 선언

void UART3_Data_Recv_Callback();

5.3. UART 수신 Callback 함수 호출

UART에 대한 인터럽트는 "stm32f4xx_it.c"함수에서 호출되기 때문 해당 함수에서 Callback 함수 호출

 

  if(__HAL_UART_GET_FLAG(&huart3,UART_FLAG_RXNE) == SET){
    UART3_Data_Recv_Callback();
  }

5.4. UART 수신 Callback 함수 작성

void UART3_Data_Recv_Callback(){

}

6. UART 수신 인터럽트를 통해 데이터 수신

 

 

 

 

 

void UART3_Data_Recv_Callback(){
  char data = 0;

  if(HAL_UART_Receive(&huart3,(uint8_t*)&data,1,10) != HAL_OK){
    return;
  }

  qData.push(data);
}

 

 

7. 수신된 데이터 출력

    if(qData.empty() == false){
      char data = qData.front();
      qData.pop();

      HAL_UART_Transmit(&huart3,(uint8_t*)&data,1,10);
    }

 

소스 코드:

https://github.com/MainForm/STM32_UART_echo