반응형

2.2인치 ILI9341 TFT LCD를 아두이노와 함께 사용해 보자.


알리에서 약 5천원에 구매한 ILI9341.


Logic Signal Voltage Level은 3.3V이지만 J1을 납땜해 연결하면 5V의 Signal도 입력 받을 수 있다(납땝이 좀 지저분하게 됐다). 하지만 이 방법 보다는 Logic Level Converter를 사용하는게 좋다.


원래 J1은 이렇게 떨어져 있다.


사실 ILI9341은 아두이노가 아니라 라즈베리파이와 함께 사용해보려 했지만 인터넷에 있는 대부분의 자료들이 더 이상 적용되지 않았다. 백라이트조차 켜지지 않았다. 라즈베리파이 운영체제의 업데이트, 소프트웨어의 업데이트 등으로 변경된 내용이 많아 좀 더 정리가 필요했다.



아두이노와 연결 하자.


ILI9341 - Arduino

DC - 9

CS - 10

RESET - 8

MOSI - 11

MISO - 12

SCK - 13

LED - 3.3V

VCC - 5V

GND - GND


아두이노IDE에서 File - Examples - Adafruit ILI9341 - graphictest을 선택하면 아래 소스가 로드된다.


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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/***************************************************
  This is our GFX example for the Adafruit ILI9341 Breakout and Shield
  ----> http://www.adafruit.com/products/1651
  Check out the links above for our tutorials and wiring diagrams
  These displays use SPI to communicate, 4 or 5 pins are required to
  interface (RST is optional)
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!
  Written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
 
 
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
 
// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10
 
// Adafruit shield가 아닌 경우 아래와 같이 핀 추가.
#define TFT_RST 8
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_CLK 13
 
// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
 
void setup() {
  Serial.begin(9600);
  Serial.println("ILI9341 Test!"); 
 
  tft.begin();
 
  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX); 
  
  Serial.println(F("Benchmark                Time (microseconds)"));
  delay(10);
  Serial.print(F("Screen fill              "));
  Serial.println(testFillScreen());
  delay(500);
 
  Serial.print(F("Text                     "));
  Serial.println(testText());
  delay(3000);
 
  Serial.print(F("Lines                    "));
  Serial.println(testLines(ILI9341_CYAN));
  delay(500);
 
  Serial.print(F("Horiz/Vert Lines         "));
  Serial.println(testFastLines(ILI9341_RED, ILI9341_BLUE));
  delay(500);
 
  Serial.print(F("Rectangles (outline)     "));
  Serial.println(testRects(ILI9341_GREEN));
  delay(500);
 
  Serial.print(F("Rectangles (filled)      "));
  Serial.println(testFilledRects(ILI9341_YELLOW, ILI9341_MAGENTA));
  delay(500);
 
  Serial.print(F("Circles (filled)         "));
  Serial.println(testFilledCircles(10, ILI9341_MAGENTA));
 
  Serial.print(F("Circles (outline)        "));
  Serial.println(testCircles(10, ILI9341_WHITE));
  delay(500);
 
  Serial.print(F("Triangles (outline)      "));
  Serial.println(testTriangles());
  delay(500);
 
  Serial.print(F("Triangles (filled)       "));
  Serial.println(testFilledTriangles());
  delay(500);
 
  Serial.print(F("Rounded rects (outline)  "));
  Serial.println(testRoundRects());
  delay(500);
 
  Serial.print(F("Rounded rects (filled)   "));
  Serial.println(testFilledRoundRects());
  delay(500);
 
  Serial.println(F("Done!"));
 
}
 
 
void loop(void) {
  for(uint8_t rotation=0; rotation<4; rotation++) {
    tft.setRotation(rotation);
    testText();
    delay(1000);
  }
}
 
unsigned long testFillScreen() {
  unsigned long start = micros();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  tft.fillScreen(ILI9341_RED);
  yield();
  tft.fillScreen(ILI9341_GREEN);
  yield();
  tft.fillScreen(ILI9341_BLUE);
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
  return micros() - start;
}
 
unsigned long testText() {
  tft.fillScreen(ILI9341_BLACK);
  unsigned long start = micros();
  tft.setCursor(00);
  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(1);
  tft.println("Hello World!");
  tft.setTextColor(ILI9341_YELLOW); tft.setTextSize(2);
  tft.println(1234.56);
  tft.setTextColor(ILI9341_RED);    tft.setTextSize(3);
  tft.println(0xDEADBEEF, HEX);
  tft.println();
  tft.setTextColor(ILI9341_GREEN);
  tft.setTextSize(5);
  tft.println("Groop");
  tft.setTextSize(2);
  tft.println("I implore thee,");
  tft.setTextSize(1);
  tft.println("my foonting turlingdromes.");
  tft.println("And hooptiously drangle me");
  tft.println("with crinkly bindlewurdles,");
  tft.println("Or I will rend thee");
  tft.println("in the gobberwarts");
  tft.println("with my blurglecruncheon,");
  tft.println("see if I don't!");
  return micros() - start;
}
 
unsigned long testLines(uint16_t color) {
  unsigned long start, t;
  int           x1, y1, x2, y2,
                w = tft.width(),
                h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  yield();
  
  x1 = y1 = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t     = micros() - start; // fillScreen doesn't count against timing
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = w - 1;
  y1    = 0;
  y2    = h - 1;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = 0;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = w - 1;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
  t    += micros() - start;
 
  yield();
  tft.fillScreen(ILI9341_BLACK);
  yield();
 
  x1    = w - 1;
  y1    = h - 1;
  y2    = 0;
  start = micros();
  for(x2=0; x2<w; x2+=6) tft.drawLine(x1, y1, x2, y2, color);
  x2    = 0;
  for(y2=0; y2<h; y2+=6) tft.drawLine(x1, y1, x2, y2, color);
 
  yield();
  return micros() - start;
}
 
unsigned long testFastLines(uint16_t color1, uint16_t color2) {
  unsigned long start;
  int           x, y, w = tft.width(), h = tft.height();
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(y=0; y<h; y+=5) tft.drawFastHLine(0, y, w, color1);
  for(x=0; x<w; x+=5) tft.drawFastVLine(x, 0, h, color2);
 
  return micros() - start;
}
 
unsigned long testRects(uint16_t color) {
  unsigned long start;
  int           n, i, i2,
                cx = tft.width()  / 2,
                cy = tft.height() / 2;
 
  tft.fillScreen(ILI9341_BLACK);
  n     = min(tft.width(), tft.height());
  start = micros();
  for(i=2; i<n; i+=6) {
    i2 = i / 2;
    tft.drawRect(cx-i2, cy-i2, i, i, color);
  }
 
  return micros() - start;
}
 
unsigned long testFilledRects(uint16_t color1, uint16_t color2) {
  unsigned long start, t = 0;
  int           n, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n = min(tft.width(), tft.height());
  for(i=n; i>0; i-=6) {
    i2    = i / 2;
    start = micros();
    tft.fillRect(cx-i2, cy-i2, i, i, color1);
    t    += micros() - start;
    // Outlines are not included in timing results
    tft.drawRect(cx-i2, cy-i2, i, i, color2);
    yield();
  }
 
  return t;
}
 
unsigned long testFilledCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int x, y, w = tft.width(), h = tft.height(), r2 = radius * 2;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(x=radius; x<w; x+=r2) {
    for(y=radius; y<h; y+=r2) {
      tft.fillCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testCircles(uint8_t radius, uint16_t color) {
  unsigned long start;
  int           x, y, r2 = radius * 2,
                w = tft.width()  + radius,
                h = tft.height() + radius;
 
  // Screen is not cleared for this one -- this is
  // intentional and does not affect the reported time.
  start = micros();
  for(x=0; x<w; x+=r2) {
    for(y=0; y<h; y+=r2) {
      tft.drawCircle(x, y, radius, color);
    }
  }
 
  return micros() - start;
}
 
unsigned long testTriangles() {
  unsigned long start;
  int           n, i, cx = tft.width()  / 2 - 1,
                      cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  n     = min(cx, cy);
  start = micros();
  for(i=0; i<n; i+=5) {
    tft.drawTriangle(
      cx    , cy - i, // peak
      cx - i, cy + i, // bottom left
      cx + i, cy + i, // bottom right
      tft.color565(i, i, i));
  }
 
  return micros() - start;
}
 
unsigned long testFilledTriangles() {
  unsigned long start, t = 0;
  int           i, cx = tft.width()  / 2 - 1,
                   cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(cx,cy); i>10; i-=5) {
    start = micros();
    tft.fillTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(0, i*10, i*10));
    t += micros() - start;
    tft.drawTriangle(cx, cy - i, cx - i, cy + i, cx + i, cy + i,
      tft.color565(i*10, i*100));
    yield();
  }
 
  return t;
}
 
unsigned long testRoundRects() {
  unsigned long start;
  int           w, i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  w     = min(tft.width(), tft.height());
  start = micros();
  for(i=0; i<w; i+=6) {
    i2 = i / 2;
    tft.drawRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(i, 00));
  }
 
  return micros() - start;
}
 
unsigned long testFilledRoundRects() {
  unsigned long start;
  int           i, i2,
                cx = tft.width()  / 2 - 1,
                cy = tft.height() / 2 - 1;
 
  tft.fillScreen(ILI9341_BLACK);
  start = micros();
  for(i=min(tft.width(), tft.height()); i>20; i-=6) {
    i2 = i / 2;
    tft.fillRoundRect(cx-i2, cy-i2, i, i, i/8, tft.color565(0, i, 0));
    yield();
  }
 
  return micros() - start;
}


로드된 소스는 Adafruit shield 사용을 전제로 작성된 소스이므로 위와 같이 24~33번 라인을 수정한다.


컴파일하고 업로드하면 그래픽이 표시된다.









실행해 보면 생각만큼 빠르지는 않다. 아두이노 전용은 아니지만 STM32, ESP8266, ESP32를 위한 더 빠른 라이브러리가 있다. 아두이노에도 적용 가능하지 않을까싶다. 아래 링크를 참고하자.

TFT_eSPI


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

MX1508 모터 드라이버로 2개의 DC모터나 1개의 스텝 모터를 컨트롤 할 수 있다.

- Supply voltage: 2~10V.

- Signal input voltage 1.8~7V.


MX1508 모터 드라이버


MX1508 드라이버 다이어그램은 아니지만 위와 같은 방식으로 연결한다.


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
const int IN1 = 5;
const int IN2 = 6;
const int IN3 = 9;
const int IN4 = 10;
 
void setup() {
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);
}
 
void loop() {
  CWRotation(100);
  delay(1000);
 
  CCWRotation(200);
  delay(1000);
}
 
void CWRotation(int speed)
{
  analogWrite(IN1, speed);
  digitalWrite(IN2, LOW);
  analogWrite(IN3, speed);
  digitalWrite(IN4, LOW);
}
 
void CCWRotation(int speed)
{
  digitalWrite(IN1, LOW);
  analogWrite(IN2,speed );
  digitalWrite(IN3, LOW);
  analogWrite(IN4, speed);
}


소스를 컴파일 하고 아두이노에 업로드한다. 모터가 다른 속도로 정회전, 역회전을 반복한다.


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

NodeMCU(ESP-12E/ESP8266)를 이용해 LED를 제어하는 서버를 만들어 보자.


2020/03/10 - [Raspberry Pi & Arduino] - How to program ESP32-CAM using Arduino UNO - 아두이노로 ESP32-CAM 프로그래밍 하기


NodeMCU를 준비한다.


ESP8266모듈이 내장된 NodeMCU를 사용하기 위해 'Preferences - Additional Boards ManagerURLs:'에 http://arduino.esp8266.com/stable/package_esp8266com_index.json을 입력한다.


Boards Manager에서 esp를 검색하고 esp8266을 설치한다.


Tools - Board에서 NodeMCU 1.0 (ESP-12E Module)을 선택한다.



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
#include <ESP8266WiFi.h>
 
const char* ssid = "Your ssid";
const char* password = "Your password";
 
WiFiServer server(80);
WiFiClient client;
String request;
int status = LOW;
 
void setup() {
  Serial.begin(9600);
 
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
 
  Serial.print("Connecting to ");
  Serial.println(ssid);
 
  WiFi.begin(ssid, password);
  // Tells the server to begin listening for incoming connections.
 
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.println("WiFi connected!!");
  server.begin();
  Serial.println("Server started.");
 
  Serial.print("Use this URL to connect to the server: ");
  Serial.print("http://");
  Serial.println(WiFi.localIP());
}
 
void loop() {    
  client = server.available();
  // Gets a client that is connected to the server and has data available for reading.
  // The connection persists when the returned client object goes out of scope;
  // you can close it by calling client.stop().
  if (!client) {
    delay(100);
    
    return;
  }
  
  Serial.println("New client connected.");    
  
  while (!client.available()) {
    // Returns the number of bytes available for reading (that is, the amount of data
    // that has been written to the client by the server it is connected to).
    delay(100);
  }
 
  request = client.readStringUntil('\r');
  Serial.print("Request from the client: ");
  Serial.println(request);
  client.flush();
 
  if (request.indexOf("LED=ON"!= -1) {
    digitalWrite(LED_BUILTIN, HIGH);
    status = HIGH;
  } else if (request.indexOf("LED=OFF"!= -1) {
    digitalWrite(LED_BUILTIN, LOW);
    status = LOW;
  }
 
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html");
  client.println("");
  client.println("<!DOCTYPE HTML>");
  client.println("<html>");
  client.print("LED is turned ");
  if (status)
    client.print("On");
  else
    client.print("Off");
  client.println("<br><br>");
  client.println("<a href=\"/LED=ON\" title=\"Turn the LED on\"><button>Turn on</button></a>");
  client.println("<a href=\"/LED=OFF\" title=\"Turn the LED off\"><button>Turn off</button></a>");
  client.println("</html>");  
 
  //client.stop();
  // client.stop()을 호출하면 제대로 작동하지 않는다.
  Serial.println("Client disconnected!!");
  delay(100);
}


위 소스를 컴파일하고 NodeMCU에 업로드한다.


시리얼 모니터를 확인하면 와이파이에 연결되고 URL이 표시된다.


스마트폰이나 컴퓨터로 URL에 접속하면 위와 같은 화면이 표시된다.


'Turn on'버튼을 클릭하면 서버로 URL/LED=ON 요청을 보내고 서버에서는 LED=ON 문자열을 감지해 NodeMCU의 built-in LED를 켠다. (실제 built-in LED의 동작은 반대로 된다. LED가 꺼진다.)


'Turn off'버튼을 클릭하면 서버로 URL/LED=OFF 요청을 보내고 서버에서는 LED=OFF 문자열을 감지해 NodeMCU의 built-in LED를 끈다. (실제 built-in LED의 동작은 반대로 된다. LED가 켜진다.)


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

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
:
반응형

아두이노 프로 마이크로를 이용해 간단한 USB키보드를 만들 수 있다.


2019/10/27 - [C, C++] - Sending a keyboard input 키 입력 보내기


Arduino Pro Micro Pin Map


Tactile Switch를 연결한다.

D4 - Tactile Switch - GND


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Keyboard.h>
 
const char PIN_RETURN = 4;
 
void setup() {
  // put your setup code here, to run once:
  pinMode(PIN_RETURN, INPUT_PULLUP);
  Keyboard.begin();
}
 
void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(PIN_RETURN)== LOW)
  {
    Keyboard.press(KEY_RETURN);
    delay(100);
    Keyboard.release(KEY_RETURN); // Keyboard.releaseAll();
    delay(100);
  }
 
  delay(100);
}
 
// https://www.arduino.cc/reference/en/language/functions/usb/keyboard/


스위치를 누르면 Enter키가 입력되는 소스.

※ 참고: https://www.arduino.cc/reference/en/language/functions/usb/keyboard/


Arduino Leonardo 보드를 선택하고 컴파일후 업로드 한다.



장치 관리자를 확인하면 'HID 키보드 장치'로 인식된다. 스위치를 누르면 Enter키가 입력된다.


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

nRF24L01 모듈은 Serial Peripheral Interface(SPI) 프로토콜을 사용하여 2.4GHz 무선 통신이 가능하다.


중국에서 구매한 nRF24L01 모듈 2개.


8개의 핀이 있다.


nRF24L01의 핀맵.


아두이노의 핀맵. nRF24L01과 연결할 핀을 확인 한다.



이렇게 연결 한다.


[nRF24L01 - Arduino]

VCC - 3.3V

GND - GND

CSN - 8

CE - 7

MOSI - 11

SCK - 13

IRQ - N/A

MISO - 12


통신을 해야 하므로 2개 모두 연결해 준다.


수신 프로그램을 컴파일 하고 아두이노에 업로드 한다.


송신 프로그램을 컴파일 하고 다른 아두이노에 업로드 한다.



수신 프로그램이 업로드된 아두이노의 시리얼 모니터를 확인해 보자.

통신이 잘 안된다면 10μF 커패시터를 연결 하고 3.3V 외부 전원을 사용 하자.


GND is the Ground Pin. It is usually marked by encasing the pin in a square so it can be used as a reference for identifying the other pins.


VCC supplies power for the module. This can be anywhere from 1.9 to 3.9 volts. You can connect it to 3.3V output from your Arduino. Remember connecting it to 5V pin will likely destroy your nRF24L01+ module!


CE (Chip Enable) is an active-HIGH pin. When selected the nRF24L01 will either transmit or receive, depending upon which mode it is currently in.


CSN (Chip Select Not) is an active-LOW pin and is normally kept HIGH. When this pin goes low, the nRF24L01 begins listening on its SPI port for data and processes it accordingly.


SCK (Serial Clock) accepts clock pulses provided by the SPI bus Master.


MOSI (Master Out Slave In) is SPI input to the nRF24L01.


MISO (Master In Slave Out) is SPI output from the nRF24L01.


IRQ is an interrupt pin that can alert the master when new data is available to process.


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

I2C 프로토콜과 SSD1306 드라이버를 사용하는 0.96인치 OLED를 아두이노나 NodeMCU에서 간단하게 사용 할 수 있다.


중국에서 구매한 0.96인치 I2C OLED. SSD1306 드라이버를 사용하고 파란색 화면이 나온다.

(케이스에는 SSD1315라고 표기 되어 있다)


디스플레이 보호 스티커가 붙어 있다.


떼자.


뒷면



아래와 같이 연결한다.

[OLED - 아두이노]

VCC - 5V

GND - GND

SCL - A5

SDA - A4


실제 OLED와는 약간 다르다.


Library Manager에서 adafruit gfx를 검색하고 설치 한다.


Dependencies도 모두 설치 한다.



adafruit ssd1306도 검색해서 설치 한다.


ssd1306_128X64_i2c 예제를 로드한다.


OLED의 주소를 0x3C로 바꾼다.


컴파일하고 아두이노에 업로드 하면 여러가지 예제 화면이 출력 된다.



0.91인치 OLED.


핀맵은 0.96인치 OLED와 동일 하다.


0.96인치 해상도: 128 X 64

0.91인치 해상도: 128 X 32


0.91인치 OLED는 SCREEN_HEIGHT를 32로 바꿔서 테스트 한다.


Adafruit 라이브러리는 용량이 굉장히 크다. 필요 하다면 좀 더 작고 가벼운 U8g2 라이브러리를 사용하자.


그림 출력을 위한 1비트 픽셀 BMP(Black and White) 변환이 필요 하다면 이 링크나 아래 프로그램을 사용하자.

ezBMP.exe



반응형
Posted by J-sean
: