행복한 하루

라즈베리파이 제로 프로젝트(17) – Pioneer600 모듈 1-wire 온도센서 (DS18B20) 본문

RaspberryPi/Raspberry Pi Zero

라즈베리파이 제로 프로젝트(17) – Pioneer600 모듈 1-wire 온도센서 (DS18B20)

변화의 물결 2021. 3. 27. 19:06

 

 

안녕하세요.

 

  이번에도 온도센서에 대해서 확인해보겠습니다. 기압 센서 할 때도 나오고, 습도 센서 할 때도 나오는 기초적인 센서인데 또 등장했습니다. 그러나 센서들마다 통신 방식(I2C, ADC)이 있기 때문에 이번에는 1-wire 방식을 알아본다고 생각하시면 도움이 될 겁니다.

 

Pioneer600에 DS18B20 장착

  - DS18B20 장착할 때 방향 주의하시기 바랍니다.

1. 1-wire 통신 이해하기

  - 우선 DS18B20 센서의 배선하는 2가지 방법에 대해서 확인해보겠습니다. (DS18B20 Datasheet 참고)

  - uP(마이크로 프로세서) 쪽, 제어 신호를 보내는 쪽을 Master(마스터)라고 합니다. 그리고 센서 쪽을 명령어를 받아 응답해주는 쪽을 Slave라고 합니다.

 - 1선으로 통신하다 보니, 마이크로 프로세서(MCU)에서 DQ와 연결된 핀을 입력/출력 방향을 타임 차트에 맞게 바꿔주어야 합니다.

 

1) Parasite-powered 구성

  - GND와 VDD를 연결하고 DQ를 전원선으로 이용하는 것입니다. 그래서 DQ선에 풀업 저항 혹은 MOSFET을 통해 전원이 공급합니다. 그러면 실제 배선은 GND 해서 2선만 있으면 됩니다.

 

Parasite-Powered

2) External Supply 구성

  - 외부 전원을 이용하는 방법으로 VDD 핀에 전원을 연결하고 DQ는 데이터선으로 사용합니다.

 

External Supply

3) 통신 시작하기

  - DS18B20과 통신을 하려면 MCU(Master)는 최소 480us 정도 LOW 신호를 DS18B20(Slave)에게 보냅니다. 그리고 Master 데이터 핀을 입력으로 바꿔 Slave가 살아있다는 LOW 신호를 60~240us를 받습니다. (Presence pulse)

 

  - Master는 생존 신호(Presence Pulse) (?)를 받으면 ROM command를 Slave로 보낼 수 있습니다. Slave는 64비트의 ROM CODE(주소)를 가지고 있습니다. 여러 가지가 있겠지만, 현재 사용하는 것만 확인해보도록 하겠습니다.

 (3-1) ROM CODE

  Skip Rom [0xCC] : Master가 모든 Slave에게 동시에 Function Command를 보냅니다.

The master can use this command to address all devices on the bus simultaneously without sending out any ROM code information. For example, the master can make all DS18B20s on the bus perform simultaneous temperature conversions by issuing a Skip ROM command followed by a Convert T [44h] command. …

 

  (3-2) FUNCTION COMMAND

  - ROM Command를 보낸 후 Function Command를 보내서 Slave 가 다음 동작을 하도록 합니다. 여기서도 예제에서 사용한 기능만 확인해보겠습니다.

 

  (1) Convert T [0x44] : 온도 변환을 시작하라고 명령을 내립니다.

This command initiates a single temperature conversion. Following the conversion, the resulting thermal data is stored in the 2-byte temperature register in the scratchpad memory and the DS18B20 returns to its low-power idle state.

 

 - 주의할 점은 위에서 본 데이터 신호를 전원선으로 사용할 경우(Parasite-powered) 다시 신호선을 HIGH로 만들어 주어야 합니다. 변환되는 시간은 약 93.75 ~ 750ms 걸립니다. 그리고 Datasheet 상 Function Command 상 scratchpad라는 표현이 나오는데 DS18B20의 메모리라고 보시면 됩니다.

 

  (2) Read Scratchpad [0xBE] : Scratchpad(메모리)에서 온도 값을 가져옵니다.

This command allows the master to read the contents of the scratchpad. The data transfer starts with the least significant bit of byte 0 and continues through the scratchpad until the 9th byte (byte 8 – CRC) is read. The master may issue a reset to terminate reading at any time if only part of the scratchpad data is needed.

 

Initialization Timing

  (3-3) Read / Write 

  - 우선 쓰기 방법을 확인해보겠습니다. 한 slot당 한 비트를 보내고, slot 간 시간 간격이 1μs이상입니다.

 Master장치가 0을 전송할 때는 60 - 120μs동안 신호선을 low상태로 내리고, 1을 전송할 때는 1μs ~ 15μs 정도 low상태로 한 다음 High로 만듭니다. 그러면 Slave장치는 15μs - 60μs 사이에 sampling을 해서 값을 인식하게 됩니다.

 

- 다음은 한 비트 씩 읽는 방법입니다. 이제 Slave장치가 신호를 전송하려면, master장치가 1μs 이상 신호선을 LOW상태로 만들어야 합니다. 그 뒤에 Master는 input 모드로 바꿔 기다립니다, 그러면 Slave가 데이터를 전송하기 시작합니다.

  Slave가 0과 1을 전송해서 MCU가 입력받을 때 신호 전송 시간이 15μs 정도가 되면 그 안에 LOW, HIGH를 읽어야 합니다. 음영 칠해진 부분으로 Master는 대략적으로 12~15μs 사이에 sampling 해서 값을 읽어야 합니다.

 

Read/Write Timing

 

  - 위의 내용을 어떻게 직접 프로그래밍할까 고민할 수 있습니다. 위와 같이 작동하게 하는  것을 디바이스 드라이버 개발이라고 크게 표현하기도 합니다. 이런 부분은 센서 회사나 기타 장비회사에서 잘 만들어 놓아서 간편하게 사용하도록 해놓고 있습니다. 감사할 따름이죠. 아니면 아래의 링크처럼 칩에 맞게 계산해서 읽고 쓰기를 만들어 주어야 합니다

  

 - 참고로 로직 애널라이저로 DS18B20 송수신 신호를 분석 및 프로그래밍해 놓은 글이 있어 링크 걸어 두었습니다.

https://blog.naver.com/specialist0/221052694874

2. 회로도 확인

   - Pioneer600 에서는 외부 전원을 연결한 형태로 설계가 되어 있습니다. 그리고 라즈베리 파이 제로 P7핀과 DQ 핀이 연결되어 있습니다.

 

회로도

3. 연결하기

  - 전원 VCC와 GND, Data 핀만 연결하면 됩니다.

배선

4. 1-wire 드라이버 설정 하기

 - 1-wire를 사용하기 위해서 드라이버를 사용하도록 설정을 합니다.

  pi@raspberrypi:~/Pioneer600/DS18B20/fs $ raspi-config
 

  - “3.Interface Options” 선택

- “P7 1-Wire”를 선택

 - “one-wire interface를 사용 여부”에서 “Yes”를 선택합니다.

  - “Finish” 하고 Reboot 하겠냐고 물으면 OK를 선택해서 재부팅하고 다시 접속합니다.

5. 소스 확인

  - 위에서 1-wire 설명했던 내용들은 전혀 보이지 않습니다. “뭐지?”라고 생각할 수도 있습니다. 이것은 앞전에 말씀드린 디바이스 드라이버를 누군가 만들어 놓았기 때문에 쉽게 드라이버를 올라온 것을 읽어서 값을 출력해주면 됩니다.

 

  - modprobe를 사용해서 w1-gpio, w1-therm 드라이버를 적제 시킵니다. 그리고 값을 읽어 올 수 있는 경로를 확인하고 파일을 읽어 옵니다.

드라이버 올라온 경로 확인

  - strchr(buf, ’t’); 부분은 온도 데이터를 가져오는 디바이스 드라이버가 1-wire를 통해 hex 값을 만들어 실제 온도로 변환하여 버퍼 줄 때 ‘t’ 문자열 뒤에 온도 값을 담아서 보내주기 때문에 그 뒤 문자열을 시작 포인터를 받기 위해서 사용합니다.

 

  - atof() 문자열을 실수로 변환해주는 함수로 온도 값을 받아서 실수로 만들고 소수점 3 자리로 만들어서 출력해줍니다.

 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <time.h>

int main(int argc, char *argv[])
{
        char path[50] = "/sys/bus/w1/devices/";
        char rom[20];
        char buf[100];
        DIR *dirp;
        struct dirent *direntp;
        int fd =-1;
        char *temp;
        float value;

        system("sudo modprobe w1-gpio");
        system("sudo modprobe w1-therm");
        if((dirp = opendir(path)) == NULL)
        {
                printf("opendir error\n");
                return 1;
        }

        while((direntp = readdir(dirp)) != NULL)
        {
                if(strstr(direntp->d_name,"28-00000"))
                {
                        strcpy(rom,direntp->d_name);
                        printf(" rom: %s\n",rom);
                }
        }
        closedir(dirp);

        strcat(path,rom);
        strcat(path,"/w1_slave");
        while(1)
        {
                if((fd = open(path,O_RDONLY)) < 0)
                {
                        printf("open error\n");
                        return 1;
                }

                if(read(fd,buf,sizeof(buf)) < 0)
                {
                        printf("read error\n");
                        return 1;
                }

                temp = strchr(buf,'t');
                sscanf(temp,"t=%s",temp);
                value = atof(temp)/1000;
                printf(" temp : %3.3f °C\n",value);

                sleep(1);
        }
        return 0;
}

  

 

ds18b20:ds18b20.c
        gcc -Wall ds18b20.c -o ds18b20
clean:
        rm ds18b20

  pi@raspberrypi:~/Pioneer600/DS18B20/fs $ make clean

  pi@raspberrypi:~/Pioneer600/DS18B20/fs $ make

6. 동작 확인

  pi@raspberrypi:~/Pioneer600/DS18B20/fs $ ./ds18b20

 

  

  - 추가로 드라이버에서 어떤 데이터를 출력해주고 있는지 확인하려면

    temp = strchr(buf,'t');  소스코드 윗줄에

    printf("buf = %s\n",buf);

    추가해서 보시면 드라이버에서 제공해주는 값 형태를 알 수 있을 수 있습니다.

 

 

  내용이 길었는데 이해하는데 조금이나마 도움이 되셨으면 합니다.

  감사합니다.

 

 

<참고사이트>

1. DS18B20

https://learn.adafruit.com/adafruits-raspberry-pi-lesson-11-ds18b20-temperature-sensing/ds18b20

2. Maxim 1-wire 버스 프로토콜 (DS18B20)

https://blog.naver.com/specialist0/221052688558  

3. DS18B20 Datasheet

DS18B20.pdf
0.37MB

 

 

 

 

 

Comments