-
[C++] 라즈베리파이 피코 기본입출력-USB Serial라즈베리파이 피코 2023. 2. 24. 11:52
c 언어로된 예제에는 printf로 출력을 하였는데, c++의 cout으로도 출력이 될까?, stdio와 iostream의 동기화를 끊어 속도를 올려도 출력이 될까 궁금하여 실험해보았다.
피코는 USB Serial로 PC와 통신하는데 uart0 를 사용한다는 것을 명심하자. 추가적으로 uart 장치(ex Bluetooth 모듈)를 연결하려면 uart1을 사용해야한다. 이 보다 많은 uart 장치를 연결하기 위해서는 아두이노의 softwareSerial을 구현해야 한다.(구현하는데 https://sidreco.tistory.com/12 여기서 핀 인터럽트 부분을 참고하면 될 듯하다.) 다만 uart 보다 속도도 빠르고 1:n 통신이 가능한 I2C와 SPI 통신 프로토콜을 사용하는 것을 추천한다.
#src/CMakeLits.txt set(projname cout_test) file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) add_executable(${projname} ${SRC_FILES}) # pull in common dependencies target_link_libraries(${projname} pico_stdlib) # create map/bin/hex file etc. pico_add_extra_outputs(${projname}) # add url via pico_set_program_url example_auto_set_url(${projname}) #printf 출력이 USB CDC(USB Serial)로 되도록함 pico_enable_stdio_usb(${projname} 1) #printf 출력이 UART로 되지 않도록 함 pico_enable_stdio_uart(${projname} 0)
add_excuteable 이 있는 CMakeLits.txt에서 pico_stdlib를 링크하고, pico_enable_stdio_~ 설정을 하는 것을 잊지 말아야 한다.
cmake_minimum_required(VERSION 3.12) # Pull in SDK (must be before project) set(BToolDIR $ENV{PICO_SDK_PATH}/../pico-examples) include(${BToolDIR}/pico_sdk_import.cmake) include(${BToolDIR}/pico_extras_import_optional.cmake) project(pico_examples C CXX ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) if (PICO_SDK_VERSION_STRING VERSION_LESS "1.3.0") message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.3.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}") endif() set(PICO_EXAMPLES_PATH ${PROJECT_SOURCE_DIR}) # Initialize the SDK pico_sdk_init() include(${BToolDIR}/example_auto_set_url.cmake) #빌드할 코드가 담긴 폴더 이름 입력 add_subdirectory(src) add_compile_options(-Wall -Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int -Wno-unused-function # we have some for the docs that aren't called -Wno-maybe-uninitialized )
기본 예제 - c 스타일
#include <stdio.h> #include "pico/stdlib.h" int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); stdio_init_all(); while(1) { printf("Hello\n"); sleep_ms(2000); } return 0; }
stdio_init_all 은 printf가 UART or USB Serial로 출력되도록 설정해주는 함수이다.
iostream - c++ 스타일
#include <iostream> using std::cout; using std::endl; #include "pico/stdlib.h" int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); stdio_init_all(); while(1) { cout << "Hello" << endl; sleep_ms(2000); } return 0; }
이렇게 해도 문제없이 출력하는 것을 확인하였다.
iostream -동기화 해제
#include <iostream> using std::cout; using std::endl; #include "pico/stdlib.h" int main() { gpio_init(PICO_DEFAULT_LED_PIN); gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_put(PICO_DEFAULT_LED_PIN, 1); std::ios_base::sync_with_stdio(false); stdio_init_all(); while(1) { cout << "Hello" << endl; sleep_ms(2000); } return 0; }
역시 문제없이 출력된다. 이 경우 iostream이 동기화 과정을 거치지 않고 자신만의 입출력 버퍼를 사용해서 속도가 비약적으로 향상된다. 그러나 prinf와 같이 사용했을 때
printf("printf"); cout << "cout" << endl;
이렇게 사용하여도 cout이 먼저 출력될 수 있다.
그리고 남이 만든 라이브러리 안에 printf가 사용되고, 내가 main에서 cout을 사용한다면, 한 번 테스트를 해봐야 알 수 있다. 함수가 호출되고, 실행되고, 스택에 저장해둔 진행상황을 불러와 다시 main으로 돌아가는 과정이 조금 시간이 걸리기 때문에 이 경우에는 출력 순서가 뒤바뀌지 않을 가능성이 크다. 그러나 짧게 작성된 inline 함수라면 충분히 출력 순서가 뒤바뀔 수 있다.
보율?
getting started with raspberry pi pico 에서는 115200을 사용하였다.
그런데 이렇게 해도 문제없이 작동하였고,
아두이노 시리얼 모니터에서 보드 이름은 아무거나 선택하고 시리얼 포트를 열어 확인해보았을 때, 보율을 뭘 설정하든 제대로 출력이 되었다. (아두이노에서 이러면 안된다.) 컴퓨터와 시리얼 통신할 때는 동기모드를 사용하거나 uart 레지스터를 사용하지만 usb 프로토콜을 사용하는 것 같다.
다만 uart 통신으로 다른 모듈/ic와 통신할 때는 보율을 지켜줘야 한다.(피코에서도 동기 모드가 있는지 모르겠다.)
'라즈베리파이 피코' 카테고리의 다른 글
[C/C++] 라즈베리파이 피코 기본입출력 -GPIO (0) 2023.02.25 [C++] LiquidCrystal_I2C_PICO (2) 2023.02.22