로봇/STM32

STM32 UART로 보드 제어하기

with-RL 2023. 3. 1. 20:26

이번 과정은 UART 통신을 이용해 STM32 보드에 명령을 보내고 명령을 실행하는 기능을 구현하는 과정입니다.

아래 과정은 아래 환경과 보드를 이용했습니다.

  • Windows 11 Home
  • STM32CubeIDE-1.11.2
  • STM32 NUCLEO-F103RB 보드

1. 프로젝트 생성하기

  • STM32 프로젝트를 생성합니다.

  • 다음과 같이 동작하는 프로그램을 작성하도록 하겠습니다.
    ◦ 사용자는 UART를 이용해 STM32에 명령을 보냅니다. (1 ~ 9 사이의 숫자)
    ◦ 이때 Interrupt가 발생합니다.
    ◦ Interrupt Cabllback에서 명령에 해당하는 기능을 수행합니다. (1: LED 끄기, 2: LED 켜기)
    ◦ STM32는 명령 수행 결과를 UART를 이용해 출력합니다.

2. 핀 설정 및 소스코드 생성하기

  • UART 통신을 하기 위해서 'Connectivity' > 'USART2'에서 아래와 같이 설정합니다.
    ◦ Mode: Asynchronous
    ◦ 'Parameter Settings' > 'Basic Parameters' > 'Baud Rate': 9600

  • 'Connectivity' > 'USART' > 'NVIC Settings'에서 'USART2 global interrupt'의 'Enabled'를 선택합니다.

  • 'System Core' > 'GPIO' > 'PA5' 핀의 User Label을 'LED'로 변경합니다.

  • 버튼에 해당하는 'PC13' 핀을 'GPIO_EXTI13'으로 설정합니다. (기본값)

  • 'System Core' > 'GPIO' > 'PC13' 핀의 값을 아래와 같이 변경합니다.
    ◦ GPIO mode: 'External Interrupt Mode with Rising edge trigger detection'
    ◦ GPIO Pull-up/Pull-down: 'No pull-up and no pull-down'
    ◦ User Label: 'BTN'

  • 'System Core' > 'GPIO' > 'NVIC'에서 'Exit line[15:10] interrupts'의 'Enabled'를 선택합니다.

  • 'System Core' > 'NVIC' > 'NVIC'에서 아래 두 포트의 'Enabled'를 선택합니다.
    ◦ USART2 golbal interrupt
    Exit line[15:10] interrupts

  • 'Ctrl + S' 또는 'Code Generation' 버튼을 눌러서 코드를 생성합니다.

  • main.h 파일에 아래와 같이 설정한 핀들이 지정된 것을 확인할 수 있습니다.

  • stm32f1xx_hal_gpio.c 파일에 GPIO Interrupt를 처리하기 위한 함수가 __weak로 정의되어 있는 것을 확인할 수 있습니다.

  • stm32f1xx_hal_uart.c 파일에 UART Interrupt를 처리하기 위한 함수가 __weak로 정의되어 있는 것을 확인할 수 있습니다.

3. printf를 UART로 출력하기 위한 설정

  • printf를 이용한 출력이 UART로 출력될 수 있도록 설정하는 과정입니다.
  • 프로젝트를 선택한 후 마우스 메뉴버튼을 눌러서 뜨는 팝업메뉴에서 'Properties'를 선택합니다.

  • 실행되는 Properties 창에서 'C/C++ Build' > 'Settings' > 'Tool Settings' > 'MCU Settings'를 선택한 후 'Use float with printf form newlib-nono (-u _printf_float)'를 선택합니다.

  • main.c 파일의 /* USER CODE BEGIN Includes */ 아래와 같이 include를 추가합니다.
#include <stdio.h>

  • main.c의 /* USER CODE BEGIN PFP */ 다음에 아래 코드를 추가합니다.
int __io_putchar(int ch)
{
     (void) HAL_UART_Transmit(&huart2, (uint8_t*) &ch, 1, 100);
     return ch;
}

4. 코드 작성 및 컴파일

  • UART를 이용해 데이터를 수신할 1byte buffer를 선언합니다.
uint8_t rx_data;

  • /* USER CODE BEGIN 2 */ 다음에 UART 입력이 발생하면 수신 Interrupt가 발생하도록 아래 코드를 추가합니다.
HAL_UART_Receive_IT(&huart2, &rx_data, 1);
  • /* USER CODE BEGIN 3 */ 다음에 주기적으로 LED가 깜빡이도록 아래 코드를 추가합니다.
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);  // LED On
HAL_Delay(500);
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);  // LED Off
HAL_Delay(500);

  • /* USER CODE BEGIN 4 */ 다음에 Button이 눌리면 'Button Pressed' 메시지가 출력되도록 아래 코드를 입력합니다.
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin == BTN_Pin)
	{
		printf("Button Pressed\r\n");
	}
}
  • 방금 전에 작성한 'HAL_GPIO_EXTI_Callback' 함수 다음에 UART 입력이 발생하면 'Key Pressed' 메시지를 출력하고 다음 UART 입력을 기다리도록 아래 코드를 입력합니다.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART2) {
		printf("Key Pressed: %c\r\n", rx_data);
		HAL_UART_Receive_IT(&huart2, &rx_data, 1);
	}
}

  • 툴바에서 'Build Debug' 버튼을 눌러서 컴파일 실행합니다.

5. 다운로드 및 디버깅

컴파일된 이미지를 다운로드하고 테스트합니다.

  • Teraterm을 실행하고 아래와 같이 Serial을 선택합니다.

  • 버튼을 누르면 'Button Pressed'를 키보드를 입력하면 'Key Pressed'가 출력되는 것을 확인할 수 있습니다.

6. '1'을 입력하면 LED가 켜지고 '2'를 입력하면 LED가 꺼지도록 수정

  • /* USER CODE BEGIN 0 */ 아래쪽에 아래와 같이 수행할 수 있는 명령을 출력할 수 있도록 하는 함수를 생성합니다.
void print_cmd()
{
	printf("----------\r\n%s\r\n%s\r\n----------\r\nEnter Command:\r\n",
			"1: LED On",
			"2: LED Off");
}

  • /* USER CODE BEGIN 2 */ 아래쪽에 print_cmd() 함수를 실행하도록 해서 최초에 실행가능한 명령을 출력하도록 수정합니다.
print_cmd();
  • /* USER CODE BEGIN 3 */ 아래쪽에 기존 코드를 삭제하고 아무런 일도 수행하지 않도록 아래와 같이 수정합니다.
HAL_Delay(1000);

  • HAL_UART_RxCpltCallback 함수를 아래와 같이 수정합니다.
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart->Instance == USART2) {
		if (rx_data == '1')
		{
			printf("LED On execute\r\n");
			HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
		}
		else if (rx_data == '2')
		{
			printf("LED Off execute\r\n");
			HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
		}
		HAL_UART_Receive_IT(&huart2, &rx_data, 1);
		print_cmd();
	}
}

  • 코드 수정이 완료 됐으니 컴파일하고 실행합니다.
    아래와 같이 메뉴가 출력되고 1을 입력하면 LED가 켜지고 2를 입력하면 LED가 꺼지는 것을 확인할 수 있습니다.