반응형

Windows API(CreateFile)을 이용해 간단히 아두이노와 시리얼 통신을 할 수 있다.


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
char state;
 
void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Arduino ready.");
}
 
void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available())
  {
    state = Serial.read();
    while (Serial.available())
    {
      Serial.read();  // 첫 번째 문자만 입력받고 나머지는 버린다.
    }
    
    if (state == '0')
    {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("LED OFF");
    } else
    {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED ON");
    }
  }
 
  delay(100);
}


위 소스를 컴파일 하고 아두이노에 업로드 한다. 시리얼 모니터를 통해서도 Builtin LED를 제어할 수 있다.


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
#ifndef SERIALCLASS_H_INCLUDED
#define SERIALCLASS_H_INCLUDED
 
#define ARDUINO_WAIT_TIME 2000
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
class Serial
{
private:
    //Serial comm handler
    HANDLE hSerial;
    //Connection status
    bool connected;
    //Get various information about the connection
    COMSTAT status;
    //Keep track of last error
    DWORD errors;
 
public:
    //Initialize Serial communication with the given COM port
    Serial(const char* portName);
    //Close the connection
    ~Serial();
    //Read data in a buffer, if nbChar is greater than the
    //maximum number of bytes available, it will return only the
    //bytes available. The function return -1 when nothing could
    //be read, the number of bytes actually read.
    int ReadData(char* buffer, unsigned int nbChar);
    //Writes data from a buffer through the Serial connection
    //return true on success.
    bool WriteData(const char* buffer, unsigned int nbChar);
    //Check if we are actually connected
    bool IsConnected();
 
 
};
 
#endif // SERIALCLASS_H_INCLUDED


Serial class header.


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
#include "SerialHeader.h"
 
Serial::Serial(const char* portName)
{
    //We're not yet connected
    this->connected = false;
 
    //Try to connect to the given port throuh CreateFile
    //CreateFile may need to be replaced with CreateFileA or...
    //Project - XXX Properties - Configuration Properties - Advanced - Character Set - Use Multi-Byte Character Set
    this->hSerial = CreateFileA(portName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);
 
    //Check if the connection was successfull
    if (this->hSerial == INVALID_HANDLE_VALUE)
    {
        //If not success full display an Error
        if (GetLastError() == ERROR_FILE_NOT_FOUND) {
 
            //Print Error if neccessary
            printf("ERROR: Handle was not attached. Reason: %s not available.\n", portName);
 
        }
        else
        {
            printf("ERROR!!!");
        }
    }
    else
    {
        //If connected we try to set the comm parameters
        DCB dcbSerialParams = { 0 };
 
        //Try to get the current
        if (!GetCommState(this->hSerial, &dcbSerialParams))
        {
            //If impossible, show an error
            printf("failed to get current serial parameters!");
        }
        else
        {
            //Define serial connection parameters for the arduino board
            dcbSerialParams.BaudRate = CBR_9600;
            dcbSerialParams.ByteSize = 8;
            dcbSerialParams.StopBits = ONESTOPBIT;
            dcbSerialParams.Parity = NOPARITY;
            //Setting the DTR to Control_Enable ensures that the Arduino is properly
            //reset upon establishing a connection
            dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
 
            //Set the parameters and check for their proper application
            if (!SetCommState(hSerial, &dcbSerialParams))
            {
                printf("ALERT: Could not set Serial Port parameters");
            }
            else
            {
                //If everything went fine we're connected
                this->connected = true;
                //Flush any remaining characters in the buffers 
                PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR);
                //We wait 2s as the arduino board will be reseting
                Sleep(ARDUINO_WAIT_TIME);
            }
        }
    }
 
}
 
Serial::~Serial()
{
    //Check if we are connected before trying to disconnect
    if (this->connected)
    {
        //We're no longer connected
        this->connected = false;
        //Close the serial handler
        CloseHandle(this->hSerial);
    }
}
 
int Serial::ReadData(char* buffer, unsigned int nbChar)
{
    //Number of bytes we'll have read
    DWORD bytesRead;
    //Number of bytes we'll really ask to read
    unsigned int toRead;
 
    //Use the ClearCommError function to get status info on the Serial port
    ClearCommError(this->hSerial, &this->errors, &this->status);
 
    //Check if there is something to read
    if (this->status.cbInQue > 0)
    {
        //If there is we check if there is enough data to read the required number
        //of characters, if not we'll read only the available characters to prevent
        //locking of the application.
        if (this->status.cbInQue > nbChar)
        {
            toRead = nbChar;
        }
        else
        {
            toRead = this->status.cbInQue;
        }
 
        //Try to read the require number of chars, and return the number of read bytes on success
        memset(buffer, 0, nbChar);
        if (ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL))
        {
            return bytesRead;
        }
 
    }
 
    //If nothing has been read, or that an error was detected return 0
    return 0;
 
}
 
 
bool Serial::WriteData(const char* buffer, unsigned int nbChar)
{
    DWORD bytesSend;
 
    //Try to write the buffer on the Serial port
    if (!WriteFile(this->hSerial, (void*)buffer, nbChar, &bytesSend, 0))
    {
        //In case it don't work get comm error and return false
        ClearCommError(this->hSerial, &this->errors, &this->status);
 
        return false;
    }
    else
        return true;
}
 
bool Serial::IsConnected()
{
    //Simply return the connection status
    return this->connected;
}


Serial class source.



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
#include <iostream>
#include "SerialHeader.h"
 
using namespace std;
 
int main()
{
    Serial* ser = new Serial("\\\\.\\COM3");
    char message[255];    
 
    if (ser->IsConnected()) {
        cout << "Serial Communication Connected." << endl;
        // memset(message, 0, sizeof(message));
        // Serial::ReadData() 내부에서 memset이 실행된다.
        ser->ReadData(message, sizeof(message));
        cout << "Message from Arduino: " << message << endl;
    } else {
        cout << "Device can not be found or can not be configured." << endl;
 
        return 0;
    }
    
    while (true) {
        cout << "0: Off, 1 : On, q(Q) : Quit" << endl << "Choose : ";        
        cin >> message;
 
        if (!strcmp(message, "q"|| !strcmp(message, "Q")) {
            break;
        } else if (!strcmp(message, "0")) {            
            ser->WriteData("0"1);
            Sleep(200); // 아두이노와의 시리얼 통신을 위한 대기 시간.            
            ser->ReadData(message, sizeof(message));
            cout << "Message from Arduino: " << message << endl;
        } else {
            ser->WriteData("1"1);
            Sleep(200); // 아두이노와의 시리얼 통신을 위한 대기 시간.            
            ser->ReadData(message, sizeof(message));
            cout << "Message from Arduino: " << message << endl;
        }
    }
 
    return 0;
}


Windows에서 위 소스를 실행하면 연결된 아두이노의 Builtin LED를 제어할 수 있다.


※ 참고: Arduino and C++ (for Windows)



반응형
Posted by J-sean
:
반응형

파이썬 모듈인 pySerial을 이용해 간단히 아두이노와 시리얼 통신을 할 수 있다.


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
char state;
 
void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
  Serial.println("Arduino ready.");
}
 
void loop() {
  // put your main code here, to run repeatedly:
  if (Serial.available())
  {
    state = Serial.read();
    while (Serial.available())
    {
      Serial.read();  // 첫 번째 문자만 입력받고 나머지는 버린다.
    }
    
    if (state == '0')
    {
      digitalWrite(LED_BUILTIN, LOW);
      Serial.println("LED OFF");
    } else
    {
      digitalWrite(LED_BUILTIN, HIGH);
      Serial.println("LED ON");
    }
  }
 
  delay(100);
}


위 소스를 컴파일 하고 아두이노에 업로드 한다. 시리얼 모니터를 통해서도 Builtin LED를 제어할 수 있다.



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
import serial
import time
import sys
 
try:
    ser = serial.Serial('COM5'9600, timeout = 1)
    time.sleep(1)
except:
    print("Device can not be found or can not be configured.")
    sys.exit(0)
 
if (ser.readable()):
    print(ser.readline().decode(), end =''# 아두이노 준비 상태 확인.
    # 아두이노에서 Serial.println("Arduino ready"); 명령으로 데이터를 보내기 때문에
    # Serial 통신으로 읽어온 데이터에는 줄바꿈 문자(\r\n)가 이미 포함되어 있다.
    # Serial.print("Arduino ready");으로 바꾸면 end = ''가 필요 없다. 
 
while (True):
    print("\n0: Off, 1: On, q(Q): Quit\nChoose: ", end = '')    
    state = input()
 
    if state == 'q' or state == 'Q':
        break
    elif state == '0':
        ser.write(b'0')
        print(ser.readline().decode(), end = '')
    else:
        ser.write(b'1')
        print(ser.readline().decode(), end = '')
 
    time.sleep(0.1)
 
ser.close()


Windows에서 위 소스를 실행하면 연결된 아두이노의 Builtin LED를 제어할 수 있다.

※ 참고: https://pythonhosted.org/pyserial/




이 프로그램과 Arduino IDE의 시리얼 모니터를 동시에 실행시킬 수는 없다.


반응형
Posted by J-sean
: