MCU의 데이터를 컴퓨터로 보거나 컴퓨터에서 MCU에 데이터를 전송하고자 할 때 UART 시리얼 통신을 사용한다.

 

https://www.devicemart.co.kr/goods/view?no=1290042

 

FT232RL 아두이노 USB to UART 모듈 [SZH-EK072]

FTDI FT232RL 칩셋 / Mini USB 포트 / 33 X 17mm

www.devicemart.co.kr

컴퓨터 USB와 통신하기 위해 USB to UART ic인 FT232를 사용하여 MCU와 USB와 연결할 것이다.

 

기본적인 설정은 다루지 않을 것이다.

 

 

UART 코드 생성 (0)

USART1의 Mode는 Asynchronous로 사용하여 비동기 모드로 사용할 것이다.

 

Project Manger -> Advanced Settings에 들어가 HAL에서 LL로 변경하여 코드를 생성하면 된다.

 

 

코드 - TX (1)

971p
972p

RM0090 데이터시트 USART 부분에 데이터 전송 과정과 전송 타이밍이 나온다.

 

main.c

1
 MX_USART1_UART_Init();

 

코드의 내부를 보면 1번부터 6번까지의 과정이 이미 생성이 된 것을 알 수 있다.

 

즉 추가로 레지스터 설정을 하지 않아도 USART_DR 레지스터에 데이터를 쓰면 데이터 전송을 할 수 있다.

 

1
2
3
4
5
6
7
void USART_Transmit(USART_TypeDef *USARTx, uint8_t * data, uint16_t length){
    uint16_t i=0;
    for(i=0;i<length;i++){
        LL_USART_TransmitData8(USART1,data[i]);
        while(!LL_USART_IsActiveFlag_TXE(USART1));
    }
}
 

 

데이터시트를 참고하여 데이터를 전송하는 함수를 만들었다.

 

LL_USART_TransmitData8(); 함수는 DR 레지스터에 값을 넣는 함수이다.

 

LL_USART_IsActiveFlag_TXE(); 함수는 TXE flag에 따라 0 또는 1을 return 하는 함수이다.

 

 

1
2
#include <stdio.h>
#include <string.h>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  /* USER CODE BEGIN 2 */
  uint32_t count=0;
  uint16_t length;
  uint8_t data[20];
 
  memset(data,0x00,sizeof(data));
  length=sprintf(data,"start\r\n");
  USART_Transmit(USART1,data,length);
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      LL_mDelay(200);
      count++;
      memset(data,0x00,sizeof(data));
      length=sprintf(data,"count:%d\r\n",count);
      USART_Transmit(USART1,data,length);
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

 

memset과 sprintf를 사용하기 위해 stdio.h와 string.h를 include 해준다.

 

memset으로 data의 모든 값들을 전부 0x00으로 바꿔준다.

 

sprintf로 " " 내부의 문자열을 data배열에 저장한다.

 

USART_Transmit(); 함수로 데이터를 전송한다.

 

결과

MCU에 코드를 올리고 FT232 모듈을 사용해 SmarTTY, Realterm과 같은 터미널 프로그램으로 데이터를 받아보면 이런 결과를 얻을 수 있다.

 

 

코드 - printf (2)

USART_Transmit() 함수로 데이터를 전송할 수 있지만  data배열을 선언하고 sprintf로 문자열을 옮기고 다시 함수를 불러 데이터를 전송하는 과정이 매우 귀찮을 수 있다.

 

따라서 기존 c언어 printf함수를 사용하여 MCU에서도 간단하게 데이터 출력이 가능하도록 하겠다.

 

main.c

1
2
3
4
5
6
7
8
9
#include <stdio.h>
 
int _write(int file,uint8_t* p, int len){
    for(int i=0;i<len;i++){
        LL_USART_TransmitData8(USART1,p[i]);
        while(!LL_USART_IsActiveFlag_TXE(USART1));
    }
    return len;
}
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /* USER CODE BEGIN 2 */
  uint32_t count=0;
 
  printf("start\r\n");
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      LL_mDelay(200);
      count++;
      printf("print count:%d\r\n",count);
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

 

main.c에서 _write() 함수만 추가하면 간단하게 코드를 넣을 수 있고 데이터 출력이 가능하다.

 

_write() 함수 내부에 UART로 출력하도록 코드를 짜면 printf를 사용하여 데이터를 출력할 수 있다.

 

결과

MCU에 코드를 올려 터미널 프로그램으로 확인해 보면 잘 작동하는 모습을 볼 수 있다.

 

 

 

-

한 번에 UART RX, RX DMA에 관한 내용을 쓰려했지만 양이 너무 많아져 2개로 나눠야 할 것 같다.

 

UART로 데이터를 컴퓨터로 전송하는 것은 드론을 만들 때 중요하다.

 

드론의 데이터를 보면서 버그가 난 부분을 빠르게 찾기 위해 많이 사용하며, 세팅되어 있는 값들을 볼 때 자주 사용한다.

 

다음에 바로 쓸 RX는 드론의 파라미터를 바꾸거나, GPS 데이터를 받고 리시버의 데이터를 받을 때 사용하므로 매우 중요한 부분이다.

 

 

 

추가-

ddtxrx.tistory.com/entry/STM32-Circular-Buffer-printf

 

[STM32] Circular Buffer printf

수정 (2021.03.17) DMA의 TC 인터럽트를 사용하지 않아도 작동되게 조금 수정을 했다. ========================================== MCU의 UART 메시지를 출력하기 위해 printf를 사용하여 데이터를 출력했었다...

ddtxrx.tistory.com

Circular Buffer로 구현한 printf 글이다.

Posted by DDTXRX
,