November 24, 2017

디바이스마트 미디어:

[33호]너무 쉬운 아두이노 DIY ⑤ – 캐롤송 카드 & 컬러링 온도계

Cap 2016-01-15 16-19-06-424

너무 쉬운 아두이노 DIY ⑤

캐롤송 카드 & 컬러링 온도계

글 | 신상석 ssshin@jcnet.co.kr

 

이 강의는 아두이노를 가지고 간단하게 생활에 필요한 용품을 만들어 보는 강의입니다. 뚝딱뚝딱 뭔가 자신만의 DIY 용품을 만들어 보는 쏠쏠한 재미가 있는 강의라고나 할까요? 이미 주변에 아두이노와 관련한 많은 책이 출간되었고 카페나 블로그를 통하여 강의가 진행된 경우도 꽤나 많이 있는데도 불구하고, 이 지면을 통하여 강의를 개설한 이유는 다음과 같습니다.

1. 아두이노의 초보자들을 위한 쉽고 재미있는 강의가 거의 없는 것 같아, 가능하면 초등학생(?)까지도 함께 해 볼 수 있는 그런 강의를 한 번 해보고 싶어서…
2. 아두이노를 가지고 뭔가 조금은 다른, 자신만의 창의적인(?) DIY를 할 수 있는 자리를 만들어주고 싶어서…
3. 디바이스마트매거진은 임베디드와 관련된 독자들이 많고, 발행 부수도 많아, 저와 제가 속한 회사(제이씨넷) 그리고 임베디드홀릭 카페의 홍보에 도움이 될 것 같아서…

현재 구상하고 있는 회차별 내용을 간략하게 정리해 보면 다음과 같습니다. (변경될 수 있습니다.)

회차 내용
1 3색 신호등 만들기
2 카멜레온 반지, 스위치를 이용한 신호등 게임기
3 FND로 만드는 디지털전압계, 카운트다운 계수기
4 어두워지면 켜지는 정원등, 공중회전그네
5 캐롤송 카드, 컬러링 온도계
6 스마트폰으로 조정하는 스마트카

앞으로 즐겁고 알찬 강의가 될 수 있도록 최선을 다할 것을 약속 드리며, 이 강의를 보는 독자들도 메일이나 카페를 통하여 Q&A(Question & Answer)나 피드백을 주셔서, 함께 정감을 나눌 수 있는 계기가 되기를 기대해 봅니다.

여러분, 안녕하세요. 날씨가 많이 추워지고 있습니다. 눈의 계절 겨울이 시작되고 있고, 2015년도 저물어가고 있습니다. 연말(年末)을 즐겁게 마무리하는 의미로 오늘은 다가오는 크리스마스에 사용할 멋진 캐롤송 카드와 집안에 장식하면 좋을 듯한 컬러링 온도계를 만들어보도록 하겠습니다. 카드를 열면 신나는 징글벨 음악이 나오는 캐롤송 카드를 예쁘게 만들어서 사랑하는 연인에게 선사하고, 실내 온도가 낮아지거나 높아지면 경보음이 울리는 컬러링 온도계를 만들어서 거실에 설치해 보세요~재미있을 것 같죠?

■ 소리   

아두이노를 가지고 소리를 내고 음악을 연주하기 전에 일단 소리에 대하여 간단히 알아보고 가겠습니다. 소리는 공기를 진동시켜 생성된 압력파가 귀의 고막으로 전달되어 감지되는 것인데요. 보통은 일정한 주파수를 갖는 정현파(正弦波, 사인파) 형태로 나타냅니다. 전자회로로 소리를 생성할 때는 디지털 주기 파형으로 HIGH값과 LOW값을 순간적으로 바꾸는 형태이므로 정현파가 아니라 구형파(矩形波, 사각파) 형태가 되는데 이 구형파는 정현파에 비하여 소리가 날카롭고 귀에 거슬리는 단점이 있습니다. 아두이노의 경우, DAC(Digital Analog Converter, 디지털-아날로그 변환기)를 내장한 아두이노 두에(DUE)를 제외한 다른 아두이노는 오직 구형파 형태만 생성할 수 있습니다. 우리가 가지고 있는 아두이노 UNO도 그러니까 구형파만 만들 수 있는 것이지요.

33 아두이노  (1)

소리를 구분 짓는 요소는 크게 3가지가 있는데, 그것은 높이, 세기, 맵시(소리의 3요소라 함)입니다. 소리의 높이는 보통 음계로 나타내는데, 진동수(주파수)가 많아지면(높아지면) 높은 음의 소리가 나게 됩니다. 소리의 세기는 보통 데시벨(dB)로 나타내는데, 진폭(파고)이 클 수로 큰(센) 소리가 되겠습니다. 마지막으로 소리의 맵시는 파형의 형태로 구분되는데, 소리를 생성한 소스(원인)에 따라 소리의 생긴 모양(파형)이 다르게 나타나는 것으로, 맵시가 다르기 때문에 같은 높이의 같은 세기의 소리라도 피아노 소리와 바이올린 소리는 구별이 되는 것입니다. 아래 그림을 보면 이해가 조금 더 쉽게 될 것 같네요.

33 아두이노  (2)

 

■ 삐에조 버저    

소리에 대한 기초를 공부했으니까, 이번에는 소리를 만들어내는 도구인 버저(buzzer)에 대하여 알아보겠습니다.

33 아두이노  (3)

버저는 전자석의  코일에 단속적(斷續的)으로 전류를 보내어 철판 조각을 진동시켜 내는 소리 생성 장치를 말합니다. 소리를 내는 원리는 아래와 같이 소리를 내는 철편이 전자석 근처에 있어서 전자석에 전류를 흘리면 전자석이 철편을 잡아당겨 붙게 되면서 소리가 나는 것이지요. 이렇게 전류를 흘렸다 끊었다 하는 동작을 1초에 몇 번 수행하는가에 따라, 주파수를 높이면 높은 음의 소리가 나게 되고 주파수를 낮추면 낮은 음의 소리가 나게 되는 것입니다.

33 아두이노  (4)

한편, 우리는 삐에조 버저를 사용할 것인데, 이것은 압전 현상을 이용한 것입니다. 석영(quartz)이나 세라믹과 같은 물질에 전압을 가하면 물체에 변형(늘어짐과 수축)이 생기게 되는데 이를 이용하면 공기를 진동시켜 소리를 낼 수 있습니다. 아래 왼쪽 그림은 삐에조 버저를 분해하여 본 것인데, 둥그런 판처럼 생긴 것은 수정진동자를 포함하여 2개의 서로 다른 물질이 접착된 원형 판입니다. 전원을 가하거나 끊게 되면 석영 판이 늘어나거나 수축되어 원형 판이 아래 오른쪽 그림과 같이 굽혀졌다 펴졌다 하면서 공기를 진동시켜 소리가 나게 되는 것입니다.

33 아두이노  (5) 33 아두이노  (6)

삐에조 버저도 종류가 여러가지 있지만 여기서는 간단한 BPE-1404P-40의 규격을 간단히 살펴보고 가겠습니다.

33 아두이노  (2)

5V를 연결해주고, 4000Hz 근처의 주파수를 삐에조 버저 양단에 걸어주면 약 80 데시벨(dB) 정도 크기의 소리가 날 것 같네요. 사람들이 보통 이야기하는 소리의 크기가 약 50~60 데시벨(dB) 정도이고, 청소기 돌리는 소리가 70~80 데시벨(dB) 정도라고 하니 거리가 떨어져 있다 해도 동작시키면 꽤나 큰 소리가 들릴 것 같습니다.

■ 삐 ~ 소리내기    

이 정도면 기초 지식은 갖추었으니, 삐에조 버저로 소리를 내 보도록 하겠습니다. 일단은 욕심 부리지 말고 “삐~” 소리를 4000Hz의 소리로 내 보겠습니다.
아두이노는 좋은 것이, 이렇게 보편적으로 필요로 할 것 같은 기능은 거의 다 함수(라이브러리)로 만들어 놓았다는 것입니다. 버저도 예외는 아니어서 아두이노는 소리를 내는 함수로 tone( )이라는 아주 편리한 함수를 제공합니다. 아래 내용을 보시지요.

tone(pin, frequency, duration)
– pin : 소리를 출력할 핀 번호
– frequency : 출력할 소리의 주파수
– duration : 출력할 소리의 지속 시간(ms), 인수를 생략하는 경우는 noTone() 함수를 호출하기 전까지 소리 출력이 계속됨

여기서 주의하셔야 하는 것은 tone 함수를 사용하여 버저를 제어할 경우, 버저는 반드시 PWM(Pulse Width Control)이 가능한 핀에 연결하여야 한다는 것입니다(아두이노에서 PWM이 가능한 핀은 핀 번호에 물결 표시(‘~’)가 있음).
예를 들어 5번 핀에 삐에조 버저를 연결하고, tone(5, 4000, 3000) 을 실행하면 4000Hz의 소리가 3000ms(3초) 동안 생성되겠습니다. 이거야 정말 쉽네요. 벌써 해답이 나와 버렸습니다. 바로 해 봐야겠죠?

[아두이노 연결]
아두이노 연결은 아래와 같습니다. 연결이 너무 간단하여 설명이 필요 없겠습니다. 삐에조 버저의 (+) 부분은 PWM 제어가 가능한 5번핀에 연결하고, (-) 부분은 GND에 연결하면 끝! 와우~ 정말 쉽다!

33 아두이노  (7)

[알고리즘]
구현한 규격은 조금 전에 예로 들었던, 4000Hz 음높이로 삐~ 소리를 3초간 내는 것으로 합니다. 알고리즘이라고 할 것도 없지만 굳이 형식을 취한다면 이렇게 되겠습니다.

33 아두이노  (1)

[스케치 프로그램]
자, 그럼 프로그램을 작성해 보시지요.

너무 쉬워서 바로 갑니다.

#define PIEZO 5

void setup()
{
pinMode(PIEZO, OUTPUT); // PIEZO 버저 핀은 출력
}

void loop()
{
tone(PIEZO, 4000, 3000); // 4Khz(4000) 주파수로 3초(3000) 동안 출력
delay(3000); // tone 함수 자체는 시간을 소모(delay)하지 않음
while(1) ; // 3초후 정지, 다시 시작하려면 RESET 버튼을 누름
}

tone() 함수 자체는 시간을 소모하지 않고 내부적으로 Timer/Counter를 사용하여 파형을 만드는 것이므로 소리가 날 동안 다른 일을 진행하지 않을 것이면 delay()를 주어서 동기를 맞추어 줄 필요가 있다는 것만 조심하면 될 듯 합니다.
바로 실행시켜 보겠습니다.

삐–

와~ 소리가 잘 나네요.(한 번 더 실행해 보려면 아두이노의 RESET 버튼을 누르면 됩니다!)

33 아두이노  (13)

동영상 보러가기

■ 음계      

일단 한 걸음을 내디뎠으니 반은 온 것이나 다름 없습니다. 본격적으로 캐롤송 노래 연주를 위한 작업에 들어가야 하는데, 일단, 연주를 하려면 음계를 알아야 하니까 이것부터 해결하고 가지요.
음계는 “음악에 쓰이는 음을 높이의 차례대로 배열한 음의 층계”(두산백과사전)라고 사전에 정의되어 있습니다. 쉽게 말해서 “도, 레, 미, 파, 솔, 라, 시, 도”를 말하는 것이지요. 기본 음의 주파수는 세계적으로 표준 주파수가 이미 정해져 있습니다. 예를 들어 6번째 옥타브의 주파수는 아래와 같습니다.

33 아두이노

아래쪽 ‘도’와 위쪽 ‘도’의 주파수를 비교해 보면 주파수가 2배 차이가 나는 것을 알 수 있지요. 어쨌든 음계에 따라 주파수가 정해져 있으므로 우리가 원하는 노래의 음계를 안다면, 당연히 주파수를 알 수 있고, 주파수를 안다면 그 주파수를 tone( ) 함수를 이용하여 음의 길이만큼만 실행하면 원하는 노래를 연주할 수 있을 것 같습니다. 그렇다면, 음계와 음의 길이는 악보를 찾으면 되고, 음계에 해당되는 주파수만 찾으면 되는데, 이건 당연히 … 누군가가 정리해 놓았겠죠?

맞습니다. 아두이노 예제에서 pitches.h 라는 파일을 제공하는데 여기에 각 음계에 해당되는 주파수가 모두 정의되어 있답니다. 위의 6번째 옥타브에 해당되는 것만 살펴보면 요렇게 …

#define NOTE_C6 1047 // 도 (6옥타브)
#define NOTE_CS6 1109
#define NOTE_D6 1175 // 레 (6옥타브)
#define NOTE_DS6 1245
#define NOTE_E6 1319 // 미 (6옥타브)
#define NOTE_F6 1397 // 파 (6옥타브)
#define NOTE_FS6 1480
#define NOTE_G6 1568 // 솔 (6옥타브)
#define NOTE_GS6 1661
#define NOTE_A6 1760 // 라 (6옥타브)
#define NOTE_AS6 1865
#define NOTE_B6 1976 // 시 (6옥타브)
#define NOTE_C7 2093 // 도 (7옥타브)

위의 표보다 음의 개수가 많은 것은 반음에 해당되는 것도 모두 정의되어 있기 때문인데, 하나씩 비교하여 보면 똑같다는 것을 알 수 있습니다. 음. 그럼, 이 pitches.h 파일만 include 하여 프로그램을 작성하면 되니까 이제 프로그램 작성 준비도 모두 마친 것 같습니다.
알고 보면 별 것 아니죠?

■ 캐롤송 카드     

자, 이제 준비가 다 되었으니 오늘의 메인 메뉴인 DIY 캐롤송 카드를 만들어 봅시다. GO, GO~ 먼저 기능 규격부터 살펴봅니다.

[기능 규격]

카드를 열면 3초 후에 징글벨 노래가 나오는 캐롤송 카드 만들기

이번엔 어떻게 구현하면 될 지 방법을 잠시 생각해 보겠습니다.

[구현 방법]

(1) 아두이노 PWM 핀에 삐에조 버저의 (+) 단자를, GND에 (-) 단자를 연결하고, PWM을 이용하여 ‘징글벨’ 음계에 해당되는 주파수를 음표 길이에 해당하는 시간만큼 연이어서 출력
(2) 음계에 해당되는 파일은 아두이노에 이미 “pitches.h”이 존재하므로 이를 include 하여 사용
(3) 크리스마스 카드를 만들거나 준비한 후 카드 양단에 전도성 패드를 붙이고 한쪽은 아두이노의 RESET 신호를, 다른 한 쪽은 GND에 연결해 놓고, 카드가 접혀져 있는 상태에는 두 신호가 연결되도록 함 (클립 등으로 접함, RESET 상태)
(4) 카드가 열리면 RESET 신호가 단락되도록 하여 아두이노가 실행되면서 3초후에 징글벨 노래가 연주됨

[알고리즘]

정리된 알고리즘은 아래와 같습니다.

33 아두이노  (3)

[아두이노 연결]
크리스마스 카드와 아두이노, 버저의 연결 방법은 다음과 같이 되겠네요~

(1) 지난번 버저를 연결한 형태에 추가하여, RESET 핀과 GND 핀을 점퍼선으로 끌어내어 카드가 서로 겹치는 부분에 테이프 등을 이용하여 끝을 X자 형태가 되도록 부착
(2) 카드를 접어서 RESET 점퍼선과 GND 점퍼선이 서로 단락이 되도록 하고 이 부분을 클립 등을 이용하여 고정

33 아두이노  (8)

[스케치 프로그램]
자, 그럼 아래의 징글벨 노래 악보를 보면서 프로그램을 작성해 봅시다.
길이가 길어서 저는 첫번째 줄 악보만 입력하겠으니 여유가 조금 있으신 분들은 나머지 음계를 모두 채워서 프로그램 해보시기 바랍니다.

33 아두이노  (9)

 

#include “pitches.h”
#define PIEZO 5

// 징글벨 첫 소절 음계 : 알기 쉽게 다장조의 음계로 변환하여 처리
int song[ ] = { NOTE_G4, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_G4, 0, // 솔미레도솔(쉼표)
NOTE_G4, NOTE_E5, NOTE_D5, NOTE_C5, NOTE_A4, 0, // 솔미레도라(쉼표)
NOTE_A4, NOTE_F5, NOTE_E5, NOTE_D5, NOTE_B4, 0, // 라파미레시(쉼표)
NOTE_G5, NOTE_G5, NOTE_F5, NOTE_D5, NOTE_E5, NOTE_C5, 0 }; // 솔솔파레미도(쉼표)

// 징글벨 첫 소절 연주시간
int time[ ] = { 250, 250, 250, 250, 750, 250, // 8분음표 = 250ms
250, 250, 250, 250, 750, 250,
250, 250, 250, 250, 750, 250,
250, 250, 250, 250, 500, 250, 250 };

void setup() // 한 번만 연주하게 하기 위하여
// 실행 프로그램을 setup()에서 처리
{
int i;
pinMode(PIEZO, OUTPUT); // PIEZO 버저핀은 출력
delay(3000); // 카드를 열고 3초후에 연주 시작
for (i=0; i<25; i++) // 연주 길이만큼 숫자 조정
{
tone(PIEZO, song[i], time[i]); // 배열순으로 노래 재생
delay(time[i]);
}
}

void loop() // 한 번만 연주하게 하기 위하여
{ // loop()에서는 아무 것도 처리하지 않음
}

 

노래는 한 번만 들으면 되므로 loop()가 아닌 setup() 내부에 프로그램한 점이 예전 것과 약간 다르며, 만약 연주가 반복되게 하려면 loop() 내부에 프로그램을 넣으면 됩니다.
한편, 프로그램 실행시 한가지 주의할 점은 pitches.h 파일을 추가하는 방법인데, pitches.h 파일은 다음과 같은 방법으로 현재 실행 디렉토리에 가져와야 합니다. (그냥 임의로 파일을 옮겨 놓으면 에러가 발생하므로 주의!)

(1) 프로그램에서 [스케치] ▶ [파일추가] 메뉴 선택
(2) 파일 대화 상자가 나오면 “C:\Program Files(x86)\Arduino\examples2.Digital\toneKeboard\pitches.h”를 선택하여 추가
(3) 새로운 탭이 열리면서 현재 실행 디렉토리에 pitches.h 파일이 자동으로 생성됨
(4) 이 상태에서 컴파일 후 업로드 실행

자, 어떻게 되었나요? 캐롤송이 잘 나오나요? 브라보!!! 라구요?

33 아두이노  (14)

동영상 보러가기

눈도 오고 흥겨운 캐롤송도 나오고, 기분도 UP되는 크리스마스와 연말연시를 기대해 봅니다.
Merry Christmas & Happy New Year!

이제, 두번째 DIY 작품을 만들어 보기 전에 잠시 휴식을 취하겠습니다.
각자 나름대로 스트레칭도 하고, 바깥의 신선한 공기도 마신 후 다시 시작하시지요. 모두 휴식~!

■ 온도 센서    

오늘의 두번째 DIY 주제는 “경보 장치가 내장된 컬러링 온도계”입니다.
컬러 LED를 이용하여 현재의 온도를 색깔로 나타내주고, 설정 온도 범위를 벗어나면 주기적으로 버저를 울려주는 온도계를 만들어 안방이나 거실에 장착해 보는 것으로 하겠습니다.
온도센서는 영어로는 Thermistor라고 하는데, 이것은 니켈이나 코발트, 구리, 철 등의 화합물로 이루어진 물질을 이용하여 온도를 측정하는 센서입니다. 보통 이 물질은 아래 그림과 같이 온도가 높아지면 저항값이 내려가고, 온도가 내려오면 저항값이 올라가는 특성을 가지는데 이러한 성질을 잘 이용하면 온도를 측정할 수 있습니다.

33 아두이노  (10)

예를 들어, 어떤 Thermistor 저항은 100°C 경우 1KΩ 이하, 0°C 경우 15KΩ 정도, -10°C 경우 25KΩ 정도가 됩니다.
온도값에 따라 저항값이 달라진다면, 예전에 이와 비슷한 성질을 갖는 센서가 있었는데…
예. 광센서! 빛의 세기에 따라 저항값이 달라지는 물질이었죠.
이것을 아래와 같이 연결한 후 “? V” 에 해당되는 지점을 아두이노의 ADC 포트(A0)에 연결한 후 이 값을 측정하면 광량을 측정할 수 있었습니다. 기억나시나요? 안난다면… 다시 복습! Back to the Future!

33 아두이노  (3)

그렇다면 이번에도 이와 비슷하게 아래와 같이 Thermistor를 연결하면 예전과 마찬가지로 측정이 가능하지 않을까요?

33 아두이노  (4)

예. 맞습니다. 원리가 같으니까 예전처럼 하면 되겠습니다. 온도센서가 아날로그 온도센서인 경우에는 그냥 이렇게 처리하면 되겠습니다.
그런데 한가지 더 생각해 볼 것은 아날로그 온도센서의 경우는 위에서 본 것과 같이 온도 변화에 따른 저항값이 선형적이지 않게 변화되므로 사용자가 이를 고려하여 프로그램하는 것이 매우 귀찮고 쉽지 않은 작업이라는 것입니다. 그리고 또 하나는 라즈베리파이 같이 ADC 포트가 아예 없는 마이크로콘트롤러들도 있습니다. 그래서 온도의 정확도도 높이고, 인터페이스도 단순하게 만든 디지털 온도센서가 출현하게 되었는데(물론 이것도 내부적으로는 아날로그 온도센서를 내장하고 있습니다.) 그 형태는 아래와 같습니다.

33 아두이노  (5)
내부에 디지털로직이 함께 결합되어 외부와는 UART(Universal Asynchronous Receiver/Transmitter)나 I2C(Inter Integrated Circuit), SPI(Serial Pheriperal Interface)와 같은 시리얼통신 인터페이스를 통하여 아두이노 내부의 마이크로콘트롤러에 연결되는 것이고, 이를 통하여 측정된 온도값이 전달되는 것입니다.
온도센서 모듈은 여러가지가 있지만 오늘은 I2C 통신 인터페이스를 제공하는 제이씨넷사의 JMOD-TEMP-1 디지털 온도센서를 사용하여 DIY 설계를 진행해 보겠습니다. JMOD-TEMP-1 디지털 온도센서 모듈을 사용하기 위하여는 일단 I2C에 대하여 먼저 알아야 하기 때문에, 이것부터 먼저 간단히 공부해 봅시다.

■ I2C 통신 프로토콜    

I2C는 “I Square C”라고 발음하는데, Philips 사가 1980년에 제안한 근거리용 직렬 동기식 양방향 통신 규격을 말합니다. SCL(Serial Clock, 마스터 제공 클록), SDA(Serial Data, 마스터와 슬레이브가 공유하는 데이터)의 2개 신호만 사용하여 통신하며, 최대 128개의 기기(센서 등)를 연결할 수 있는데 통신 속도는 100kbps, 400kbps, 3.4Mbps의 3가지가 대표적입니다.
연결된 모습을 보면 아래와 같습니다. SDA와 SCL 신호는 Open Drain/Open Collector 방식으로 연결되기 때문에 풀업 저항(R1, R2)을 장착해 주어야 하며 저항값은 보통 10KΩ 이상입니다.

33 아두이노  (6)

아두이노를 연결하는 경우 I2C 통신 프로토콜에 대하여 자세하게 알아야 할 필요는 없지만, 어느 정도는 원리를 이해하는 것이 도움이 될 것 같아 조금만 더 설명하도록 하겠습니다. 이 부분이 너무 어려운 분들은 세부적인 내용을 이해하지 않아도 되며, 다만, 이러한 일을 실행해야만 통신이 이루어진다는 점만 이해하고 넘어가셔도 되겠습니다.
아래 그림은 I2C 통신 규격입니다. WRITE는 마스터(예-아두이노)가 슬레이브(예-온도센서)에게 데이터(예-명령어)를 전달할 때의 규격이고 READ는 마스터(예-아두이노)가 슬레이브(예-온도센서)로부터 데이터(예-온도값)를 전달받을 때의 규격입니다.

33 아두이노  (11)

(WRITE)일 때의 동작을 간단히 설명해 보면, 다음과 같습니다.

1. 마스터는 START 신호 생성
2. 마스터는 통신하고자 하는 슬레이브 어드레스(7비트) + READ/WRITE 상태(1비트, 1이면 READ, 0이면 WRITE, 여기서는 WRITE이므로 1)의 총 8비트 생성
3. 2번 과정에서 생성한 슬레이브 어드레스에 해당되는 슬레이브가 ACKNOWLEDGE 신호 생성(해당 슬레이브가 없으면 ACKNOWLEDGE가 생성되지 않음-에러)
4. 마스터는 슬레이브에 전달하고자 하는 데이터값(예-명령어) 생성
5. 슬레이브는 데이터값을 취한 후 ACKNOWLEDGE 생성(이후 다수의 데이터가 필요한 경우 4번, 5번 과정을 필요한 만큼 반복, 마지막은 ACKNOWLEDGE를 생성하지 않을 수도 있음)
6. 마스터는 STOP 신호 생성

(READ)일 때의 동작을 간단히 설명해 보면, 다음과 같습니다.

1. 마스터는 START 신호 생성
2. 마스터는 통신하고자 하는 슬레이브 어드레스(7비트) + READ/WRITE 상태(1비트, 1이면 READ, 0이면 WRITE, 여기서는 READ이므로 0)의 총 8비트 생성
3. 2번 과정에서 생성한 슬레이브 어드레스에 해당되는 슬레이브가 ACKNOWLEDGE 신호 생성(해당 슬레이브가 없으면 ACKNOWLDEGE가 생성되지 않음-에러)
4. 슬레이브는 마스터에게 전달하고자 하는 데이터값(예-온도값) 생성
5. 마스터는 데이터값을 취한 후 ACKNOWLEDGE 생성(이후 다수의 데이터가 필요한 경우 4번, 5번 과정을 필요한 만큼 반복, ACKNOWLEDGE를 생성하지 않음)
6. 마스터는 STOP 신호 생성

여기서 START 신호와 STOP 신호, 데이터 전송값 등을 전달하는 방법은 앞서 이야기한 대로 SCL 및 SDA 신호를 아래와 같은 형태로 생성하여 처리합니다. 이해가 조금 어려운 분들은 너무 고민하지 마시고, “그냥 그렇게 된다는구만~~~” 하고 넘어가셔도 됩니다.

33 아두이노  (12)

어쨌든 결론은 이러한 I2C 통신 방법을 이용하면 아두이노가 I2C 인터페이스를 제공하는 온도센서에게서 온도값을 읽어올 수 있다는 것이지요. 얼추~ 이해는 되셨죠? 그럼, 얼른 다음으로 넘어가 봅시다.

■ JMOD-TEMP-1    

백그라운드 지식을 갖추었으니 이제 우리가 타겟으로 삼은 JMOD-TEMP-1 온도센서에 대하여 알아봅시다.
사용자 설명서에 의하면 JMOD-TEMP-1 규격은 아래와 같습니다.

· LM75A 온도센서를 기본으로 한 I2C 디지털 온도센서 모듈
· 측정 범위 : -55° ~ 125°C
· 동작 전압 : 2.7V ~ 5.5V
· 아두이노나 AVR과의 연결이 쉬운 소켓핀 타입의 I2C 인터페이스 제공
· SDA 및 SCL 신호에 pullup 저항 제공
· 내부 어드레스 A6~A3은 “1001”로 정해져 있으며, 어드레스 신호(A2, A1, A0) 값은 0과 1의 값을 선택할 수 있도록 선택용 점퍼 제공(예를 들어 점퍼를 모두 연결하면 A6~A0는 0b1001111=0x4F가 되고, 점퍼를 하나도 연결하지 않으면 A6~A0는 0b1001000=0×48이 됨)

외관은 아래와 같이 생겼습니다. 실제 크기는 엄지 손톱 크기 정도로 작습니다.

33 아두이노  (13)

배치도를 이용하여 자세히 살펴보면 아래와 같습니다. I2C 인터페이스이므로 당연히 SCL, SDA을 아두이노에 연결해야 하고, 부가적으로 VCC(+5V)와 GND도 함께 연결해 주어야 함은 물론입니다. O.S 신호는 여기서는 사용하지 않으므로 O.S 신호를 제외한 아래 4개의 신호만 아두이노와 전선으로 연결해주면 되겠습니다. 또한, A2~A0 점퍼의 장착 여부에 따라 JMOD-TEMP-1의 슬레이브 어드레스가 결정되므로 이것은 사용자가 결정하여야 합니다.

33 아두이노  (4)

다른 것은 생각하지 않고, 아두이노와 JMOD-TEMP-1과의 연결만을 나타내보면 아래와 같습니다.

[아두이노 연결]
1. JMOD-TEMP-1은 VCC(+5V), GND, SCL, SDA 신호를 해당되는 아두이노 신호와 연결
2. SCL은 아두이노의 A5 핀에, SDA는 아두이노의 A4 핀에 연결 (A5, A4 핀은 아두이노가 I2C 통신을 이용하는 경우 각각 SCL, SDA 신호로 고정됨)

33 아두이노  (14)

 

■ 아두이노 ISC 라이브러리    

LM75A에 대하여 알아보기 전에, 우리는 아두이노를 사용하여 I2C 통신을 구현하여야 하므로 일단 아두이노에서 I2C 통신을 위하여 제공하는 라이브러리가 어떤 것이 있는지 알아보는 것이 더 좋겠습니다. 왜냐하면, 이것을 알아야 이 라이브러리를 사용하여 LM75A로부터 온도값을 읽어올 스케치 프로그램에 사용할 수 있기 때문입니다. 아래를 보시지요.

[아두이노에서 제공하는 I2C 관련 함수(라이브러리)]

· Wire.begin() // I2C 버스 활성화, I2C 버스 사용 처음에 반드시 실행
· Wire.beginTransmission(address); // Start 전송 (버스 시작), address = 슬레이브 어드레스
· Wire.write(data); // Write (데이터값 Write), data = Write할 데이터값(바이트 크기)
· Wire.endTransmission(); // Stop 전송 (버스 종료)
· Wire.requestFrom(address, count); // Read Request (데이터 요청), address = 슬레이브 어드레스, count = 요청하는 데이터의 개수(바이트 수)
· Wire.available() // 데이터 도착 확인, return값 = Read한 데이터 개수
· Wire.read(); // Read (데이터값 입력), return값 = 데이터 값(바이트 크기)

물론 위 라이브러리를 사용하려면, 아두이노 스케치 프로그램의 첫머리에 “#include <Wire.h>”를 넣어주어야 하는 것도 잊지 말아야 합니다.

■ LM75A 구조 및 동작    

JMOD-TEMP-1은 내부에 온도센서 IC 칩인 LM75A를 내장하고 있으므로, 아두이노와 JMOD-TEMP-1과의 동작은 실제로는 아두이노와 LM75A와의 동작을 의미합니다. 그러므로 우리는 이제 LM75A에 대한 정보를 알아야 하겠네요. 아래는 LM75A의 구조입니다.

33 아두이노  (15)

VCC, GND 신호는 전원 신호이며, SCL, SDA 신호는 I2C 신호, A2, A1, A0 신호는 LM75A의 슬레이브 어드레스를 결정하는 어드레스 신호임은 앞에서 살펴본 것과 같습니다. A2, A1, A0 신호는 JMOD-TEMP-1 내부에 점퍼를 이용하여 값을 지정해 주는 형태로 구현되어 있으므로(이번 DIY에서는 점퍼를 장착하지 않은 상태로 진행하므로 A6~A0 = 0b1001000 = 0×48 임) 아두이노와의 직접적인 연결 신호는 VCC, GND, SCL, SDA 신호가 되겠습니다.
LM75A는 주기적으로 내부의 아날로그 온도센서의 값을 읽어 이것을 ‘Temperature Register’에 저장하는데, I2C 버스를 통하여 LM75A 내부의 ‘Temperature Register’ 값을 읽어 오려면 아래와 같은 절차를 밟아야 합니다. (LM75A datasheet 참조 요망)

(1) Start (버스 시작) 실행 및 타겟 어드레스 지정
(2) Configuration Register를 지정하는 데이터 값(00)을 Write
(3) Configuration Register가 저장할 값(01 = Temperature Register)을 Write
(4) Stop (버스 종료) 실행
(5) Start (버스 시작) 실행 및 타겟 어드레스 지정
(6) Temperature Register를 지정하는 데이터 값(01)을 Write
(7) Temperature Register로부터 2바이트 데이터를 Read 하고 이 값을 지정
(8) Stop (버스 종료) 실행

구조도를 보면서 보충 설명을 조금 더 하자면, LM75A는 내부에 Pointer Register를 가지고 있는데, 이 Pointer Register에 저장한 값(0×00~0×03)에 따라 순서대로 오른쪽 4개의 레지스터(Configuration Regitser(0×00), Temperature Register(0×01), TOS Register(0×02), THYST Register(0×03)) 중 하나를 지정하게 되고, 이 상태에서 연속하여 데이터를 읽거나(Read) 쓰면(Write), 지정된 레지스터에 대하여 값을 읽거나(Read), 쓰게(Write) 됩니다. 참고로, 세부적인 버스 상의 동작을 그림으로 나타내면 아래와 같습니다. (조금 어렵게 느껴지는 분은 그냥 넘어가셔도 됩니다.)

33 아두이노  (17)

이제 동작은 알았으니 Configuration Register의 내용과 Temperature Register의 내용이 무엇을 의미하는지만 알면 되겠습니다. 다시 LM75A 데이터시트를 찾아봐야 하겠네요. 아래와 같이 나옵니다.

33 아두이노  (5)

Nomal 모드로 동작하면 되고(B0 = 0), 다른 값들은 별 의미가 없으니 Configuration Register의 값은 0×00 으로 하면 되겠습니다.

33 아두이노  (6)

Temp Register 데이터의 값은 11비트로 부호(Sign) 비트 + 7비트 정수 + 3비트 소수 형태를 갖추고 있습니다. 2’s complement 형식으로 표현하고 있으므로 이것을 처리하면 순수 온도를 표시할 수 있을 것 같습니다. 여기서 2’s complement 표현 방식이란 음수를 표현할 때, 양수로 표현한 데이터의 complement를 취한 후(2진수로 나타내는 경우 모든 비트의 0과 1을 반대로 1과 0으로 바꿈) 이 값에 1을 더해서 표현하는 방법을 말합니다. 예를 들어 8비트의 표현에서 -3은 양수인 3의 2진값을(0b00000011), complement를 취하고(0b11111100) 여기에 1을 더해서(0b11111101) 표현하는 것입니다. 우리는 소수첫째자리를 0.5 단위까지만 표현하는 것으로 하겠습니다.
오우~, 이제 구현에 필요한 기본적인 백그라운드(Background)는 갖추어진 것 같네요.
그렇다면 최종 목표인 “경보장치가 내장된 컬러링 온도계”를 완성하러 가아죠? 계속 GO~ GO~

■ 경보장치가 내장된 컬러링 온도계    

언제나 그렇듯이 일단 목표(타겟)를 정해야 합니다. 무엇을 만들까? 어떤 기능을 하도록 만들까? 주요 기능 규격에 해당되는 것은 일단 정하고 가는 것이 중요합니다. 자, 정해볼까요?

[기능 규격]
1. 겨울철 실내(생활) 온도에 따라 컬러 LED의 색깔이 변함 (각각의 색깔은 1도 정도의 온도 변화에 따라 단계별로 변하도록 함 (보통 20도 정도가 적당한 온도라고는 하나 약간 추운듯한 느낌이 들고, 체온으로 시험해보기 위해서 아래와 같이 임의로 결정함. 여름철에는 프로그램을 다르게 해야 되겠죠?)

33 아두이노  (7)
2. 5초 마다 온도를 측정하여 온도 변화가 예전 온도와 1도 이상 오르면 높은 음으로 “삐~” 알람을 1초간 울리고, 1도 이상 내리면 낮은 음으로 “삐~” 알람을 1초간 울림
3. 최저온도(24도) 미만이거나 최고온도(29)도 이상이면 높은 음과 낮은 음을 혼합하여 “삐~뽀~삐~뽀~”를 4초간 울림

온도센서 값을 읽어오는 것은 조금 전에 배웠고, 컬러 LED의 색깔을 결정하는 방법과 tone() 함수를 이용하여 소리를 만드는 것은 이전 DIY에서 배웠으니 이것들을 조합하면 해결 방법을 찾을 수 있을 것 같습니다.

[연결도]
사용되는 부품은 아두이노 외에 3색 LED, 삐에조버저, 온도센서가 있으면 되겠네요. 3색 LED는 공통 캐소드 타입을 사용하고(RGB 핀 번호는 3색 LED마다 다를 수 있으니 각 모듈마다 확인 후 사용 요망), 버저는 삐에조버저를, 온도센서는 JMOD-TEMP-1 모듈을 사용하는 것으로 하면, 연결도는 아래와 같이 될 것 같습니다.

33 아두이노26

[알고리즘]
자, 이제 어떻게 위의 기능을 구현할 지 찬찬히 생각해봐야 할 때입니다. 일단, 온도센서로 온도를 재고, 여기에 대응되는 색깔을 찾아서 이것을 3색 LED에 디스플레이 하고, 이전(5초전)에 잰 온도보다 1도 이상 온도가 올라갔거나 내려갔으면 “삐~” 알람을 울리고, 마지막으로 온도가 24도 보다 작거나 29도 보다 크면 “삐~뽀~삐~뽀~” 알람을 울리면 되겠네요. 다시 정리해 보면 아래와 같이 되겠습니다.

33 아두이노  (8)
자, 그러면 차근차근 하나씩 구현해 볼까요?
이번 구현처럼 코드의 양이 조금 많아 지는 경우에는 코드를 처음부터 끝까지 한꺼번에 프로그램하기 보다는 기능 단위나 블록 단위로 나누어 프로그램을 작성하면 조금 더 편리합니다. 알고리즘에 쓰는 용어로 Divide-and-Conqure 방식이 자주 이용됩니다. 이것은 전체의 문제를 몇 개의 큰 덩어리로 잘라 따로 따로 해결 방법을 찾는 방식입니다. 예를 들어 올림픽 행사를 치른다고 할 때, 정부의 여러 부처가 역할을 분담하여 일을 맡고, 각 부처는 다시 하부조직인 부나 실, 팀 등으로 구분하여 일을 처리하는 것을 생각하면 이해가 빠를 겁니다. 비슷한 방법으로 프로그램에서는 이렇게 큰 덩어리로 구분한 것 각각을 하나의 함수로 할당하여 처리하면 조금 더 편리합니다. 단, 함수로 처리할 때는 입력과 출력을 정확하게 정의하여야 하는 것을 잊으시면 안됩니다.

그럼, 위의 내용을 함수로 한 번 표현해 보겠습니다.

온도값 읽기 : read_temp( )
– 리턴값 = 1바이트의 정수 온도값

온도값을 3색 LED에 디스플레이 : display_temp(unsigned char temperature)
– 입력값 = 1바이트의 온도값
– 리턴값 = 없음

알람음 발생 : tone(pin, frequency, duration)
– 아두이노 제공 라이브러러리

tone(pin, frequency, duration)
– pin : 소리를 출력할(버저가 연결된) 핀 번호
– frequency : 출력할 소리의 주파수
– duration : 출력할 소리의 지속 시간(ms)

위 함수를 기본으로 프로그램을 작성해 보겠습니다.

일단 read_temp()와 display_temp(temperature)는 잠시 후에 따로 코딩하도록 하고 전체 아우트라인을 작성해 보지요. (#include와 #define및 global 변수 선언도 일단은 생략하고 추후 코드 합체 시 넣겠습니다.)

void setup()
{
pinMode(PIEZO, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);

Wire.begin(); // I2C 활성화
Wire.beginTransmission(temp_addr); // Start (버스 시작) 및 타겟 어드레스 지정
Wire.write(byte(0×01)); // Configuration 레지스터(01) 지정
Wire.write(byte(0×00)); // Configuration 레지스터에 값(00)을 Write : Normal 모드
Wire.endTransmission(); // Stop (버스 종료)
}

void loop()
{
int i;

temperature = read_temp();// JMOD-TEMP-1 모듈로부터 측정된 온도를 읽어옴
display_temp(temperature); // 3-컬러 LED에 온도에 해당되는 색깔을 디스플레이
if ((temperature < TEMP_LOW) || (temperature >= TEMP_HIGH)) // (현재 온도 < 최저 온도) 또는 (현재 온도 >= 최고 온도) 인 경우는 “삐~뽀~삐~뽀~”(6옥타브 ‘도’ 음과 4옥타브 ‘’도’ 음을 번갈아 2번 울림
{
tone(PIEZO, NOTE_C6, 1000); delay(1000);
tone(PIEZO, NOTE_C4, 1000); delay(1000);
tone(PIEZO, NOTE_C6, 1000); delay(1000);
tone(PIEZO, NOTE_C4, 1000); delay(1000);
}
if (temperature >= (pre_temperature + TEMP_DIFF)) // 온도 1도 증가시
tone(PIEZO, NOTE_C6, 1000);// “삐~”(6옥타브 ‘도’ 음) 알람 1초 울림
else if (temperature <= (pre_temperature + TEMP_DIFF)) // 이전(5초전) 온도와 1도 차이가 나는지 비교
tone(PIEZO, NOTE_C4, 1000); // “삐~”(4옥타브 ‘도’ 음) 알람 1초 울림
pre_temperature = temperature; // 다음 측정시(5초후) 비교를 위하여 현재 온도값 저장
delay(5000); // 5초마다 측정
}

코딩은 간단하니까 주석을 보면 전체적인 흐름은 쉽게 이해가 될 것 같습니다.
삐에조버저와 3색 LED의 3핀은 모두 “~” 표시가 있는 digital 핀에 할당된 것을 주의해서 보시고(이 핀들은 모두 analog 출력 – 엄밀하게 말하면 pwm digital 출력이 가능하여야 하므로), 또한 TEMP_LOW 및 TEMP_HIGH 값은 자신이 원하는 대로 DIY해서 선택하면 되겠네요. 저는 테스트를 고려하여 24도~29도를 기준으로 잡았습니다.
그럼, 이제 read_temp() 함수를 프로그램해 보겠습니다. 모두 함께 해보시지요!

unsigned char read_temp(void)// 1 바이트 처리 (0~127도까지 표현 가능하므로)
{
unsigned char c, d;
Wire.beginTransmission(temp_addr); // Start (버스 시작) 및 타겟 어드레스 지정
Wire.write(byte(0×00)); // Temperature 레지스터(00) 지정
Wire.requestFrom(temp_addr, 2); // 2 bytes read
while(Wire.available() < 2) ; // Wating 2 byte available
c = Wire.read(); // 첫번째 데이터 저장
d = Wire.read(); // 두번째 데이터 저장
Wire.endTransmission(); // Stop (버스 종료)
return(c); // 온도의 정수부분만 반환
}

LM75A의 출력은 2’s complement 형태의 2바이트 값으로 되어 있다고 했는데, 우리는 실내온도 범위만 측정하려고 하니까 그냥 간단하게 온도값 중 정수값만 취하여 처리하도록 하겠습니다. (소수점까지 계산하려면 귀찮으니까요…) 즉, 읽어온 데이터 중 앞의 1바이트가 정수부분이고, 이 바이트의 MSB(Most Significant Bit, Bit7)만 부호인데, 실내에서는 이 값이 0이므로(영상 온도) 이것만 return 값으로 돌려주면 되겠네요. 엄청 쉽죠?

계속해서, 이번에는 display_temp(temperature) 함수를 작성해 보겠습니다. 온도값의 범위에 따라 위에서 정해진 색깔을 3색LED에 표현하면 되겠습니다. 이것은 예전 강좌(카멜레온링)를 또 참조해서 작성해야 할 것 같으니까 시간이 조금 더 걸리겠네요. 한 10분 기다릴테니, 자, 기억을 더듬거나 찾아서 해보실까요?

아, 참 이번에는 색깔 정하는 것을 그냥 아래 색상표에서 골라서 하는 것으로 해보시지요. 첫번째 바이트가 빨강에 대한 값이고, 두번째 바이트가 녹색, 세번째 바이트가 파랑입니다. 데이터는 지난번처럼 2차원 어레이로 처리하면 되겠구요.

33 아두이노  (1)

우리가 온도에 따라 사용하고자 하는 색과 여기에 해당하는 코드를 위 색상표에서 찾으면 아래와 같이 될 것 같습니다.

33 아두이노 08888

 

#define TEMP_SKYBLUE 24
#define TEMP_GREEN 25
#define TEMP_YELLOW 26
#define TEMP_ORANGE 27
#define TEMP_WINE 28
#define TEMP_RED 29

int color[7][3] = {{0×00, 0×00, 0xFF}, {0×00, 0xFF, 0xFF}, {0×00, 0xFF, 0×00}, {0xFF, 0xFF, 0×00}, {0xFF, 0×99, 0×00}, {0xFF, 0×00, 0xFF}, {0xFF, 0×00, 0×00}};// 7가지 색, 각 색마다 3가지 값, 2차원 어레이

void display_temp(unsigned char temperature)
{
if (temperature < TEMP_SKYBLUE)
{analogWrite(RED_LED, color[0][0]); analogWrite(GREEN_ LED, color[0][1]); analogWrite(BLUE_LED, color[0][2]);} // 파랑
else if (temperature < TEMP_GREEN)
{analogWrite(RED_LED, color[1][0]); analogWrite(GREEN_ LED, color[1][1]); analogWrite(BLUE_LED, color[1][2]);} // 하늘색
else if (temperature < TEMP_YELLOW)
{analogWrite(RED_LED, color[2][0]); analogWrite(GREEN_ LED, color[2][1]); analogWrite(BLUE_LED, color[2][2]);} // 연두
else if (temperature < TEMP_ORANGE)
{analogWrite(RED_LED, color[3][0]); analogWrite(GREEN_ LED, color[3][1]); analogWrite(BLUE_LED, color[3][2]);} // 노랑
else if (temperature < TEMP_SCARLET)
{analogWrite(RED_LED, color[4][0]); analogWrite(GREEN_ LED, color[4][1]); analogWrite(BLUE_LED, color[4][2]);} // 주황
else if (temperature < TEMP_RED)
{analogWrite(RED_LED, color[5][0]); analogWrite(GREEN_ LED, color[5][1]); analogWrite(BLUE_LED, color[5][2]);} // 자주
else
{analogWrite(RED_LED, color[6][0]); analogWrite(GREEN_ LED, color[6][1]); analogWrite(BLUE_LED, color[6][2]);} // 빨강
}

 

휴, 이제 코드는 다 살펴 본 것 같지요? 그럼 전체를 합쳐 보겠습니다. 이번에는 #include와 #define및 global 변수 선언도 필요한 것은 다 맞추어 넣어서 완성해야겠네요.

#include <Wire.h> // I2C 관련 라이브러리 사용 (JMOD-TEMP-1 억세스용)
#include “pitches.h” // tone() 함수 사용

#define TEMP_LOW 24 // 알람 기준 최저 온도
#define TEMP_HIGH 29 // 알람 기준 최고 온도
#define TEMP_DIFF 1 // 알람을 울리는 온도차

#define PIEZO 3 // 삐에조버저는 3번핀에 할당
#define RED_LED 5 // 빨강색은 5번핀에 할당
#define GREEN_LED 6 // 초록색은 9번핀에 할당
#define BLUE_LED 9 // 파랑색은 6번핀에 할당

#define TEMP_SKYBLUE 24
#define TEMP_GREEN 25
#define TEMP_YELLOW 26
#define TEMP_ORANGE 27
#define TEMP_WINE 28
#define TEMP_RED 29

const int temp_addr = 0×48;

int color[7][3] = {{0×00, 0×00, 0xFF}, {0×00, 0xFF, 0xFF}, {0×00, 0xFF, 0×00}, {0xFF, 0xFF, 0×00}, {0xFF, 0×99, 0×00}, {0xFF, 0×00, 0xFF}, {0xFF, 0×00, 0×00}}; // 7가지 색, 각 색마다 3가지 값, 2차원 어레이

unsigned char temperature;
unsigned char pre_temperature;

unsigned char read_temp(void) // 1바이트 처리 (0~127도까지 표현 가능하므로)
{
unsigned char c, d;
Wire.beginTransmission(temp_addr); // Start (버스 시작) 및 타겟 어드레스 지정
Wire.write(byte(0×00)); // Temperature 레지스터(00) 지정
Wire.requestFrom(temp_addr, 2); // 2 bytes read
while(Wire.available() < 2) ; // Wating 2 byte available
c = Wire.read(); // 첫번째 데이터 저장
d = Wire.read(); // 두번째 데이터 저장
Wire.endTransmission(); // Stop (버스 종료)
return(c); // 온도의 정수부분만 반환
}

void display_temp(unsigned char temperature)
{
if (temperature < TEMP_SKYBLUE)
{analogWrite(RED_LED, color[0][0]); analogWrite(GREEN_ LED, color[0][1]); analogWrite(BLUE_LED, color[0][2]);} // 파랑
else if (temperature < TEMP_GREEN)
{analogWrite(RED_LED, color[1][0]); analogWrite(GREEN_ LED, color[1][1]); analogWrite(BLUE_LED, color[1][2]);} // 하늘색
else if (temperature < TEMP_YELLOW)
{analogWrite(RED_LED, color[2][0]); analogWrite(GREEN_ LED, color[2][1]); analogWrite(BLUE_LED, color[2][2]);} // 연두
else if (temperature < TEMP_ORANGE)
{analogWrite(RED_LED, color[3][0]); analogWrite(GREEN_ LED, color[3][1]); analogWrite(BLUE_LED, color[3][2]);} // 노랑
else if (temperature < TEMP_WINE)
{analogWrite(RED_LED, color[4][0]); analogWrite(GREEN_ LED, color[4][1]); analogWrite(BLUE_LED, color[4][2]);} // 주황
else if (temperature < TEMP_RED)
{analogWrite(RED_LED, color[5][0]); analogWrite(GREEN_ LED, color[5][1]); analogWrite(BLUE_LED, color[5][2]);} // 자주
else
{analogWrite(RED_LED, color[6][0]); analogWrite(GREEN_ LED, color[6][1]); analogWrite(BLUE_LED, color[6][2]);} // 빨강
}
void setup()
{
pinMode(PIEZO, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(BLUE_LED, OUTPUT);

Wire.begin(); // I2C 활성화
Wire.beginTransmission(temp_addr); // Start (버스 시작) 및 타겟 어드레스 지정
Wire.write(byte(0×01)); // Configuration 레지스터(01) 지정
Wire.write(byte(0×00)); // Configuration 레지스터에 값(00)을 Write : Normal 모드
Wire.endTransmission(); // Stop (버스 종료)
}

void loop()
{
int i;

temperature = read_temp(); // JMOD-TEMP-1 모듈로부터 측정된 온도를 읽어옴
display_temp(temperature); // 3-컬러 LED에 온도에 해당되는 색깔을 디스플레이
if ((temperature < TEMP_LOW) || (temperature >= TEMP_HIGH)) // 현재 온도 < 최저 온도 또는 현재 온도 >= 최고 온도 인 경우는 “삐~뽀~삐~뽀~”(6옥타브 ‘도’ 음과 4옥타브 ‘’도’ 음을 번갈아 2번 울림 {
tone(PIEZO, NOTE_C6, 1000); delay(1000);
tone(PIEZO, NOTE_C4, 1000); delay(1000);
tone(PIEZO, NOTE_C6, 1000); delay(1000);
tone(PIEZO, NOTE_C4, 1000); delay(1000);
}
if (temperature >= (pre_temperature + TEMP_DIFF))
tone(PIEZO, NOTE_C6, 1000); // “삐~”(6옥타브 ‘도’ 음) 알람 1초 울림
else if (temperature <= (pre_temperature – TEMP_DIFF)) // 이전(5초전) 온도와 1도 차이가 나는지 비교
tone(PIEZO, NOTE_C4, 1000); // “삐~”(4옥타브 ‘도’ 음) 알람 1초 울림
pre_temperature = temperature; // 다음 측정시(5초후) 비교를 위하여 현재 온도값 저장
delay(5000); // 5초마다 측정
}

조금 긴 것 같긴 한데… 컴파일하고, 에러가 없다면 업로드하고, 잘 돌아라~ 얍! 이 상태에서 손가락을 JMOD-TEMP-1에 부착된 LM75A에 갖다 대면 온도가 좀 오를 테니… 한 번 해 보지요. 아래 동영상처럼 되겠네요.

33 아두이노  (9)

동영상 보러가기

손을 갖다대면 체온에 의하여 온도가 1도 올라갈 때마다 색깔이 변하고 높은 “삐~” 소리가 나지요.
손을 떼면 다시 온도가 1도 떨어지니까 낮은 “삐~” 소리가 나구요.
계속 누르고 있으면 온도가 계속 올라가서 29도 이상으로 올라가면 빨강색 LED가 켜지면서 “삐~뽀~삐~뽀~” 소리가 나는 모습을 볼 수 있겠습니다.
오~ 이번에도 성공입니다. (사실은 1번에 성공한 것이 아니라 10번도 더 고쳤답니다. 글자 오타부터 가지 각색의 에러는 항상 나타나므로 디버깅을 해서 모든 오류가 수정된 후에야 성공이지요. 여러분도 10번 정도 수정하여 성공한다면 정상입니다!)
시간이 되면 온도계 테두리도 만들고 좀 꾸미면 그럴 듯 하게 될 것 같으므로 그것은 여러분이 챙기시기 바랍니다.
오늘은 캐롤송카드와 컬러링 온도계를 제작해 보았습니다. 나름대로 자신에게 맞도록 노래를 바꾸거나 설정 온도값을 바꾸거나 구미에 맞도록 DIY하여 사용하시면 될 것 같습니다.
오늘도 수고 많이 하셨고, 다음 DIY 시간은 마지막 시간으로 “스마트폰으로 조정하는 스마트카”를 DIY해 보도록 하겠습니다.

모두모두 안녕~~~

 

 

Leave A Comment

*