이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Raspberry Pi와 Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560), WiFi 모듈을 사용 합니다.

node-js-i2c-comm

Node.js i2c communication
Raspberry Pi에서 Node.js를 이용한 I2C(Inter Integrated Circuit) 통신

    I2C 통신은 동기 방식의 Serial 통신으로 2개의 신호선(SDA, SCL) 만을 사용하고, 여러개의 Master와 Slave를 사용할 수 있는 장점이 있다. 이러한 장점 때문에 비교적 가까운 거리( 특별한 장치를 사용하지 않는 경우 2.7m에서 최대 5m( Clock speed와 통신선의 상태에 따라 변동이 있음) 이내에서 통신이 가능)에 있는 여러개의 장치(센서나 모터 등)를 제어 하여야 하는 경우 유리 하다.




  • 필요한 배경 지식
    • HTML: Web pages 작성에 필요한 Markup language
    • JavaScript: Web pages 작성에 필요한 Programming language
    • Node.js: JavaScript 기반으로 구성된 서버 사이드 서비스를 JavaScript로 구현할 수 있게 하는 런타임 환경
    • Linux OS: Raspberry Pi의 OS 가 Linux 이다.
    • Atmel 개발 환경: Atmel Studio 7 개발 환경과 ATmega128 보오드를 사용 한다.
    • ATmega128의 i2c 통신에 대한 이해가 필요 하다.
  • Raspberry Pi에서 I2C(Inter Integrated Circuit) 통신을 위한 설정
    • "sudo raspi-config" 명령을 사용하여 I2C 사용을 Enable 하여야 한다.
    • 참고자료: UART 통신을 위한 설정 방법과 같기 때문에 "UART 통신을 위한 설정" 과 아래 사진을 참고 하여 설정 한다.

      "sudo raspi-config" 명령 다음에 "Interface Options"을 선택하면 아래와 같은 창이 열린다. 이 창에서 "P5 I2C"을 선택하고 "Would you like the ARM I2C interface to be enabled?" Yes를 선택하여 I2C를 Enable로 설정 한다.

    • 아래 명령으로 user-mode I2C port를 확인 할 수 있다.
    • ls /dev/*i2c*

      Raspberry Pi 3인경우 " /dev/i2c-1 " 메세지가 출력 된다.

    • 아래 명령으로 Raspberry Pi에 연결된 I2C Device를 확인 할 수 있다.
    • sudo i2cdetect -y 1

      Raspberry Pi에 연결된 I2C Device를 보여 주는 터미널 응답

      윗 터미널 응답은 I2C bus address 0x48 번지와 0x49 번지에 I2C Device가 연결된 것을 보여 준다.


  • Raspberry PI I2C 통신 Protocol
    • I2C 통신을 위한 구성(회로 연결)
    • I2C 통신은 Master device와 Slave device로 구성 된다. Master와 Slave device는 1개 이상일 수 있다.

      I2C 통신을 위한 회로 연결 예: Raspberry PI는 내부에 Rp(Pull up resistor)를 내장하고 있기 때문에 회로 구성시 연결 할 필요가 없다.


    • I2C 통신 Protocol
      • Master device에서 Slave device로 2 Byte를 전송하는 Timing 예
        • Master device에서 Start bit를 I2C Bus에 출력 한다.
        • Master device에서 Slave address(7 Bits)와 Write 신호(0) 1 Bit를 출력 한다.
        • Slave address(7 Bits)와 일치하는 Slave device가 선택되고 선택된 Slave device에서 I2C Bus에 Acknowledge(Ack) 신호를 출력 한다.
        • 선택된 Slave device의 Ack 신호를 받은 Master device에서 8 Bits Data를 전송 한다.
        • 8 Bits Data를 전송 받은 Slave device는 다시 Ack 신호를 출력 한다.
        • 위 List에서 4 - 5 번을 N번 반복하면 N Byte의 Data를 Slave device에 전송 할 수 있다.
      • Slave device로 부터 Master device로 1 Byte를 수신하는 Timing 예
        • Master device에서 Start bit를 I2C Bus에 출력 한다.
        • Master device에서 Slave address(7 Bits)와 Read 신호(1) 1 Bit를 출력 한다.
        • Slave address(7 Bits)와 일치하는 Slave device가 선택되고 선택된 Slave device에서 I2C Bus에 Acknowledge(Ack) 신호를 출력 하고,
        • 계속하여 Master device에 8 Bits Data를 전송 한다.
        • Slave device에서 Master device에 Data 전송이 종료되면 Not Ack 상태가 되고 Read 동작이 종료(Stop) 된다.

  • Node.js i2c-bus
    • Node.js i2c-bus는 Raspberry Pi와 같은 Linux 보드에서 i2c 통신(Promises, async/await, asynchronous callbacks, synchronous 방식)실행을 지원한다.

    • i2c-bus 설치하기
      • 아래 명령으로 i2c-bus를 설치한다.
      • npm install i2c-bus

      i2c-bus API는 Functions, Class Bus, Class PromisifiedBus, Class I2cFuncs로 구성되어 자료의 양이 너무 많기 때문에 여기서는 자주 사용하는 함수와 SMBus만 설명한다.

      참고자료: https://www.npmjs.com/package/i2c-bus

    • i2c-bus API: Functions
      • openSync(busNumber [, options])
        • busNumber - Open 하려고 하는 I2C bus/adapter의 번호, 0: /dev/i2c-0, 1: /dev/i2c-1, ...
        • options: forceAccess - 커널 드라이버 또는 모듈에서 이미 사용중인 경우에도 I2C 버스의 장치에 대한 액세스를 허용할지 여부를 지정하는 부울 값이다. Linux의 I2C_SLAVE_FORCE에 해당한다. forceAccess의 유효한 값은 true 및 false 이다. 기본값은 false 임.
        • 동기식 개방 함수로 새로운 Bus 객체를 반환한다.

      • open(busNumber [, options], cb)
        • busNumber - Open 하려고 하는 I2C bus/adapter의 번호, 0: /dev/i2c-0, 1: /dev/i2c-1, ...
        • options: forceAccess - 커널 드라이버 또는 모듈에서 이미 사용중인 경우에도 I2C 버스의 장치에 대한 액세스를 허용할지 여부를 지정하는 부울 값이다. Linux의 I2C_SLAVE_FORCE에 해당한다. forceAccess의 유효한 값은 true 및 false 이다. 기본값은 false 임.
        • cb - 이 함수의 실행이 완료되면 실행되는 callback 함수
        • 비동기식 개방 함수로 새로운 Bus 객체를 반환한다. callback 함수에는 하나의 인수(err)가 전달된다.

      • openPromisified(busNumber [, options])
        • busNumber - Open 하려고 하는 I2C bus/adapter의 번호, 0: /dev/i2c-0, 1: /dev/i2c-1, ...
        • options: forceAccess - 커널 드라이버 또는 모듈에서 이미 사용중인 경우에도 I2C 버스의 장치에 대한 액세스를 허용할지 여부를 지정하는 부울 값이다. Linux의 I2C_SLAVE_FORCE에 해당한다. forceAccess의 유효한 값은 true 및 false 이다. 기본값은 false 임.
        • 비동기식 개방 함수로 처리되면(resolved) PromisifiedBus 개체를 생성하는 Promise를 반환한다.

          Promise 객체에 대한 참고자료: https://developer.mozilla.org/ko/docs/의 "Using promises"

          주: 프로그램을 위한 i2c PromisifiedBus 자료는 https://www.npmjs.com/package/i2c-bus를 참고하고 위 "Promise 객체에 대한 참고자료"는 Promise를 이해하기 위한 자료로만 사용하는 것이 좋다.

    • i2c-bus API: Class Bus
    • Bus 클래스의 모든 메서드에는 비동기 콜백 과 동기 방식이 있다. Promise 지원은 PromisifiedBus 클래스를 참조바람.

      • Free resources
        • bus.closeSync()
          • 동기식 닫기 함수로 이 인스턴스에서 사용하는 시스템 리소스를 해제한다.

        • bus.close(cb)
          • cb - 이 함수의 실행이 완료되면 실행되는 callback 함수
          • 비동기식 닫기 함수로 이 인스턴스에서 사용하는 시스템 리소스를 해제한다. callback 함수에는 하나의 인수(err)가 전달된다.

      • SMBus(System Management Bus)
      • SMBus은 I2C 통신을 가능하게 하여 주는 Library 이다. 여기서는 자주 사용하는 SMBus 함수 만 설명 한다.

        • bus.writeByteSync(addr, cmd, byte)
          • addr - I2C device address
          • cmd - command code
          • byte - data byte. byte is an unsigned integer in the range 0 to 255.
          • 이 함수는 Slave device에 1 Byte의 Command(사용하는 시스템에 때라 Address 또는 Data로 사용 할 수 있음)와 1 Byte Data를 전송 한다.

            이 함수가 실행 될 때 I2C Bus 신호 Timing 은 아래와 같다.

          • Master device에서 Start bit를 I2C Bus에 출력 한다.
          • Master device에서 Slave address(7 Bits)와 Write 신호(0) 1 Bit를 출력 한다.
          • Slave address(7 Bits)와 일치하는 Slave device가 선택되고 선택된 Slave device에서 I2C Bus에 Acknowledge(Ack) 신호를 출력 한다.
          • 선택된 Slave device의 Ack 신호를 받은 Master device에서 8 Bits Data(cmd)를 전송 한다.
          • 8 Bits Data를 전송 받은 Slave device는 다시 Ack 신호를 출력 한다.
          • Ack 신호를 받은 Master device에서 8 Bits Data(val)를 한번 더 전송 한다.
          • 8 Bits Data를 전송 받은 Slave device는 다시 Ack 신호를 출력 한다.
        • bus.readByteSync(addr, cmd)
          • addr - I2C device address
          • cmd - command code
          • 이 함수는 Slave device에 1 Byte의 Command(사용하는 시스템에 때라 Address 또는 Data로 사용 할 수 있음)를 전송하고, 1 Byte Data를 Slave device로 부터 수신 한다.

            이 함수가 실행 될 때 I2C Bus 신호 Timing 은 아래와 같다.

            Master device에서 Slave device로 명령(cmd) 전송 하기

          • Master device에서 Command를 Slave device에 전송하기 위하여 Start bit를 I2C Bus에 출력 한다.
          • Master device에서 Slave address(7 Bits)와 Write 신호(0) 1 Bit를 출력 한다.
          • Slave address(7 Bits)와 일치하는 Slave device가 선택되고 선택된 Slave device에서 I2C Bus에 Acknowledge(Ack) 신호를 출력 한다.
          • 선택된 Slave device의 Ack 신호를 받은 Master device에서 8 Bits Data(cmd)를 전송 한다.
          • 8 Bits Data를 전송 받은 Slave device는 Ack 신호를 출력 한다.
          • Master device가 Slave device로 부터 1 Byte Data 수신 하기

          • Master device에서 Data를 Slave device로 부터 수신 하기 위하여 Start bit를 I2C Bus에 출력 한다.
          • Master device에서 Slave address(7 Bits)와 Read 신호(1) 1 Bit를 출력 한다.
          • Slave address(7 Bits)와 일치하는 Slave device가 선택되고 선택된 Slave device에서 I2C Bus에 Acknowledge(Ack) 신호를 출력 하고,
          • 계속하여 Master device에 8 Bits Data를 전송 한다.
          • Slave device에서 Master device에 Data 전송이 종료되면 Not Ack 상태가 되고 Read 동작이 종료(Stop) 된다.
        • bus.readWordSync(addr, cmd)
          • addr - I2C device address
          • cmd - command code
          • 이 함수는 Slave device에 1 Byte의 Command(사용하는 시스템에 때라 Address 또는 Data로 사용 할 수 있음)를 전송하고, Word Data(2 Byte)를 Slave device로 부터 수신 한다.

    • i2c-bus API: Class PromisifiedBus
    • PromisifiedBus 클래스의 모든 메서드는 비동기 promise 형식을 갖는다. 동기(synchronous)와 비동기 콜백(asynchronous callback) 방식은 Bus 클래스를 참조바람.

      • Free resources
        • promisifiedBus.close()
          • 동기식 닫기 함수로 기본 리소스가 해제되면 인수없이 처리되는 Promise를 반환한다. 만약 닫는 동안 오류가 발생하면 Reject되는 Promise를 반환한다.

      • SMBus(System Management Bus)
        • promisifiedBus.readByte(addr, cmd)
          • addr - I2C device address
          • cmd - command code
          • 비동기 SMBus byte 읽기. 성공적으로 처리시 읽은 Byte data를 Promise로 반환하고, 오류가 발생하면 rejected Promise를 반환한다. Byte data는 0에서 255 사이의 부호없는 정수이다.

        • promisifiedBus.readWord(addr, cmd)
          • addr - I2C device address
          • cmd - command code
          • 비동기 SMBus word 읽기. 성공적으로 처리시 읽은 Word data를 Promise로 반환하고, 오류가 발생하면 rejected Promise를 반환한다. Word data는 0에서 65535 사이의 부호없는 정수이다.

        • promisifiedBus.writeByte(addr, cmd, byte)
          • addr - I2C device address
          • cmd - command code
          • byte - data byte. byte is an unsigned integer in the range 0 to 255.
          • 비동기 SMBus byte 쓰기. 성공시 인수없이 Promise를 반환하고, 오류가 발생하면 rejected Promise를 반환한다.

        • promisifiedBus.writeWord(addr, cmd, word)
          • addr - I2C device address
          • cmd - command code
          • word - data word. word is an unsigned integer in the range 0 to 65535.
          • 비동기 SMBus word 쓰기. 성공시 인수없이 Promise를 반환하고, 오류가 발생하면 rejected Promise를 반환한다.


  • I2C 통신을 이용한 측정 과 제어 예
    • I2C 통신을 이용한 측정 과 제어 시스템 구성 예

    • I2C 통신을 이용한 온도 측정(DS1621) 예
      • 윗 I2C 통신을 이용한 측정 과 제어 시스템 구성 예에서 Raspberry PI를 Master로 온도 센서(DS1621)를 Slave device로 사용 한다.

        참고자료: 온도 센서(DS1621) 자료(DS1621-Digital-Thermometer.pdf)

      • 학습 포인트
        • I2C 통신을 사용한 Master 와 Slave device(이 예에서는 DS1621 온도센서) 사이의 Data 송수신에 대한 이해
        • DS1621 온도센서에 대한 이해.
        • SMBus 대한 이해. 동기 방식과 프로미스(Promise) 객체를 사용하는 방식의 이해
      • 실험을 위한 준비
        • Raspberry Pi와 온도 센서(DS1621)의 I2C 통신선 연결
        • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 온도 센서(DS1621)를 연결 한다.

          • Raspberry Pi SDA1(Pin3) <-> DS1621 SDA(Pin1) : 2-wire serial 통신을 위한 Data input/output pin.
          • Raspberry Pi SCL1(Pin5) <-> DS1621 SCL(Pin2) : 2-wire serial 통신을 위한 Clock input/output pin.
          • Raspberry Pi 3.3V(Pin1) <-> DS1621 VDD(Pin8) : VDD pin.
          • Raspberry Pi GND(Pin9) <-> DS1621 GND(Pin4) : Ground pin.
        • 온도센서 번호(번지) 설정 하기
          • DS1621의 Pin7(A0), Pin6(A1), Pin5(A2)를 사용하여 온도 센서의 번호(번지)를 설정 한다.
          • 온도 센서의 번호(번지)를 설정 예
            • 0번(이 예에서는 0번 장치를 0x48 번지로 설정 하였다.): A0 <- GND, A1 <- GND, A2 <- GND
            • 주: DS1621 Device를 사용하는 경우 이 장치에서 설정하는 A1A2A0 앞에 1001 Code가 추가되기 때문에 A1A2A0 가 000 인 경우 장치의 주소는 0x48(1001000) 번지가 된다.


      • 동기 방식을 이용한 SI2C 통신(디지털 온도계) 프로그램 예: i2c-th-meter-sync.js
      • 아래 프로그램은 Node.js 환경에서 사용하는 i2c-bus Library의 동기방식 API를 사용한 예 이다.

        
        // i2c-th-meter-sync.js
        const i2c = require('i2c-bus');
         
        const DS1621_ADDR = 0x48;
        const CMD_ACCESS_CONFIG = 0xac;
        const CMD_READ_TEMP = 0xaa;
        const CMD_START_CONVERT = 0xee;
        
        // DS1621로 부터 읽은 온도 Data(rawTemp)를 섭씨 온도 값으로 변환한다.
        const toCelsius = (rawTemp) => {
        	const halfDegrees = ((rawTemp & 0xff) << 1) + (rawTemp >> 15);
         
        	if ((halfDegrees & 0x100) === 0) {
        		return halfDegrees / 2; // Temp +ve
        	}
         
        	return -((~halfDegrees & 0xff) / 2); // Temp -ve
        };
        
        // i2c 통신을 사용하여 DS1621 부터 온도를 읽어 Console에 출력하는 함수
        function displayTemperature() {	
        	const i2c1 = i2c.openSync(1);
        
            // 온도 변환(측정)모드를 One shot mode로 설정한다.
        	i2c1.writeByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG, 0x01);
         
        	// DS1621 가 사용 중인 경우(non volatile memory busy) 사용이 종료 될때까지 대기한다.
        	while (i2c1.readByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG) & 0x10) {
        	}
         
        	// One shot mode 온도 변환을 시작한다.
        	i2c1.sendByteSync(DS1621_ADDR, CMD_START_CONVERT);
         
        	// One shot mode이기 때문에 변환이 완료 되기를 기다린다.
        	while ((i2c1.readByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG) & 0x80) === 0) {
        	}
         
        	// DS1621로 부터 온도 Data를 읽는다. Data Format은 DS1621 자료를 참고할 것.
        	const rawTemp = i2c1.readWordSync(DS1621_ADDR, CMD_READ_TEMP);
        	// 온도 단위를 섭씨(Celsius)로 변환한다.
        	let degrees = toCelsius(rawTemp);
            // Console에 온도 값을 출력한다.
        	console.log('temp: ' + degrees);
         
            // i2c bus를 close 한다.
        	i2c1.closeSync();
        	return degrees;
        };
        
        // 온도 측정 주기를 1.5Sec로 설정한다.
        setInterval(displayTemperature, 1500);
              

      • 비동기 방식(Promise)을 이용한 SI2C 통신(디지털 온도계) 프로그램 예: i2c-th-meter-promises.js
      • 아래 프로그램은 Node.js 환경에서 사용하는 i2c-bus Library의 비동기방식 API를 사용한 프로그램 예이다. 이 예에서는 비동기방식(Callback 과 Promise) 중 Promise를 사용한다.

        
        // i2c-th-meter-promises.js
        const i2c = require('i2c-bus');
        
        const DS1621_ADDR = 0x48;
        const CMD_ACCESS_CONFIG = 0xac;
        const CMD_READ_TEMP = 0xaa;
        const CMD_START_CONVERT = 0xee;
         
        // DS1621로 부터 읽은 온도 Data(rawTemp)를 섭씨 온도 값으로 변환한다.
        const toCelsius = (rawTemp) => {
        	const halfDegrees = ((rawTemp & 0xff) << 1) + (rawTemp >> 15);
         
        	if ((halfDegrees & 0x100) === 0) {
        		return halfDegrees / 2; // Temp +ve
        	}
         
        	return -((~halfDegrees & 0xff) / 2); // Temp -ve
        };
         
        // i2c 통신을 사용하여 DS1621 부터 온도를 읽어 Console에 출력하는 함수
        // 이 예에서는 프로그램을 읽기 쉽게하기 위하여 non volatile memory busy 상태인 경우 기다리는 명령과
        // 변환(측정) 시작 명령 다음에 변환 종료를 기다리는 명령을 생략하였기 때문에 첫 측정 값은 틀린 값을 출력한다.
        // i2c-th-meter-promis-wait-basic.js에서는 이 문제가 발생하지 않는다.
        function displayTemperature() {	
          // i2c bus를 Open하고 Promise object(Bus)를 반환 한다. 
          i2c.openPromisified(1).
          // 온도 변환(측정)모드를 One shot mode로 설정한다.
          // i2c1: i2c.openPromisified(1) 실행 결과로 반환된 Promise object(Bus)
          then(i2c1 => i2c1.writeByte(DS1621_ADDR, CMD_ACCESS_CONFIG, 0x01).
        	// One shot mode 온도 변환을 시작한다.
            then(_ => i2c1.sendByte(DS1621_ADDR, CMD_START_CONVERT)).
        	// DS1621로 부터 온도 Data를 읽는다. Data Format은 DS1621 자료를 참고할 것.
            then(_ => i2c1.readWord(DS1621_ADDR, CMD_READ_TEMP)).
        	// 온도 단위를 섭씨(Celsius)로 변환하여 Console에 출력한다.
            then(rawData => console.log(toCelsius(rawData))).
            // i2c bus를 close 한다.
        	then(_ => i2c1.close())
          // i2c.openPromisified(1) 실행 중 Error 가 발생하는 경우 Error 메세지를 출력한다.
          ).catch(console.log);
        };
        
        // 온도 측정 주기를 1.5Sec로 설정한다.
        setInterval(displayTemperature, 1500);
              

      • 비동기 방식(Promise)과 동기 방식을 이용한 SI2C 통신(디지털 온도계) 프로그램 예: i2c-th-meter-promis-wait-basic.js
      • 아래 예는 비동기방식(Promise object를 사용)과 동기식 방식을 혼합하여 사용하는 예 이다.

        
        // i2c-th-meter-promis-wait-basic.js
        const i2c = require('i2c-bus');
        
        const DS1621_ADDR = 0x48;
        const CMD_ACCESS_CONFIG = 0xac;
        const CMD_READ_TEMP = 0xaa;
        const CMD_START_CONVERT = 0xee;
         
        // DS1621로 부터 읽은 온도 Data(rawTemp)를 섭씨 온도 값으로 변환한다.
        const toCelsius = (rawTemp) => {
        	const halfDegrees = ((rawTemp & 0xff) << 1) + (rawTemp >> 15);
         
        	if ((halfDegrees & 0x100) === 0) {
        		return halfDegrees / 2; // Temp +ve
        	}
         
        	return -((~halfDegrees & 0xff) / 2); // Temp -ve
        };
        
        // i2c 통신을 사용하여 DS1621 부터 온도를 읽어오는 함수
        function displayTemperature() {	
          // i2c bus를 Open하고 Promise object(Bus)를 반환 한다.
          i2c.openPromisified(1).
          // 온도 변환(측정)모드를 One shot mode로 설정한다.
          // i2c1: i2c.openPromisified(1) 실행 결과로 반환된 Promise object(Bus)
          then(i2c1 => i2c1.writeByte(DS1621_ADDR, CMD_ACCESS_CONFIG, 0x01).
        	// PromisifiedBus 인스턴스를 동기식 명령에 사용할 수 있는 Bus instance로 반환한다.
            then(_ => i2c1.bus()).
        	// DS1621 가 사용 중인 경우 사용이 종료 될때까지 대기한다.
        	// 반환된 Bus instance(i2cSync)를 이 bus의 동기식 명령에 사용한다.
        	// 반복하여 Data를 읽어 Test 하는 while 내에는 동기식 명령을 사용하여야 한다.
        	// 동기식 readByteSync는 Byte data를 Return 하고,
        	// 비동기(Promise) readByte는 Promise를 Return 한다.
        	// 프로그램이 한 줄인 경우에는 ( ) 내에 작성한다. 실행 결과는 별도의 Return 문 없이 Return 된다.
        	// 프로그램이 여러 줄인 경우에는 { } 내에 작성한다. 실행 결과는 Return 문을 사용하여 Return 된다.
            then(i2cSync => {while (i2cSync.readByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG) & 0x10){}
        	}).
        	// One shot mode 온도 변환을 시작한다.
            then(_ => i2c1.sendByte(DS1621_ADDR, CMD_START_CONVERT)).
        	// PromisifiedBus 인스턴스를 동기식 명령에 사용할 수 있는 Bus instance로 반환한다.
            then(_ => i2c1.bus()).
        	// 반환된 Bus instance(i2cSync)를 이 bus의 동기식 명령에 사용한다.
        	// One shot mode이기 때문에 변환이 완료 되기를 기다린다.
            then(i2cSync => {while ((i2cSync.readByteSync(DS1621_ADDR, CMD_ACCESS_CONFIG) & 0x80) === 0){}
        	}).
        	// DS1621로 부터 온도 Data를 읽는다. Data Format은 DS1621 자료를 참고할 것.
            then(_ => i2c1.readWord(DS1621_ADDR, CMD_READ_TEMP)).
        	// 온도 단위를 섭씨(Celsius)로 변환하여 Console에 출력한다.
            then(rawData => (console.log('temp: ' + toCelsius(rawData)) )).
            // i2c bus를 close 한다.
            then(_ => i2c1.close())
          // i2c.openPromisified(1) 실행 중 Error 가 발생하는 경우 Error 메세지를 출력한다.
          ).catch(console.log);
        };
        
        // 온도 측정 주기를 1.5Sec로 설정한다.
        setInterval(displayTemperature, 1500);
              

      • 실험 방법
        • 예제 프로그램을 다운로드하여 저장한다.
        • Putty로 Raspberry Pi에 Login 하고, 프로그램이 있는 폴더로 이동 한다.
        • 다음 명령으로 i2c-th-meter-sync.js를 실행 한다.
        • node i2c-th-meter-sync.js

        • 동일한 방법으로 i2c-th-meter-promises.js 와 i2c-th-meter-promis-wait-basic.js 프로그램도 실행하고 결과를 확인한다.

    • I2C 통신을 이용한 Embedded Microcontroller 제어(Master(Raspberry PI) - Slave(Embedded Microcontroller)) 예
      • 윗 I2C 통신을 이용한 측정 과 제어 시스템 구성 예에서 Raspberry PI를 Master로 Embedded Microcontroller(ATmega128)를 Slave device로 사용 한다.

      • I2C 통신을 이용한 Embedded Microcontroller 제어를 위한 Raspberry Pi(Master) 측 프로그램 예: i2c-avr-master-basic.js
      • 주: 위 프로그램 실행을 위하여는 아래 명령으로 "readline-sync"를 설치하여야 한다.

        npm install readline-sync

      • I2C 통신을 이용한 Embedded Microcontroller 제어를 위한 ATmega128 보드(Slave) 측 c 예: cho_avr_i2c_slave_basic.zip
      • i2c 통신 중요 c 프로그램 예: avr_i2c_slave_basic.c

      • 학습 포인트
        • Raspberry PI(Master)와 ATmega128(Slave) 사이의 I2C 통신 실험(node.js와 SMBus Library 사용)
        • I2C 통신을 위한 ATmega128 프로그램(c 언어 사용) 작성에 대한 이해
        • SMBus 대한 이해
      • 실험을 위한 준비
        • Raspberry Pi와 ATmega128의 I2C 통신선 연결
        • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 ATmega128 보드의 TWI(AVR에서는 I2C 통신을 TWI라고 함) 신호선을 연결 한다.

          • Raspberry Pi SDA1(Pin3) <-> ATmega128 보드의 TWI Data 신호선 : 2-wire serial 통신을 위한 Data input/output pin.
          • Raspberry Pi SCL1(Pin5) <-> ATmega128 보드의 TWI Clock 신호선 : 2-wire serial 통신을 위한 Clock input/output pin.
          • Raspberry Pi GND(Pin9) <-> ATmega128 보드의 GND : Ground pin.
          • 주의: Raspberry Pi 와 Atmega128 보드의 전원선(Vdd)은 서로 연결하면 안 된다. Raspberry Pi는 3.3V를 Atmega128 보드는 5V 전원을 사용하는 경우가 많기 때문임.
      • 실험 방법
        • cho_avr_i2c_slave_basic.zip File을 다운로드 하여 압축을 풀고 실행 File(cho_avr_i2c_slave_basic.hex)을 ATmega128 보드에 Up load 하고 실행 한다.
        • 모니터 프로그램을 ATmega128 보드의 uart0에 연결(Baudrate: 19200)하고 실행 한다.
        • Putty로 Raspberry Pi에 Login 하고, i2c-avr-master-basic.js가 있는 폴더로 이동 한다.
        • 다음 명령으로 i2c-avr-master-basic.js를 실행 한다.
        • node i2c-avr-master-basic.js

        • Putty 창의 메세지에 따라 명령을 입력 하면 ATmega128 보드에 연결된 모니터에 Putty에서 입력한 명령(문자열)이 출력 되고, Putty 창에는 ATmega128에서 전송한 "AVR i2c testing" 메세지가 출력 된다.
    • I2C 통신(Master(Raspberry PI) - Slave(Embedded Microcontroller)) 이용한 LED 제어 예
      • 윗 I2C 통신을 이용한 측정 과 제어 시스템 구성 예에서 Raspberry PI를 Master로 Embedded Microcontroller(ATmega128)를 Slave device로 사용 한다.

      • I2C 통신을 이용한 Embedded Microcontroller의 LED 제어를 위한 Raspberry Pi(Master) 측 Python 프로그램 예: i2c-avr-master-led.js
      • I2C 통신을 이용한 Embedded Microcontroller의 LED 제어를 위한 ATmega128 보드(Slave) 측 c 프로그램 예: cho_avr_i2c_slave_led.zip
      • i2c 통신 중요 c 프로그램 예: avr_i2c_slave_led.c

      • 학습 포인트
        • Raspberry PI(Master)와 ATmega128(Slave) 사이의 I2C 통신 실험(Python 언어와 SMBus Library 사용)
        • LED 제어를 위한 Command 설계와 ATmega128 제어 프로그램 작성에 대한 이해
      • 실험을 위한 준비
        • Raspberry Pi와 ATmega128의 I2C 통신선 연결
        • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 ATmega128 보드의 TWI 신호선을 연결 한다.

          • Raspberry Pi SDA1(Pin3) <-> ATmega128 보드의 TWI Data 신호선 : 2-wire serial 통신을 위한 Data input/output pin.
          • Raspberry Pi SCL1(Pin5) <-> ATmega128 보드의 TWI Clock 신호선 : 2-wire serial 통신을 위한 Clock input/output pin.
          • Raspberry Pi GND(Pin9) <-> ATmega128 보드의 GND : Ground pin.
          • 주의: Raspberry Pi 와 Atmega128 보드의 전원선(Vdd)은 서로 연결하면 안 된다. Raspberry Pi는 3.3V를 Atmega128 보드는 5V 전원을 사용하는 경우가 많기 때문임.
        • 8Bit-LED-array-module 제작 예를 참고하여 ATmega128의 PORTF에 LED Array를 연결 한다.
      • 실험 방법
        • cho_avr_i2c_slave_led.zip File을 다운로드 하여 압축을 풀고 실행 File(cho_avr_i2c_slave_led.hex)을 ATmega128 보드에 Up load 하고 실행 한다.
        • Putty로 Raspberry Pi에 Login 하고, i2c-avr-master-led.js가 있는 폴더로 이동 한다.
        • 다음 명령으로 i2c-avr-master-led.js를 실행 한다.
        • node i2c-avr-master-led.js

        • Putty 창의 메세지에 따라 명령을 입력 하며 ATmega128 보드에 연결된 LED의 동작이 명령과 일치 하는지 확인 한다.
  • Web 환경과 I2C 통신을 이용한 디지털 온도 측정(DS1621) 예
    • Web 환경에서 I2C 통신을 이용한 측정 과 제어 시스템 구성 예


      Web 환경에서 디지털 온도 측정(DS1621)을 위한 Web Page 예

    • 원격 측정(I2C 통신(디지털 온도계)) 프로그램 예
    • 학습 포인트
      • Web 환경을 이용한 원격 측정(제어)에 대한 이해
      • I2C 통신을 사용한 Server 와 Device(이 예에서는 DS1621 온도센서) 사이의 Data 송수신에 대한 이해
      • Timer를 사용하여 일정한 주기 간격으로 측정 하기.
      • DS1621 온도센서에 대한 이해.
    • 실험을 위한 준비
      • Raspberry Pi와 온도 센서(DS1621)의 I2C 통신선 연결
      • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 온도 센서(DS1621) 2개를 연결 한다.

        • Raspberry Pi SDA1(Pin3) <-> DS1621 SDA(Pin1) : 2-wire serial 통신을 위한 Data input/output pin.
        • Raspberry Pi SCL1(Pin5) <-> DS1621 SCL(Pin2) : 2-wire serial 통신을 위한 Clock input/output pin.
        • Raspberry Pi 3.3V(Pin1) <-> DS1621 VDD(Pin8) : VDD pin.
        • Raspberry Pi GND(Pin9) <-> DS1621 GND(Pin4) : Ground pin.
      • 온도센서 번호(번지) 설정 하기(이 예에서는 2개의 온도 센서를 사용 하였음)
        • DS1621의 Pin7(A0), Pin6(A1), Pin5(A2)를 사용하여 온도 센서의 번호(번지)를 설정 한다.
        • 온도 센서의 번호(번지)를 설정 예
          • 0번(0x48 번지): A0 <- GND, A1 <- GND, A2 <- GND
          • 1번(0x49 번지): A0 <- VDD, A1 <- GND, A2 <- GND
    • 실험 방법
      • 적당한 폴더에 Server 측 프로그램(web-i2c-th-meter.js)을 복사하여 web-i2c-th-meter.js File을 만든다.
      • web-i2c-th-meter.js File이 있는 폴더에 /html/ 폴더를 만들고 이 폴더에 Client 측 프로그램(web-i2c-th-meter.html)을 복사하여 web-i2c-th-meter.html File을 만든다.
      • Putty로 Raspberry Pi에 Login 하고, web-i2c-th-meter.js이 있는 폴더로 이동 한다.
      • 다음 명령으로 web-i2c-th-meter.js를 실행 한다.
      • node web-i2c-th-meter.js

      • Chrome browser를 실행하고 아래 예를 참고하여 Web server에 연결 하면 web-i2c-th-meter.html 페이지가 Load 된다.
      • http://Raspberry Pi의 IP 주소:2880/web-i2c-th-meter.html

        2880은 공유기에서 포트포워드로 설정한 포트 번호 이다.

      • web-i2c-th-meter.html 페이지에서 "실내 온도 읽어 오기" 와 "실외 온도 읽어 오기" 버튼을 이용하여 온도를 측정 한다.
      • 1초 간격으로 온도가 자동으로 갱신되도록 하려면 web-i2c-th-meter.html 페이지의 onLoadFunc() 함수 내의 clockTime() 함수의 Comment 처리를 해제 한다.
      • 주: jQuery를 이용한 프로그램도 동일한 방법으로 실험할 수 있다.

  • Web 환경에서 Raspberry PI와 ATmega128 사이 i2c 통신을 이용한 LED 제어
    • 윗 Web 환경에서 I2C 통신을 이용한 측정 과 제어 시스템 구성 예에서 Raspberry PI를 Master로 ATmega128 보드(LED 연결)를 Slave device로 사용 한다.

      Web 환경에서 LED 제어 위한 Web Page 예

    • Web 환경에서 I2C 통신을 이용한 LED 제어 프로그램(Raspberry PI 에서 실행되는 Server와 Client 프로그램) 예: web-i2c-avr-led.zip
    • 학습 포인트
      • Web 환경을 이용한 원격 제어에 대한 이해
      • I2C 통신을 사용한 Master 와 Slave Device(이 예에서는 ATmega128 보드) 사이의 Data 송수신에 대한 이해
      • Embedded Microcontroller의 LED 제어를 위한 ATmega128 보드(Slave) 측 c 프로그램 작성
      • ATmega128의 Timer interrupt를 사용하여 일정한 주기로 제어 하기.
    • 실험을 위한 준비
      • Raspberry Pi와 ATmega128의 I2C 통신선 연결
      • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 ATmega128 보드의 TWI 신호선을 연결 한다.

        • Raspberry Pi SDA1(Pin3) <-> ATmega128 보드의 TWI Data 신호선 : 2-wire serial 통신을 위한 Data input/output pin.
        • Raspberry Pi SCL1(Pin5) <-> ATmega128 보드의 TWI Clock 신호선 : 2-wire serial 통신을 위한 Clock input/output pin.
        • Raspberry Pi GND(Pin9) <-> ATmega128 보드의 GND : Ground pin.
        • 주의: Raspberry Pi 와 Atmega128 보드의 전원선(Vdd)은 서로 연결하면 안 된다. Raspberry Pi는 3.3V를 Atmega128 보드는 5V 전원을 사용하는 경우가 많기 때문임.
      • 8Bit-LED-array-module 제작 예를 참고하여 ATmega128의 PORTF에 LED Array를 연결 한다.
    • 실험 방법
      • 적당한 폴더에 web-i2c-avr-led.zip을 다운로드하여 압축을 해제하면 Server 측 프로그램(web-i2c-avr-led.js)과 Client 측의 프로그램 web-i2c-avr-led.html이 있는 html 폴더, ATmega128 보드를 위한 File이 이 있는 avr 폴더가 생성된다.
      • Putty로 Raspberry Pi에 Login 하고, web-i2c-th-meter.js가 있는 폴더로 이동 한다.
      • 다음 명령으로 web-i2c-avr-led.js를 실행 한다.
      • node web-i2c-avr-led.js

      • Chrome browser를 실행하고 아래 예를 참고하여 Web server에 연결 하면 web-i2c-avr-led.html 페이지가 Load 된다.
      • http://Raspberry Pi의 IP 주소:2880/

        2880은 공유기에서 포트포워드로 설정한 포트 번호 이다.

      • web-i2c-avr-led.html 페이지의 LED 제어 버튼을 이용하여 ATmega128 보드의 LED를 제어 한다.
      • 주: jQuery를 이용한 프로그램도 동일한 방법으로 실험할 수 있다.