IoT (5) - I2C 프로토콜 예제: MCP3428 제어
Updated:
5. I2C 프로토콜 예제: MCP3428 ADC 제어
이번 포스트에서는 I2C 프로토콜을 이용하는 또 다른 예제를 소개한다. MCP3428 은 Microchip
사의 ADC 모듈로 I2C 프로토콜을 이용해 제어할 수 있지만, 이전에 소개한 ADT7420 센서와 제어 방식에 약간의 차이가 있다.
5.1 Non-Register I2C Slave (NRI2S)
I2C Slave
로 동작하는 MCP3428 는 다른 I2C Slave
모듈과 마찬가지로 Slave
주소와 내부 레지스터에 접근하는 방식으로 이용해 제어가 가능하다. 한 가지 특이한 점은 MCP3428 이 Non-Register I2C Slave (NRI2S) 라는 것이다. I2C 에 대해 어느정도 친숙한 사람은 알겠지만, NRI2S 라는 단어는 필자가 임의로 만들어낸 단어이다. NRI2S 라고 언급한 이유에 대해서는 MCP3248 데이터 시트의 I2C Write 시퀀스를 보면 어느정도 납득이 갈 것이다.
위 그림은 MCP3428 의 동작 모드를 설정하기 위한 I2C Write 예시이다. 그림에서 1st Byte
는 Slave
주소와 R/W 비트(0
)에 해당되고, 2nd Byte
는 MCP3428 ADC의 동작 모드를 설정하는 값에 해당한다. MCP3428 에는 4 개의 ADC 채널을 가지고 있는데, 만약 One-Shot 모드로 0번 채널에서 데이터를 읽고 싶은 경우 2nd Byte
값을 0x80 = 0b10000000
으로 설정해주면 된다.
특이한 점으로는 configuration 레지스터의 주소 값을 별도로 Write 하지 않고, Slave
주소 다음에 곧바로 configuration 값을 Write 하고 있다는 점이다. 원래 I2C Write 시에는 Slave
주소 Write 이후, 해당 Slave
의 내부 레지스터 주소와 그 주소에 입력하고 싶은 값을 Write 하는데, MCP3428 데이터 시트를 보면 레지스터 주소 값을 입력하는 단계가 생략되어 있다.
위 그림은 MCP3428 동작 모드 설정 이후 ADC 값을 읽는 과정을 보여주며, 이 또한 레지스터 주소를 입력하는 단계가 생략되어 있는 것을 볼 수 있다. 즉, 이러한 방식으로 제어되는 I2C Slave
모듈도 있음을 소개하고자 하였다.
5.2 예제 코드
다음은 Arduino
에서 MCP3428 ADC 측정 값을 읽은 뒤 시리얼 모니터에 값을 출력하는 예제 코드의 일부이다. Arduino
의 경우 처음 프로그램 동작 시 setup()
함수를 한 번 실행하고, 이후 loop()
함수를 반복적으로 수행한다. 아래 코드에서 Wire.begin()
은 Arduino
의 I2C Master
를 활성화 시키는 함수이고, generalCallReset()
함수를 이용해 MCP3428 을 초기화 한다.
void setup() {
// put your setup code here, to run once:
// Initialise I2C communication as MASTER
Wire.begin();
Serial.begin(115200);
while(!Serial);
Serial.println("Start serial-interface");
// reset MCP3428 ADC (general Call Reset)
generalCallReset();
delay(10);
}
다음은 2초 마다 4 개의 채널의 ADC 값을 Arudino
시리얼 모니터로 출력하는 코드의 예시를 보여준다. Wire.beginTransmission(0x68)
함수는 I2C Slave
와 통신하기 위해 주소 값을 Write 하는 용도로 사용되었고, 본 예제에서는 Slave
주소가 0x68
인 경우를 가정하고 있다.
void loop() {
uint8_t buffer[3];
uint8_t status;
int adc_code;
// put your main code here, to run repeatedly:
for (uint8_t ch = 0; ch < 4; ch++) {
// Start conversion for a ch in single-sot mode
Wire.beginTransmission(0x68);
Wire.write(0x80 | (ch << 5)); // initiate One-shot Mode
Wire.endTransmission();
delay(5);
Wire.requestFrom(0x68, 2);
for (int i = 0; i < 2; i++)
buffer[i] = Wire.read();
// Convert the data to 12-bits
adc_code = ((buffer[0] & 0x0F) << 8) + buffer[1];
if(adc_code > 2047)
adc_code -= 4095;
Serial.print("ADC channel: ");
Serial.print(ch);
Serial.print(" ");
Serial.print(adc_code);
Serial.print(", ");
Serial.println(adc_code/2047.0*2.048, 4);
}
delay(2000);
}
Wire.write(0x80|(ch<<5))
코드는 MCP3428 의 한 채널 (ch
)을 One-Shot 모드로 동작하도록 설정해주는 부분이고, Wire.requestFrom(0x68, 2)
코드를 이용해 Slave
에 Read 명령을 전송하며, 실제 값은 Wrie.read()
함수를 이용해 1 byte
단위로 읽는다.
Reference
https://www.microchip.com/wwwproducts/en/MCP3428 [PDF]
Comments