1. Nucleo-G071RB 보드의 UART 연결(평가보드 UART와 PC 연결 형태)
1) Nucleo-G071RB 보드 구성
외부 핀을 연결해서 테스트할 수 있지만, 평가보드(Eval Board)에는 ST-LINK와 함께 시리얼통신을 할 수 있는 가상 COM PORT를 지원합니다.
보드에 전원을 인가하고 장치 관리자의 포트를 확인하면 STLink Virtual COM PORT가 추가되어 있습니다. STM32 CUBE IDE 프로그램을 설치할 때 보통 같이 설치가 되나 그렇지 않다면 검색을 해서 별도로 설치해 주어야 합니다.
2) Nucleo-G071RB UART 회로 부분
STM32G071의 UART2_RX, TX와 STM32F103의 STLK_RX, TX가 연결되어 시리얼 통신을 하게 하고 이것을 다시 HOST PC와 가상 시리얼 통신포트 USB를 통해 통신을 합니다.
쉽게 말해 USB to UART 기능을 추가해 놓았습니다.
2. USART 프로젝트
1) 프로젝트 생성
이전 내용에서 프로젝트 생성하는 방법을 알고 있다는 전제로 간단하게 진행하도록 하겠습니다.
새로운 STM32 프로젝트를 원하는 이름으로 생성합니다.
STM32G071RB경우, 위에서 본 회로도에서 G071의 UART2가 F103 MCU와 연결되어 USB와 PC를 다시 연결해 주는 것을 알 수 있습니다.
2) 프로젝트 설정
Nucleo 보드로 설정했다면 기본 USART 설정은 되어 있을 것입니다. 그러나 STLK-UART 포트 번호는 사용하는 보드마다 다를 수 있습니다. 현재 G071RB는 USART2번이 PC와 연결할 수 있습니다.
설정을 확인하면 Baud Rate 115200 bps, Data 8bit 등 기본 설정으로 되어 있고, 그대로 사용합니다.
NVIC Setting은 Polling 방식을 먼저 확인 후에 Interrupt 방식을 확인하겠습니다.
3) 기타 설정
System Core의 RCC 등 설정은 이전 글에서 본 것과 동일하게 각자 보드의 맞춰서 작업합니다.
Necleo-G071RB 경우,
System Core->RCC->HSE : Disable
Timers->RTC->Mode : Activate Clock Source 체크
Clock Configuration도 최대 클럭이 나오도록 설정합니다. 사용하는 보드마다 PLL 설정값은 다를 수 있습니다.
나머지는 기본 설정으로 사용합니다. 그리고 저장해서 기본 코드를 자동 생성합니다.
3. USART 소스코드 작성
1) 폴링(Polling) 방식으로 전송
(1) 전송부 함수
사용할 함수는 HAL_UART_Transmit()입니다.
Drivers/STM32G0xx_HAL_Driver/Src/stm32g0xx_hal_uart.c 소스파일에 구현부가 있습니다. 인터럽터 방식의 함수와 다르게 마지막 인자에 Timeout 인자가 하나 더 있습니다.
Timeout 인자 값은 전송완료 대기 시간으로 밀리초(ms) 값이며, 무한대기에 빠지지 않고, 전송완료하지 못하면 에러를 발생해서 다른 작업을 할 수 있게 해 줍니다.
(2) 전송부 구현
main.c함수의 while문 주변에 간단한 문자열 배열을 만들고 그 배열을 HAL_UART_Transmit() 함수로 전송하는 함수를 호출합니다. sizeof() -1은 null 종단 문자를 제외한 크기를 나타내며, 전송이 완료될 때까지 최대 1초 동안 기다립니다.
/* USER CODE BEGIN 2 */
uint8_t uart_data[] = "Uart Test Message\r\n";
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_UART_Transmit(&huart2, uart_data, sizeof(uart_data) -1, 1000);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
(3) PC 시리얼 프로그램
소스코드를 빌드하고 Run As 혹은 Debug As를 해서 작성한 코드를 다운로드합니다. Putty, Tera Term과 같은 시리얼 통신프로그램을 실행해서 데이터를 확인하면 됩니다. 중요한 것은 장치관리자에서 확인한 COM PORT와 설정한 Baud Rate 값으로 PC 프로그램을 맞춰 실행해야 합니다.
(4) 결과 확인
1초마다 입력한 메시지가 PC COM Port로 전송되는 것을 확인할 수 있습니다.
2) 인터럽트(Interrupt) 방식으로 작성
(1) USART2 인터럽트 활성화
위에서 본 USART2 설정에서 인터럽트 설정을 체크합니다. 저장을 하면 필요한 코드가 자동으로 추가됩니다.
(2) 전송부 함수
STM32G0xx_HAL_Drivr/Src/stm32g0xx_hal_uart.c 파일에 구현된 HAL_UART_Transmit_IT 함수를 찾을 수 있습니다. HAL_UART_Transmit과 차이는 Timeout 인자가 하나 없고 이름에 _IT가 붙어 있습니다. 그래서 polling과 유사하게 구현할 수 있습니다.
(3) 전송부 구현
main.c함수의 while문 주변에 간단한 문자열 배열을 만들고 그 배열을 HAL_UART_Transmit_IT() 함수로 전송하는 함수를 호출합니다.
/* USER CODE BEGIN 2 */
uint8_t uart_data[] = "Uart Interrupt Test Message\r\n";
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_UART_Transmit_IT(&huart2, uart_data, sizeof(uart_data) -1);
HAL_Delay(1000);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
(4) 결과 확인
입력한 "Uart Interrupt Test Message" 메시지가 1초마다 PC COM Port로 전송되는 것을 확인할 수 있습니다.
3) 인터럽트를 이용한 수신부 (LoopBack 구현)
(1) 수신부 함수
인터럽트 방식으로 데이터를 수신하기 위해서는 몇 가지 함수를 알고 있어야 합니다.
HAL_UART_Receive_IT 함수는 STM32 HAL 라이브러리에서 제공하는 함수로, UART를 통해 데이터를 비동기적으로 수신하는 데 사용됩니다.
이 함수는 인터럽트 방식을 사용하여 데이터를 수신하며, 데이터 수신이 완료하면 수신 완료 인터럽트를 발생시켜 콜백 함수를 호출합니다.
이 방식을 통해 메인 루프가 데이터 수신 대기 상태에 빠지지 않고 다른 작업을 할 수 있습니다.
HAL_UART_RxCpltCallback 함수는 UART 수신이 완료되었을 때 호출됩니다.
이 콜백 함수는 HAL_UART_Receive_IT 함수를 사용하여 데이터를 인터럽트 방식으로 수신할 때, 수신이 완료되면 자동으로 호출됩니다.
(2) 송수신 Loopback 구현
main.c 파일에 1byte를 저장할 수 있는 변수를 하나 선언합니다. /* USER CODE BEGIN PV */ 부분에 변수를 하나 선언합니다.
/* USER CODE BEGIN PV */
volatile uint8_t rxd;
/* USER CODE END PV */
/* USER CODE BEGIN 4 */ 부분에 송신, 수신 콜백함수를 구현합니다.
HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) 함수는 UART 수신이 완료될 때 호출되며, huart->Instance가 USART2인지 확인합니다.
만약 USART2이면, HAL_UART_Transmit_IT(&huart2, &rxd, 1) 함수를 호출하여 USART2로 수신한 1byte(rxd) 데이터를 비동기적으로 전송합니다.
HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) 함수는 UART 전송이 완료될 때 호출되며 huart->Instance가 USART2인지 확인합니다.
만약 USART2이면, HAL_UART_Receive_IT(&huart2, &rxd, 1) 함수를 호출하여 USART2에서 1바이트 데이터를 비동기적으로 수신 대기(수신 인터럽트를 다시 활성화)합니다.
/* USER CODE BEGIN 4 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
HAL_UART_Receive_IT(&huart2, &rxd, 1);
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
if (huart->Instance == USART2) {
HAL_UART_Transmit_IT(&huart2, &rxd, 1);
}
}
/* USER CODE END 4 */
처음 시작할 때 바로 데이터를 받을 수 있게 수신 인터럽트를 활성화해 놓습니다.
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart2, &rxd, 1);
/* USER CODE END 2 */
(3) 결과 확인
터미널창에 키를 입력하면 화면에 입력한 키값이 나타납니다.
1byte씩 데이터를 보내면 Echo처럼 보낸 값을 받을 수 있습니다.
3. 인터럽트와 폴링 모드 간략 장단점
인터럽트 모드는 효율적인 CPU 사용과 빠른 응답을 제공하지만, 구현이 복잡하고 인터럽트 오버헤드(컨텍스트 스위칭, 인터럽트 빈도 등)가 발생할 수 있습니다.
폴링 모드는 간단하게 구현할 수 있지만, CPU 자원을 많이 소비하고 응답 시간이 느릴 수 있습니다.
어떤 모드를 선택할지는 애플리케이션의 요구사항과 시스템 자원의 여유에 따라 결정하면 됩니다. 특정 상황에서는 두 모드를 함께 사용하는 하이브리드 접근 방식도 고려해 볼 수 있습니다.
약간은 복잡하다고 생각할 수 있는데, Uart를 사용할 때 2가지 방식이 있고(사실, DMA 방식이 하나 더 있음), 이렇게 사용하는구나 정도로 이해하면 어떨까 합니다. 조금 더 효율적으로 사용하기 위해서는 링버퍼를 사용할 수 있습니다.
감사합니다.
<참고 자료>
1. 임베디드 콘트롤러 기초 5차시 - STEP 교육과정
2. STM32F4 HAL 라이브러리를 이용하여 인터럽트 방식으로 UART 사용하기
https://blog.naver.com/ajoo92/221539334918
3. How to use HAL_UART_Receive_IT to receive uart data?
'Embedded > STM32' 카테고리의 다른 글
STM32 시리즈 ADC 실습하기 - Nucleo-G071RB (0) | 2025.03.03 |
---|---|
STM32 시리즈 ADC와 DAC 이론 학습 - Nucleo-G071RB (0) | 2025.02.27 |
STM32 시리즈 UART 이론 학습 - Nucleo-G071RB (STM32F 차이점) (2) | 2025.02.18 |
STM32 시리즈 타이머(Timer) 실습하기 - Nucleo-G071RB (0) | 2025.02.15 |
STM32 시리즈 타이머(Timer) 이론 학습 (5) | 2025.02.13 |