ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C++] LiquidCrystal_I2C_PICO
    라즈베리파이 피코 2023. 2. 22. 19:06

    아두이노의 LiquidCrystal_I2C를 라즈베리파이 피코 용으로 구현해보았다. 모든 기능을 다 구현하진 않았고, 내가 아두이노에서 썻던 주요 기능만 구현하였다. (텍스트 스크롤 같은 기능은 배열을 이용해서도 충분히 구현가능하다.) PCF8574 IIC I2C가 변환모듈로 사용되고, 4행 이하의 LCD면 호환이 될 것이다.

     

    참고

    https://github.com/johnrickman/LiquidCrystal_I2C

     

    GitHub - johnrickman/LiquidCrystal_I2C: LiquidCrystal Arduino library for the DFRobot I2C LCD displays

    LiquidCrystal Arduino library for the DFRobot I2C LCD displays - GitHub - johnrickman/LiquidCrystal_I2C: LiquidCrystal Arduino library for the DFRobot I2C LCD displays

    github.com

    라즈베리파이 피코 예제 pico-examples\i2c\lcd_1602_i2c\lcd_1602_i2c.c

    아트멜 스튜디오와 아두이노로 배우는 ATmega328 프로그래밍 Chapter 21 허경용 지음

     

    배경 지식

    그냥 텍스트 LCD에서

    RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
    0 0 0 0 0 0 0 0 0 1

    이렇게 입력이 된 다음 EN 핀에 펄스를 하나 보내면
    EN 핀의 하강 엣지에서 명령이 처리되어 디스플레이가 클리어 된다.(RS = 0 이면 command로 처리)

    또 이런 상태에서 '1' = 49(in ASCI) = 0b00110001 = 0x31

    RS R/W DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
    1 0 0 0 1 1 0 0 0 1

    이렇게 입력이 된 다음 EN 핀에 펄스를 하나 보내면
    EN 핀의 하강엣지에서 명령이 처리되어 현제 커서에 '1'이 출력된다. (RS = 1 면 텍스트 명령으로 처리)

    I2C 확장이 붙어있어도 I2C 통신으로 0x01을 보내면

    DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0
    0 0 0 0 0 0 0 1

    이렇게 처리가 된다.  
    다만 RS(Register Select), R/W(Read/Write), EN(Enable)을 제어하기 위해서, 펄스와 함께 데이터를 보내게 된다. 처음 보낼때는 특정 비트를 세트하여 보냈다가 두번째 보낼때는 특정 비트를 클리어하여 보낸다. 백라이트 명령도 펄스를 보낼 때 해당 비트마스트를 보낼 데이터와 or 연산하여 전송하는 것으로 처리한다.

     

    비트마스크

      RS R/W EN Backlight On
    16진수 0x01 0x02 0x04 0x08
    이진수 0b0000001 0b00000010 0b00000100 0b00001000
    십진수 1 2 4 8

    *Backlight On 이 펄스로 전송되지 않으면 Backlight Off 된다.

    **해당 비트에 펄스가 전송되지 않으면, LCD에 대응되는 핀은 0이 된다.

     

    하위 4비트가 추가 명령 전달을 위해 펄스 신호용으로 사용되는 걸 알 수 있다. 눈치가 빠르다면 상위 니블(상위 4비트)만 데이터 전송에 쓰인다는 것을 알 수 있을 것이다. 만약 LCD 클리어 명령인 0x01을 그냥 보내려고 하면 펄스 비트 마스크와 위치가 곂처 제대로 전송하지 못할 것이다. 따라서 데이터를 4비트씩 나눠 보내게 되는데, value & ~0x0f한 값을 먼저 전송하여 상위 니블을 보내고, (value << 4) & ~0x0f 하여 하위 니블을 보낸다.(& ~0x0f 연산을 하는 이유는 보낼 때 하위 니블을 클리어 시켜 펄스 신호와 썩이지 않도록 하기 위함이다.)

     

    한가지 더 조심해야 될 부분이 LCD는 8비트 모드가 기본이다. 우리는 4비트 모드로 전송하므로, LCD를 4비트 모드로 바꾸기 위해서, 0x03, 0x03, 0x03, 0x02를 보내야 한다.(데이터 시트를 안보고 라이브러리만 뜯어봐서 정확히 왜 인지는 잘 모른다. 아두이노 라이브러리와 예제의 주석을 참고하여 알아냈다.)

     

    LCD에 보내는 명령에 대해서는 아트멜 스튜디오와 아두이노로 배우는 ATmega328 프로그래밍 Chapter 21 부분을 보거나 그냥 LCD를 사용하는 방법을 참고하면 다 나온다. 아니면 나처럼 남들이 작성한 상수값을 적당히 복붙해도 된다.(피코 예제 것을 복붙했다.)

     

    DDRAM의 메모리 주소

    DDRAM의 크기는 문자 80개를 담을 수 있는 크기이며, LCD를 한줄 출력으로 설정한 경우, 메모리 주소는 0x00(0)부터 0x4f(79)까지 연속적이게 된다. LCD를 두줄 출력으로 설정할 경우 메모리가 각각 문자 40개 들어갈 용량으로 나눠진다.

    LCD가 16x2라고 할 때

    0x00(0)     0x0f(15)       0x27(39)
    0x40(64)     0x4f(79)       0x67(103)

    화면 이동 명령을 내리지 않았다면, 메모리의 0열 부터 15열 까지만 보여진다. 0번째 행은 0x00~0x0f, 1번째 행은 0x40~0x4f에 쓰여진 값이 LCD 화면에 표시된다.

     

    그러면 20x4인 LCD는 어떨까? 20x4면 DDRAM을 모두 사용하는데

    0행(0열~ 19열) (시작 주소: 0x00)   2행(0열~ 19열) (시작 주소: 0x14)
    1행(0열~19열) (시작 주소: 0x40)   3행(0열~ 19열) (시작 주소: 0x54)

    0행에서 오버 플로우를 일으켰더니 2행에 표시되는 걸로 봐서 메모리가 이렇게 되어 있다.(시작 주소는 라이브러리 뜯어보면서 알게됨)

     

    코드

    https://github.com/sidreco214/LiquidCrystal_I2C_PICO

     

    GitHub - sidreco214/LiquidCrystal_I2C_PICO: LiquidCrystal_I2C for Raspberry Pi Pico

    LiquidCrystal_I2C for Raspberry Pi Pico. Contribute to sidreco214/LiquidCrystal_I2C_PICO development by creating an account on GitHub.

    github.com

     

    LiquidCrystal_I2C_PICO.h

    #include <string>
    using std::string;
    #include "pico/stdlib.h"
    #include "hardware/i2c.h"
    #include "pico/binary_info.h"
    
    #ifndef byte
    typedef uint8_t byte;
    #endif
    
    // commands
    #define LCD_CLEARDISPLAY  0x01
    #define LCD_RETURNHOME  0x02
    #define LCD_ENTRYMODESET  0x04
    #define LCD_DISPLAYCONTROL  0x08
    #define LCD_CURSORSHIFT  0x10
    #define LCD_FUNCTIONSET  0x20
    #define LCD_SETCGRAMADDR  0x40
    #define LCD_SETDDRAMADDR  0x80
    
    // flags for display entry mode
    #define LCD_ENTRYSHIFTINCREMENT  0x01
    #define LCD_ENTRYLEFT  0x02
    
    // flags for display and cursor control
    #define LCD_BLINKON  0x01
    #define LCD_CURSORON  0x02
    #define LCD_DISPLAYON  0x04
    
    // flags for display and cursor shift
    #define LCD_MOVERIGHT  0x04
    #define LCD_DISPLAYMOVE  0x08
    
    // flags for function set
    #define LCD_5x8DOTS 0x00
    #define LCD_5x10DOTS  0x04
    #define LCD_2LINE  0x08
    #define LCD_8BITMODE  0x10
    
    // flag for backlight control
    #define LCD_BACKLIGHT  0x08
    #define LCD_NOBACKLIGHT 0x00
    
    #define LCD_ENABLE_BIT  0x04
    
    //Modes for send_byte
    #define LCD_CHARACTER  1
    #define LCD_COMMAND    0
    
    //byte write delay(us)
    #define LCD_DELAY 600
    
    class LiquidCrystal_I2C_PICO {
        private:
        uint8_t _addr; //address of I2C
        uint _SDApin;
        uint _SCLpin;
    
        i2c_inst_t *_i2c;
        uint8_t _numlines;
        uint8_t _rows;
        uint8_t _cols;
    
        uint8_t _displaycontrol; //control display, cursor and toggle of blink on cursor
        uint8_t _backlight;
    
        private:
        void write_byte(uint8_t val);
        void pulse_enable(uint8_t val);
        void send_byte(uint8_t val, uint8_t mode);
    
        public:
        /// @brief Constructer of LiquidCrystal_I2C for Raspberry Pi Pico, I2C0 is used with default SDA and SCL pins (GP4, GP5 on a pico)
        /// @param address I2C address of LCD, expected 0x27 or 0x3F
        /// @param rows The number of rows on LCD
        /// @param columns The number of columns on LCD
        LiquidCrystal_I2C_PICO(uint8_t address, uint8_t rows, uint8_t columns);
    
        
        /// @brief Constructer of LiquidCrystal_I2C for Raspberry Pi Pico
        /// @param address address I2C address of LCD, expected 0x27 or 0x3F
        /// @param rows The number of rows on LCD
        /// @param columns The number of columns on LCD
        /// @param i2c Either \ref i2c0 or \ref i2c1
        /// @param SDApin i2c0 is on 0, 4, 8, 12, 16, 20, i2c1 is on 2, 6, 10, 14, 18, 26
        /// @param SCLpin i2c0 is on 1, 5, 9, 13, 17, 21, i2c1 is on 3, 7, 11, 15, 19, 27
        LiquidCrystal_I2C_PICO(uint8_t address, uint8_t rows, uint8_t columns, i2c_inst_t *i2c, uint8_t SDApin, uint8_t SCLpin);
    
        void init(); //Initialize LCD, You must run it once before using this class
        void clear();
        void setCursor(uint8_t row, uint8_t col);
        inline void write(char ch);
        void print(char ch);
        void print(string str);
    
        void noDisplay();
        void display();
        void noCursor();
        void cursor();
        void noBlink();
        void blink();
        void noBacklight();
        void backlight();
    
        /// @brief Create custom char recorded in CGRAM
        /// @param location Assigned location of your char(Location range is from 0 to 7)
        /// @param charmap uint8_t array[8]
        void creatChar(uint8_t location, uint8_t charmap[]);
    };
    
    inline void LiquidCrystal_I2C_PICO::write(char ch) {
        send_byte(ch, LCD_CHARACTER);
    }

    인라인 함수는 헤더 파일 안에 같이 선언해주거나, 분리하여 선언하였다면 include 할 때 cpp까지 include 해야 한다. 템플릿과 마찬가지로 인라인 함수는 컴파일 타임에 치환해주어야 하기 때문이다.

     

    LiquidCrystal_I2C_PICO.cpp

    #include "LiquidCrystal_I2C_PICO.h"
    
    void LiquidCrystal_I2C_PICO::write_byte(uint8_t val) {
        i2c_write_blocking(_i2c, _addr, &val, 1, false);
    }
    
    void LiquidCrystal_I2C_PICO::pulse_enable(uint8_t val) {
        sleep_us(LCD_DELAY);
        write_byte(val | LCD_ENABLE_BIT);
        sleep_us(LCD_DELAY);
        write_byte(val & ~LCD_ENABLE_BIT);
        sleep_us(LCD_DELAY);
    }
    
    void LiquidCrystal_I2C_PICO::send_byte(uint8_t val, uint8_t mode) {
        uint8_t highNible = mode | (val & 0xf0) | _backlight;
        uint8_t lowNible = mode | ((val << 4) & 0xf0) | _backlight;
    
        write_byte(highNible);
        pulse_enable(highNible);
        write_byte(lowNible);
        pulse_enable(lowNible);
    }
    
    LiquidCrystal_I2C_PICO::LiquidCrystal_I2C_PICO(uint8_t address, uint8_t rows, uint8_t columns)
    : _addr(address), _rows(rows), _cols(columns), _i2c(i2c0), _SDApin(4), _SCLpin(5) {
        _displaycontrol = LCD_DISPLAYCONTROL;
        _backlight = LCD_BACKLIGHT;
    
        i2c_init(_i2c, 100 * 1000);
    
        //gpio setting
        gpio_set_function(_SDApin, GPIO_FUNC_I2C);
        gpio_set_function(_SCLpin, GPIO_FUNC_I2C);
        gpio_pull_up(_SDApin);
        gpio_pull_up(_SCLpin);
    
        //Make the I2C pins available to picotool
        bi_decl(bi_2pins_with_func(_SDApin, _SCLpin, GPIO_FUNC_I2C));
    }
    
    LiquidCrystal_I2C_PICO::LiquidCrystal_I2C_PICO(uint8_t address, uint8_t rows, uint8_t columns, i2c_inst_t *i2c, uint8_t SDApin, uint8_t SCLpin)
    : _addr(address), _rows(rows), _cols(columns), _i2c(i2c), _SDApin(SDApin), _SCLpin(SCLpin) {
        _displaycontrol = LCD_DISPLAYCONTROL;
        _backlight = LCD_BACKLIGHT;
    
        i2c_init(_i2c, 100 * 1000);
    
        //gpio setting
        gpio_set_function(_SDApin, GPIO_FUNC_I2C);
        gpio_set_function(_SCLpin, GPIO_FUNC_I2C);
        gpio_pull_up(_SDApin);
        gpio_pull_up(_SCLpin);
    
        //Make the I2C pins available to picotool
        bi_decl(bi_2pins_with_func(_SDApin, _SCLpin, GPIO_FUNC_I2C));
    }
    
    
    
    void LiquidCrystal_I2C_PICO::init() {
        //the chip begins in 8bit Mode, try to set 4bit mode
        send_byte(0x03, LCD_COMMAND);
        send_byte(0x03, LCD_COMMAND);
        send_byte(0x03, LCD_COMMAND);
        send_byte(0x02, LCD_COMMAND);
    
        send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
        _displaycontrol |= LCD_DISPLAYON; 
        send_byte(_displaycontrol, LCD_COMMAND);
        send_byte(LCD_FUNCTIONSET | LCD_2LINE | LCD_5x8DOTS, LCD_COMMAND);
        clear();
    }
    
    void LiquidCrystal_I2C_PICO::clear() {
        send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::setCursor(uint8_t row, uint8_t col) {
        if(row > _rows) row = _rows-1;
        if(col > _cols) col = _cols-1;
        uint8_t row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
        send_byte(0x80 | (col + row_offsets[row]), LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::print(char ch) {
        write(ch);
    }
    
    void LiquidCrystal_I2C_PICO::print(string str) {
        for(int i=0; i<str.length(); i++) send_byte(str[i], LCD_CHARACTER);
    }
    
    
    
    void LiquidCrystal_I2C_PICO::noDisplay() {
        _displaycontrol &= ~LCD_DISPLAYON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::display() {
        _displaycontrol |= LCD_DISPLAYON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    
    void LiquidCrystal_I2C_PICO::noCursor() {
        _displaycontrol &= ~LCD_CURSORON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::cursor() {
        _displaycontrol |= LCD_CURSORON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    
    void LiquidCrystal_I2C_PICO::noBlink() {
        _displaycontrol &= ~LCD_BLINKON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::blink() {
        _displaycontrol |= LCD_BLINKON;
        send_byte(_displaycontrol, LCD_COMMAND);
    }
    
    void LiquidCrystal_I2C_PICO::noBacklight() {
        _backlight = LCD_NOBACKLIGHT;
        write_byte(0);
    }
    
    void LiquidCrystal_I2C_PICO::backlight() {
        _backlight = LCD_BACKLIGHT;
        write_byte(0);
    }
    
    void LiquidCrystal_I2C_PICO::creatChar(uint8_t location, uint8_t charmap[]) {
        location &= 0x7;
        send_byte(LCD_SETCGRAMADDR | (location << 3), LCD_COMMAND);
        for(int i=0; i<8; i++) send_byte(charmap[i], LCD_CHARACTER);
    }

     

    예제

    아두이노 함수와 사용이 똑같다. 피코는 I2C가 2개 있고, 연결할 수 있는 GPIO포트도 여러개인데, 오버로딩된 생성자를 사용하면 이를 설정할 수 있다.

    예제처럼 생성자를 사용하면 

    I2C0를 사용하고, GP4,5를 사용한다.

    #include "pico/stdlib.h"
    #include "LiquidCrystal_I2C_PICO.h"
    
    #define LCD_ROWS 2
    #define LCD_COLS 16
    LiquidCrystal_I2C_PICO lcd(0x27,LCD_ROWS,LCD_COLS);
    
    int main() {
        gpio_init(PICO_DEFAULT_LED_PIN);
        gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
        gpio_put(PICO_DEFAULT_LED_PIN, 1);
    
        lcd.init();
    
        //test screen
        for(int i=0; i<LCD_ROWS; i++) for(int n=0; n<LCD_COLS; n++) {
            lcd.setCursor(i,n);
            lcd.print('>');
            sleep_ms(500);
            lcd.clear();
        }
    
        //test char
        lcd.setCursor(0,0);
        lcd.print('c');
    
        //test char*
        char str[] = "HelloPico";
        lcd.setCursor(1,0);
        lcd.print(str);
    
        //test string
        lcd.setCursor(1,10);
        lcd.print("LCDI2C");
    
        sleep_ms(3000);
        lcd.clear();
    
        //noDisplay, display
        lcd.setCursor(0,0);
        lcd.print("test display");
        lcd.noDisplay();
        sleep_ms(1000);
        lcd.display();
    
        sleep_ms(3000);
        lcd.clear();
    
        //cursor
        lcd.setCursor(0,0);
        lcd.print("test cursor");
        lcd.cursor();
        sleep_ms(1000);
        lcd.noCursor();
    
        sleep_ms(3000);
        lcd.clear();
    
        //cursor blink
        lcd.setCursor(0,0);
        lcd.print("cursor blink");
        lcd.blink();
        sleep_ms(1000);
        lcd.noBlink();
    
        sleep_ms(3000);
        lcd.clear();
    
        //test backlight
        lcd.setCursor(0,0);
        lcd.print("test backlight");
        lcd.noBacklight();
        sleep_ms(2000);
        lcd.backlight();
        lcd.clear();
    
        //test creatChar
        byte bell[8] = {0b00100,
                        0b01110,
                        0b01110,
                        0b01110,
                        0b11111,
                        0b00000,
                        0b00100,
                        0b00000
                        };
        lcd.creatChar(0,bell);
        lcd.setCursor(0,0);
        lcd.print(byte(0));
        
        return 0;
    }

    참고로 byte = uint8_t = unsigned char 이다.

    라이브러리 적용방법

    main 함수가 정의된 곳에 같이 LiquidCrystal_I2C_PICO.h와 LiquidCrystal_I2C_PICO.cpp를 넣고, cpp 파일을 add_excuteable에 추가해도 되지만, 내가 직접 작성한 것만 src에 있는게 유지보수 관리하기 편할 것이다.

    (방법을 찾아서 수정 2023.02.23)

    경로쓸때 절대경로로 적어도 되는데, 디바이스가 바뀌면 매번 경로를 수정해주어야 한다.(덤으로 \를 모두 /이걸로 바꿔야 한다.) 이미 추가된 환경변수인 PICO_SDK_PATH를 이용하기 위해 사진처럼 pico-lib를 추가한다.

    폴더를 연다음

    cmd /c git clone https://github.com/sidreco214/LiquidCrystal_I2C_PICO.git

    명령어를 입력하면(git 콘솔을 열어서 해도 상관 없다.)

    cmd 창이 순식간에 열렸다가 닫히며 다운로드가 완료된다.

     

    예제 프로젝트 만들기 

    원하는 곳에 폴더를 만들고, src 폴더를 만들어서 예제 코드를 담은 main.cpp를 만든다. 이름은 원하는 데로 해도 되지만, CMakeLists.txt에 바뀐 이름을 제대로 수정해주어야 한다.(.vscode 하고, CMakeLists.txt는 다른 피코 프로젝트의 것을 복붙한뒤 조금만 수정해주면 편하다. CMakeLists.txt 내용 밑에서 다 보여줄 것이다.)

    set(projname lcd_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)
    target_link_libraries(${projname} LiquidCrystal_I2C_PICO) #중요 라이브러리 링크하기
    
    # create map/bin/hex file etc.
    pico_add_extra_outputs(${projname})
    
    # add url via pico_set_program_url
    example_auto_set_url(${projname})

    src에 있는 CMakeLists.txt 는 이렇게 작성해주면 된다.

    projname = project name이고 중복되는 부분을 여러번 쓰기 귀찮아 변수로 치환하였다.

     

    file() 이 명령어를 사용하여 현 폴더 안에 cpp 파일을 모두 검색해서 add_executeable 에 추가하도록 하였다.

    (비권장이긴 한데 VScode를 열거나 CmakeLists.txt를 수정한 뒤 저장할 때 마다 cmake 가 자동으로 새로 실행되니 문제 없다.)

     

    피코 기본 라이브러리 추가하듯 라이브러리 링크해주면 된다.

     

    여기있는 CMakeLists.txt는

    cmake_minimum_required(VERSION 3.12)
    
    # Pull in SDK (must be before project)
    set(BToolDIR $ENV{PICO_SDK_PATH}/../pico-examples) #PICO_SDK_PATH가 아직 정의 안됨, pico_sdk_import.cmake에 정의되어 있음
    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)
    
    #외부 디렉터리 추가, 외부 디렉터리인 경우, 바이너리를 어디에 생성할 건지까지 명시해야 함
    #바이러니 경로는 상대적으로 적는다면 ${CMAKE_CURRENT_BINARY_DIR} 기준으로 해석되며, 이값의 기본값은 현폴더/build
    set(PICO_LIB_PATH ${PICO_SDK_PATH}/../pico-lib)
    add_subdirectory(${PICO_LIB_PATH}/LiquidCrystal_I2C_PICO LiquidCrystal_I2C_PICO)
    
    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
            )

    pico-example 안에 있는 CMakeLists.txt를 변형한 것으로 외부 디렉터리 추가 부분을 유심히 봐주면 된다.

     

    add_subdirectory 2번째 인수에 적은 바이러니 경로에 해당 디렉터리에 대한 Makefile이 생성된다.

     이렇게 말이다.

     

     

    다시 여기로 돌아와서 build 폴더를 만든 뒤 콘솔에서 cmake해도 되고, VS코드로 lcd_test 폴더를 연 뒤 F7을 눌러서 빌드해도 된다.

     

    참고로 VScode로 열었다면

    이렇게 선택화면이 뜰텐데, arm-none-eabi 컴파일러를 선택해주면 된다.

    아니면

    이렇게 세팅한 뒤, 콘솔상에서 자동으로 실행되는 cmake 가 완료되면, 코드가 빨간밑줄 없이 제대로 보일 것이다.

    가끔 이렇게 해도 빨간줄이 남을 수 있는데, 한번 F7눌러서 빌드하고 나면 사라진다.

    빌드가 완료되면 부트셋 버튼을 누른채로 라즈베리파이 피코를 연결해 준 뒤(띵동 소리나면 버튼에서 손 때도 된다.)

    VScode에서 git 콘솔을 열어서(ctrl + `(tab 위에 있음))

    cd build/src
    cp lcd_test.uf2 E:/

    입력해주면(드라이브 문자는 다를 수 있으니 주의, 걍 드래그 드롭해도 된다.)

    업로드가 완료되고, Pico mass storage가 자동으로 연결해제되면서 코드가 실행된다.

     

    LCD1602 테스트 영상

    LCD 2004 테스트 영상(#define 부분에 행 4,열 20으로 수정해야 함) 

    LCD 작성과 쓰기가 너무 빨리 반복되면 초반에 > 이게 이동할 때 처럼 글자가 잘 안보이게 된다. 피코에서 공급하는 전원은 3.3V이니 가변저항값을 아두이도에서 쓸 때보다 낮춰야 제대로 글자가 보일 것이다.

    댓글

Designed by Tistory.