#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <wiringPi.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <math.h>
#define MAX_TIME 85 // 안정적으로 데이터를 읽기 위해 타이밍 85로 정의
#define PIN 2 // PIN number for DHT11
// 서버 정보 정의
#define SERVER_ADDRESS "192.168.45.8"
#define SERVER_PORT 8080
// 변수 정의
int data[5] = {0, 0, 0, 0, 0};
float sum_temp = 0.0;
float sum_humidity = 0.0;
int read_times = 0;
int sample_count = 0;
// 함수 선언
void read_data();
void send_average(int sock);
void *server_thread(void *arg);
int main(void)
{
pthread_t thr_id;
printf("Temperature and Humidity Check through DHT11 Sensor\\n");
// wiringpu initialize & 실패 시 에러 메시지 출력
if (wiringPiSetupGpio() == -1)
{
perror("WiringPi initialization failed\\n");
return -1;
}
// 센서 데이터와 서버 연결을 위한 스레드 생성 & 실패 시 에러 메세지 출력
if (pthread_create(&thr_id, NULL, server_thread, NULL) != 0)
{
perror("Thread creation failed\\n");
return 1;
}
// 스레드 종료
pthread_join(thr_id, NULL);
return 0;
}
// 서버 연결을 위한 thread 생성
void *server_thread(void *arg)
{
struct sockaddr_in server_addr;
int sock;
// 소켓 생성
sock = socket(AF_INET, SOCK_STREAM, 0);
// 실패 시 에러 메세지 출력
if (sock == -1)
{
perror("Socket creation error\\n");
return NULL;
}
// server_add 0으로 초기화
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);
server_addr.sin_port = htons(SERVER_PORT);
// 서버에 연결 & 실패 시 에러 메세지 출력
if (connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
{
perror("Server connection failed");
close(sock);
return NULL;
}
// 성공 시 연결 성공 메세지 출력
printf("Connected to server\\n");
// 서버로 20초 간격으로 측정 데이터 평균 send
while (1)
{
send_average(sock);
delay(2000);
}
close(sock);
return NULL;
}
// 센서로부터 데이터 read
void read_data()
{
int state = HIGH;
int count = 0;
int bit_index = 0;
memset(data, 0, sizeof(data)); // 데이터를 받아 올 array 초기화
pinMode(PIN, OUTPUT); // set the pin to output mode - 파이의 핀 사용 준비
// DHT11은 PIN을 LOW로 설정하고 18ms동안 유지시 이를 데이터 요청 신호로 인식
digitalWrite(PIN, LOW); // 데이터를 받기 위해 pin을 low로 설정
delay(18); // state를 low로 18초간 유지
// PIN을 HIGH로 설정하고 40ms동안 유지시켜 센서가 데이터를 준비할 수 있는 시간을 제공
digitalWrite(PIN, HIGH); // 핀 high로 설정 - 데이터 요청 신호 종료
delayMicroseconds(40); // 센서가 준비될 때까지 40ms 대기
pinMode(PIN, INPUT); // 센서로 부터 데이터를 받기 위한 준비가 되었음을 PIN을 input으로 설정
// 데이터 읽기
for (int i = 0; i < MAX_TIME; i++)
{
count = 0;
// 각 상태에 대한 count 세기
while (digitalRead(PIN) == state)
{
count++;
delayMicroseconds(1);
// 무한루프 탈출
if (count == 255)
{
break;
}
}
// pin의 현재 상태 저장
state = digitalRead(PIN);
// 무한루프 탈출
if (count == 255)
{
break;
}
/*
처음 3번은 연결상태 확인하는 handshake부분 - 무시
DHT11 센서의 각 비트는 HIGH, LOW 상태 변화 페어로 전달함
홀수 - HIGH, 짝수 - LOW -> LOW 신호의 길이를 측정해 비트를 결정함
LOW는 비트의 시작을 알림, HIGH의 상태 길이는 비트 값을 나타냄(26-28ms:0, 70ms:1)
=> LOW 상태 이후 HIGH 상태 길이 측정하여 비트 값 결정함
*/
if ((i >= 4) && (i % 2 == 0))
{
int bit_pos = (bit_index / 8); // byte position - 현재 비트가 어느 바이트에 위치하는지
int bit_shift = 7 - (bit_index % 8); // bit shift position - 바이트 내에서의 비트의 위치.
// 비트 값 결정 후 바이트와 위치에 저장 , HIGH 상태가 16ms보다 길면 1, 짧으면 0으로 결정
int bit_value;
// count에 따라 bit_value 결정
if (count > 50)
{
bit_value = 1;
}
else
{
bit_value = 0;
}
// 결정된 비트 값을 바이트 내 올바른 위치로 이동
int shifted_bit = bit_value << bit_shift;
// data 배열에서 현재 비트를 저장할 바이트 값 get
int current_byte = data[bit_pos];
// 이동된 비트 값을 현재 바이트 값과 결합
current_byte |= shifted_bit;
// 결합된 결과 data에 다시 저장
data[bit_pos] = current_byte;
// 옆으로 index 이동
bit_index++;
}
}
// 체크섬 확인 및 데이터 출력
if ((bit_index >= 40) && (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)))
{
float humidity = (float)data[0] + (float)data[1] * 0.1;
float temperature = (float)data[2] + (float)data[3] * 0.1;
// 평균 출력을 위해 humidity,temp. 더하기
sum_humidity += humidity;
sum_temp += temperature;
// valid 한 데이터가 들어온 것에 대한 times 추가
read_times++;
printf("Humidity = %.1f%% Temperature = %.1f°C\\n", humidity, temperature);
}
else
{
printf("Invalid data. skip! \\n");
}
}
// 평균 계산 및 data send to server
void send_average(int sock)
{
char message[100];
read_data();
sample_count++;
// 측정 횟수가 10번이 넘어가면 메세지 출력
if (sample_count >= 10)
{
// valid한 값이 측정되었을 때만 평균 계산
if (read_times > 0)
{
// 평균 계산
float avg_humidity = sum_humidity / read_times;
float avg_temp = sum_temp / read_times;
// 메세지 출력
printf("Average Temperature and Humidity are calculated!\\n");
printf("Average Temperature = %.1f°C, Average Humidity = %.1f%%\\n", avg_temp, avg_humidity);
// message에 저장
snprintf(message, sizeof(message), "%.1f %.1f", avg_temp, avg_humidity);
// 서버에 전달 실패시 메세지 출력
if (send(sock, message, strlen(message), 0) == -1)
{
perror("Transmission failed");
}
}
// valid한 데이터가 센서로부터 얻지 못했을 때 오류 메세지 출력
else
{
printf("No valid data to calculate averages\\n");
}
// 반복해서 데이터를 읽고자 변수 초기화
sample_count = 0;
sum_humidity = 0.0;
sum_temp = 0.0;
read_times = 0;
}
}
: 센서로부터 온습도 데이터를 읽어와 서버로 전달하는 코드
서버에 연결한 후 2초 간격으로 센서로부터 데이터를 읽어오고, 10번 데이터를 수집한 후 서버로 유효한 데이터의 평균 값을 계산하여 전달한다
main
server_thread
send_average
call)read_data
send_average
read_data
call) 평균 값 계산 및 서버로 전달