반응형
라즈베리파이 2대를 사용한 UART 채팅 프로그램 C언어 사용
연결은 라즈베리파이 GPIO 번호 8번(TXD), 9번(RXD) 핀에 MAX232 통신 모듈이나, USB to Serial 포트 등을 양쪽으로 연결하여 테스트 해야 하지만 여기서는 간단하게 라즈베리파이 1과 라즈베리파이2 의 8, 9번 핀\을 크로스로 연결하여 테스트 한다. Python 코드는 아래 C언어 예제 코드 뒤에 나온다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | #include <stdio.h> #include <stdbool.h> #include <string.h> #include <errno.h> #include <pthread.h> #include <wiringPi.h> #include <wiringSerial.h> #define STX 0x02 #define ETX 0x03 #define ACK 0x06 #define NCK 0x15 #define RED "\033[31m" #define DEFAULT "\033[0m" #define BLUE "\033[34m" #define GREEN "\033[32m" bool Rcv_End = false; unsigned char Last_Packet[256]; int NAK_CNT = 0; int ser; unsigned char make_LRC(const char *packet) { unsigned char LRC = 0x00; int x; for( x = 0; packet[x] != 0x00; x++) { LRC = ((LRC + (unsigned char)packet[x]) & 0xFF); } LRC = (~LRC + 1) & 0xFF; return LRC; } void send(const char *packet) { int x, len; unsigned char LRC; Last_Packet[0] = STX; strcpy((char *)Last_Packet + 1, packet); len = strlen(Last_Packet); Last_Packet[len ] = ETX; Last_Packet[len + 1] = 0x00; LRC = make_LRC(Last_Packet + 1); Last_Packet[len + 1] = LRC; Last_Packet[len + 2] = 0x00; for( x = 0; Last_Packet[x] != 0x00; x++) { serialPutchar (ser, Last_Packet[x]) ; } printf( "%sSend:%s%s\n", BLUE, packet, DEFAULT); return; } char *check_packet(char *val) { static char buffer[256]; char tmp[256]; char lrc; strcpy(tmp, val + 1); //remove STX tmp[strlen(tmp) - 1] = 0x00; //remove LRC lrc = make_LRC(tmp); if(lrc == val[strlen(val) -1]) { strcpy(buffer, tmp); buffer[strlen(buffer) -1] = 0x00; //remove ETX } else { buffer[0] = 0x00; } return buffer; } void *rs232_receive_thread(void *p) { char val, *rcv_data; char data[256]; int x, index = 0; memset(data, 0x00, sizeof(data)); while (1) { val = 0x00; if(serialDataAvail (ser)){ val = serialGetchar (ser); } if(0x00 == val){ delay(2); continue; } if(val == ACK){ // printf ("\033[37mSend:OK ACK rcv \033[0m\n"); continue; } if(val == NCK){ //packet currupted ->resend 3 times printf ("%s Packet Currupted ->NAK received %s", RED, DEFAULT); if(++NAK_CNT < 4){ for( x = 0; Last_Packet[x] != 0x00; x++) { serialPutchar (ser, Last_Packet[x]) ; } } else{ //drop packet NAK_CNT = 0; } continue; } if(val == ETX){ data[index++] = val; while (1){ if(serialDataAvail (ser)){ val = serialGetchar (ser); if(0x00 == val){ delay(2); continue; } Rcv_End = true; data[index++]= val; break; } } } else{ Rcv_End = false; data[index++] = val; } if(true == Rcv_End){ rcv_data = check_packet(data); if(0 == strlen(rcv_data)){ printf("%s Invalid Packet Received ->NAK DATA:%s %s\n", RED, data, DEFAULT); serialPutchar (ser, NCK) ; } else{ printf("%s RCV:%s %s\n", GREEN, rcv_data, DEFAULT); serialPutchar (ser, ACK) ; } index = 0; memset(data, 0x00, sizeof(data)); } delay(2); } } int main() { int x, thr_id; char buf[256]; pthread_t p_thread; if ((ser = serialOpen ("/dev/ttyAMA0", 9600)) < 0) { fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ; return 1 ; } if (wiringPiSetup () == -1) { fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ; return 1 ; } thr_id = pthread_create(&p_thread, NULL, rs232_receive_thread, (void *)NULL); while(1){ gets(buf); send(buf); } return 0; } |
라즈베리파이 2대를 사용한 UART 채팅 프로그램 Python 사용
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | #!/usr/bin/env python import serial import sys, time #파이썬에서 쓰레드 기능 구현을 위해 필요 import threading import commands import binascii import RPi.GPIO as GPIO #중요한 제어 문자 NAK_CNT = 0 STX = 0x02 ETX = 0x03 ACK = 0x06 NCK = 0x15 Last_Packet= "" Rcv_End = False Debug = False #출력 문자 색 제어 RED = "\033[31m" DEFAULT = "\033[0m" BLUE = "\033[34m" GREEN = "\033[32m" # ISO 1155 표준 LRC 계산식 def make_LRC(packet): LRC = 0x00 for ch in packet: LRC = ((LRC + ord(ch[0])) & 0xFF) LRC = (~LRC + 1) & 0xFF return LRC # UART 패킷을 송신 def send(packet): global Last_Packet bytes = [STX] LRC = 0x10 Last_Packet = "".join(map(chr, bytes)) Last_Packet += packet bytes = [ETX] Last_Packet += "".join(map(chr, bytes)) LRC = make_LRC(Last_Packet[1:len(Last_Packet)]) bytes = [LRC] Last_Packet += "".join(map(chr, bytes)) ser.write(Last_Packet) print "S:", binascii.hexlify(bytearray(Last_Packet)) print "\033[34mSend:", packet, DEFAULT return # LRC 체크가 성공여부 체크 def check_packet(val): lrc = make_LRC(val[1:len(val) - 1]) if(lrc == ord(val[len(val) -1])): if(Debug == True): print BLUE, "LRC Check Success :", lrc, DEFAULT print "CHECK:", binascii.hexlify(bytearray(val)) ret = val[1: len(val) -2] else: if(Debug == True): print RED, "LRC Check Fail", lrc, "!= ",ord(val[len(val) -1]), DEFAULT print "CHECK:", binascii.hexlify(bytearray(val)) ret = "" return ret """ UART 채널은 완전 이중화(Full Duplex)이기 때문에 별도 쓰레드에서 수신처리 가능 """ def rs232_receive_thread(): global Last_Packet data = "" while 1: val = ser.read(1) if(0 == len(val)): time.sleep(0.002) continue ival = ord(val[0]) if(Debug == True): print "R:", binascii.hexlify(bytearray(val)) if(ival == ACK): if(Debug == True): print "\033[37mSend:OK ACK rcv \033[0m" continue if(ival == NCK): #packet currupted ->resend 3 times print "\033[31m", "Packet Currupted ->NAK received", "\033[0m" if(++NAK_CNT < 4): ser.write(Last_Packet) else: #drop packet NAK_CNT = 0 continue; if(ival == ETX): data += val while True: val = ser.read(1) #receive Last LRC if(len(val) == 1): Rcv_End = True data += val break else: Rcv_End = False data += val if(True == Rcv_End): rcv_data = check_packet(data) if(0 == len(rcv_data)): print RED, "Invalid Packet Received ->NAK DATA:", data, DEFAULT bytes = [NCK] ser.write("".join(map(chr, bytes))) else: print GREEN, "RCV:", rcv_data, DEFAULT bytes = [ACK] ser.write("".join(map(chr, bytes))) data = "" time.sleep(0.002) # 수신 전용 쓰레드를 만들어 실행시킴 def rs232_receive_svc(): print ('rs232 receive svc') th = threading.Thread(target=rs232_receive_thread) th.start() # 여기에서부터 프로그램 시작! print "RS232 Chatting Application" #루프백 테스트에 사용할 UART용 가상 파일 ttyAMA0(ttyS0)를 연다. if(GPIO.RPI_REVISION < 3): ser = serial.Serial(port = "/dev/ttyAMA0", baudrate=9600, timeout=2) else: ser = serial.Serial(port = "/dev/ttyS0", baudrate=9600, timeout=2) if (ser.isOpen() == False): ser.open() #만약 ttyAMA0에 데이터가 남아있으면 비우고 새로 시작한다. ser.flushInput() ser.flushOutput() #수신 쓰레드 생성 rs232_receive_svc() try: while True: #송신할 채팅 문장을 입력받아서 송신 packet = raw_input("") send(packet) except KeyboardInterrupt: print "RS232 Chatting Application End" finally: ser.close() print "Good by!" |
이미지출처 : element114.com
반응형
'라즈베리파이' 카테고리의 다른 글
라즈베리파이 BMP180 대기압 측정센서 C와 Python 코드 (0) | 2019.03.26 |
---|---|
모든 센서종류, 센서타입 리스트 (0) | 2019.03.26 |
라즈베리파이 UART loopback 테스트 - C, Python 구현 (0) | 2019.03.22 |
라즈베리파이 GPIO 인터럽트 사용 Python 예제 (0) | 2019.03.22 |
라즈베리파이 GPIO 인터럽트 사용 C 예제 (0) | 2019.03.22 |