티스토리 뷰
DS18B20은 섭씨 -55 ~ +125도까지의 온도를 측정할 수 있다. 이 범위는 8비트 데이터로 충분히 처리할 수 있는 값이다. 즉, 8개의 LED로 표현이 가능하다는 뜻이다. 그러나 LED로 표시되는 온도값은 2진수이므로 사람이 직관적으로 현재 온도값을 알기가 쉽지 않다. 그래서 이번 글에서는 DS18B20에서 읽어 온 온도값을 좀 더 쉽게 알아볼 수 있는 방법에 대해서 설명하도록 하겠다.
아무래도 사람이 현재 온도를 한눈에 인식하려면 수은주처럼 막대그래프 모양이 좋을것 같다. 따라서 이번 프로젝트는 현재 온도값을 막대그래프 형태로 표시하는 방법에 대해서 알아볼 것이다.
LED의 개수가 많으면 현재 온도값만큼 LED를 켜면 좋겠지만, 가지고 있는 보드에는 단지 8개의 LED밖에 없으므로 최대한 8개의 LED로 온도를 표시하는 좋은 방법을 찾아야만 하겠다.
여러가지 방법이 있겠지만 현재의 정확한 온도값을 표현하는 것보다 프로그램이 시작할 때의 온도값 대비 그 이후에 얼마만큼의 온도 변화가 생겼는지만 표현하기로 하겠다. 이를 위하여 다음과 같은 시나리오를 구상해 봤다.
1. 프로그램이 시작 되면 초기화 과정을 수행하는 setup() 함수 마지막 부분에서 현재 온도를 한번 읽어 saved_temp라는 이름의 변수에 저장한다.
2. 반복 수행되는 loop() 함수에서 현재 온도값을 읽어 cur_temp변수에 저장한다.
3. cur_temp값이 saved_temp 값보다 커서, 즉, 온도가 올라가면 그 온도차만큼 LED를 더 켠다.
4. 반대로 cur_temp값이 saved_temp 값보다 작은 경우, 즉, 온도가 내려가면 그 수만큼 LED의 불을 끈다.
5. 시작 온도와 현재 온도의 변화가 없을때는 4개의 LED를 켜는것으로 한다. 즉, 프로그램이 시작되면 기본적으로 4개의 LED가 켜질것이고 온도가 1도 올라가면 LED를 5개 켠다. 다시 온도가 내려가면 순차적으로 LED가 하나씩 꺼지게 한다.
6. 시작 온도보다 +/- 4도까지만 표현이 가능하므로 이 이상의 온도차에 대해서는 최대 4까지만 차이가 나도록 보정을 해준다.
7. 푸쉬 버튼을 누르면 마지막으로 DS18B20으로부터 읽어 온 현재 온도값을 saved_temp 변수에 저장한다. 이렇게 되면 초기화 하는 효과를 볼 수 있다.
이 정도로 프로그램을 어떻게 작성할 지 예상해 본 후에 실제 어떻게 LED로 표현할 것인지 결과도 미리 생각해 보아야겠다. 다음과 같은 모습으로 표현하면 될것 같다.
cur - saved | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 |
LED | xxxxxxxx | xxxxxxxo | xxxxxxoo | xxxxxooo | xxxxoooo | xxxoooo | xxoooooo | xooooooo | oooooooo |
위의 표를 코드로 만들려면 배열을 이용하면 쉽게 구현할 수 있을것 같다.
led[] = {0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff};
portd->port = led[cur_temp - saved_temp + 4];
그러나 약간의 C코딩 테크닉을 발휘해서 좀더 세련되게 표현할 수도 있다. 이미 LED 제어 - 부록에서 쉬프트연산을 이용하면 동일한 결과를 얻을수 있다는 것을 설명하였다.
portd->port = (1 << (cur_temp - saved_temp + 4)) - 1;
자, 이제 실제 코드를 만들어 보자. 결과는 다음과 같은 코드가 나올것이다.
#define CRC8INIT 0x00
#define CRC8POLY 0x8C // = X^8+X^5+X^4+X^0
uint8_t crc8(uint8_t *data, int len)
{
uint8_t crc = CRC8INIT;
uint8_t i;
while (len--)
{
crc = crc ^ *data++;
for (i=0; i<8; i++)
{
crc = (crc & 0x01) ? CRC8POLY ^ (crc >> 1) : (crc >> 1);
}
}
return crc;
}
int8_t saved_temp, cur_temp;
int8_t read_current_temperature(void)
{
int8_t temp = cur_temp;
read_scratchpad();
if (crc8(scratchpad, sizeof(scratchpad)) == 0)
temp = ((scratchpad[1] << 4) & 0xF0) | ((scratchpad[0] >> 4) & 0x0F);
return temp;
}
void setup(void)
{
portb->ddr = 0x00;
portb->port = PUSH_BTN;
portd->ddr = 0xFF;
portd->port = 0x00;
saved_temp = read_current_temperature();
}
void loop(void)
{
cur_temp = read_current_temperature();
if (cur_temp - saved_temp > 4)
cur_temp = saved_temp + 4;
else if (cur_temp - saved_temp < -3)
cur_temp = saved_temp - 4;
portd->port = (1 << (cur_temp - saved_temp + 4)) - 1;
if (!(portb->pin & PUSH_BTN))
saved_temp = cur_temp;
}
위의 코드를 이용하여 보드에서 어떻게 동작되는지 확인해 보자. 프로그램이 시작되면 4개의 LED가 켜진 상태로 보일것이다. 온도가 올라가면 차례로 LED의 불이 하나씩 더 켜지고, 온도가 내려가면 하나씩 꺼질것이다. 다시 온도계를 초기화 하려면 푸쉬버튼을 누르면 즉시 4개의 LED로 켜지는 동작을 수행함으로 초기화 되는것을 확인할 수 있다.
위의 동영상은 온도를 높인 상태에서 푸쉬버튼을 눌러 초기화를 하였기 때문에 상온에서는 LED가 한개만 켜진 상태로 시작되는것을 볼 수 있다. 손으로 DS18B20을 잡으면 서서히 LED가 하나씩 켜져가는 것을 볼 수 있다.
'입문' 카테고리의 다른 글
UART - 원리와 연결 (2) | 2016.03.29 |
---|---|
_delay_ms (10) | 2016.03.27 |
LED 온도계 2 (5) | 2016.03.22 |
LED 온도계 1 (6) | 2016.03.20 |
푸쉬 버튼과 LED제어 연동 2 (1) | 2016.03.15 |