ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • CH.05 라즈베리파이 GPIO 및 센서 활용하기
    Raspberry Pi ( python ) 2023. 3. 3. 15:28

    1 _ GPIO 제어 및 테스트

     

    1) 지니의 설정을 바꿔서 python 코드를 읽을 수 있게 만들기.

    제작 -> 빌드설정으로 이동

    Compile에 python3으로 변경

    Execute에서 python3으로 변경

     

    2) 파이썬 코드 작성하기

    ** 코드 마지막에 GPIO.cleanup()은 스크립트 실행 시에 GPIO 모드 세팅 등을 초기화하고 리소스를 반환시켜서 중복이나 GPIO핀 쇼트 등의 하드웨어적인 문제를 방지할 수 있다.

     

    GPIO 4번 핀에 1초 동안 신호를 주고 1초동안 신호를 꺼서 LED가 10회 깜빡이도록 만들었다.

     

    import RPi.GPIO as GPIO
    -> as GPIO 명령어로 RPi.GPIO 모듈이름을 GPIO로 요약해서 사용할 수 있다
    
    import time
    -> RPi.GPIO 모듈과 LED를 켜고 끄는 시간을 설정하기 위해 time 모듈을 불러옴
    
    GPIO.setmode(GPIO.BOARD)
    GPIO.setmode(GPIO.BCM)
    -> GPIO의 핀번호 설정은 두 가지가 있다.
    BOARD 모드는 2열 헤더 핀의 번호 순서대로 나열한 것이고,
    BCM 모드는 약속된 GPIO 번호로 표시하는 것이다.
    
    GPIO.setup(channel, GPIO.OUT)
    -> 사용하고자 하는 GPIO 채널을 출력으로 설정
    
    GPIO.output(channel, 1) -> High(3.3V)를 출력한다.
    GPIO.output(channel, 0) -> Low(0V)를 출력한다.
    
    time.sleep(1)
    -> 1초간 시간을 대기하는 명령어

     


    3) 푸시 버튼 스위치 실습 (Polling 방식)

    ** GPIO.setup(button_pin, GPIO.in, pull_up_down=GPIO.PUD_DOWN)

    -> 버튼 핀의 입력설정, PULL DOWN 설정

    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_UP) -> 풀업 설정
    GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) -> 풀다운 설정

     


    4) 푸시 버튼 스위치 실습 (Event 알림 방식)

     : 버튼에 이벤트를 걸어서 임의의 함수를 실행시킨다.

    GPIO.add_event_detect(channel, GPIO.RISING, callback=my_callback)
    -> 핀이 상승(RISING) 을 감지했을 때, 즉 입력 값이 0에서 1로 변했을 때
    임의의 함수 my_callback 을 실행한다.
    하강은 (FALLING) 을 사용한다

     


    5) 푸시 버튼 입력으로 LED 실습

    ** bouncetime : 버튼을 동작할 때 잘못된 신호가 입력되는 것을 방지한다.

     


    2 _ PWM 제어

     : Pulse Width Modulation 제어는 주기전으로 반복되는 ON, OFF 신호를 통해서 모터, 팬의 속도나 LED 등의

    밝기 등을 제어 할 수 있다.

    반복되는 pulse 신호의 주기에서 ON신호가 지속되는 시간의 비율을 Duty Cycle 이라고 하며, 이 듀티비가

    클수록 팬속도나 LED밝기가 커진다.

     

    1) PWM으로 LED 실습

    p = GPIO.PWM(channel, frequency)
    -> PWM 인스턴스 p 생성
    
    p.start(dc)
    -> 듀티비 dc는 0에서 100사이의 값
    
    p.ChangeFrequency(freq)
    -> 주파수(Hz) 변경
    
    p.ChangeDutyCycle(dc)
    -> 듀티비 변경 ( 0 <= dc <= 100.0 )
    
    p.stop()
    -> PWM 종료
    
    for dc in range(0,101,5):	# dc 값이 0에서 100까지 5만큼 증가
    	p.ChangeDuty(dc)		# dc 값으로 p의 듀티비 변경

     


    2) PWM으로 부저 실습

    #-*- coding: utf-8 -*-
    
    # 필요한 라이브러리를 불러옵니다.
    import RPi.GPIO as GPIO
    import time
    
    # 불필요한 warnin 제거, GPIO핀의 번호 모드 설정
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    
    # GPIO 18번 핀을 출력으로 설정
    GPIO.setup(18, GPIO.OUT)
    # PWM 인스턴스 p를 만들고 GPIO 18번을 PWM 핀으로 설정, 주파수 = 100HZ
    p = GPIO.PWM(18,100)
    
    # 4옥타브 도~시, 5옥타브 도의 주파수
    Frq = [ 262, 294, 330, 349, 392, 440, 493, 523]
    speed = 0.5 # 음과 음 사이 연주시간 설정(0.5초)
    
    p.start(10)
    
    try:
        while 1:
            for fr in Frq:
                p.ChangeFrequency(fr)
                time.sleep(speed)
    
    except KeyboardInterrupt:
        pass
    p.stop()
    GPIO.cleanup()

     


    3) 초음파센서 실습

     : 초음파센서의 작동 원리는 tiger pin에 스타트 펄스 신호를 주면 HC-SR04에서 사운드 웨이브를 전방으로 쏘아서

    물체에 반사되어 돌아오는 시간만큼 Echo 핀으로 펄스신호를 보낸다.

     

    파이썬 코드

    #-*- coding: utf-8 -*-
    
    import RPi.GPIO as GPIO
    import time
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    
    TRIG = 23
    ECHO = 24
    print("Distance measurement in progress")
    
    GPIO.setup(TRIG,GPIO.OUT)
    GPIO.setup(ECHO,GPIO.IN)
    
    GPIO.output(TPIG, False)
    time.sleep(2)
    
    try:
    	while True:
        	GPIO.output(TRIG, True)
            time.sleep(0.00001)
            GPIO.output(TRIG, False)
            
            while GPIO.input(ECHO)==0:
            	start = time.time()
            while GPIO.input(ECHO)==1:
            	stop = time.time()
                
            check_time = stop - start
            distance = check_time * 34300 / 2
            print("Distance : %.1f cm" % distance)
            time.sleep(0.4)
            
    except KeyboardInterrrupt:
    	GPIO.cleanup()

     


    2 _ 아날로그 신호와 SPI 통신

     - 아날로그 : 어떤 자료를 '길이', '각도' 또는 '전압'과 같이 외부적인 원인에 의해 연속적으로 변하는 것들을 물리량으로 나타내는 것을 의미한다.

     

    1) 아날로그 신호를 라즈베리 파이로 읽어오기

     - 라즈베리 파이의 GPIO는 아두이노와는 다르게 디지털 입력만 가능하다. 그래서 ADC 기능을 가진 MCP3008 이라는 IC를 사용하여 아날로그에서 변환된 디지털 값을 SPI통신을 이용하여 라즈베리파이로 읽을 것이다.

     

    2) SPI 통신의 이해

     - SPI 통신은 라즈베리나 아두이노 같은 마스터 장치와 주변장치들과의 시리얼 통신을 위한 통신방식입니다.

    SPI 통신을 위해서 기본적으로 마스터에서 (3개의 SPI 신호선 + 슬레이브의 갯수) 만큼의 신호선이 필요하다.

     

     - 3개의 SPI 기본신호

    MISO (master in slave out) : 슬레이브에서 마스터로 데이터가 이동

    MOSI (master out slave in) : 마스터에서 슬레이브로 데이터가 이동

    SCLK (serial clock) : 통신의 동기화를 맞추기 위한 신호로 마스터에서 만들어 보낸다.

    CS or SS (chip select or slave select) : 나머지 신호선들은 슬레이브 장치의 개수만큼 있는데 각각의 선은 슬레이브를 선택하는 신호선

     

     - 직렬통신의 동기와 비동기

    일반적인 시리얼(직렬) 통신은 비동기식으로 데이터를 보내는 쪽과 받는 쪽이 서로 알 수 없는 상태라서 비동기식 통신을 위해서는 각각의 1byte 데이터를 보내기 전에 start bit 와 끝낸 후에 stop bit이 피룡하고 서로 같은 통신 속도로 데이터를 전송해야한다.

    1) 아날로그 전압을 MCP3008로 읽어오기

    #-*-coding:utf-8-*-
    
    # 필요한 라이브러리를 불러옵니다.
    import spidev
    import time
    # 딜레이 시간 (센서 측정 간격)
    delay = 0.5
    # MCP3008 채널중 센서에 연결한 채널 설정
    pot_channel = 0
    # SPI 인스턴스 spi 생성
    spi = spidev.SpiDev()
    # SPI 통신 시작하기
    spi.open(0, 0)
    # SPI 통신 속도 설정
    spi.max_speed_hz = 100000
    # 0 ~ 7 까지 8개의 채널에서 SPI 데이터를 읽어옵니다.
    def readadc(adcnum):
      if adcnum > 7 or adcnum < 0:
        return -1
      r = spi.xfer2([1, 8 + adcnum << 4, 0])
      data = ((r[1] & 3) << 8) + r[2]
      return data
    
    while True:
      # readadc 함수로 pot_channel의 SPI 데이터를 읽어옵니다.
      pot_value = readadc(pot_channel)
      print ("---------------------------------------")
      print("POT Value: %d" % pot_value)
      time.sleep(delay) # delay 시간만큼 기다립니다.

     - 가변저항을 변경하면 MCP3008에서 읽는 초음파 값이 변한다.

     


    2) LDR 센서 실습

     - LDR은 광센서 모듈로서 빛의 세기에 따라서 저항값이 달라지는 소자이다.

    주위가 밝으면 저항값이 줄어들고, 주위가 어두워지면 저항값이 증가한다.

    (주위가 밝으면 LDR 센서의 저항이 줄어들어 3.3V에 가까운 전압이 MCP3008의 0번 채널에 입력되고

    주위가 어두우면 LDR 센서의 저항이 커져서 입력 전압이 작아진다.)

    #-*- coding: utf-8 -*-
    
    # 필요한 라이브러리를 불러옵니다.
    import spidev
    import time
    
    # 딜레이 시간 (센서 측정 간격)
    delay = 0.5
    
    # MCP3008 채널중 센서에 연결한 채널 설정
    ldr_channel = 0
    
    # SPI 인스턴스 spi 생성
    spi = spidev.SpiDev()
    
    # SPI 통신 시작하기
    spi.open(0, 0)
    
    # SPI 통신 속도 설정
    spi.max_speed_hz = 100000
    
    # 0 ~ 7 까지 8개의 채널에서 SPI 데이터를 읽어옵니다.
    def readadc(adcnum):
      if adcnum > 7 or adcnum < 0:
        return -1
      r = spi.xfer2([1, 8 + adcnum << 4, 0])
      data = ((r[1] & 3) << 8) + r[2]
      return data
    
    while True:
     # readadc 함수로 ldr_channel의 SPI 데이터를 읽어옵니다.
      ldr_value = readadc(ldr_channel)
      print ("---------------------------------------")
      print("LDR Value: %d" % ldr_value)
      time.sleep(delay)

     - 주위가 밝을 때 value가 700대였다가 센서를 가려서 주위를 어둡게 만들면 value가 200대로 떨어진다.

     


    3) 조이스틱 실습

     : 조이스틱의 X축 Y축 움직임에 따라 저항값이 변하는 가변저항이 달려있어서 X축 Y축 움직임이나 방향등을 표현할 수 있고 조이스틱을 수직으로 눌러서 스위치 기능도 가능한 모듈.

    #-*- coding: utf-8 -*-
    
    # 필요한 라이브러리를 불러옵니다.
    import spidev
    import time
    
    # 딜레이 시간 (센서 측정 간격)
    delay = 0.5
    
    # MCP3008 채널설정
    sw_channel = 0
    vrx_channel = 1
    vry_channel = 2
    
    # SPI 인스턴스 spi 생성
    spi = spidev.SpiDev()
    
    # SPI 통신 시작하기
    spi.open(0, 0)
    
    # SPI 통신 속도 설정
    spi.max_speed_hz = 100000
    
    # 0 ~ 7 까지 8개의 채널에서 SPI 데이터를 읽어옵니다.
    def readadc(adcnum):
      if adcnum > 7 or adcnum < 0:
        return -1
      r = spi.xfer2([1, 8 + adcnum << 4, 0])
      data = ((r[1] & 3) << 8) + r[2]
      return data
    
    # 무한루프
    while True:
      # X, Y 축 포지션
      vrx_pos = readadc(vrx_channel)
      vry_pos = readadc(vry_channel)
      # 스위치 입력
      sw_val = readadc(sw_channel)
      # 출력
      print("X : {} Y : {} SW : {}".format(vrx_pos, vry_pos, sw_val))
      # delay 시간만큼 기다림
      time.sleep(delay)

     - 조이스틱을 움직이지 않을 때 X축, Y축이 500정도이고, X축 Y축을 좌우로 움직이면 0~1023까지 변화하고

    조이스틱을 아래로 누르면 SW값이 변한다.

     


    3 _ I^2C 통신

     : I^2C 는 SPI 통신처럼 동기식 시리얼통신(직렬통신)이며 마스터 기기들과 슬레이브 기기들 간의 통신이 가능하면서

    2개의 통신라인(SDA, SCL)만으로 가능하여서 쉽게 구성이 가능합니다. SPI 통신에서는 슬레이브 기기가 추가 될 때마다 CS통신라인이 필요한 것에 비해 I^2C에서는 추가가 필요 없다.(하나의 통신 라인으로 여러개의 슬레이브와 소통할 수 있다)

    간단하게 동시에 많은 기기를 연결할 수 있지만 속도가 느려서 보통 저속의 주변장치 사이의 통신에 사용된다.

     

    ** I^2C 연결은 간단하게 SDA, SCL 선만 연결하면 되고 라즈베리 파이에는 SDA와 SCL에 이미 PULL UP 저항이 장착되어

    있어서 추가할 필요가 없다.

     

     1) BMP180 (대기압 센서) 실습

     - I^2C 테스트 툴을 설치해야한다.

     - BMP180의 주소 확인 ( 주소는 0x77 )

     - Adfruit BMP180 라이브러리 설치

     - BMP180으로 기온 (Temp) , 대기압 (Pressure) , 고도 (Altitude) 를 측정한 모습.

     


     2) OLED 디스플레이 실습

     

Designed by Tistory.