이 블로그는 임베디드 컴퓨터를 이용한 장치(시스템) 개발과 원격제어에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Microchip 사의 ATmega128를 사용한 보드와 Arduino Mega 보드(ATmega2560), Raspberry Pi Pico, Raspberry Pi, WiFi 모듈을 사용 합니다.

uart-pico-arduino

Pi Pico UART - Arduino
Raspberry Pi Pico UART(Serial Communication) - Arduino


  • Raspberry Pi Pico UART
    • UART 개요
      • 참고자료: "RP2040 A microcontroller by Raspberry Pi" 4.2.UART

      • RP2040의 UART
        • RP2040에는 ARM Primecell UART(PL011)(Revision r1p5)를 기반으로 하는 2개의 동일한 UART가 있다.
        • 각 UART는 다음 기능을 지원한다.
          • 분리된 32x8 Tx 와 32x12 Rx FIFO Buffer
          • clk_peri에 의하여 Clock 되는 Programmable baud rate generator
          • 전송시 자동으로 삽입되고 수신시 자동으로 제거되는 Standard asynchronous communication bits(start, stop, parity)
          • Line break detection
          • Programmable serial interface(5, 6, 7, or 8 bits)
          • 1 or 2 stop bits
          • Programmable hardware flow control
        • 각 UART는 GPIO muxing 테이블에 정의된 여러 GPIO 핀에 연결할 수 있다.
        • 참고자료: Raspberry Pi Pico Pinout

      • UART 가 실행하는 중요 기능
        • 주변 장치에서 수신한 직렬 데이터를 병렬로 변환한다.
        • 주변 장치로 전송하는 병렬 데이터를 직렬로 변환한다.
        • CPU는 AMBA APB 인터페이스를 통해 데이터 및 제어/상태 정보를 읽고 쓴다.
        • 송신 및 수신 데이터는 내부 FIFO 메모리로 버퍼링되어 송신 및 수신 모드에서 최대 32바이트를 독립적으로 저장할 수 있다.
        • UART 내부 기준 클럭 입력(UARTCLK)에서 송신 및 수신에 공통으로 사용하는 클럭을 생성하는 프로그래밍 가능한 Baud rate generator가 포함되어 있다.
        • 업계 표준 16C650 UART 장치와 유사한 기능을 제공한다.
        • UART 모드에서 최대 921600bps 속도를 지원한다.
        • 수신(타임아웃 포함), 전송, 모뎀 상태 및 오류 조건이 발생할 경우 개별적으로 마스크 가능한 인터럽트를 발생 시킨다.
        • DMA(Direct Memory Access) 컨트롤러와 인터페이스하기 위한 DMA 요청 신호를 발생 시킨다.
        • 수신 중에 프레임, 패리티 또는 중단 오류가 발생하면 적절한 오류 비트가 설정되고 FIFO에 저장된다.
        • 만약 Overrun condition이 발생하면 Overrun 레지스터 비트가 즉시 설정되고 FIFO에 데이터가 덮어쓰기 되지 않는다.
      • UART block diagram과 중요 기능
        • UART block diagram

        • AMBA APB interface
          • AMBA APB 인터페이스는 상태/제어 레지스터 와 송수신 FIFO의 액세스를 위한 읽기 및 쓰기 디코드 신호를 생성한다.
        • Register block
          • Register block은 AMBA APB 인터페이스를 통해 기록되거나 읽을 데이터(UART 제어와 기능 수행에 필요한 데이터)를 저장한다.
        • Baud rate generator
          • Baud rate generator에는 내부 클럭(Baud16 및 IrLPBaud16 신호)을 생성하는 free-running counters가 포함되어 있다. Baud16은 UART 송수신 제어를 위한 타이밍 정보를 제공한다. Baud16은 baud rate의 16배의 주파수를 갖는 펄스 스트림이다.
        • Transmit FIFO
          • Transmit FIFO는 8비트 너비에 32개 깊이의 FIFO 메모리 버퍼이다. CPU에서 작성된 데이터는 전송 로직에서 읽을 때까지 FIFO에 저장된다. 전송 FIFO를 비활성화하여 1바이트만 저장하는 레지스터 처럼 작동하게 할 수 있다.
        • Receive FIFO
          • Receive FIFO는 12비트 너비에 32개 깊이의 FIFO 메모리 버퍼이다. 수신된 데이터와 해당 오류 비트는 APB 인터페이스를 통해 CPU가 읽을 때까지 수신 로직을 통해 수신 FIFO에 저장된다. 수신 FIFO를 비활성화하여 1바이트만 저장하는 레지스터 처럼 작동하게 할 수 있다.
        • Transmit logic
          • Transmit logic은 전송 FIFO에서 읽은 데이터에 대해 병렬-직렬 변환을 수행한다. 제어 로직은 시작 비트로 시작하는 직렬 비트 스트림을 먼저 출력하고, 최하위 비트(LSB)로 시작하는 데이터 비트를 먼저 출력한 다음, 패리티 비트를 차례로 출력하고, 제어 레지스터에서 프로그래밍된 구성에 따라 정지 비트를 출력한다.
        • Receive logic
          • Receive logic은 유효한 시작 펄스가 감지된 후 수신된 비트 스트림에 대해 직렬-병렬 변환을 수행한다. 오버런, 패리티, 프레임 오류 검사 및 라인 중단 감지도 수행되며, 이러한 상태는 수신 데이터에 추가되어 FIFO에 저장된다.
        • Interrupt generation logic
          • 개별 마스크 설정이 가능한 인터럽트는 UART에 의해 생성된다. 개별 인터럽트 요청은 OR 함수로 결합되어 생성되며 프로세서 인터럽트 컨트롤러에 연결된다.
        • DMA interface
          • UART는 DMA 컨트롤러에 연결하는 인터페이스를 제공(Section 4.2.5 UART DMA Interface 참고요)한다.

  • 자주 사용하는 UART 관련 함수 - C/C++ SDK
    • UART의 초기화와 기능을 설정하는 함수
      • Serial.begin(): UART를 초기한다. UART를 사용하기 전에 실행하여야 한다.
        • 기본형:
          • Serial.begin(speed)
          • erial.begin(speed, config)
        • 매개 변수
          • Serial: Serial port object
          • speed: Bits per second (baud). Data types: long.
          • config: Data, Parity, Stop bits를 설정한다. 설정 예는 아래와 같다.
            • SERIAL_8N1: 8 Data Bits(5 - 8), No Parity, One Stop bits. Arduino default
            • SERIAL_8E2: 8 Data Bits(5 - 8), Even Parity, 2 Stop bits
            • SERIAL_7O1: 7 Data Bits(5 - 8), Odd Parity, 1 Stop bits
        • Returns: Nothing
        • Code 예
      • Serial.end(): UART를 비활성화하여 RX 와 TX 핀을 일반 입력 및 출력에 사용할 수 있게한다. 다시 사용하려면 다시 초기화해야 한다.
        • 기본형: Serial.end()
        • 매개 변수
          • Serial: Serial port object
        • Returns: Nothing
      • Serial.flush(): 출력 중인 직렬 데이터의 전송이 완료될 때까지 기린다.
        • 기본형: Serial.flush()
        • 매개 변수
          • Serial: Serial port object
        • Returns: Nothing
      • serialEvent(): 데이터가 준비된 경우 루프()의 끝에서 호출된다. Serial.read()를 사용하여 이 데이터를 읽는다.
        • 기본형:
        • 매개 변수
          • statements: Arduino에서 사용할 수 있는 Statements
        • Returns: Nothing
      • Serial.setTimeout(): 직렬 데이터를 대기할 최대 시간(Milliseconds)를 설정한다. 기본값은 1000 Milliseconds 이다.
        • 기본형: Serial.setTimeout(time)
        • 매개 변수
          • Serial: Serial port object
          • time: 직렬 데이터를 대기할 최대 시간(Milliseconds)
        • Returns: Nothing
    • 읽기(Read) 기능을 수행하는 함수
      • Serial.read(): UART에서 한 문자를 읽는다. 이 기능은 문자를 읽을 때까지 기다린다.
        • 기본형: Serial.read()
        • 매개 변수
          • Serial: Serial port object
        • Returns: 사용 가능한 직렬 데이터의 첫 번째 바이트(사용 가능한 데이터가 없는 경우 -1). Data type: int.
        • Code 예
      • Serial.readBytes(): 직렬 포트에서 버퍼로 문자를 읽는다. 지정된 길이의 문자를 읽었거나 시간이 초과되면 기능이 종료된다(Serial.setTimeout() 참고요).
        • 기본형: Serial.readBytes(buffer, length)
        • 매개 변수
          • Serial: Serial port object
          • buffer: 문자를 저장할 버퍼이다. 허용되는 데이터 형식: 문자 또는 Byte 배열
          • length: 읽을 문자(Byte) 수. 허용되는 데이터 형식: int.
        • Returns: 버퍼에 입력된 문자(Byte) 수. 데이터 유형: size_t.
      • Serial.readBytesUntil(): Serial.read 직렬 버퍼에서 배열(Array)로 문자를 읽는다. 지정된 길이가 읽혔거나, 시간 초과된 경우(Serial.setTimeout() 참조) 또는 종료 문자가 감지된 경우(이 경우 함수는 제공된 종료 문자 이전의 문자까지 문자를 반환함) 종료된다. 종료 문자는 버퍼에 반환되지 않는다.
        • 기본형: Serial.readBytesUntil(character, buffer, length)
        • 매개 변수
          • Serial: Serial port object
          • character: 종료 문자. 허용되는 데이터 형식: char.
          • buffer: 문자를 저장할 버퍼이다. 허용되는 데이터 형식: 문자 또는 Byte 배열
          • length: 읽을 문자(Byte) 수. 허용되는 데이터 형식: int.
        • Returns: 버퍼에 입력된 문자(Byte) 수. 데이터 유형: size_t. 0 또는 0보다 작은 값(<=0)이 반환된 경우는, 문자 입력 전에 시간 초과가 발생했거나 문자 입력 전에 종료 문자가 발견되었음을 의미한다.
      • Serial.readString(): 직렬 버퍼에서 문자열로 문자를 읽는다. 시간이 초과되면 기능이 종료된다(setTimeout() 참고요).
        • 기본형: Serial.readString()
        • 매개 변수
          • Serial: Serial port object
        • Returns: 직렬 버퍼에서 읽은 문자열
        • Code 예
      • Serial.readStringUntil(): 직렬 버퍼에서 문자열로 문자를 읽는다. 시간이 초과되면 기능이 종료된다(setTimeout() 참고요).
        • 기본형: Serial.readStringUntil(terminator)
        • 매개 변수
          • Serial: Serial port object
          • terminator: 종료 문자. 허용되는 데이터 형식: char.
        • Returns: 직렬 버퍼에서 종료 문자까지 읽은 전체 문자열
      • Serial.peek(): 입력되는 직렬 데이터의 첫 번째 바이트(문자)를 반환한다. 내부 직렬 버퍼에서 데이터를 제거하지 않는다.
        • 기본형: Serial.peek()
        • 매개 변수
          • Serial: Serial port object
        • Returns: 사용 가능한 직렬 데이터의 첫 번째 바이트(사용 가능한 데이터가 없는 경우 -1). Data type: int.
    • 쓰기(Write) 기능을 수행하는 함수
      • Serial.print(): 데이터를 읽을 수 있는 ASCII 텍스트로 직렬 포트에 인쇄한다.
        • 숫자는 각 숫자에 대해 ASCII 문자를 츌력한다.

          실수는 ASCII 문자를 사용하여 츌력되고, 기본 형태는 소수점 두 자리로 츌력된다.

          문자와 문자열은 그대로 전송된다.

        • 기본형:
          • Serial.print(val)
          • Serial.print(val, format)
        • 매개 변수
          • Serial: Serial port object
          • val: 츌력할 값. 허용되는 데이터 유형: 모든 데이터 유형.
          • format: 츌력 형태을 지정한다.
        • Returns: Write 한 바이트 수를 반환한다. 그러나 이 숫자를 읽는 것은 선택 사항이다. 데이터 유형: size_t.
        • Coding 예
          • Serial.print(x, DEC); // x 값을 10진수(Decimal)로 출력한다.
          • Serial.print(x, HEX); // x 값을 16진수(Hexadecimal)로 출력한다.
          • Serial.print(x, OCT); // x 값을 8진수(Octal)로 출력한다.
          • Serial.println(x, BIN);// x 값을 8진수(Binary)로 출력한다.
          • Serial.print("\t"); // tab 코드를 출력한다.
          • Serial.println(); // Carriage return을 출력한다.
      • Serial.println(): 데이터를 읽을 수 있는 ASCII 텍스트로 출력하고, 데이터 다음에 Carriage return code(ASCII 13 또는 '\r')와 Newline code(ASCII 10 또는 '\n')를 출력한다.
        • 기본형:
          • Serial.println(val)
          • Serial.println(val, format)
        • 매개 변수
          • Serial: Serial port object
          • val: 츌력할 값. 허용되는 데이터 유형: 모든 데이터 유형.
          • format: 츌력 형태을 지정한다.
        • Returns: Write 한 바이트 수를 반환한다. 그러나 이 숫자를 읽는 것은 선택 사항이다. 데이터 유형: size_t.
      • Serial.write(): Binary data를 직렬 포트에 Write 한다.
        • 기본형:
          • Serial.write(val)
          • Serial.write(str)
          • Serial.write(buf, len)
        • 매개 변수
          • Serial: Serial port object
          • val: 츌력할 값(Single byte)
          • str: 츌력할 String(Series of bytes)
          • buf: 츌력할 배열(Array: Series of bytes)
          • len: 배열(Array)에서 출력할 Byte 수
        • Returns: 출력한 문자(Byte) 수. 데이터 유형: size_t.
    • UART의 상태(값)을 확인하는 함수
      • if(Serial): 지정한 직렬 포트가 준비되었는지 여부를 나타낸다.
        • 기본형: if(Serial)
        • 매개 변수: None
        • Returns: 지정한 직렬 포트를 사용할 수 있는 경우 True를 반환한다.
        • Code 예
      • Serial.available(): 직렬 포트에서 읽을 수 있는 문자(Byte) 수를 가져온다. 이 데이터는 이미 도착하여 직렬 수신 버퍼(64바이트 저장)에 저장된 데이터이다.
        • 기본형: Serial.available()
        • 매개 변수
          • Serial: Serial port object
        • Returns: 읽을 수 있는 Byte 수
      • Serial.availableForWrite(): Write 동작을 중단하지 않고 직렬 버퍼에 쓸 수 있는 문자(Byte) 수를 가져온다.
        • 기본형: Serial.availableForWrite()
        • 매개 변수
          • Serial: Serial port object
        • Returns: Write 할 수 있는 문자(Byte) 수

  • Raspberry Pi Pico UART 프로그램 예
    • UART basic
      • Pi Pico 개발보드는 내장된 USB 단자(Serial), 보드의 UART0 핀(Serial1), 보드의 UART1 핀(Serial2)을 이용하여 Serial communication을 할 수 있다.

        이 프로그램은 Keyboard로 부터 한 문자를 읽어 이 문자와 문자열 메세지를 출력한다.

      • 개발보드에 내장된 USB 단자를 사용하는 경우 실험 회로 구성 예: 내장된 USB 단자를 사용하기 때문에 별도의 UART 신호를 연결하지 않아도 된다.
      • 개발 보드의 UART0 핀(Serial1)또는 보드의 UART1 핀(Serial2)를 사용하는 실험 회로 구성 예: 개발보드의 UART 핀을 사용하기 때문에 PC의 USB 포트와 개발보드의 UART 핀을 연결하기 위한 별도의 USB - UART 변환 모듈을 필요로 한다.
      • UART 통신를 위한 설정과 문자 Input/Output 프로그램 예: uart-basi-pico.ino
      • 실험을 위한 준비
        • UART 통신을 위한 PC와 Pi Pico 개발보드의 신호 연결
          • Pi Pico 개발보드의 USB 단자를 사용하는 경우에는 별도의 신호 연결이 필요 없다.
          • Pi Pico 개발보드의 UART0를 사용하는 경우
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Pi Pico 개발보드의 TXD0(GP0)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Pi Pico 개발보드의 RXD0(GP1)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Pi Pico 개발보드의 GND를 연결한다.
            • 주의: 컴퓨터(USB --> UART(RS232) 변환 모듈)의 전원 전압(Vdd)과 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 연결하지 않는다. USB --> UART와 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 다를 수 있다.

              주: 사용하는 Boards Manager에 따라 사용하는 TXD0와 RXD0의 핀 번호가 다를 수 있다. 이 예에서는 "Raspberry Pi Pico/RP2040 by Earle F. Philhower,III" Boards Manager를 사용하였다.

          • Pi Pico 개발보드의 UART1를 사용하는 경우
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Pi Pico 개발보드의 TXD1(GP8)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Pi Pico 개발보드의 RXD1(GP9)를 연결한다.
            • 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Pi Pico 개발보드의 GND를 연결한다.
            • 주의: 컴퓨터(USB --> UART(RS232) 변환 모듈)의 전원 전압(Vdd)과 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 연결하지 않는다. USB --> UART와 Pi Pico 개발보드의 전원 전압(Vdd)은 서로 다를 수 있다.

              주: 사용하는 Boards Manager에 따라 사용하는 TXD1와 RXD1의 핀 번호가 다를 수 있다. 이 예에서는 "Raspberry Pi Pico/RP2040 by Earle F. Philhower,III" Boards Manager를 사용하였다.

      • 실험 방법
        • "File → New Sketch"를 실행하여 새 Project를 생성한다.
        • Arduino IDE의 Tool 메뉴에서 Board와 Port를 설정 한다.
        • 위 프로그램을 Arduino IDE의 Sketch 편집창에 복사하고 "File → Save As..."를 실행하여 Sketch를 저장 한다.
        • 사용하는 UART에 따라 Serial port object(사용 가능한 Object: Serial, Serial1, Serial2)를 변경한다.
        • Upload 하여 프로그램을 실행한다.
        • 실험
          • 모니터 프로그램 실행하기
            • Arduino IDE에 포함된 모니터 프로그램을 이용하는 경우
              • "Tool → Serial Monitor"를 실행하면 모니터 창이 열린다.
              • 주: Arduino Serial Monitor는 창의 첫 라인을 입력 라인으로 사용하고, 아래 부분을 출력창으로 사용하기 때문에 실제 모니터를 사용하는 경우와 출력 위치가 다르게 된다.

            • PC에 설치된 별도의 모니터 프로그램을 이용하는 경우
              • PC에서 모니터 프로그램(예: Tera Term, Putty 등, OC-Console 프로그램은 바르게 동작하지 않음)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
              • Serial1 또는 Serial2 객체를 사용하는 경우에는 Serial Port 번호를 확인하고 필요한 설정(Serial Port와 Baudrate(9600) 등을 설정)을 한다.

              주: Serial 객체를 사용하는 경우에는 Arduino IDE도 동일한 Port를 사용하기 때문에 개발보드에 프로그램을 Upload 하는 경우 모니터 프로그램을 종료하여야 한다.

          • 모니터에 "Input Char: " 메세지가 출력된다.
          • PC의 Keyboard에서 문자를 입력하면 입력한 문자가 출력된다.

    • UART 통신를 이용한 LED 제어
      • 이 예는 Pi Pico 개발보드 UART를 이용하여 Pi Pico 개발보드의 LED를 제어(On, Off)하는 예이다.

        실험 회로 구성 예

      • UART 통신를 이용한 LED 제어 프로그램 예: uart-led-control.ino
      • 실험을 위한 준비
        • PC와 Pi Pico 개발보드 연결
          • Pi Pico 개발보드의 USB 단자를 UART0로 사용하기 때문에 별도의 신호 연결은 필요 없다.
      • 실험 방법
        • "File → New Sketch"를 실행하여 새 Project를 생성한다.
        • Arduino IDE의 Tool 메뉴에서 Board와 Port를 설정 한다.
        • 위 프로그램을 Arduino IDE의 Sketch 편집창에 복사하고 "File → Save As..."를 실행하여 Sketch를 저장 한다.
        • Upload 하여 프로그램을 실행한다.
        • 실험
          • 모니터 프로그램 실행하기
            • Arduino IDE에 포함된 모니터 프로그램을 이용하는 경우
              • "Tool → Serial Monitor"를 실행하면 모니터 창이 열린다.
              • 주: Arduino Serial Monitor는 창의 첫 라인을 입력 라인으로 사용하고, 아래 부분을 출력창으로 사용하기 때문에 실제 모니터를 사용하는 경우와 출력 위치가 다르게 된다.

            • PC에 설치된 별도의 모니터 프로그램을 이용하는 경우
              • PC에서 모니터 프로그램(예: Tera Term, Putty 등, OC-Console 프로그램은 바르게 동작하지 않음)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
              • Arduino IDE에서 Serial Port를 확인하고 필요한 설정(Serial Port와 Baudrate(9600) 등을 설정)을 한다.
              • 주: Arduino IDE도 동일한 Port를 사용하기 때문에 개발보드에 프로그램을 Upload 하는 경우 모니터 프로그램을 종료하여야 한다.

          • 모니터에 "LED Turn on: y , Turn off: n : " 메세지가 출력된다.
          • y 제어 문자를 입력하면 LED 가 Turn on 되고, n 제어 문자를 입력하면 LED 가 Turn off 된다.
    • UART Interrupt를 이용한 UART-LED control
      • 이 예는 Pi Pico 개발보드 UART Interrupt을 이용하여 Pi Pico 개발보드의 LED를 제어(On, Off)하는 예이다.

        실험 회로 구성은 위 UART-LED control을 참고바람.

      • UART 통신를 이용한 LED 제어 프로그램 예: uart-led-interrupt.ino
      • 실험을 위한 준비: "UART 통신를 이용한 LED 제어"를 참고 바람
      • 실험 방법: "UART 통신를 이용한 LED 제어"를 참고 바람

  • Raspberry Pi Pico UART - Arduino 관련 페이지 보기