'RS232'에 해당되는 글 2건

  1. 2017.12.24 CAN 통신이란?
  2. 2017.03.18 아두이노의 시리얼 통신


CAN(Controller Area Network) 프로토콜은 Bosch사에서 1986년 자동차 전장 용으로 처음 개발되었으며 1991년에 스펙 2.0이 발표되었고 현재 국제 표준 프로토콜로 성장하였습니다. 이는 호스트 컴퓨터 없이 3개 이상의 MCU나 controller, 장치들이 서로 다중 통신이 가능하며, 메시지는 우선순위 따라 ID(Identifier)를 할당하고 이 ID를 이용해 메시지를 구별합니다. 다양한 에러 감지 메커니즘이 상호 보완적으로 에러를 감지하기 때문에 높은 안정성을 보장하며, 메시지 전송 시 에러가 감지되면 자동적으로 해당 메시지를 즉시 재전송하는 기능이 있기 때문에 다른 프로토콜에 비해서 에러 회복 시간이 짧다는 것입니다.


차량에 적용하는 CAN 통신의 예제


버스가 유휴 상태인 경우 모든 CAN 노드는 메시지를 보낼 수 있고, 전송된 모든 메시지는 모든 노드에서 수신됩니다. 수신 노드는 ID 필터링 기준에 따라 메시지의 무시 여부를 판단합니다. 정교한 오류 감지 및 결함 격리 메커니즘과 문제가 발생한 메시지의 재전송으로 데이터 무결성과 일관성이 보장합니다. 또한 두 개 이상의 CAN 노드가 동시에 메시지 전송을 요청하는 경우 우선순위가 가장 높은 메시지가 즉시 버스 액세스 권한을 획득하도록 프로토콜이 보장합니다. 현재는 CAN의 안정성과 신뢰성 등 장점이 입증되어 항공기, 의료기 등에 사용되고 IoT application에서도 사용되는 추세입니다.


가장 쉽고 편리하고 익숙한 UART 통신은 별도의 transceiver가 필요없고 모든 MCU가 반드시 내장하게 됩니다. 그러나 보통 115200bps로 대략 10kbps로 느리며 한 바이트 통신이라는 단점이 있습니다. 예를 들어, 드론 제어를 할 경우에 다수의 센서 등과 같이 여러 바이트가 하나의 패킷이 되는 경우에는 패킷을 분리하는 작업이 용이하지 않다는 것입니다. 뿐만 아니라 UART는 하나의 장치와 두개의 선으로 독립적이야 하나 관성센서보드, 제어보드, 초음파센서보드, GPS, 무선통신만으로 5개를 초과하여 10가닥 이상이 필요하다는 것입니다.


CAN을 지원하는 MCU의 경우에는 한번에 8-byte 데이터를 전송하는 HW 패킷을 제공하므로 UART(보통 RS232/RS485) 통신에서는 패킷 통신을 위해 위에서 말한 것처럼 사용자가 일일이 패킷 형식을 만들어 주고 수신 받을 때도 그런 해석이 필요하지만 CAN은 8byte 데이터를 담는 HW 패킷 통신을 기본으로 함으로, 사용자는 데이터 버퍼에 데이터를 쓰고 전송만 하면 그 외 모든 처리는 하드웨어가 알아서 하므로 분산제어 분야 적용에도 용이하다는 것입니다.


CAN 통신의 특징:

1) 2선 twist pair를 이용한 전기적 differential 통신을 하므로 저가이며 전기적인 잡음에 매우 강해 신뢰성이 우수합니다.

2) 이론적으로 2,032개의 장치들을 연결할 수 있으나 CAN transceiver에 따라 최대 노드수(32, 64, 128...)는 달라 집니다.

3) 통신 버스를 공유하고 있는 CAN controller들은 모두가 마스터(master)가 될 수 있는 Multi-Master 통신을 합니다.

4) 40m 내에서 최대 1Mbps로 우수한 통신 속도를 갖습니다.

5) 8byte 데이터 전송을 하는 하드웨어 패킷을 제공합니다.

6) 다수의 MCU, DSP 등에 기본으로 내장되어 있습니다.

7) 통신 프로토콜/에러 처리를 하드웨어적으로 처리합니다.

8) PLUG & PLAY를 제공합니다.


CAN transceiver는 프레임이라는 패킷으로 CAN 네트워크에서 데이터를 전송하며, CAN 2.0B 버전 이후에 29bit 식별자를 갖는 extended data format의 간단한 설명입니다.



    • SOF(Start Of Frame) - 메시지 시작을 표시하며, 무부하 기간 이후 버스의 노드를 동기화하기 위해 사용

    • Identifier(ID, 식별자) - 메시지의 우선순위를 가리며 2진 값이 더욱 낮을수록 우선순위는 더욱 높아짐

    • RTR(Remote Transmission Request) - 원격 전송 요청 비트, 이 비트가 '0'이면 데이타 프레임이고, '1'이면 메세지가 원격 전송 요청을 의미

    • SRR(Substitute Remote Request) - 표준 프레임의 RTR 위치에 점유

    • IDE(IDentifier Extension) - 이 비트가 '0'이면 표준 CAN 식별자를 전송하고, '1'이면 확장 CAN 식별자를 전송을 의미

    • R0, R1 - 예약비트

    • DLC(Data Length Code) - 데이터 프레임의 데이터 바이트 수(0~8)

    • Data Field - 8byte(64bit) 전송 데이터, MSB부터 전송.

    • CRC(Cyclic Redundancy Check) - 16bit(15bit + 구획문자) 16bit checksum으로 오류 검출 Field.

    • ACK(ACKnowledge Field) - 2bit(1bit + 구획문자)로 오류가 없는 메시지가 전송되었다는 것을 나타냄.

    • EOF(End Of Frame Field) - 메세지(프레임) 종료 Field

    • IFS(Inter Frame Space) - 컨트롤러가 요구하는 시간의 양을 포함하며, 메시지 버퍼 영역에서 적절한 위치로 정확하게 수신된 프레임을 이동시킴


대표적인 CAN Transceiver로는 PCA82C250/C251가 있습니다.



'Flight Controller 이해 > 인터페이스' 카테고리의 다른 글

드론에서 사용되는 무선 통신  (1) 2017.03.09
TWI(I2C) 통신이란?  (0) 2014.03.24
Posted by Nature & Life
Embedded Lecture/Arduino2017. 3. 18. 12:51


사람도 다른 사람과 의사소통을 위해서 말을 주고받듯이 Arduino Uno도 주변 장치와 소통을 위해서 소위 통신이라는 것을 해야 합니다. Ardunio Uno 보드가 PC나 주변 장치와 유선 통신을 하기 위해서는 지원하는 시리얼 통신(serial communication) 방법이 있습니다. '시리얼'이란 직렬로 병렬 통신과 구분되는 용어로, 병렬(parallel) 통신은 과거 PC가 프린터와 통신하던 방법으로 다수의 선을 이용하여 통신하기에 단위 시간에 많은 데이터를 주고 받을 수 있는 장점이 있습니다.


그러나 병렬 통신은 도로의 폭에 비유할 수 있는 다수의 선을 이용하기에 장치와 거리가 먼 경우에 비용이 커지게 된다는 것입니다. 하지만 최소한의 선로로 빠르게 데이터의 송수신이 가능하다면 가성비는 커지기에 근래에 시리얼 통신 방법이 보다 다양하게 사용되고 있다는 것입니다. Arduino Uno 보드에서는 몇가지 시리얼 통신 방법을 지원하는데 우선 USART를 이용하는 방법입니다. 시리얼 통신은 크게 동기와 비동기 방식으로 구분됩니다.


동기 통신이란 데이터를 전송시 클럭(clock)을 함께 전송하여 받는 쪽에서 이 클럭을 기준으로 미리 정해진 통신 규격(protocol)에 따라 데이터를 취하는 방식입니다. 따라서 데이터의 양방향 통신을 위해서 송신과 수신에 각각 한가닥의 선을 할당하고 클럭을 위한 선을 고려하면 3가닥으로 직관적인 통신이 가능하다는 것입니다. 이를 USRT(Universal Synchronous Receiver and Transmitter)라 명명합니다.


뿐만 아니라 비동기 방식이 있는데 이는 클럭이 필요없이 오직 2가닥으로만 통신하는 방법으로 선로에 대한 비용을 더 감소시킬 수 있지만 하드웨어가 복잡해지는 단점이 있습니다. 그러나 동기식 처럼 수신 쪽에서 항상 대기할 필요 없이 다른 일을 하다가 데이터의 송수신이 가능하므로 MCU의 속도가 빠르게 개선되는 요즈음 필요한 방식이라는 것입니다. 이를 UART(Universal Asynchronous Receiver and Transmitter)라 부릅니다.


USART는 USRT와 UART 방식을 모두 지칭하는 것으로 Arduino Uno 보드는 동기식과 비동기식을 모두 지원합니다. 참고로 RS232, RS485는 시리얼 통신을 위한 전기적 혹은 하드웨어의 규격을 나타내는 말입니다. 이 보드에 사용하는 UART는 주로 Arduino IDE와 같은 PC와의 통신에 사용됩니다. 0번(Rx)과 1번(Tx) 핀을 사용하며 데이터는 MCU로부터 USB 통신을 담당하는 칩을 경우하여 USB 신호로 상호 변환된 후 PC와 송수신하게 됩니다. 또한 아두이노가 PC와의 통신을 수행하고 있다면 이 핀들을 다른 용도로 사용하면 안되며, 통신을 수행할 때에는 TX, RX라고 표시된 LED가 점멸함을 확인할 수 있습니다.



UART와 관련되 아두이노의 라이브러리는 Serial 클래스를 확인하시기 바랍니다. 다음은 UART의 예제입니다. PC에서 문자 하나를 받아서 그것이 '0'이면 LED를 끄고 '1'이면 LED를 켜는 프로그램으로, 아두이노는 데이터가 사용자로부터 들어올 때까지 대기 상태로 있다가 데이터가 입력되면 수행하게 됩니다.


#define LED 13
  void setup() {
 pinMode(LED, OUTPUT);
 Serial.begin(9600);
}
void loop() {
 if ( Serial.available() ) {
   char command = Serial.read();
   if (command == '0') {
     digitalWrite(LED, LOW);
     Serial.println("LED off.");
   }
   else if (command == '1') {
     digitalWrite(LED, HIGH);
     Serial.println("LED on.");
   }
     else {
     Serial.print("Wrong command :");
     Serial.println(command);
     }
  }
}


Serial.begin(long baud_rate) 함수는 UART 통신을 초기화 시키고, 통신 속도(baud rate)를 지정합니다.


Serial.available() 함수는 수신되어 내부 버퍼(64 byte)에 저장된 데이터의 개수를 반환합니다. 만일 버퍼가 비어있다면 0을 반환합니다.


Serial.read() 함수는 수신되어 내부 버퍼(64 byte)에 저장된 데이터 중 가장 첫 번째 데이터(ASCII코드)를 읽어서 반환합니다. 이 함수가 수행되면 내부 버퍼의 크기는 하나씩 줄어들며, 내부 버퍼가 비었다면 -1을 반환합니다.


Serial.print(val) 함수는 입력값을 ASCII값으로 변환하여 PC에 출력하며, 전송된 데이터의 바이트 수를 반환합니다. 비동기 통신 방식이므로 데이터가 전송되기 전에 반환하게 됩니다. 인수 val은 어떤 데이터 타입도 가능합니다.다. 예를 들면,


Serial.print(78) -> "78"

Serial.print(1.23456) -> "1.23456"

Serial.print('N') -> "N"

Serial.print("Hello world.") -> "Hello world."


두 번째 인수로 출력 형식을 지정할 수도 있습니다. 예를 들면,


Serial.print(78, BIN) gives "1001110"

Serial.print(78, OCT) gives "116"

Serial.print(78, DEC) gives "78"

Serial.print(78, HEX) gives "4E"

Serial.println(1.23456, 0) gives "1"

Serial.println(1.23456, 2) gives "1.23"

Serial.println(1.23456, 4) gives "1.2346"


Serial.println() 함수는 출력 문자열의 끝에 줄바꿈 기호 '\r\n' 가 자동으로 붙는다는 점 외에는 Serial.print()함수와 동일한 동작을 수행합니다.


이 예제에서 내부 버퍼란 전송된 데이터가 일시적으로 저장되는 내부 메모리를 말하며 데이터가 전송된 순서대로 저장됩니다. Arduino Uno의 내부 버퍼의 크기는 64 byte인데, 수신된 데이터를 사용하려면 내부 버퍼에서 이 데이터를 읽어내야 하는데 이때 사용되는 함수가 Serial.read() 함수입니다. 가장 먼저 전송된 데이터 하나를 읽어낸 후 그 데이터는 버퍼에서 삭제되며, 만약 버퍼가 비었다면 -1을 반환합니다. 따라서 버퍼에 읽어낼 데이터가 있는지 없는지를 먼저 검사하는 것이 일반적이고 이때 사용되는 함수가 Serial.available()입니다.



'Embedded Lecture > Arduino' 카테고리의 다른 글

인터럽트와 volatile 지시자  (1) 2017.03.18
아두이노의 TWI(I2C) 통신  (0) 2017.03.18
인터럽트의 처리(1)  (0) 2017.03.12
LED 깜박이기  (0) 2017.03.12
아두이노(Arduino) 코딩의 시작  (0) 2017.03.12
Posted by Nature & Life