임베디드/STM32 (ARM Cortex - M4)

[STM32] UART

O_oz 2023. 10. 20. 21:48
반응형

STM32에는 UART와 USART 포트 내장되어 있다

오늘은 그중에서 UART를 이용한 개발 보드와 PC간의 통신에 대하여 알아볼 것이다

 

UART (Universal Asynchronous Receiver Transmitter)는 비동기식 직렬 포트로 PC와 개발 보드간의 통신 포트이다

 

비동기식이란 클락 없이 데이터만 보내기 때문에 수신측이 받는 데이터가 언제 시작하고 언제 끝나는지 알 수 있는 방법이 없다

그렇기 때문에 8bit의 송신 데이터마다 Start bit와 Stop bit를 줘서 데이터 하나가 어디서부터 어디까지인지 표현한다

또 오류 검출을 위한 parity bit가 추가되는 경우도 있다

송수신측은 미리 합의된 보율 (Baud Rate, bps)로 데이터를 전송한다

 

STM32F429ZI 보드같은 경우 마이크로 5핀 케이블을 사용하는 것만으로도 PC와 UART 통신이 가능한데, 다른 보드의 경우에는 TX, RX 핀을 각각 수신측과 송신측으로 교차하여 연결하고 GND에 핀하나만 꽂으면 UART 통신을 사용할 수 있다

 

이제 UART를 사용해보자

먼저 ioc에서 위와같이 설정해주고

 

보율을 설정하고 저장해서 코드를 생성해준다

 

코드를 생성하면 main.c에서 코드가 생성된 것을 확인할 수 있고 아래와 같이 코드를 작성해준다

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
// --------------------
// call by SysTick_Handler of stm32f4xx_it.c
// ARM default timer
// enter here every 1ms
volatile int t1ms_counter = 0;	// volatile : for disable optimize
void HAL_SYSTICK_Handler(void)
{
	t1ms_counter++;	// 1ms timer
}

//----------  printf start ----------
#ifdef __GNUC__
/* With GCC, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC_ */
/**
  * @brief  Retargets the C library printf function to the USART.
  * @param  None
  * @retval None
  */
PUTCHAR_PROTOTYPE   // Add for printf
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART3 and Loop until the end of transmission */
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}
//----------  printf end ----------
/* USER CODE END 0 */

표시된 부분에 해당 코드를 작성하게 되면 printf() 함수로 PC에 출력할 수 있다

이 기능을 프로그램 오류를 잡는데 사용하면 유용하다

또 나중에 사용할 수도 있는 t1ms_counter를 선언했는데, 이 함수는 프로그램이 실행되면 매 1ms마다 counter가 증가하여 timer로 사용할 수 있다

 

그럼이제 컴포트 마스터를 설치하고 printf() 출력을 확인해보자

http://withrobot.com/data/?mod=document&uid=12

 

ComPortMaster 설치 파일

그동안 많은 분들이 사용해 주셨던 ComPortMaster 프로그램을 제공해 드립니다. 첨부파일을 다운로드 받으셔서 ZIP 압축을 해제하시고 실행하면 ComPortMaster 프로그램이 설치됩니다.

withrobot.com

장치관리자에서 포트 넘버를 확인하자

나의 경우에는 6번 포트

 

컴포트 마스터를 실행하고 디바이스에 포트 넘버, 보율에 아까 입력했던 9600을 입려하고 open port를 누른다

개발 보드를 연결하고 전원을 킨 상태여야 한다

 

이제 코드를 작성해보자

main.c의 while문 위에 프로그램을 시작한다는 것을 알리는 코드를 작성하고

 

led.c에 printf()를 추가한 뒤, main의 while문 안에서 led_main()을 호출하면 버튼에 맞춰서 입력한 string이 PC에 출력된다

 

이렇게

 

이번에는 PC에서 개발 보드로 데이터를 전송해보자

main.c에 데이터를 받을 변수를 추가하고 인터럽트를 받는 함수를 호출해준

usart.h에 위와 같이 작성한 다음

#include "uart.h"
#include <string.h>		// strncmp, strlen

extern void led_all_on(void);
extern void led_all_off(void);
extern void led_on_up(void);
extern void led_on_down(void);

extern uint8_t rx_data;				// PC
extern UART_HandleTypeDef huart3;

#define COMMAND_LENGTH 40

volatile unsigned char rx_buff[COMMAND_LENGTH];	// UART3으로부터 수신된 char를 저장하는 공간 \n라인 만날때까지
volatile int rx_index = 0;						// rx_buff의 save 위치
volatile  int newline_detect_flag = 0;			// new line을 만날을 때 indicator ex) ledallon\n

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart3)	// comport master와 연결된 uart
	{
		if (rx_index < COMMAND_LENGTH)	// 현재까지 들어온 byte가 40byte를 넘지 않으면
		{
			if (rx_data == '\n' || rx_data == '\r')
			{
				rx_buff[rx_index] = 0;	// '\0'을 삽입
				newline_detect_flag = 1;	// newline을 만났다는 flag set
				rx_index = 0;	// 다음 message 저장을 위해 rx_index 초기화
			}
			else
			{
				rx_buff[rx_index] = rx_data;
				rx_index++;
			}
		}
		else
		{
			rx_index = 0;
			printf("Message Overflow!\n");
		}
		// 주의 : 반드시 HAL_UART_Receive_IT를 call 해줘야 다음 INTTERUPT 발생
		HAL_UART_Receive_IT(&huart3, &rx_data, 1);
	}
}

void pc_command_processing(void)
{
	if (newline_detect_flag)	// comport master로부터 완전한 문장이 들어오면 (\n을 만나면)
		{
			newline_detect_flag = 0;
			printf("%s\n", rx_buff);
			if (!strncmp(rx_buff, "led_all_on", strlen("led_all_on")))
			{
				led_all_on();
				return;
			}
			if (!strncmp(rx_buff, "led_all_off", strlen("led_all_off")))
			{
				led_all_off();
				return;
			}
			if (!strncmp(rx_buff, "led_on_up", strlen("led_on_up")))
			{
				led_on_up();
				return;
			}
			if (!strncmp(rx_buff, "led_on_down", strlen("led_on_down")))
			{
				led_on_down();
				return;
			}
		}
}

uart.c에 위와 같이 코드를 작성한다

comport master로 메시지를 입력하면 해당하는 기능을 작동시킨다

 

다시 main.c로 돌아와서 pc_command_processing() 함수를 extern 해주고 위와 같이 while문 안에서 함수를 실행한다

 

 

반응형