본문 바로가기

전자공학을 즐겁게/누구나 취미전자공학

Python을 이용한 UART 활용 - pyserial과 xmodem

728x90
반응형

임베디드 컴퓨팅에서 UART는 두 컴퓨터의 통신에 사용이 됩니다. 특히 한 컴퓨터의 출력 장치로서 현재의 동작 상태를 출력하고, 다른 컴퓨터는 그 출력을 받아 상태를 확인하는 용도로 많이 사용을 합니다. 컴퓨터의 출력을 해석하기 위하여, 다른 한쪽 컴퓨터는 UART의 입력을 받아 그 내용을 해석하는 프로그램을 수행하기도 합니다. 또한, 한 컴퓨터에서 다른 한 컴퓨터로 파일을 전송하기도 하지요. 여기에서 컴퓨터는 넓은 의미로, 작은 MCU에서부터 가정용이나 업무용으로 사용이 되는 고성능 컴퓨터까지 아우릅니다. 

 

용도가 무엇이든 UART로 정보를 보내고 받는 작업을 할 필요가 있습니다.

Python을 사용해서 UART를 통하여 데이터를 주고받고, 파일을 전송하는 것에 대하여 이야기해 볼까 합니다.

Python이기 때문에 Windows가 되었든, Linux가 되었든, 심지어 Raspberry Pi에서든, Python Interpreter가 동작하는 어떤 컴퓨터에서도 동일하게 동작할 수 있을 것입니다. 하드웨어와 관련된 어플리케이션이라면 아무래도 라즈베리 파이를 많이 사용하겠지요.

 

Python에서 UART 시리얼 포트 사용하기 - pyserial

우선 UART를 통하여 데이터를 쓰고 읽는 방법을 살펴 보겠습니다.

Python에서 UART에 데이터를 주고받기 위하여 사용하는 모듈은 pyserial입니다.

pyserial에 대한 정보는 https://pypi.org/project/pyserial/에서 확인할 수 있습니다.

 

pyserial 모듈이 설치되어 있지 않다면 Command Line에서 다음 명령으로 설치할 수 있습니다.

pip install pyserial

 

pyserial이 설치되어 있다면 다음 명령으로 모듈 정보를 확인할 수 있을 것입니다.

pip show pyserial

 

pyserial을 사용하여 UART 쓰고 읽기

pyserial을 Python code에서 사용하기 위해서 pyserial 모듈을 import 합니다.

import serial

 

import pyserial이 아니라 import serial입니다.

 

데이터를 쓰고 읽기 위하여 UART 시리얼 포트의 인스턴스를 만듭니다.

 

Linux 계열에서는 다음과 같이 됩니다.

uart = serial.Serial('/dev/ttyUSB0', baudrate=115200, rtscts=True)

 

Windows에서는 다음처럼 될 것입니다.

uart = serial.Serial('COM11', baudrate=115200, rtscts=True)

 

첫번째 인자는 포트 이름입니다. baudrate은 지정하지 않는다면 기본값은 9600 bps입니다. 하드웨어 흐름제어를 나타내는 rtscts의 기본값은 False입니다. 더 많은 내용은 pyserial의 Documentation 페이지 참조하세요. 

 

Serial 클래스의 인스턴스를 생성한 이후에는 이 클래스 인스턴스를 통하여 읽고 쓸 수 있습니다.

# Write a string to UART Serial Port
uart.write("Hello".encode("utf-8"))

# Read a byte from UART Serial Port and print
print(uart.read().decode("utf-8"))

 

write/read 매써드는 Byte array를 인자로 사용하기 때문에 String으로부터 인코드/디코드가 필요합니다. String을 직접 UART에 쓰거나, UART로부터 읽은 값을 바로 print 할 수 없습니다.

 

다음 코드는 특정 파일을 열어서 UART 시리얼 포트에 출력하는 코드입니다.

import serial

uart = serial.Serial('/dev/ttyUSB0', baudrate=115200, rtscts=True)

with open('./LICENSE') as in_file:
    for line in in_file.read():
        uart.write(line.encode('utf-8'))

print('Send complete')

uart.close() # Close serial port.

 

다음 코드는 UART 시리얼 포트로부터 수신된 값을 화면에 계속 출력하는 코드입니다.

import serial

uart = serial.Serial('/dev/ttyAMA2', baudrate=115200, rtscts=True)

while True:
    byte = uart.read()
    print(byte.decode("utf-8"), end='')

uart.close() # Close serial port

 

위의 예에서는 단순히 텍스트를 읽고 쓰는 작업만 했지만, 수신된 텍스트를 해석하여 원하는 동작을 하도록 코드가 만들어질 수도 있을 것입니다.

 

Python에서 파일 전송 - xmodem

두 컴퓨터 사이에는 단순히 텍스트나 바이트열만 주고받는 것이 아니라 파일을 전송해야 하는 경우가 있습니다. 

요즘에는 작은 MCU의 펌웨어 업데이트를 위하여 이미지 파일을 UART를 통하여 전송하는 경우가 있습니다. 이때, 많이 사용되는 파일 전송 규약이 XMODEM입니다. 

XMODEM은 1970년대에 다이얼 업 모뎀을 사용하는 BBS라는 것이 나타나던 시절에 서로 파일을 교환하기 위하여 만들어진 규약입니다. 요즘에는 다이얼 업 모뎀을 사용할 일이 없고, 더 발전된 형태의 규약들이 많이 나왔기 때문에 원래의 용도에는 사용이 거의 되지 않지만, 이 규약은 매운 간단해서 작은 용량으로 구현할 수가 있어서 MCU의 펌웨어 업데이트를 위하여 많이 사용이 되는 것입니다. 

 

Python에서 XMODEM을 지원하는 package는 xmodem입니다.

UART 시리얼 포트를 위한 전송을 위해서는 pyserial 모듈 또한 필요하고, Serial 클래스의 인스턴스도 필요합니다. 또한, 전송 동작을 구현하기 위한 한 바이트를 읽고 쓰는 함수도 구현되어 XMODEM 클래스 인스턴스에 인자로 전달되어야 합니다.

 

import serial
import xmodem

ser = serial.Serial('/dev/ttyUSB0', 
                    baudrate=115200, 
                    bytesize=serial.EIGHTBITS, 
                    parity = serial.PARITY_NONE, 
                    stopbits=serial.STOPBITS_ONE, 
                    rtscts=True)

def getc(size, timeout=1):
    return ser.read(size) or None

def putc(data, timeout=1):
    return ser.write(data) or None

modem = xmodem.XMODEM(getc, putc, pad=b'\00')

 

XMODEM은 수신 측의 신호로 전송이 시작되어야 하기 때문에 송신 측을 먼저 준비시킵니다. 송신을 XMODEM.send 매써드를 사용하면 됩니다.

with open('./FILE_TO_SEND', "rb") as source_file:
    result = modem.send(source_file)

 

수신 측은 파일을 쓰기 속성으로 열고, XMODEM.recv 매써드를 사용합니다.

with open('./RECEIVED_FILE', "wb") as destination_file:
    result = modem.recv(destination_file)

 

송수신의 결과는 XMODEM.sendXMODEM.recv 매써드에서 return 된 결과를 확인하여 판단할 수 있습니다.

송신이 성공적으로 끝났다면, XMODEM.send 매써드는 True를, 실패했다면 False를 return 합니다.

수신이 성공적이었다면, XMODEM.recv 매써드는 수신된 바이트 수를, 실패했다면 None을 return 합니다.

 

pyserial과 xmodem 모듈을 사용하여 XMODEM 파일 전송 프로그램 만들기

pyserial과 xmodem 모듈을 사용하여 범용으로 사용할 수 있는 XMODEM 파일 전송 프로그램을 만들어 보았습니다.

코드는 아래 링크에서 확인하세요.

 

https://github.com/sangyoungn/play_with_RPi/blob/main/xmodem_transfer_example/xmodem_transfer.py

 

play_with_RPi/xmodem_transfer_example/xmodem_transfer.py at main · sangyoungn/play_with_RPi

Example Codes for Raspberry Pi. Contribute to sangyoungn/play_with_RPi development by creating an account on GitHub.

github.com

 

데모 영상, 그리고 +α

다음 영상에서 XMODEM에 대한 추가적인 내용과 코드 데모를 확인하세요. PC와 라즈베리 파이 사이에서 UART 시리얼 포트를 통한 데이터 교환과 파일 전송을 하였습니다.

 

https://www.youtube.com/watch?v=B6EMcglI8i4

 

오늘도 즐거운 하루 보내세요!

728x90
반응형