본문 바로가기

개발자/Raspberry Pi

라즈베리파이와 MCP3208 ADC 컨버터 사용하기 - 회로와 소스코드





라즈베리파이와 MCP3208 ADC 컨버터 사용하기 - 회로와 소스코드 


라즈베리파이의 GPIO는 아두이노와는 다르게 디지털 입력만 가능하도록 되어있다. 라즈베리파이는 ADC(Analog Digital Converter)가 내장되어있지 않다. 그래서 별도의 ADC를 사용해서 ADC 기능을 추가해야 한다. 여기서는 MCP3208 AD 컨버터를 SPI 인터페이스를 이용해서 사용하는 방법을 설명한다.


조도센서는 광량(빛의 세기)를 센싱하여 전기적 신호로 출력하는 센서이다. 센서의 출력은 단순히 밝고 어두운 상태 만을 표시해주는 디지털 출력과 빛의 세기에 따라 값이 변하는 아날로그 출력이 있다. 테스트 할 때는 조도 센서를 사용하여 디지털 출력과 아날로그 출력 각각에 대해 실습하는게 좋은데 여기서는 아날로그 출력만을 볼것이다.


사용되는 조도센서는 6495 (4-핀) 모델 이다. 조도센서는 일정 밝기 이상에서 하이가 출력되는 디지털 출력과 빛의 양에 따라 값이 변하는 아날로그 출력이 있다. 먼저 아날로그 출력을 이용한다. 아날로그 출력 값은 8채널 12bit 아날로그 디지털 컨버터인MCP3208을 이용하여 디지털 값으로 변환하여 출력한다.


조도센서의 외형과 핀 배치는 아래 그림과 같다.


센서의 특징과 전기적 특성을 아래에 나타내었다.


특징


1. 모델명 : GL5537(5Pie Photo Resistor)  

2. 종류 : Cds Photo CELL

2. 감도 조절 (파란색 가변저항 조정)밝기와 주변 빛의 세기를 감지

3. 출력 : 아날로그 전압 출력, 디지털 스위치 출력 (0, 1)

4. Power dissipation : 100mW  

5. Max Voltage : 150Vdc or AC

6. Temp.Range: : -30~+70℃


전기적 특성


- 작동 전압 : 3.3V ~ 5V DC

- 출력 : 아날로그 전압 출력, 디지털 스위치 출력 (0, 1)

- Light Resistance at 10Lux(at 25): min 20, max 50Kohm- 측정 조건 VDD = 5V , T = 25 ℃

- Gamma Value at 10~100Lux: 0.7typ

- Dark Resistance at 0 Lux(10sec after shut off 10Lux): min 2Mohm

- Peak Spectrol Response: min 550, max 650nm


이번엔 ADC 컨버터 MCP3208 에 대해 알아보자.


MCP3208 은  8-Channel 12-Bit A/D Converters 이다. 즉, 센서의  아날로그 출력 값을 12비트의 디지털 값으로 변환하는 ADC 칩이다. 예를들어 0v ~ 3.3v 의 센서 출력 값을 0 ~ 4095 (12bit) 의 디지털 값으로 변환해주는 기능을 한다. 라즈베리파이는 GPIO (General Purpose Input / Output), SPI, I2C, 그리고 UART 통신 포트들을 가진다. 그러나 아쉽게도 ADC 기능이 없다. 때문에 MCP3208 ADC 칩을 이용하여 외부에 ADC 기능을 가지도록 한다. 라즈베리파이와 MCP3208간에는 SPI 통신으로 ADC 데이터를 가져온다.


MCP3208은 아래와 같은 핀 구조를 가지고 있다. 그 아래는 Pin 기능을 보여준다. 





이를 아래의 회로도와 같이 라즈베리파이의 SPI 포트와 연결한다. MCP3208은 총 8개의 ADC 채널(CH0~CH7)을 가지고 있다. 이번 강좌에서는 조도센서의 아날로그 출력을 CH0에 연결하고 가변저항을 돌려가면서 ADC 값이 변하는 것을 테스트 한다. 이용하고자 하는 센서를 CH0 ~ CH7 어느 곳에 연결하여 사용해도 무방하다.



사용시에 라즈베리 파이의 SPI 기능이 Disable 되어 있을때는 아래 설정 화면으로 들어가 Enable 활성화 시켜준다.








소스코드를 아래와 같은 명령으로 입력한다. 윈도우에서 마우스로 긁어서 카피한 코드는 편집 화면에서 마우스 오른쪽 키를 사용하여 붙여넣기 할 수 있다.


$nano getlightsensor.c 하여 아래 소스코드를 넣는다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <wiringPi.h> 
#include <wiringPiSPI.h> 
 
#define CS_MCP3208 11 //GPIO 8 
#define SPI_CHANNEL 0 
#define SPI_SPEED 1000000 //1Mhz
 
// spi communication with Rpi and get sensor data 
 
int read_mcp3208_adc(unsigned char adcChannel) 
{
    unsigned char buff[3];
    int adcValue = 0;
    
    buff[0= 0x06 | ((adcChannel & 0x07>> 2);
    buff[1= ((adcChannel & 0x07<< 6);
    buff[2= 0x00;
    
    digitalWrite(CS_MCP3208, 0);
    wiringPiSPIDataRW(SPI_CHANNEL, buff, 3);
    
    buff[1= 0x0f & buff[1];
    adcValue = (buff[1<< 8 ) | buff[2];
    
    digitalWrite(CS_MCP3208, 1);
    
    return adcValue;
}
 
int main(void) {
 
    unsigned char adcChannel_light = 0;
 
    int adcValue_light = 0;
 
    float vout_light;
    float vout_oftemp;
    float percentrh = 0;
    float supsiondo = 0;
    
    printf("start");
 
    
    if(wiringPiSetupGpio() == -1)
    {
        fprintf(stdout, "Unable to start wiringPi :%s\n", strerror(errno));
        return 1;
    }
    
    if(wiringPiSPISetup(SPI_CHANNEL, SPI_SPEED) == -1)
    {
        fprintf(stdout, "wiringPiSPISetup Failed :%s\n", strerror(errno));
        return 1;
    }
    
    pinMode(CS_MCP3208, OUTPUT);
    
    while(1)
    {
        adcValue_light = read_mcp3208_adc(adcChannel_light);
        
        //printf("Humiity = %u temparature = %u\n", adcValue_humi, adcValue_temp);
        printf("light sensor = %u\n", adcValue_light);
        
        delay(100);
    }
    return 0;
}
 
cs



컴파일은 아래와 같다.


$ gcc -o getlightsensor getlightsensor.c -lwiringPi


실행은 


$sudo ./getlightsemsor


아래와 같이 조도센서를 가렸다 하면서 테스트 하면 아래와 같은 결과를 볼 수 있다.



아주 밝은 빛일때의 조도센서 출력 값

 

보통 밝기에서의 조도센서 출력 값

 

어둡게 하였을 경우 조도센서 출력 값



질문사항이나 궁금한 사항은 댓글에 주세요. 





  • shs 2017.06.23 09:30 댓글주소 수정/삭제 댓글쓰기

    안녕하세요. 유용한 글 정말 잘 읽었습니다 ^^
    가스센서(mq-2)를 라즈베리파이에 연결해서 검출 값을 받으려고 하는데요, 아날로그 센서여서
    adc컨버터 PCF8591(i2c기능)을 사용하고 있습니다. 이게 4채널인데 제가 1채널에만 센서를 연결했음에도 불구하고
    나머지 채널도 다같이 값이 변동합니다.
    채널 0번에 가스센서를 연결했을 때, 시작 값이 [160,120,255,160] 이렇게 나오고 가스를 감지했을 때 [200,120,255,160] 이렇게 다른 값은 변하지 않고 채널 0번만 값이 변해야 한다고 생각을 했는데, 다른 채널에는 아무것도 연결을 안했음에도 불구하고 같이 [200,231,240,200] 이렇게 변합니다.
    연결이 잘못되었나 해서 다시 연결만 여러번 했는데 값은 여전히 다같이 변동합니다..
    따라서 나오는 값도 이게 맞게 측정되는 것인지도 의문이 듭니다..ㅠㅠ

  • 안녕하세요? I2C 인터페이스로 가스센서 연결하셨군요. 위에서 설명한것은 SPI 인터페이스로 ADC 사용한 것이니 좀 다를거고... 해서 자료를 찾아봤어요. http://wiringpi.com/extensions/i2c-pcf8591/

    여기 가보시고 구글에서 raspberry pi i2c pcf8591 이렇게 검색해보세요. 나중에 한번 해봐야겠네요. 감사합니다.

  • lsw 2017.11.08 10:15 댓글주소 수정/삭제 댓글쓰기

    안녕하세요.
    글 많이 도움되었어요. 그런데 궁금한게 있습니다..
    라즈베리파이 - MCP3208 - LM35DZ(온도센서)
    이렇게 구성하고 있는데요. 보여주신 회로에서 3.3V > 5V 로 변경하고 위와 같이 연결하였는데 아무런 출력이 나오지 않네요..
    제가 어떤걸 놓친게 있나요? ㅜㅜ

  • 3.3V 전원을과 V ref 전원을 5V 로 하시면 잘 하신거구요. 출력이 혹시 0으로 나오지 않나요? 그러니까 AD 컨버전 한 데이터가 계속 0 으로 나오는데, 이 문제는 저도 잘 모르겠습니다. 라즈베리 파이 3 로 변경되고서 기존 프로그램 데이터가 잘 안나오는 현상이 생겼습니다. 찾는대로 포스팅 하겠습니다.

    • lsw 2017.11.08 17:16 댓글주소 수정/삭제

      감사합니다 ㅜㅜ
      저 혹시나 이게 도움이 될지 모르겠는데 SPI 찾아보다 gpio load spi 명령을 하라해서 입력했는데

      "You need to run the raspi-config program (as root) and select the
      modules (SPI or I2C) that you wish to load/unload there and reboot.
      There is more information here:
      https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=97314"

      이러한 문구가 발생되구요...

      그리고,
      /etc/modprobe.d/raspi-blacklist.conf 에서 " #blacklist spi-bcm2708" 추가하였습니다...

      혹시 여기서 문제점이 있을 것 같기도해서 추가 질문드려요 ㅜㅜ

  • 라즈베리 파이3 에서는 설명하신 부분들이 자동으로 설정 됩니다. SPI Interface 를 사용한 ADC 칩은 반드시 동작해서 아날로그 값을 출력해야 되는데 - 아뿔사, 그러고 보니 다른 라즈베리 파이에서는 ADC 가 다 잘 동작되는 것으로 봐서는 환경문제같기도 합니다. 라즈베리 파이의 내부 설정 문제요. 이미지 부터 다시구워 처음부터 다시 해보는 방법도 해봐야겠습니다. 감사합니다.

  • lsw 2017.11.09 16:11 댓글주소 수정/삭제 댓글쓰기

    안녕하세요!

    일단, 같이 해결해주시려고 해서 정말 감사드립니다 ㅠㅠ
    문제 해결하였습니다.
    저 추가로 질문드린 부분에 gpio load spi에서 저런 메시지가 왜 발생되는지는 잘 모르겠습니다..

    위에 제공해주신 코드중에 " #define CS_MCP3208 11 //GPIO 8 " 여기서 SCLK port로 설정되더라구요
    " #define CS_MCP3208 8 //GPIO 8 " 이렇게 변경해주니까 잘 됩니다.

    wiringPiSetup (void);
    wiringPiSetupGpio (void);

    함수에서 따라 pin 번호가 달라지나보더라구요~~

    정말 감사합니다!!

  • 위 spi/i2c 로드하라는 메세지는 $raspi-config 설정에 가서 인에이블 하시고 부팅시 자동으로 인에이블 하라고 yes 로 설정하면 됩니다.

    그리고 아래 알려주신거 정말 감사합니다. 몇 달째 원인을 찾지 못하고 있었는데 알려주시니 너무 감사합니다. 그런 문제가 있었다니. 테스트 해보겠습니다.

  • raspberry 2018.01.24 19:12 댓글주소 수정/삭제 댓글쓰기

    MCP3208 사용할때 데이터를 받는 샘플링 속도를 조절 할 수 있나요??

    • 안녕하세요~ 특별히 정해진 샘플링 속도는 없습니다. 사용자가 센서에서 데이터를
      읽어오는 횟수가 중요합니다. 자주 읽어오든, 몇 초에 한번씩 읽어오든. 물론 ADC 자체의 샘플링 속도는 있지만, SPI 인터페이스 방식이라 데이터를 읽어오는 과정은 ADC 샘플링 속도에 영향을 받지 않습니다. 코드를 수정해서 여러번 해보시면 됩니다. ^^

  • terry0112 2018.04.09 16:57 댓글주소 수정/삭제 댓글쓰기

    안녕하세요, 라즈베리파이로 mcp3208을 연결하다가 여러번 터진 뒤에 이 글을 읽고 성공했습니다. 감사합니다. 그런데 코드를 보니 cs핀을 wiringPi 기준에서 11번 핀(채널 1)으로 설정하시고 데이터를 읽을 때 10번 핀(채널 0)으로 읽으셨는데 혹시 특별한 이유가 있나요?

    • 해결하셨다니 대단하십니다. 감사하고요~^^. 라즈베리 파이에 CS(chip select) 핀이 두 개인데 그중 CS0(물리번호 24번) gpio 11번을 쓴다는 이야깁니다.
      회로도는 초기 라즈베리파이 버전이라 이름이 틀립니다. 수정해야겠네요.
      데이터를 읽을때는 핀에는 상관이 없습니다. SPI 인터페이스니까 mosi, miso 이런 핀으로 adc3208 의 채널 0~ 채널7중의 하나를 읽어오는 것입니다. 메인 소스에 보면 adc channel = 0 이 바로 채널을 의미합니다. 감사합니다.

    • terry0112 2018.04.10 23:53 댓글주소 수정/삭제

      아 그렇군요, 사실 그것 때문에 1주 동안 고민해서요 ㅠㅠ. 초기 회로인줄 몰랐네요. 이 코드 그대로 넣고 라즈베리파이 제로 w랑 연결해도 그냥 됩니다. cs핀이 맞지 않은데도 데이터가 정확하게 들어오더라고요. 혹시 왜 그러신지 아시나요?

  • 아~ 그러니까 프로그램은 정확합니다. CS0에 연결도 잘 하신겁니다. 핀 네임에 너무 신경쓰지 마시고 데이터를 얻는 방법을 이해하시면 됩니다. 덕분에 많이 배웁니다. 감사합니다. 날 좋네요 ^^

  • 비밀댓글입니다

  • 위에서 주어진 코드에서는 mcp3208코드를 불러오는것 같은데 혹시 mcp3208.py코드 알려주실수 있을까요ㅠㅠ