i2cProject_with_Jetson

Jetson Nano와 아두이노 간의 I2C 통신 1)

찬영_00 2024. 11. 2. 14:51

이번에 Jetson Nano와 아두이노 간 I2C 통신을 해보러고 한다.

이유는 현재 내가 구현한 기구가 Jetson Nano와 아두이노가 시리얼 통신으로 데이터를 주고 받기 때문이다.

시리얼 통신은 고속이지만 현재 나는 하나의 젯슨 나노에서 5개정도의 아두이노를 다루고 있고, 이는 USB 포트 부족뿐 아니라 아두이노에 전원 공급이 USB로는 5V를 주기 때문에 DC 잭으로 주어 안정적인 시스템을 구축하고 싶기 때문이다.

 

개발 환경

- 아두이노 메가 2560

- 젯슨나노 B01 4GB

- 우분투 20.04

 

먼저 간단한거 먼저 시작해보자!

 


 

Jetson Nano를 Master, Arduino를 Slave로 설정하자!

 

일단 아두이노를 Slave로 만들어주자

#include <Wire.h>

#define LED           13

// Slave address
#define SLAVE_ADDRESS 0x57

// Register address
#define WRITE_REGISTER 0x01
#define READ_REGISTER  0x02

// LED control
#define LED_ON         0xAC
#define LED_OFF        0x1F

bool ledState = false;

void setup() {
  pinMode(LED, OUTPUT);
  Wire.begin(SLAVE_ADDRESS);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}

void loop() {
  // Do any other tasks here if needed
  delay(100);
}

void receiveEvent() {
  int registerAddress = Wire.read();
  if (registerAddress == WRITE_REGISTER) {
    int value = Wire.read();
    if (value == LED_ON){
      digitalWrite(LED, HIGH);
      ledState = true;
    }
    else if (value == LED_OFF){
      digitalWrite(LED, LOW);
      ledState = false;
    }
  }
}

void requestEvent() {
   Wire.write(ledState ? LED_ON : LED_OFF);
}

 

나는 Arduino Mage2560에 내장된 LED를 사용하였다.

I2C를 사용할 때 아두이노는 풀업저항이 내장되어 있지만, 일반 다른 보드는 확인해보고 풀업저항이 내장되어있지 않을경우 10k옴 정도를 달아주면 된다. (보드마다 다름)

 

먼저 아두이노의 슬레이브 주소값을 지정해준다. (나는 0x57로 했음)

또한 LED를 껏다 켰다 하게끔 간지나게 레지스터 주소마냥 정해주었다.

I2C의 함수들에 대한 설명은 아래 블로그를 참고하라

https://blog.naver.com/dkwltmdgus/220776103020

 

[아두이노] I2C 통신 적용해보기

이번 포스팅은 실 사용에 대한 포스팅이니 I2C 통신 개념과 보드별 핀은 아래 포스팅을 참조해주세...

blog.naver.com

 

그리고 업로드를 진행한다.

다음으로 젯슨나노에서 아두이노가 인식되는지 확인한다.


젯슨나노에서 아두이노 I2C주소 확인하기

 

아두이노와 젯슨나노를 I2C 연결한다.

* 그라운드 연결해주는거 잊지마세요

여기서 아두이노는 DC잭으로 연결해주었다.

 

젯슨나노의 pinout은 다음을 참고하라

https://jetsonhacks.com/nvidia-jetson-nano-j41-header-pinout/

 

NVIDIA Jetson Nano J41 Header Pinout - JetsonHacks

JetsonHacks is a site devoted to developing on the NVIDIA Jetson Development Kits.

jetsonhacks.com

 

 

연결 후 다음 명령어를 터미널에 입력해줘라

sudo i2cdetect -r -y 1

 

나는 젯슨나노 pin 3,5번에 연결했으므로 i2c 1번이기 때문에 명령어 맨 뒤에 1를 작성해주었다.

위에 아두이노 주소인 57번이 뜬것을 확인했으면 인식이 잘 되고 있는 것이다.

이제 젯슨나노에서 코드를 짜주자

 

 

젯슨나노에 아두이노 제어 코드 올리기

젯슨나노에 먼저 i2c라이브러리를 설치해주자

sudo apt-get install libi2c-dev

 

이후 아무 이름을 정해서 아래 코드를 실행해봐라

 

#include <iostream>         // 표준 입력 및 출력을 위한 헤더. std::cout, std::cin을 사용하여 콘솔 입출력을 처리합니다.
#include <fcntl.h>         // 파일 제어를 위한 헤더. open() 함수에 사용됩니다.
#include <unistd.h>        // POSIX 운영 체제 API에 대한 정의를 포함하는 헤더. close(), sleep() 함수를 사용합니다.
#include <linux/i2c-dev.h> // I2C 장치를 제어하기 위한 정의를 포함하는 헤더. I2C 관련 상수와 구조체를 제공합니다.
#include <sys/ioctl.h>     // 장치 제어를 위한 헤더. ioctl() 함수를 사용하여 I2C 슬레이브 주소 설정에 사용됩니다.
#include <signal.h>        // 시그널 처리를 위한 헤더. Ctrl+C와 같은 인터럽트를 처리하기 위해 사용됩니다.
#include <cstring>         // 문자열 관련 함수들에 대한 정의를 포함하는 헤더. 필요 시 문자열 비교 등에 사용될 수 있습니다.

#define I2C_DEVICE      "/dev/i2c-1"  // Jetson Nano의 I2C 포트
#define SLAVE_ADDRESS   0x57          // 아두이노의 I2C 주소
#define WRITE_REGISTER  0x01          // LED 제어를 위한 레지스터 주소
#define LED_ON          0xAC          // LED 켜기 명령
#define LED_OFF         0x1F          // LED 끄기 명령

int file;  // I2C 파일 디스크립터

// I2C 장치 열기
int openI2CDevice() {
    int f = open(I2C_DEVICE, O_RDWR);
    if (f < 0) {
        std::cerr << "I2C 장치를 열 수 없습니다." << std::endl;
        return -1;
    }

    // 슬레이브 주소 설정
    if (ioctl(f, I2C_SLAVE, SLAVE_ADDRESS) < 0) {
        std::cerr << "슬레이브 주소를 설정할 수 없습니다." << std::endl;
        close(f);
        return -1;
    }
    return f;
}

// LED 제어 함수
void controlLED(bool turnOn) {
    unsigned char buffer[2];
    buffer[0] = WRITE_REGISTER;
    buffer[1] = turnOn ? LED_ON : LED_OFF;

    if (write(file, buffer, 2) != 2) {
        std::cerr << "데이터 전송에 실패했습니다." << std::endl;
    } else {
        std::cout << "LED " << (turnOn ? "켜기" : "끄기") << " 명령을 보냈습니다." << std::endl;
    }
}

// 프로그램 종료 시 클린업
void cleanup(int signum) {
    if (file >= 0) {
        close(file);
    }
    std::cout << "\n프로그램을 종료합니다." << std::endl;
    exit(0);
}

int main() {
    // 시그널 핸들러 등록
    signal(SIGINT, cleanup);

    file = openI2CDevice();
    if (file < 0) return -1;

    std::string command;

    while (true) {
        std::cout << "명령어를 입력하세요 (ON/OFF): ";
        std::cin >> command;

        if (command == "ON") {
            controlLED(true);
        } else if (command == "OFF") {
            controlLED(false);
        } else {
            std::cout << "유효하지 않은 명령어입니다. 'ON' 또는 'OFF'를 입력하세요." << std::endl;
        }
    }

    cleanup(0);  // 프로그램 종료 시 클린업 함수 호출
    return 0;
}

 

코드를 작성한후 컴파일을 해준다.

g++ master_led_13.cpp -o master_led_13 -li2c

실행 파일 이름을 나는 master_led_13으로 하고 싶어서 저렇게 지었고, 다른 이름으로 해도 된다.

그리고 뒤에 -li2c는 i2c-lib를 링크하기 위한 옵션이다.

마지막으로 코드를 실행해주면 된다.

sudo ./master_led_13

 

이렇게 LED가 ON을 입력하면 켜지고, OFF을 입력하면 꺼진다.

 

아래 영상은 시연영상이다.

 

https://www.youtube.com/watch?v=rbFhOjCtU30

 

 

 

다음 포스터에서 2개의 아두이노 메가를 I2C통신으로 동작하는 것을 포스팅하겠다