사용 중인 아두이노 IDE 버전이 2.3.4인데 버그 때문에 코딩이 불편합니다. 정의로 이동하는 기능(F12)과 바로가기 링크(Ctrl+LMB)가 수시로 먹통이 되어 코드 추적이 너무 힘듭니다. 컴파일 속도도 엄청 느려요. 그래서 Visual Studio Code로 프로젝트를 옮겨봅니다.
PlatformIO 새 프로젝트를 만들고 기존 Arduino 프로젝트를 마이그레이션 해봅니다.
여기서 사용된 PlatformIO IDE 버전은 3.4.4입니다.
Visual Studio Code 설치
VSCode를 설치하는 것은 매우 쉽습니다. 설치 파일
중요한 것은 설치 과정에서 탐색기 단축메뉴에 열기 항목을 등록하는 설정을 선택하는 것입니다.
Code(으)로 열기 메뉴가 없으면 정말 불편해요!
Visual Studio Code 설정
멀티탭
이 기능은 VS2022 업데이트에 추가되어 유용했는데, VSCode에도 있습니다.
설정에서 wrap tabs를 검색하고 해당 설정 항목을 체크합니다.
수많은 탭이 멀티라인으로 표시되어 탐색이 빨라집니다.
Visual Studio Code 확장
VSCode를 실행 후 필수 확장을 설치합니다.
- PlatformIO IDE
- C/C++
필요에 따라 추가 확장을 설치합니다.
- Korean Language Pack for Visual Studio Code
- C/C++ Extension Pack
- Clang-Format
Clang-Format (문서 서식)
문서 서식을 적용해 주는 확장입니다. VS2022에서는 마우스로 상세한 설정이 가능하지만 VSCode는 모든 게 코드입니다.🤣
Clang_format_fallback Style 설정에서 여러 가지 포맷 스타일을 지정할 수 있습니다.
일부 코드로 스타일 비교를 해봅니다.
WebKit ⭐⭐⭐
- 탭은 공백 4칸입니다.
- 메서드 중괄호는 새 줄에서 시작하며, 조건문 중괄호는 같은 줄에서 시작합니다.
- 배열 요소에 공백이 적용됩니다.
- 주석이 길면 매개변수가 다음줄로 이동합니다.
Microsoft ⭐
- 탭은 공백 4칸입니다.
- 중괄호는 새 줄에서 시작합니다.
- 붙어있는 줄의 주석은 세로 정렬됩니다.
- 줄이 길면 매개변수가 하나씩 다음줄로 이동합니다.
Visual Studio ⭐
- 탭은 공백 2칸입니다.
- 그 외에는 Microsoft와 스타일이 같습니다.
GNU ⭐
- 탭은 공백 2칸입니다.
- 배열 요소에 공백이 적용됩니다.
- 모든 중괄호는 새 줄에서 시작합니다.
- 줄이 길면 모든 매개변수가 새 줄에서 시작합니다.
- 붙어있는 줄의 주석이 길면 세로 정렬이 안 됩니다.
- 메서드와 소괄호 사이에 공백이 적용됩니다.
Mozilla ⭐
- 메서드의 중괄호는 새 줄에서 시작합니다.
- 배열 요소에 공백이 적용됩니다.
Chromium⭐⭐⭐
- 세미콜론과 한 줄 주석 사이에 공백 2칸이 적용됩니다.
Google⭐⭐⭐
- 크롬과 구글은 스타일이 같습니다.
LLVM⭐⭐⭐⭐
- 모든 중괄호의 시작은 줄 끝에 위치합니다.
- 탭은 공백 2칸입니다.
- 세미콜론과 한 줄 주석 사이에 공백 1칸이 적용됩니다.
C#을 주로 다루는 개발자들에게는 현대적인 LLVM 스타일이 익숙합니다. 줄 너비 제한만 조정하면 될 것 같습니다.
사용자 정의 스타일 ⭐⭐⭐⭐⭐
설명과 같이 설정 값을 사용자 지정할 수 있습니다. C_Cpp.clang_format_fallbackStyle 또는 C_Cpp.clang_format_style 설정 항목에 입력합니다. C_Cpp.clang_format_style 설정이 우선 적용됩니다.
{BasedOnStyle : LLVM, ColumnLimit : 0, AlignConsecutiveAssignments: AcrossEmptyLinesAndComments}
드디어 원하던 스타일이 적용되었습니다.🤩
Word Wrap (줄 바꿈)
매개변수가 다음줄로 이동하는 것은 각 줄의 글자 수가 제한되어 있기 때문입니다. 이는 작은 해상도에서 편집하기 위한 것이라고 하지만 창 크기를 줄이면 여전히 가로 스크롤이 생깁니다.
이렇게 줄 번호가 새로 적용되는 것은 상당히 불편하기 때문에 글자 수 제한을 늘리고 자동 줄 바꿈 기능을 활성화해야 합니다.
새 프로젝트
PIO Home 페이지에서 New Project 버튼을 누르고
- Name은 프로젝트 이름을 입력합니다. 폴더명으로 사용됩니다.
- Board는 Espressif ESP32 Dev Module을 선택합니다. TTGO와 Heltec 같은 주요 브랜드는 목록에서 제품명을 선택합니다.
- Framework는 Arduino를 선택합니다. 코딩이 편해집니다.
Location 항목을 체크하면 내 문서 PlatformIO 폴더에 프로젝트가 생성되고, 별도 위치에 저장하려면 체크 해제 합니다. 상위 폴더를 선택하고 Finish 버튼을 누르면 자동으로 프로젝트 이름으로 폴더가 생성됩니다.
platformio.ini
제일 먼저 편집할 파일입니다. 보드는 TTGO T-Display를 사용 중입니다.
[env:lilygo-t-display]
platform = espressif32
board = lilygo-t-display
framework = arduino
monitor_speed = 115200
monitor_speed = 115200 줄을 추가해야 시리얼 모니터링에서 글자가 깨지지 않습니다.
업로드 속도
platformio.ini에서 보드 설정은 platformio에 등록된 보드 정보를 사용합니다. lilygo-t-display의 보드값은 platform-espressif32/boards/lilygo-t-display.json에 정의되어 있습니다.
전송 속도 기본값은 460800이므로 921600을 적용하려면 아래처럼 지정합니다.
upload_speed = 921600
라이브러리 설치
#include <TinyGPSPlus.h> 를 추가했는데 프로젝트에 해당 라이브러리가 없으면 PlatformIO - Libraries에서 라이브러리를 검색하여 추가하면 설치됩니다.
라이브러리 버전 지정
버전 형식은 semver 규칙에 따라 작성합니다.
; ^ 기호는 기능(호환 가능한) 버전을 적용
; 1.1.0 이상이며 2.0.0 미만인 버전
mikalhart/TinyGPSPlus@^1.1
; ~ 기호는 패치 버전을 적용
; 1.1.0 이상이며 1.2.0 미만인 버전
mikalhart/TinyGPSPlus@~1.1
; ! 기호는 특정 버전을 제외
; 1.1.0 이상이며 1.2.0 미만인 버전에서 1.1.2를 제외
mikalhart/TinyGPSPlus@~1.1, !1.1.2
; 메이저 번호가 0이면 베타 버전이므로 패치만 적용합니다.
; 0.1.0 이상이며 0.2.0 미만인 버전
mikalhart/TinyGPSPlus@^0.1
; 0.0.1인 버전
mikalhart/TinyGPSPlus@^0.0.1
버전 지정은 platformio.ini 파일에서 편집할 수 있습니다.
[env:lilygo-t-display]
platform = espressif32
board = lilygo-t-display
framework = arduino
monitor_speed = 115200
lib_deps =
bitbank2/PNGdec@^1.0.3
bodmer/TFT_eSPI@^2.5.43
paulstoffregen/Time@^1.6.1
mikalhart/TinyGPSPlus@^1.1.0
bxparks/AceButton@^1.10.1
adafruit/Adafruit AHTX0@^2.0.5
adafruit/Adafruit BMP280 Library@^2.6.8
adafruit/ENS160 - Adafruit Fork@^3.0.1
위와 같이 작성하면 됩니다. 각 줄은 탭 1개로 들여 쓰기 합니다. 위 라이브러리 설정은 .pio/libdeps/환경이름/integrity.dat 파일로 저장됩니다.
※ @부터 모두 삭제하면 버전을 무시합니다. 메이저 버전이 판올림되면 이전 버전과 호환 문제가 생기므로 프로젝트를 라이브러리에 맞게 수정해야 합니다.
Git 또는 압축 파일을 지정할 때
PlatformIO에 등록되지 않은 라이브러리를 사용하려면 .git 주소를 지정하거나 .zip, .gz 파일 주소를 지정하면 됩니다.
; 외부 Git 저장소
https://github.com/gioblu/PJON.git#v2.0
; 패키지 폴더 이름 지정
IRremoteESP8266=https://github.com/markszabo/IRremoteESP8266/archive/master.zip
.git 뒤의 #blahblah 는 특정 분기를 지정할 때 사용합니다.
압축 파일 주소를 지정할 때에는 라이브러리 이름을 앞에 입력합니다.
라이브러리 업데이트
이미 라이브러리가 설치되어 있다면 패키지 업데이트 명령을 실행합니다. 터미널은 VSCode 터미널이 아닌, PlatformIO의 터미널을 실행해야 합니다.
pio pkg update
위 명령어를 실행하면 패키지가 업데이트 됩니다.
main.cpp
새 프로젝트를 만들면 자동으로 생성되는 파일입니다. 쓸데없는 예제 코드가 있어서 삭제하기 귀찮습니다.
아두이노 IDE에서 사용하는 키워드를 컴파일하려면 아래 코드를 추가해야 합니다.
#include <Arduino.h>
아래처럼 코딩됩니다.
#include <Arduino.h>
#include "blahblah.h"
void setup() {
Serial.begin(115200);
tft.begin();
}
void loop() {
// blahblah
}
blahblah.h
Arduino IDE에서는 .ino 파일을 여러 개 만들어서 코드를 분할할 수 있지만, PlatformIO IDE에는 병합 기능이 없습니다. 그래서 .h, .cpp 파일을 각각 만들고 include 해야 합니다.
각 헤더 파일에 포함된 #include는 #ifndef ~ #endif로 중복을 제한 할 수 있지만 포맷 스타일이 적용되지 않으므로 #pragma once를 사용하면 코드가 깔끔해집니다.
// Header
#pragma once
#include <Arduino.h>
#include <SPI.h>
#include <TFT_eSPI.h>
extern TFT_eSPI tft;
extern uint8_t pageNum;
extern bool pagePulse;
extern uint8_t pageTotal;
#include <PNGdec.h>
extern PNG png;
void pngDraw(PNGDRAW *);
uint8_t conv2d(const char *);
void loopLCD();
다른 .cpp 파일에서 클래스 인스턴스와 변수를 초기화하려면 인스턴스와 변수 형식 앞에 extern 키워드를 붙입니다.
메서드는 초기화가 없으므로 extern이 필요 없습니다. 매개변수는 형식만 입력합니다.
클래스는 .h 파일에 정의하면 깔끔해집니다.
blahblah.cpp
#include <Arduino.h>
#include "blahblah.h"
TFT_eSPI tft = TFT_eSPI();
uint8_t pageNum = 1;
bool pagePulse = true;
uint8_t pageTotal = 5;
TFT_eSprite tftspr = TFT_eSprite(&tft);
PNG png;
이렇게 .cpp 파일에서 인스턴스와 변수가 초기화되었습니다. 헤더에 선언되었기 때문에 main.cpp나 다른 파일에서 접근할 수 있습니다.
이런 식으로. ino 파일을 분할하면 됩니다.
빌드
PlatformIO 상태표시줄 도구 모음에서 ✔️ 아이콘을 누르면 컴파일이 됩니다.
빌드와 업로드를 한번에 하려면 ➡️ 아이콘을 누릅니다.
Arduino IDE는 수 분이 걸리는 작업을 PlatformIO IDE는 매우 빠른 속도로 완료합니다.
고급 기능
여러 보드 환경에서 라이브러리 목록을 변수로 적용하기
보드 설정마다 lib_deps 목록을 추가하면 관리하기가 어렵습니다. 이때에는 변수를 사용해봅니다.
[common]
lib_deps_external =
bitbank2/PNGdec@^1.0.3
bodmer/TFT_eSPI@^2.5.43
paulstoffregen/Time@^1.6.1
mikalhart/TinyGPSPlus@^1.1.0
bxparks/AceButton@^1.10.1
adafruit/Adafruit AHTX0@^2.0.5
adafruit/Adafruit BMP280 Library@^2.6.8
adafruit/ENS160 - Adafruit Fork@^3.0.1
[env:lilygo-t-display]
platform = espressif32
board = lilygo-t-display
framework = arduino
monitor_speed = 115200
lib_deps = ${common.lib_deps_external}
위와 같이 [섹션]을 만들고 설정 키를 만들고 값을 입력합니다.
다른 그룹에서 ${섹션.키}를 지정하면됩니다.
.cpp 에서 환경 변수 가져오기
[env:T_Display]
build_flags =
-DFOO -DBAR=1
-DENV_NAME=$PIOENV
-D CURRENT_TIME=$UNIX_TIME
-DFLOAT_VALUE=1.23457e+07
build_flags 키를 추가하고 -D 파라미터를 사용하면 됩니다. - 뒤의 글자 하나만 인식하므로 변수명 띄어쓰기는 상관없습니다.
// .h, .cpp
#if (ENV_NAME == T_Display)
#define LCD_WIDTH 135
#define LCD_HEIGHT 240
#endif