Arduino

Arduino Serial Part 1

기하 2022. 3. 13. 00:18

http://www.martyncurrey.com/arduino-serial-part-1/

 

 

하드웨어 시리얼


하드웨어 직렬은 이름에서 알 수 있듯이 Arduino 하드웨어에 내장되어 있습니다.

즉, RX 및 TX 핀(핀 0 및 1)이라고 표시된 전용 핀이 있습니다. 

모든 Arduino에는 적어도 하나의 하드웨어 직렬 채널이 있습니다.

Mega와 같은 일부는 더 많은 것을 가지고 있습니다.

 

Arduino에 USB 커넥터가 있는 경우

직렬 채널이 UART-USB 어댑터 칩을 통해 USB에 연결될 가능성이 매우 높습니다. 

일반적인 아두이노는 다 이렇기 때문에 USB를 사용할 때 시리얼 모니터로 출력할 수 있습니다.

일부 Arduino 또는 Arduino 호환 보드에는 UART-USB 칩이 없습니다. 

즉, PC에 직접 연결할 수 없으며 어댑터가 필요합니다. 

Mini Pro에는 직렬 핀이 있지만 USB 커넥터는 없습니다.

 

하드웨어 시리얼은 최고의 성능을 가지며 가장 강력하고 신뢰할 수 있습니다. 

이것은 사용 가능한 경우 항상 최상의 솔루션이지만 주의 사항이 있습니다. 

Arduino IDE는 하드웨어 직렬을 사용하여 Arduino에 업로드하므로

새 스케치를 업로드할 때 RX 및 TX 핀에 연결된 것을 분리해야 할 수도 있습니다.

 

하드웨어 시리얼은 다음을 수행할 수 있습니다.
   – 동시에 전송 및 수신
   – Arduino가 다른 작업을 수행하는 동안 작동
   – 빠른 전송 속도 처리

 

Mega 및 Due와 같은 일부 Arduino에는 1개 이상의 하드웨어 직렬이 있습니다. 

ATMega328 기반 아두이노에는 단 하나만 있습니다.

 

하드웨어 시리얼은 IDE에 통합되어 있으며 라이브러리를 추가할 필요가 없습니다.

시리얼 연결을 시작하려면 serial.begin() 명령을 사용하기만 하면 됩니다.

SoftwareSerial

소프트웨어 시리얼은 표준 Arduino IDE의 일부인 라이브러리입니다. 

그것을 사용하려면 스케치에 라이브러리를 추가해야 하며 사용하려는 핀을 알려줍니다. 

여기에서는 핀 2와 3으로 초기화됩니다. 수신용 핀 2와 전송용 핀 3입니다.

SoftwareSerial은 IDE와 함께 제공되고

대부분의 Arduino 핀을 사용할 수 있기 때문에 매우 편리한 솔루션이지만 단점이 있습니다. 

매우 느리거나 매우 빠른 속도에서는 신뢰할 수 없으며 작동 방식 때문에 타이밍에 문제가 발생할 수 있습니다.

 

SoftwareSerial은 데이터를 수신할 때 핀변경 인터럽트를 사용하고

수신 및 전송 모두 지연 루프를 사용하며 지연되는 동안 인터럽트는 비활성화됩니다. 

이것은 스케치를 차단한다는 것을 의미합니다. 

코드는 단순히 앉아서 다른 작업을 수행하기 전에 SoftwareSerial이 완료될 때까지 기다립니다.

 

인터럽트가 비활성화되어 있기 때문에 SoftwareSerial은 인터럽트를 사용하는 모든 것을 방해합니다.

 

SoftwareSerial:
    – Arduino IDE가 표준으로 제공됩니다.
    – 거의 모든 핀과 함께 사용할 수 있음(아래 참조)
    – 동시에 전송 및 수신할 수 없음
    – 여러 인스턴스를 가질 수 있지만 한 번에 하나의 인스턴스만 활성화할 수 있음
    – 매우 느리거나 빠른 전송 속도에서는 그다지 좋지 않습니다. 

      전송 속도는 9600 – 38400 범위로 유지되어야 합니다.
     기본적으로 Arduino IDE와 함께 제공되는 라이브러리가 필요합니다.

전송 속도가 다른 softwareSerial을 사용해 보십시오. 

신뢰할 수 있는 통신을 가장 빨리 얻을 수 있는 것은 무엇입니까? 

내 자신의 실험에서 38400은 내가 100% 오류 없는 통신을 얻을 수 있었던 가장 빠른 것이며

이것은 Arduino가 다른 일을 많이 하지 않을 때만 가능했습니다. 

38400 이후에는 오류가 표시되기 시작합니다.

SoftwareSerial은 편리하고 상당히 유연하지만 최고의 소프트웨어 시리얼 선택은 아닙니다.

 

AltSoftSerial


AltSoftSerial은 Teensy 범위의 보드를 만든 Paul Stoffregen이 작성했습니다. 

이것은 최고의 소프트웨어 직렬 구현이며 가능한 경우 기본 SoftwareSerial 대신 사용해야 합니다.

 

AltSoftSerial 라이브러리는 PJRC 웹 사이트 또는 라이브러리 관리자를 통해 사용할 수 있습니다. 

AltSoftSerial은 일반 SoftwareSerial 라이브러리와 다른 접근 방식을 취합니다. 

사용하는 핀은 고정되어 있고 핀 8은 수신, 핀 9는 전송(일반 Arduino만 해당)이며

핀 10의 PWM이 비활성화됨을 의미하는 16비트 타이머를 사용합니다.

 

AltSoftSerial:
   – 동시에 송수신할 수 있습니다.
   – 하드웨어 직렬 및 기타 라이브러리를 함께 사용할 때 간섭 최소화 –
     다른 소프트웨어 직렬보다 고속에서 더 안정적
   – 고정 핀: 수신용 핀 8, 전송용 핀 9(일반 Arduino만 해당*)
   – 핀 10에서 PWM 비활성화
   – 사용 하드웨어 Timer1(16비트) 및 동일한 타이머가 필요한 다른 라이브러리에서는 작동하지 않습니다.

     *다른 유형의 Arduino에 사용된 핀에 대해서는 PJRC 웹사이트를 확인하십시오.

 

 

NeoSWSerial


NeoSWSerial은 Slash Devin이 작성했으며

차선책이거나 최소한 표준 SoftwareSerial 라이브러리보다 우수합니다. 

SoftwareSerial과 마찬가지로 대부분의 일반 핀을 사용할 수 있지만

전송 속도 범위는 9600(기본값), 19200, 31250(MIDI) 및 38400만 있습니다. 

이것은 실제로 문제가 되지 않습니다. 

일반 소프트웨어 직렬은 9600 미만 및 38400 이상에서 사용할 때

문제가 있으므로 9600보다 느리고 38400보다 빠르면 사용해서는 안 됩니다.

 

NeoSWSerial:
    – 대부분의 핀과 함께 사용할 수 있습니다.
    – 수신과 송신을 동시에 할 수 있습니다.
    – SoftwareSerial보다 RX의 인터럽트에 더 친숙합니다
    – 제한된 전송 속도 범위; 9600(기본값), 19200, 31250(MIDI) 및 38400만 해당

   github 에서 다운로드 하거나 라이브러리 관리자를 통해 추가할 수 있는 라이브러리가 필요합니다.

 

어떤 것을 사용해야 할까요?

당신이 무엇을 하고 있고 얼마나 빨리 하고 싶은지에 달려 있습니다. 

빠른 전송 속도(예: 115200 또는 2,000,000)를 사용해야 하는 경우

유일한 옵션은 하드웨어 직렬입니다. 

소프트웨어 버전은 이러한 속도를 처리할 수 없습니다.

 

초고속 속도가 필요하지 않고 핀 8과 9를 사용할 수 있는 경우 AltSoftSerial이 적합합니다. 

핀 8 또는 9가 없고 사용 가능한 전송 속도 중 하나로 NeoSWSerial을 사용할 수 있습니다. 

이 중 아무 것도 작동하지 않으면 SoftwareSerial이 남습니다.

 

두 개 이상의 빠른 직렬 연결이 필요한 경우

Mega와 같은 직렬 채널이 두 개 이상 있는 Arduino가 필요합니다.
 

소프트웨어 UART 및 USB 어댑터를 사용하여 PC와 통신

나는 대부분의 사람들이 시리얼 모니터를 사용하여 연결된 PC와 통신하기 위해

하드웨어 시리얼을 사용했을 것이라고 생각합니다. 

위의 예가 표시되지 않는 경우. 때로는 다른 연결이 유용하고

소프트웨어 직렬 중 하나와 USB 대 직렬 어댑터를 사용하여 이를 수행할 수 있습니다. 

여기서는 AltSoftSerial을 사용하고 있습니다.

 

간단한 회로. Arduino는 표준 USB 연결과 USB-직렬 어댑터를 사용하여 PC에 연결됩니다. 

USB-직렬 어댑터는 Arduino의 핀 8과 9에 연결되고

AltSoftSerial은 USB-직렬 어댑터를 통해 통신하는 데 사용됩니다. 

전원은 USB를 통해 전달됩니다. GND가 연결됩니다.

 

동일한 PC에 2개의 연결이 있으면 2개의 COM 포트가 제공됩니다. 

하나는 Arduino용이고 다른 하나는 어댑터용입니다. 

아래 예에서 Arduino는 COM 6에 있고 USB 어댑터는 COM 16에 있습니다.

// basicSerialPassThru_AltSoftSerial_001
 
#include <AltSoftSerial.h>
AltSoftSerial softSerial; 
 
char c=' ';
 
void setup() 
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    softSerial.begin(9600);  
    Serial.println("AltSoftSerial started at 9600");
}
 
void loop()
{
 
    // Read from the software serial and send to the hardware seral
    if (softSerial.available())
    {
        c = softSerial.read();
        Serial.write(c);
    }
 
    // Read from hardware serial and send to software serial
    if ( Serial.available() )
    {
        c = Serial.read();
        softSerial.write(c);  
    } 
}

모든 것을 연결하고 스케치를 업로드하고 사용해 보세요.

USB-직렬 어댑터에 대해 올바른 드라이버가 설치되어 있으면 2개의 COM 포트가 있습니다. 

Arduino용 1개, 어댑터용 1개. 이제 2개의 직렬 모니터를 열면 자신과 대화할 수 있습니다.

 

처음에는 이것이 아무 소용이 없어 보일 수 있지만

USB-직렬 어댑터를 사용하면 하드웨어 직렬이 다른 용도로 사용될 때 디버깅에 매우 유용할 수 있습니다. 

또한 USB-직렬 어댑터는 UART를 말하는 모든 장치로 교체할 수 있으며

이 웹사이트의 나머지 부분에서 제가 작성한 모든 Bluetooth 모듈을 포함하여 많은 장치가 있음을 알 수 있습니다.

 

또한 2개의 Arduino가 서로 통신하도록 하는 쉬운 방법을 형성합니다. 

 

내가 현재 작업하고 있는 한 가지 예는 IOT Wordclock입니다. 

Word clock은 Arduino와 ESP8266을 사용합니다. 

Arduino는 대부분의 작업을 수행하고

ESP8266은 제어 웹 페이지와 같은 Wi-Fi 항목을 처리하고

NIST 서버에서 시간을 가져옵니다. 

 

둘은 소프트웨어 직렬을 사용하여 UART 연결을 통해 서로 대화합니다.

다음은 AltSoftSerial을 사용하여 두 개의 Arduino를 연결하는 예입니다. 

두 Arduino에는 basicSerialPassThru_AltSoftSerial_001 스케치가 있습니다.

한쪽의 RX는 다른 쪽의 TX로 간다는 것을 기억하십시오.

basicSerialPassThru_AltSoftSerial_001 sketch

// basicSerialPassThru_AltSoftSerial_001
 
#include <AltSoftSerial.h>
AltSoftSerial softSerial; 
 
char c=' ';
 
void setup() 
{
    Serial.begin(9600);
    Serial.print("Sketch:   ");   Serial.println(__FILE__);
    softSerial.begin(9600);  
    Serial.println("AltSoftSerial started at 9600");
}
 
void loop()
{
 
    // Read from the software serial and send to the hardware serial
    if (softSerial.available())
    {
        c = softSerial.read();
        Serial.write(c);
    }
 
    // Read from hardware serial and send to software serial
    if ( Serial.available() )
    {
        c = Serial.read();
        softSerial.write(c);  
    } 
}

나는 웹사이트 전체에서 이 스케치(또는 그 버전)를 여러 번 사용했습니다. 

Bluetooth 모듈(또는 UART를 사용하는 모든 것)을 실험할 때 사용하는 스케치입니다.

스케치는 매우 간단합니다. 

먼저 하드웨어 직렬 및 소프트 직렬을 초기화한 다음

환영 메시지를 직렬 모니터에 인쇄합니다(하드웨어 직렬 채널 사용).

 

 

물론 AltSoftSerial을 시작하기 전에 컴파일러에게 라이브러리를 로드하도록 지시해야 합니다.

메인 루프 내에서 소프트웨어 직렬 채널에 사용할 수 있는 문자가 있는지 확인하고

첫 번째 문자를 읽고 하드웨어 직렬 채널에 씁니다. 이렇게 하면 직렬 모니터에 인쇄됩니다

그런 다음 하드웨어 직렬을 확인합니다. 

데이터를 사용할 수 있는 경우 첫 번째 문자를 읽고 소프트웨어 직렬 채널로 보냅니다. 

직렬 모니터로 아무 것도 보내지 않는다는 것을 알아야 합니다. 

원하는 경우 직렬 모니터에 입력된 내용을 다시 자체로 반향할 수 있습니다.

메인 루프가 지속적으로 반복되기 때문에

한 번에 하나의 문자만 읽히지만 결국 사용 가능한 모든 문자를 얻습니다.

 

버퍼 크기

대부분의 Arduino, 즉 1023바이트 이상의 RAM이 있는 Arduino에는

직렬 입력 및 출력을 위한 64 character 버퍼가 있습니다. 

대부분의 경우 이것은 괜찮지만 많은 데이터가 전송될 때는 주의가 필요합니다.

 

입력 버퍼가 가득 차면 수신된 모든 새 데이터가 삭제되고 단순히 사라집니다. 

이로 인해 때때로 예기치 않은 방식으로 데이터가 사라지는 문제가 발생할 수 있습니다.

 

200바이트의 데이터를 수신하고 있다고 상상해 보십시오. 

Arduino는 처음 64바이트를 수신하고 버퍼가 가득 찼습니다. 

데이터는 계속 도착하지만 65바이트 이상은 손실됩니다. 

버퍼가 비어 있지 않으면 65~200바이트가 손실됩니다.


이제 바이트 100이 수신되는 시점에서 데이터를 읽기 시작하는 것을 생각해 봅시다.. 

바이트 65 ~ 99는 여전히 손실되지만 버퍼에는 이제 공간이 있으므로 바이트 100 이후가 저장됩니다. 

이는 시퀀스 중간에 데이터 청크가 누락되었음을 의미합니다(바이트 65 ~ 100).


이 문제를 해결하는 유일한 방법은

버퍼를 계속 비우고 항상 새 데이터를 위한 공간이 있는지 확인하는 것입니다

(또는 버퍼 크기를 변경하지만 이는 고급 수정임).

데이터 전송이 다릅니다. 

출력 버퍼가 가득 차면 데이터가 전송될 때

나머지 데이터를 위한 공간이 있을 때까지 인쇄/쓰기 기능이 차단됩니다.

 

Serial Commands

 

 Arduino reference for serial 를 보면 직렬에 다음 명령을 사용할 수 있음을 알 수 있습니다.

 

begin()
end()
If (Serial)
print()
println()
write()
availableForWrite()
read()
readBytes()
readBytesUntil()
available()
setTimeout()
find()
findUntil()
parseFloat()
parseInt()
peek()
flush()
serialEvent()

 

대부분의 직렬 명령을 사용하지 않고

매우 복잡한 직렬 스케치를 생성하는 것이 매우 가능합니다. 

 

위의 명령 중 약 5개만 사용했습니다. 

find() 및 findUntil()과 같은 명령은 유사한 기능을 수행하지만

맹목적으로 데이터를 삭제하지 않는 고유한 루틴을 만드는 것을 선호합니다(아래에 자세히 설명). 

명령과 작동 방식을 이해하는 것이 유용하다고 생각합니다.

 

begin(baudRate)

위에서 이미 보았지만 begin()은 직렬을 시작하거나 활성화하는 데 사용됩니다. 

직렬을 시작하지 않으면 직렬이 작동하지 않습니다. 

프로그램은 정상적으로 컴파일되지만 직렬을 통해 아무 것도 전송되지 않습니다. 

양쪽 끝에서 동일한 전송 속도를 사용하는 것을 기억하십시오.

 

end()

end()는 직렬을 닫거나 비활성화합니다. 

하드웨어 직렬의 경우 일반적으로 필요하지 않지만

직렬을 사용한 후 다른 용도로 RX 및 TX 핀을 사용해야 하는 경우 사용할 수 있습니다. 

 

직렬 RX 및 TX 핀인 D0 및 D1 핀은 직렬을 사용하지 않을 때 일반 핀으로 사용할 수 있습니다. 

그럼에도 불구하고 왜 당신이 이것을하고 싶어하는지 이유를 생각할 수 없습니다. 

핀 0과 1을 사용해야 하는 경우 직렬 통신에 사용할 가능성은 거의 없습니다.

 

end()는 소프트웨어 직렬을 사용할 때 유용할 수 있습니다. 

둘 이상의 소프트웨어 직렬을 구현할 수 있지만 한 번에 하나의 채널만 사용할 수 있습니다. 

즉, 사용하려는 채널을 열고 닫아야 합니다.

 

If (Serial)

직렬 통신이 가능한지 확인하지만 주의해야 합니다.

대부분의 Arduinos Serial은 직렬 채널을 시작하지 않은 경우에도 항상 TRUE를 반환합니다.


이 명령은 USB CDC 연결이 있는 Leonardo에 사용될 때만 유용하며 예상한 대로 작동합니다. 

직렬이 사용 가능하면 TRUE이고 사용 가능하지 않으면 FALSE입니다. 

항상 TRUE를 반환하는 Leonardo의 Serial1에서는 작동하지 않습니다. 

위의 예에서 눈치채셨을 수도 있습니다

 

이것은 Leonardo를 위한 것이며 계속하기 전에 시리얼을 사용할 수 있을 때까지 기다립니다.

 

print(), println() 및 write()


나는 이미 print()와 println()의 차이점을 언급했습니다. 

println()은 캐리지 리턴과 개행 문자(\r\n)를 추가하지만 print()는 그렇지 않습니다. 

그러나 print()와 println()은 실제로 무엇을 하며 write()와 어떻게 다릅니까?

 

Arduino 참조에 따르면
Serial.write()는 직렬 포트에 바이너리 데이터를 씁니다.
Serial.print()는 사람이 읽을 수 있는 ASCII 텍스트로 직렬 포트에 데이터를 인쇄합니다.


이것은 상당히 간단하게 들리지만 어쨌든 모든 데이터 바이너리가 아닌 그 이상이 있습니다.

print()와 write()는 처음에는 같아 보이지만 몇 가지 중요한 차이점이 있습니다. 

 

print() 및 println()은 모든 숫자 값을 사람이 읽을 수 있는 ASCII 텍스트로 변환합니다. 

write()는 아무 것도 변환하지 않습니다. 

그것은 단순히 당신이주는 것을 보냅니다. 

이것은 write()를 print/println()보다 더 효율적이고 빠르게 만듭니다.

 

바이너리 텍스트와 사람이 읽을 수 있는 ASCII 텍스트의 차이점은 무엇입니까? 

값 1과 1을 나타내는 문자의 차이입니다. "1"인 IE ASCII 48입니다.

 

Serial.print(123); 직렬 모니터에 "123"이 표시됩니다(3자). 

값 123은 ASCII 문자 "1" + "2" + "3"으로 변환됩니다. 

 

Serial.write(123)는 값이 123인 단일 바이트를 보냅니다.

(123은 "{" 문자에 대한 ASCII 코드이므로 Serial.write(123)은 직렬 모니터에 "{"를 표시합니다). 

이것은 간단해 보이지만 Serial.write()는 문자열을 처리할 수 있습니다. 

 

Serial.write("123")는 ASCII 문자 "1" + "2" + "3"을 보냅니다.

이는 쓰기 명령에 값이 아닌 문자열을 주기 때문입니다. 

때로는 숫자의 문자열 표현과 실제 값을 혼동하기 쉽습니다. "1"과 1은 같지 않습니다.

 

ASCII 테이블에 익숙하지 않다면 찾아볼 가치가 있습니다. 

시작하기에 좋은 곳은 www.asciitable.com입니다.

보시다시피 Serial.print()와 Serial.write 간에 겹치는 부분이 있습니다. 

예를 들어; Serial.print("HELLO") 및 Serial.write("HELLO") 결과는 "HELLO"와 같습니다. 

차이점이 있지만 숫자를 다르게 처리하고

print()는 더 많은 데이터 유형을 처리할 수 있으며 기본 변환기가 내장되어 있습니다.

Serial.print()는 다른 기본 형식으로 값을 표시하는 데 사용할 수 있습니다. 

예를 들어 16진법 또는 2진법.

Serial.write(value);를 사용하면 어떻게 될까요? 

나는 이것을 당신이 알아보도록 맡길 것입니다.

Serial.print()는 부동 소수점 숫자를 표시하는 데 사용할 수 있습니다. 

다른 값과 마찬가지로 숫자는 ASCII로 변환되므로 값 3.1234는 "3.1234"가 됩니다. 

부동 소수점을 인쇄할 때 기본 소수점 자릿수는 2입니다. 즉,

3.12가 표시됩니다.

 

위에서 볼 수 있듯이 print()에는 선택적 두 번째 매개 변수가 있습니다. 

위에서 기본 형식을 변경하는 데 사용했습니다. 

float를 인쇄할 때 두 번째 매개변수를 사용하여 소수점 이하 자릿수를 지정할 수 있습니다.
부동 소수점 값을 자를 때 print()는 값을 반올림합니다.

불행히도 write()를 사용하여 부동 소수점 값을 보낼 수 없습니다.

컴파일러를 시도하면 "오버로드된 'write(float&)' 호출이 모호합니다" 오류가 발생합니다. 

이것은 기본적으로 write() 함수가 부동 소수점을 처리할 수 없음을 의미합니다. 

실제 값을 보내는 방법이 있으며 나중에 다루도록 하겠습니다.

 

availableForWrite()

는 직렬 출력 버퍼의 바이트 수(int)를 반환합니다. 기본적으로 쓸 남은 문자 수입니다

대부분의 사람들은 이것에 대해 크게 걱정할 필요가 없지만

다음 기능을 수행하기 전에 모든 직렬 데이터가 전송되었는지

확인해야 하는 상황에서 유용할 수 있습니다. 

 

하드웨어 직렬을 사용할 때

직렬 데이터는 백그라운드에서 전송되므로

serial.print() 명령이 데이터를 출력 버퍼에 복사하자마자 코드가 이동합니다. 

이는 데이터가 아직 전송되는 동안 코드의 다음 명령이 실행되고 있음을 의미합니다. 

Serial.flush()도 참조하십시오.

 

read()

는 직렬 입력 버퍼에서 단일 문자 또는 바이트를 읽습니다. 

직렬을 통해 수신된 데이터는 스케치가 읽을 때까지 버퍼에 저장됩니다. 

버퍼가 비어 있으면 read()는 -1을 반환합니다.

위의 스케치를 통한 직렬 통과의 예를 볼 수 있습니다.

if ( Serial.available() ) – 데이터가 사용 가능한지 확인합니다. 

Serial.available()은 버퍼의 바이트 수를 반환합니다. 

0보다 큰 값은 FALSE가 아닌 것으로 분류됩니다. 

저는 직렬 데이터를 읽기 전에

직렬 데이터의 문자가 1개 이상 있는지 확인하기 위해 여기에서 이를 사용하고 있습니다.

 

readBytes(buffer, length)

는 읽을 바이트 수를 지정할 수 있다는 점을 제외하고는 read()와 유사합니다. 

for 루프 안에 read()가 있는 것과 같습니다.

 

readBytes()에는 2개의 매개변수가 필요합니다. 

데이터를 복사할 버퍼(변수)와 읽을 바이트 수.

버퍼는 char 또는 바이트 배열(char[] 또는 byte[])
길이는 int입니다.

 

readBytes()는 복사된 바이트 수를 반환합니다. 복사된 것이 없으면 0을 반환합니다.

모든 c 배열과 마찬가지로

배열이나 버퍼가 복사하려는 데이터를 저장할 만큼 충분히 큰지 확인하십시오. 

컴파일러는 실수를 해도 스케치가 이상하게 동작하기 시작한다고 알려주지 않습니다.

 

readBytesUntil(termChar,buffer,length)

readBytes()와 비슷하지만 이제 종료 문자/바이트를 지정할 수 있습니다. 

종료 문자는 버퍼에 복사되지 않습니다.

예를 들어, 항상 바이트 값이 13으로 끝나는 데이터가 있는 경우 readBytesUntil()을 사용할 수 있습니다.

 

termChar는 char 또는 바이트
버퍼는 char 또는 바이트 배열(char[ ] 또는 byte[ ])
길이는 int입니다.

항상 동일한 길이의 데이터가 없는 경우에 유용한 명령입니다. 

명령은 종료 문자를 찾을 때까지 단순히 데이터를 읽습니다. 

수신 버퍼가 데이터를 수용할 만큼 충분히 큰지 확인해야 합니다.

 

readBytes() 및 readBytesUntil()의 기본 시간 제한은 1초(1000ms)입니다. 

이것은 setTimeout()으로 변경할 수 있습니다.

 

저는 개인적으로 readBytes() 또는 readBytesUntil()을 사용하는 것을 좋아하지 않습니다. 

모든 바이트를 사용할 수 있을 때까지(또는 시간 초과될 때까지) 대기하는 동안 스케치를 차단합니다. 

적어도 나에게 더 나은 방법은 자체 루프를 만들고 read()를 사용하여 데이터를 복사하는 것입니다. 

이를 통해 데이터의 가용성을 확인하고 데이터가 있는 경우에만 복사할 수 있습니다. 

사용할 수 있는 데이터가 없으면 다른 작업을 수행할 수 있습니다. 

이 기술의 예는 “Blink Without Delay”의 예를 참조하십시오.

 

setTimeout()

readBytes() 및 readBytesUntil()에서 사용되는 타임아웃 시간을 변경합니다. 

지정된 시간은 밀리초 단위입니다.
값은 긴 ctype 데이터 값입니다.

시간 초과를 0.5초(500ms)로 설정합니다.

 

find(searchString)

Serial.find()는 주어진 문자열(char 배열)에 대한 직렬 입력 버퍼를 확인합니다. 

문자열을 찾으면 TRUE를 반환하고 찾지 못하면 FALSE를 반환합니다(시간 초과). 

 

주의해야 할 몇 가지 사항이 있습니다.
1 – 검색할 때 버퍼에서 데이터를 삭제합니다.
2 – 작업을 수행하는 동안 스케치를 차단합니다.

 

find()는 직렬 입력 버퍼를 읽고

검색 문자열을 찾거나 버퍼를 완전히 비우고 시간 초과될 때까지 문자를 제거합니다. 

검색 문자열 "abc"가 있고 버퍼에 "1234567890"이 포함되어 있으면

find()는 버퍼를 비우고 시간 초과한 다음 FALSE를 반환합니다.

 

버퍼에 "hello world"가 포함되어 있고 "world"를 검색하면

find()가 버퍼를 통해 실행되어 "world"를 찾을 때까지 문자를 삭제합니다. 

find()는 "TRUE"를 반환합니다. 

 

"world"를 검색하는 과정에서 함수는 직렬 버퍼에서 문자열을 제거합니다. 

즉, 버퍼에 "hello world"가 포함되어 있고 "world"를 검색하면

함수는 TRUE를 반환하지만 직렬 버퍼는 비어 있습니다. 

 

"world" 이후의 버퍼에 있는 모든 데이터는 그대로 유지됩니다.

find()는 작동하는 동안 Arduino의 다른 모든 작업을 차단하고

다음 작업으로 이동하기 전에 find()가 완료될 때까지 앉아서 기다려야 합니다.

개인적으로 find()는 그다지 유용하지 않으며

직렬 데이터를 버퍼에 복사한 다음 버퍼를 검색하는 것이 훨씬 낫다고 생각합니다. 

거의 모든 프로젝트에서 주고받는 데이터를 제어하므로 데이터가 존재하는 경우

무언가에 필요할 가능성이 있으므로

데이터를 삭제하는 find()와 같은 명령을 사용하는 것은 나에게 유용하지 않습니다. 

이것은 단지 나일 수도 있습니다. 

제어할 수 없는 데이터를 수신하고

특정 값에만 관심이 있는 경우 find()를 사용할 수 있지만

데이터를 자체 버퍼에 복사한 다음 이 버퍼를 검색하는 것이 더 좋습니다.

 

findUntil(searchString, terminatingString)

findUntil()이 종결자 문자열을 추가한다는 점을 제외하고 find()와 유사합니다. 

이 함수는 다음 중 하나가 될 때까지 검색 문자열을 찾는 직렬 입력 버퍼를 검색합니다.


   1 – 검색 문자열이 발견됨
   2 – 종결자 문자열이 발견됨
   3 – 아무 것도 발견되지 않고 시간이 초과됩니다.

검색 문자열이 발견되면 함수는 TRUE를 반환하고, 찾지 못하면 FALSE를 반환합니다.
종결자 문자열이 발견되면 함수는 찾기를 중지하고 FALSE를 반환합니다.

 

고려해야 할 사소한 것. 

Arduino는 EOL 문자를 "\r" "\n" 순서로 보낸다는 것을 기억할 가치가 있습니다. 

직렬 버퍼에 "abcd/r/n"이 포함된 경우. 위는 FALSE를 반환하고 버퍼를 비웁니다. 

종료 문자열로 "\n"을 사용하면 이 함수는 여전히 FALSE를 반환하지만 버퍼에 "/r" 문자를 남깁니다. 

남아있는 캐릭터는 당신이 그것을 알지 못할 때 상황을 망칠 수 있습니다.

 

parseInt()

parseInt()는 직렬 버퍼에서 찾은 첫 번째 유효한 ASCII 형식(긴) 정수를 반환합니다. 

정수(또는 빼기 기호)가 아닌 문자는 건너뜁니다.

 

parseInt()는 정수의 일부가 될 수 있는 문자를 찾는 직렬 버퍼를 통해 실행됩니다. 

찾을 때 정수를 찾을 때까지 숫자가 아닌 문자를 삭제합니다. 

유효한 값을 찾지 못하면 버퍼를 비우고 시간이 초과되고 0을 반환합니다.

 

정수가 발견되면 정수 뒤의 모든 문자/데이터가 직렬 버퍼에 남습니다. 

버퍼에 유효한 정수만 포함된 경우

parseInt()는 사용 가능한 데이터를 읽은 다음 값을 반환하기 전에 시간 초과를 기다립니다. 

이로 인해 성능 문제가 발생할 수 있습니다.

 

버퍼에 "12345"가 포함된 경우 parseInt()는 12345를 반환하고 버퍼는 비어 있습니다.
버퍼에 "abd1234zxy"가 포함된 경우. 

parseInt()는 1234를 반환하고 버퍼에는 "xyx"가 포함됩니다. "abc"가 삭제됩니다.


버퍼에 "-3434\r\n"이 포함된 경우. 

parseInt()는 -3434를 반환하고 함수가 완료된 후 버퍼에는 "\r\n"이 표시됩니다.

 

parseInt()가 long을 반환한다는 점을 강조할 가치가 있습니다.

이는 Arduino 랜드에서 4바이트 값입니다. 

parseInt()는 값이 < 32,767인 한 Arduino int(2바이트 값)를 사용하는 경우 작동하지만

값이 > 32,767이면 문제가 발생합니다.

왜냐하면 long이 int에 복사될 때 2바이트가 손실되므로 값이 변경됩니다. 

예를 들어; 부호 있는 긴 값 2147483640은 부호 있는 정수로 변환될 때 -8로 잘립니다.

항상 반환 값을 긴 변수에 복사하십시오.

 

parseFloat()

Serial.parseFloat()는 직렬 버퍼에서 유효한 첫 번째 ASCII 형식의 부동 소수점 숫자를 반환합니다. 

이 함수는 부동 소수점 숫자를 찾을 수 없거나 시간 초과에 도달하면 빈 손(0)을 반환합니다. 

함수가 호출될 때 데이터가 버퍼에 있을 필요는 없지만

데이터가 도착하기를 기다리는 동안 함수는 코드를 차단합니다.

 

parsefloat는 숫자나 빼기 기호를 찾을 때까지

부동 소수점이 아닌 문자(숫자와 빼기가 아닌 기호)를 삭제하는 직렬 버퍼를 실행합니다. 

그런 다음 다른 부동 소수점이 아닌 문자에 도달할 때까지 부동 소수점 데이터를 읽습니다. 

그런 다음 ASCII 형식의 값을 실제 부동 소수점 값으로 변환합니다.

 

직렬 버퍼에 "abc3.1234abcdefg"가 포함된 경우. 

parseFloat()는 첫 번째 "abc"를 삭제하고 3.1234를 찾은 다음 직렬 버퍼에 "abcdefg"를 남겨둡니다.

 

Serial.peek()

Serial.peek()은 직렬 버퍼의 다음 문자를 제거하지 않고 반환합니다. 

아무것도 삭제하지 않는다는 점을 제외하고는 read()와 비슷합니다. 

고유한 파서를 만들고 방해하지 않고 다음 문자가 무엇인지 확인해야 하는 경우 매우 유용합니다.


peek()은 사용 가능한 첫 번째 문자를 읽는 데만 사용할 수 있습니다. 

read()와 달리 버퍼 포인터를 증가시키거나 버퍼를 변경하지 않으므로 연속적인 peeks()는 동일한 문자를 반환합니다.

 

Serial.flush()

이것은 내가 Arduino를 처음 시작할 때 나를 포함하여 많은 사람들이 잘못 알고 있는 명령입니다. 

특히 다른 프로그래밍 언어에 대한 경험이 있는 경우 이름에서 그것이 무엇을 하는지 안다고 가정하기 쉽습니다.

 

Arduino 참조 에는 "보내는 직렬 데이터 전송이 완료될 때까지 기다립니다 . 

(Arduino 1.0 이전에는 버퍼링된 들어오는 직렬 데이터를 대신 제거했습니다.)” 

 

IDE 1.0으로 기능이 변경되었다는 것을 아는 것 외에도 중요한 비트는

"보내는 직렬 데이터의 전송이 완료될 때까지 기다립니다."입니다. 

이것은 무엇을 의미 하는가? 

Serial.flush()가 버퍼를 즉시 지우지 않고

Arduino가 현재 직렬 데이터가 모두 전송될 때까지 기다리게 함을 의미합니다.

 

하드웨어 직렬은 백그라운드에서 작동하므로

다른 작업을 수행하는 동안 사용할 수 있습니다. 

 

Serial.print("HELLO WORLD")를 사용할 때; 

Arduino는 "HELLO WORLD" 데이터를 출력 버퍼에 복사한 다음 기본 코드로 돌아갑니다. 

그런 다음 인터럽트를 사용하여 스케치를 계속 처리하는 동안

실제로 백그라운드에서 데이터를 보냅니다. 

이것은 일반적으로 좋은 일이지만 때로는 문제가 될 수 있으며

프로그램을 계속하기 전에 모든 데이터가 전송될 때까지 기다려야 할 수도 있습니다. 

이것이 Serial.flush()를 사용할 수 있는 곳입니다. 지연 시간이 상당히 길 수 있다는 점을 염두에 두십시오.

 

serialEvent()

serialEvent()는 실제로 직렬 명령이 아닙니다. 

직렬 입력 버퍼에 데이터가 있을 때 루프마다 한 번씩 호출되는 함수입니다. 

(함수는 실제로 loop() 함수 외부에서 호출되지만 여기서는 중요하지 않습니다.) 

메인 루프() 함수 외부에 if(Serial.available)이 있는 것과 같습니다.

스케치 내부에서 serialEvent()에 대한 호출이 없음을 알아야 합니다.

호출은 loop() 호출 외부에서 수행됩니다.

위의 작업은 상당히 강력하지만 내 프로젝트에서 사용한 적이 없습니다. 

훨씬 간단하고 똑같은 효과가 있습니다.

다음은 위의 것과 정확히 동일한 출력을 생성하지만

if (Serial.available())을 사용하고 읽기 및 유지 관리가 더 쉽습니다.