본문 바로가기
라즈베리파이

[라즈베리파이] PCF8591 ADC/DAC 모듈

by sum_mit45 2023. 6. 23.
728x90
반응형

PCF8591 모듈

: 모듈 내부에서는 입력 채널과 출력 채널을 선택하기 위해 I2C 프로토콜을 사용하여 제어 레지스터를 설정한다. 그리고 A/D 변환기는 선택한 입력 채널에서 아날로그 입력 신호를 8비트 디지털 값으로 변환하고, D/A 변환기는 선택한 출력 채널에서 8비트 디지털 값을 아날로그 출력 신호로 변환한다. 따라서, PCF8591 모듈은 외부 아날로그 신호를 디지털 값으로 변환하고, 디지털 값을 아날로그 출력 신호로 변환함으로써 다양한 아날로그 및 디지털 애플리케이션에 적용할 수 있습니다.

 

8비트 다목적 A/D 및 D/A 컨버터 모듈

(1) 아날로그 신호를 디지털 신호(ADC)로 변환하거나 디지털 신호를 아날로그 신호(DAC)로 변환하는 모듈.

(2) PCF8591이 측정하는 값은 주변에서 입력된 아날로그 신호이다.

ex) 온도 센서, 빛 감지 센서, 소리 감지 센서 등 다양한 아날로그 센서를 PCF8591에 연결하여 해당 센서가 측정한 값(온도, 빛의 세기, 소리의 크기 등)을 PCF8591이 디지털 값으로 변환하여 읽어들일 수 있다. 

- 아날로그 신호란?

   아날로그 입력 신호의 크기를 256단계(2^8)로 이산화하여 숫자로 나타낸다.

   즉, 입력되는 아날로그 신호의 크기가 클수록 8비트의 값이 크게 나타나며, 작을수록 작게 나타난다. 

(3) 다룰 수 있는 데이터의 크기8비트(=1바이트)이다. 따라서 최대 숫자 범위가 0에서 255이다. 

즉, 이 모듈이 제공하는 ADC 기능을 사용하여 아날로그 입력값을 디지털로 변환할 때, 변환된 값은 0~255 까지의 숫자 중 하나이다.

반대로, DAC 기능을 사용하여 디지털 입력값을 아날로그값으로 변환할 때도, 8비트 데이터를 0부터 255까지의 아날로그 출력값을 생성한다

 

       +---------------------+
       |          VCC        |
       |          GND        |
       |                     |
       |                     |
       |       SCL (Clock)   |
       |       SDA (Data)    |
       |                     |
       |                     |
       |      AIN0 (Input)   |
       |      AIN1 (Input)   |
       |      AIN2 (Input)   |
       |      AIN3 (Input)   |
       |      AOUT (Output)  |
       +---------------------+

- VCC: 모듈에 전원을 공급하는 핀. 보통 3.3V 또는 5V 전원을 사용.
- GND: 모듈에 접지를 제공하는 핀.
- SCL: I2C 통신에서 클럭 신호를 전송하는 핀.
- SDA: I2C 통신에서 데이터를 전송하는 핀.
- AIN0, AIN1, AIN2, AIN3: 모듈의 입력 채널. 외부 아날로그 신호를 측정.
- AOUT: 모듈의 출력 채널. 디지털 값을 아날로그 출력 신호로 변환.

 

I2C (Inter-Integrated Circuit) 인터페이스를 통해 마이크로컨트롤러와 통신

(1) I2C 인터페이스: 두 개의 디지털 신호선으로 마이크로컨트롤러와 다른 디지털 장치들이 통신할 수 있는 통신 규약.

(2) I2C: 시리얼 통신의 한 형태로, 하나의 master 장치 하나 이상의 slave 장치가 서로 통신할 수 있다. master 장치전체적인 통신 프로토콜을 제어하며, slave 장치들은 마스터의 지시에 따라 데이터를 송수신한다. I2C 통신은 SDA(Serial Data)와 SCL(Serial Clock) 두 개의 신호선을 사용한다. SDA데이터를 전송하는 데 사용되고, SCL데이터 전송의 타이밍을 제어한다. SDA와 SCL은 모든 장치들 간에 공유되고, 각 장치들은 주소를 가지고 있어 마스터가 어떤 장치에게 명령을 내리는지 식별한다. 

(3) 시리얼 통신: 데이터를 비트 단위로 연속적으로 전송하는 통신방식이다. 즉, 데이터를 한 번에 여러 비트로 분할하여 전송하는 병렬 통신과 달리, 한 번에 하나의 비트만 전송한다. 데이터의 크기가 크더라도, 여러 번의 전송으로 나누어 전송할 수 있기에 데이터를 효율적으로 전송할 수 있다. 시리얼 통신에서는 데이터 전송을 위해, 데이터를 전송하는 신호선(Tx), 데이터를 수신하는 신호선(Rx)으로 2개의 신호선이 필요하다. 이 두개의 신호선은 마이크로컨트롤러와 통신하고자 하는 장치(ex. 센서, 모터 등)와 연결된다. 

(4) 마이크로컨르롤러: 하드웨어 제어를 위한 작은 컴퓨터 ex) 아두이노

라즈베리파이는 하드웨어와 소프트웨어가 결합된 싱글 보드 컴퓨터로, 리눅스 운영체제가 탑재되어 있다. 


미세먼지 농도 센서 GP2Y1014AU

미세먼지 센서 GP2Y1014AU 먼지 농도에 따라서 출력 전압을 바꾸는 아날로그 센서이다.

이 센서를 PCF8591과 연결하면, PCF8591이 아날로그-디지털 컨버터를 이용하여 해당 전압 값을 디지털 값으로 읽을 수 있다. 디지털 값은 0에서 255 사이의 값으로 나타나며, 이를 적절히 변환하면 미세먼지 농도를 추정할 수 있습니다.

 

GP2Y1014AU 미세먼지 센서의 경우, 측정된 전압 값으로부터 미세먼지 농도를 추정하는 공식은
먼지 농도(ug/m^3) = 0.17 x (Vout - 0.1) x 1000
이다. 

- Vout: GP2Y1014AU의 아날로그 출력 전압 값

* 이 공식은 GP2Y1014AU 데이터시트에서 추천되는 공식이며, 정확한 미세먼지 농도 측정을 위해서는 각각의 센서에 대해 특정한 보정 및 캘리브레이션 과정이 필요할 수 있다.

 

GP2Y1014AU 미세먼지 센서 측정 원리

: GP2Y1014AU 미세먼지 센서는 적외선 발광 다이오드(LED)와 포토다이오드로 구성되어 있다. 적외선 발광 다이오드는 적외선 광선을 발산하여 공기 중 먼지 입자와 충돌하면 흩어지는 빛을 발생시킨다. 이렇게 발생된 빛은 빛 감지기 역할을 하는 포토다이오드에 의해 측정된다.
: 미세먼지가 많아지면 적외선 발광 다이오드에서 발생한 빛이 먼지 입자에 의해 산란되는 정도가 증가한다. 이는 빛의 산란이 미세먼지 농도와 비례하기 때문이다. 이 산란된 빛은 포토다이오드로 전달되어 전압 신호를 생성한다. 따라서, GP2Y1014AU 미세먼지 센서는 적외선 발광 다이오드와 포토다이오드를 이용하여 미세먼지 농도를 측정한다. 

: 이 미세먼지 센서에서 측정된 값은 아날로그 값이다. 적외선 발광 다이오드에서 발생하는 빛의 산란 정도에 따라서 포토다이오드에서 생성되는 전압 신호가 변화하기 때문이다.
: 그러나, PCF8591 모듈과 같은 아날로그-디지털 변환기(ADC)를 이용하여 아날로그 값으로 측정한 후, 이를 디지털 값으로 변환할 수 있다. 일반적으로 아날로그-디지털 변환기 모듈은 디지털 값으로 변환하기 쉽도록 I2C 통신이나 SPI 통신 등의 인터페이스를 제공한다. 이렇게 디지털 값으로 변환된 측정 결과는 마이크로컨트롤러나 컴퓨터 등의 디지털 시스템에서 처리하여 사용할 수 있다.


미세먼지 농도 센서 GP2Y1014AU와 PCF8591 모듈 컨버터 연결하기

 

 

 


MQ-5 가스 센서의 경우, 센서 출력값은 일반적으로 가스 농도와 선형적으로 관련되어 있습니다. 측정값은 센서의 출력 전압 값이므로, 해당 값과 가스 농도 간의 정확한 수학적인 관계는 각각의 가스에 따라 다를 수 있습니다. 따라서 가스 농도 측정을 위해서는 MQ-5 가스 센서를 사용하는 특정한 응용 분야에서 보정 과정이 필요합니다.

 

 

import smbus2 # I2C 통신 라이브러리
import time # 시간 관련 라이브러리

# PCF8591 모듈의 I2C 주소 (기본값: 0x48)
DEVICE_ADDR = 0x48 

# I2C 버스 번호 (라즈베리파이의 경우 1번 버스 사용)
bus = smbus2.SMBus(1) 

# GP2Y1014AU 출력 핀 번호
dust_pin = 14 

# PCF8591 A0 채널 번호
channel = 0 

# PCF8591에서 측정된 값을 읽어와 미세먼지 농도 계산
def read_dust_sensor():
    # GP2Y1014AU에서 측정한 아날로그 값을 PCF8591의 A0 채널에서 읽어옴
    value = bus.read_byte_data(DEVICE_ADDR, channel)
    
    # 미세먼지 농도 계산
    voltage = value * 3.3 / 255 # PCF8591의 입력 전압 범위는 0~3.3V
    dust_density = 0.17 * voltage - 0.1 # GP2Y1014AU의 선형 방정식을 이용하여 미세먼지 농도 계산
    return dust_density

# 1초 간격으로 GP2Y1014AU에서 측정된 미세먼지 농도 출력
while True:
    dust_density = read_dust_sensor()
    print("미세먼지 농도: %.2f ug/m^3" % dust_density)
    time.sleep(1)

- read_dust_sensor() 함수: GP2Y1014AU의 출력 핀에서 측정된 값을 PCF8591의 A0 채널에서 읽어온 다음, 이 값을 이용해 미세먼지 농도를 계산한 것.

 

대한민국 기준으로 실내 미세먼지(PM2.5) 농도 수준은 다음과 같이 구분된다.
- 아주나쁨: 76ug/m^3 이상
- 나쁨: 36~75ug/m^3
- 보통: 16~35ug/m^3
- 좋음: 0~15ug/m^3

 

*단, 미세먼지 농도는 지역과 시간에 따라 변화할 수 있으므로 주의가 필요하다. 또한, 위의 기준은 대기 중의 미세먼지 농도를 기준으로 한 것으로, 개별 실내 환경에서 측정된 미세먼지 농도와는 차이가 있을 수 있다. 따라서, 개별 환경에서는 상황에 따라 적절한 기준을 설정하는 것이 좋다.

 

PCF8591 모듈에 GP2Y1014AU 미세먼지 센서와 MQ-5 가스 센서 연결하는 예제코드

import smbus
import time

# Define I2C bus number
bus = smbus.SMBus(1)

# Define PCF8591 address and channel numbers
address = 0x48
ain0_channel = 0
ain1_channel = 1

# Define GP2Y1014AU dust sensor parameters
VCC = 5.0  # Supply voltage
VOL = 0.4  # Output voltage at 0 ug/m3
SENSITIVITY = 0.5  # Sensitivity at 0 ug/m3
CONVERT = 0.17  # Conversion factor (ug/m3 per voltage)

# Define MQ-5 gas sensor parameters
RL_VALUE = 10.0  # Load resistance on the board, in kilo ohms
RO_CLEAN_AIR = 9.83  # Clean air resistance, in kilo ohms
GAS_HYDROGEN = 0  # Hydrogen gas
GAS_LPG = 1  # LPG gas
GAS_METHANE = 2  # Methane gas
GAS_CARBON_MONOXIDE = 3  # Carbon Monoxide gas
GAS_ALCOHOL = 4  # Alcohol gas
GAS_SMOKE = 5  # Smoke gas

# Define PCF8591 read function
def read_adc(channel):
    value = bus.read_byte_data(address, channel)
    return value

# Define GP2Y1014AU dust sensor read function
def read_dust():
    raw = read_adc(ain0_channel)
    voltage = raw / 255.0 * VCC
    dust = (voltage - VOL) / SENSITIVITY * CONVERT
    return dust

# Define MQ-5 gas sensor read function
def read_gas(gas_type):
    raw = read_adc(ain1_channel)
    voltage = raw / 255.0 * VCC
    RS = RL_VALUE * (VCC - voltage) / voltage
    if gas_type == GAS_HYDROGEN:
        GAS_R0 = 4.4
        GAS_SLOPE = -1.03
    elif gas_type == GAS_LPG:
        GAS_R0 = 3.5
        GAS_SLOPE = -0.76
    elif gas_type == GAS_METHANE:
        GAS_R0 = 4.4
        GAS_SLOPE = -1.03
    elif gas_type == GAS_CARBON_MONOXIDE:
        GAS_R0 = 4.4
        GAS_SLOPE = -1.03
    elif gas_type == GAS_ALCOHOL:
        GAS_R0 = 3.5
        GAS_SLOPE = -0.86
    elif gas_type == GAS_SMOKE:
        GAS_R0 = 3.5
        GAS_SLOPE = -0.86
    else:
        return -1
    ratio = RS / RO_CLEAN_AIR
    gas = GAS_R0 * (ratio ** GAS_SLOPE)
    return gas

# Main program loop
while True:
    dust = read_dust()
    gas = read_gas(GAS_CO)
    print("Dust Concentration (ug/m3): %.2

- 이 코드는 PCF8591 모듈에서 AIN0과 AIN1에 연결된 GP2Y1014AU 미세먼지 센서와 MQ-5 가스 센서로부터 데이터를 수집하고, 이를 이용하여 미세먼지 농도와 가스 농도를 계산하는 코드. 
- bus.write_byte(): PCF8591 모듈의 주소와 커맨드 바이트를 전송한다. 주소는 0x48이 기본값이며, AIN0의 데이터를 읽으려면 0x40, AIN1의 데이터를 읽으려면 0x41을 사용한다. 커맨드 바이트는 "데이터 시트"에서 지정된 값을 사용한다. 이 함수로 데이터를 읽어 오는데, 데이터는 8비트 unsigned int 형식으로 읽어온 후, 이를 0~255 사이의 값으로 정규화한다.
- dust_density(): GP2Y1014AU 미세먼지 센서를 이용해서 센서 값으로부터 미세먼지 농도를 계산한다. 
- gas_density(): MQ-5 가스 센서의 가스 농도와 센서 값을 비례하는 관계가 아니므로 측정한 값을 직접 가공하여 가스 농도를 계산해야 하므로 위와 같이 구현했다. 

 

 

나중에 표 그린 후, 알려준 코드

import smbus
import time

bus = smbus.SMBus(1)  # I2C bus number (1 for Raspberry Pi 3B+ and newer)

PCF8591_ADDR = 0x48  # PCF8591 address
GP2Y1014AU_PIN = 0   # PCF8591 AIN0 pin
MQ5_PIN = 1          # PCF8591 AIN1 pin

def read_adc(pin):
    """Read analog input from the specified pin."""
    bus.write_byte(PCF8591_ADDR, pin)  # set PCF8591 control byte to select the specified pin
    value = bus.read_byte(PCF8591_ADDR) # read the analog input value
    return value

def dust_density():
    """Calculate and return the dust density."""
    V_LED = 5  # LED voltage
    V_OC = read_adc(GP2Y1014AU_PIN) / 255 * 3.3  # output voltage of GP2Y1014AU
    dust_density = 0.17 * V_OC * V_LED / (V_OC + 0.1)  # dust density calculation (unit: pcs/0.01cf)
    return dust_density

def gas_concentration():
    """Calculate and return the gas concentration."""
    V_OC = read_adc(MQ5_PIN) / 255 * 3.3  # output voltage of MQ-5 gas sensor
    R_load = 10  # load resistor value (unit: kohm)
    R_s = (3.3 - V_OC) / V_OC * R_load  # sensor resistance (unit: kohm)
    gas_concentration = 0.4 * R_s  # gas concentration calculation (unit: ppm)
    return gas_concentration

while True:
    try:
        dust = dust_density()
        gas = gas_concentration()
        print("Dust density: {:.2f} pcs/0.01cf, Gas concentration: {:.2f} ppm".format(dust, gas))
        time.sleep(1)
    except KeyboardInterrupt:
        break

- 위 코드에서는 GP2Y1014AU 미세먼지 센서를 AIN0 핀에, MQ-5 가스 센서를 AIN1 핀에 연결하여 사용한다. 코드 실행시 dust_density() 함수는 미세먼지 농도를, gas_concentration() 함수는 가스 농도를 측정하여 반환한다. 반환된 값을 print문으로 출력하여 모니터에 표시한다. 무한루프 안에서 측정을 반복하며, 키보드 인터럽트가 발생할 때까지 계속 측정을 수행한다.

 

코드에서 사용된 함수들의 구현 내용은 아래와 같다. 

def get_value(channel):
    # 채널 값이 0 또는 1이 아닌 경우 예외 처리
    if channel not in range(2):
        raise ValueError('Invalid channel')

    # AIN0 또는 AIN1을 읽어서 0~255 범위로 정규화
    cmd = 0x40 + channel
    bus.write_byte(0x48, cmd)
    value = bus.read_byte(0x48)
    normalized_value = value / 255.0

    return normalized_value

def dust_density(sensor_value):
    # 미세먼지 농도 계산 공식
    return 0.17 * sensor_value - 0.1

def gas_density(sensor_value):
    # 가스 농도 계산 공식
    return ((1.0 / sensor_value) - 0.2) * 1000.0

 

 

 

라즈베리파이4, PCF8591 컨버터, GP2Y1014AU 미세먼지 센서, MQ-5 가스센서 연결

- GP2Y1014AU의 핀인 Vo는 측정한 미세먼지 농도 값이 출력되는 아날로그 출력 핀이다. VLED는 LED에 연결되는 전원 핀으로, 센서 내부의 LED에 전원을 공급하는 역할을 하기 때문에, 이 LED는 센서의 작동에 필수적이다.

 

 

구체적인 연결방법

728x90
반응형