printf("ho_tari\n");
11일차 본문
2025.03.18
오늘의 학습 목표
1. Data Sheet 보고 Coding하기
2. 동기식 protocol
(1) I2C protocol 분석
DHT11
- 온도와 습도를 모두 측정할 수 있는 센서
- 온도 : 0 ~ 50도
- 습도 : 20 ~ 90%
DHT11 통신 방식
- single bus data format으로 single-wire Two-way 방식
- 1번 측정하는데 4ms 정도 소요
- data는 40bit로 구성, 습도 정수 8bit 습도 소수 8bit 온도 정수 8bit 온도 소수 8bit checksum 8bit
- Data Format : 8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data + 8bit check sum
전체 통신 protocol
- MCU → DHT11에게 Data 전송
- MCU ← DHT11에서 Data 전송
(1) MCU에서 Start signal로 LOW Signal을 보내준 후 pull-up 후 DHT11의 응답을 기다린다.
(2) 응답신호로 DHT11에서 LOW를 보내준 후 Pull-up 후 수집한 데이터 값을 보낼 준비를 한다.
(3) 데이터 (40bit)를 전송을 한다. 완료했다면 다음 전송을 위해 50us 대기한다.
40bit를 받았을 때, Checksum 계산법
Checksum = "8bit integral RH data + 8bit decimal RH data + 8bit integral T data + 8bit decimal T data
= 0011 0101 + 0000 0000 + 0001 1000 + 0000 0000 = 0100 1101
계산된 Checksum (0100 1101) = 전송 받은 Checksum (0100 1101)이기 때문에 데이터 전송이 정상적으로 이루어졌다고 판단
→ 습도 : 0011 0101 . 0000 0000 = 53.0 %
→ 온도 : 0001 1000 . 0000 0000 = 24 ℃
세부 통신 시나리오
(1) Start Signal Handshaking : MCU가 DHT11에 Start Signal 송신 후 DHT11이 MCU에 응답
- MCU에서 Start Signal을 보낸다 (Pull Down 후 최소 18ms간 LOW 신호를 DHT11에 보내준다)
그리고 Pull-up 후 High신호를 20 ~ 40us동안 보내준다.
- 이후 DHT11은 LOW신호를 80us동안 보낸 다음 80us동안 HIGH신호를 보낸 다음 데이터 전송을 시작한다.
(2) MCU ← DHT11 Data 전송
0을 전송시
(1) 50us동안 1bit data를 LOW신호를 보낸다.
(2) HIGH 신호로 26 ~ 28us동안 보내주면 0이다.
1을 전송시
(1) 50us동안 1bit data를 LOW신호를 보낸다.
(2) HIGH신호로 70us동안 보내주면 1이다.
<main.c>
/*
* 01.LED_CONTROL.c
*
* Created: 2025-03-04 오후 4:25:34
* Author : microsoft
*/
#define F_CPU 16000000UL // 16MHZ
#include <avr/io.h>
#include <util/delay.h> // _delay_ms _delay_us
#include <avr/interrupt.h>
#include <stdio.h> // printf
#include "button.h"
#include "led.h"
#include "uart0.h"
// extern----------------------------------------------------------
extern int led_main(void); // 선언
extern void init_button(void);
extern int get_button(int button_num, int button_pin);
extern void led_all_on(void);
extern void led_all_off(void);
extern void shift_left_ledon(void);
extern void shift_right_ledon(void);
extern void shift_left_keep_ledon(void);
extern void shift_right_keep_ledon(void);
extern void flower_on(void);
extern void flower_off(void);
extern int fnd_main(void);
extern void init_uart0(void);
extern void UART0_transmit(uint8_t data);
extern void pc_command_processing(void);
extern void init_ultrasonic(void);
extern void distance_ultrasonic(void);
extern int led_state;
extern void (*funcs[])(void);
extern volatile uint8_t rx_message_received;
extern void dht11_main(void);
// 선언 ----------------------------------------------------
void init_timer0(void);
volatile int msec_count = 0;
volatile int ultrasonic_check_timer = 0;
volatile int auto_mode = 1;
volatile int led_select = 0;
FILE OUTPUT = FDEV_SETUP_STREAM(UART0_transmit, NULL, _FDEV_SETUP_WRITE);
// interrupt service routine은 반드시 main함수 이전에 정의한다.
ISR(TIMER0_OVF_vect)
{
TCNT0 = 6; // 6 ~ 256으로 돌리기 위해
msec_count++;
ultrasonic_check_timer++; // 초음파센서에 활용할 타이머!
}
int main(void)
{
init_timer0();
init_uart0();
init_ultrasonic();
stdout = &OUTPUT;
sei();
dht11_main2();
return 0;
}
// AVR의 8bit counter timer0를 초기화한다.
// 임베디드/FPGA에서 가장 중요한건 초기화 -> init함수는 특히 신경쓰기!!
void init_timer0(void)
{
// 분주 (divider / prescale)
// 16MHz / 64 down!!
// 16000000Hz / 64 = 250,000 Hz 로 만든다!
// T(주기) = 1clock에 걸리는 시간 = 1 / 250000 = 0.000004sec = 0.004ms (4us)
// 8bit timer overflow 발생 시 소요시간 = 0.004ms * 256 = 1.024ms = 0.001024sec
// -> interrupt를 정확하게 1ms마다 오게 하고싶으면,
// 사용자 지정으로 256이 아니라 250클록마다 인터럽트가 생기도록
// TCMT0 초기값 설정
TCNT0 = 6; // 정확히 1ms를 세기 위해 초기값을 0이 아니라 6으로 해준다. (250 펄스 이후에 인터럽트)
// 분주비 설정 (64)
TCCR0 |= 1 << CS02 | 0 << CS01 | 0 << CS00;
// timer overflow interrupt 허용 (TIMER0 OVF)
TIMSK |= 1 << TOIE0; // 지역 인터럽트 허용
}
<dht11.c>
/*
* dht11.c
*
* Created: 2025-03-18 오전 10:52:34
* Author: microsoft
*/
#include "dht11.h"
void init_dht11(void);
void dht11_main(void);
char * error_log = " ";
void init_dht11(void)
{
DHT_DDR |= 1 << DHT_PIN_NUM;
DHT_PORT |= 1 << DHT_PIN_NUM; // idle상태가 HIHG임
}
void signal_us_check(int duration, int binary_choice)
{
us_count = 0;
while(((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM) == binary_choice)
{
_delay_us(2);
us_count += 2;
if(us_count > duration)
{
state = TIMEOUT;
return;
}
}
}
int dht11_get_bit(void)
{
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
_delay_us(2);
us_count += 2;
if(us_count > 90)
{
state = TIMEOUT;
return -1;
}
}
if(us_count < 40) return 0;
else if(us_count >= 40) return 1;
}
void dht11_main2(void)
{
uint8_t data[5] = {0,}; // 온습도 데이터 5바이트를 저장할 공간
init_dht11();
while(1)
{
_delay_ms(1000);
memset(data, 0, sizeof(data)); // data 초기화
state = OK;
// ================ step 1 : start signal ======================
// idel상태인 HIGH를 100ms 유지 -> 이 후 LOW로 바꾸어 준다.
init_dht11();
_delay_ms(100);
DHT_PORT &= ~(1 << DHT_PIN_NUM);
_delay_ms(20); // LOW상태를 최소 18ms 유지해야함
DHT_PORT |= 1 << DHT_PIN_NUM; // start signal을 보낸 다음에는 HIGH로 유지해야함
DHT_DDR &= ~(1 << DHT_PIN_NUM); // input모드로 변경
_delay_us(1);
// response signal check
signal_us_check(50, HIGH);
if(state != OK)
{
error_log = "response signal check faile";
continue;
}
// ============= step 2 : response signal check =============
// step 2 실행 (정상적으로 DATA pin에 LOW가 감지된것)
signal_us_check(100, LOW);
if(state != OK)
{
error_log = "step 2, response signal low check faile";
continue;
}
// response high 체크
// LOW가 80us 정도 유지되고 (그니까 100us이내에) 잘 HIGH를 유지했는지 확인
signal_us_check(100, HIGH);
if(state != OK)
{
error_log = "step2, response signal high fail";
continue;
}
// 여기서 state가 OK면 hand shaking이 잘 마무리된것!!
// == DTAT LINE은 지금 LOW 상태임
// ============= step 3 : data bit receive from DHT11 =============
// 40개의 pulse를 count 한다
// -> 8비트식 한 바이트를 이루어 의미를 띄므로, 8비트씩 묶어야함
// '0' : LOW 50us, HIGH 26~28us
// '1' : LOW 50us, HIGH 70us
for(int i = 0; i<5; i++)
{
uint8_t pulse[8] = {0,}; // 1개의 pulse를 저장할 변수 (8비트 저장)
for(int j = 7; j>=0; j--)
{
// LOW 50us 확인
signal_us_check(70, LOW);
if(state == TIMEOUT)
{
i = 5;
j = -1;
error_log = "get bit, 50us low check fail";
}
// state 확인 필수!
// HIGH가 몇 us인지 확인
int dht11_bit = dht11_get_bit();
if(state == OK) pulse[j] = dht11_bit;
else error_log = "get bit, high faile";
}
// pulse를 가지고 data로 넣어주기!
if(state == OK)
{
data[i] = pulse[0] << 0 | pulse[1] << 1 | pulse[2] << 2 | pulse[3] << 3 |
pulse[4] << 4 | pulse[5] << 5 | pulse[6] << 6 | pulse[7] << 7;
}else{
error_log = "get bit fail";
}
}
// 5바이트 다 받아옴
// check sum 확인!!
if(state == OK)
{
if(data[4] != data[0] + data[1] + data[2] + data[3])
{
// check sum이 맞지 않는 상황
state = VALUE_ERROR;
}
}else{
error_log = "get bit faile 2";
}
_delay_us(60); // 제일 마지막 단계!! 50us LOW상태 유지
// 값 출력
if(state == OK)
{
printf("temp : %d.%d\n", data[2], data[3]);
printf("humidity : %d.%d\n", data[0], data[1]);
}else
{
printf("ERROR : %d\n", state);
}
_delay_ms(1000); // 2초정도 안정화 시간이 필요
}
}
void dht11_main(void)
{
uint8_t data[5] = {0,}; // 온습도 데이터 5바이트를 저장할 공간
init_dht11();
while(1)
{
memset(data, 0, sizeof(data)); // data 초기화
state = OK;
// ================ step 1 : start signal ======================
// idel상태인 HIGH를 100ms 유지 -> 이 후 LOW로 바꾸어 준다.
init_dht11();
_delay_ms(100);
DHT_PORT &= ~(1 << DHT_PIN_NUM);
_delay_ms(20); // LOW상태를 최소 18ms 유지해야함
DHT_PORT |= 1 << DHT_PIN_NUM; // start signal을 보낸 다음에는 HIGH로 유지해야함
DHT_DDR &= ~(1 << DHT_PIN_NUM); // input모드로 변경
_delay_us(1);
// response signal check
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태인지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 50)
{
// HIGH상태가 50us가 지나도 안떨어진다
// == response가 안들어 온거니까 문제가 생긴것
state = TIMEOUT;
break;
}
}
// ============= step 2 : response signal check =============
if(state == OK)
{
// step 2 실행 (정상적으로 DATA pin에 LOW가 감지된것)
us_count = 0;
while(!((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM))
{
// LOW상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 100)
{
// LOW상태가 100us가 지나도 HIGH로 안올라가면
// 뭔가 정상적인 반응이 되돌아온게 아닌것!!
state = TIMEOUT;
break;
}
}
}
// response high 체크
if(state == OK)
{
// LOW가 80us 정도 유지되고 (그니까 100us이내에) 잘 HIGH를 유지했는지 확인
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 100)
{
// HIGH상태가 100us가 지나도 안떨어지면 뭔가 문제!
state = TIMEOUT;
break;
}
}
}
// 여기서 state가 OK면 hand shaking이 잘 마무리된것!!
// == DTAT LINE은 지금 LOW 상태임
// ============= step 3 : data bit receive from DHT11 =============
// 40개의 pulse를 count 한다
// -> 8비트식 한 바이트를 이루어 의미를 띄므로, 8비트씩 묶어야함
// '0' : LOW 50us, HIGH 26~28us
// '1' : LOW 50us, HIGH 70us
if(state == OK)
{
for(int i = 0; i<5; i++)
{
uint8_t pulse[8] = {0,}; // 1개의 pulse를 저장할 변수 (8비트 저장)
for(int j = 7; j>=0; j--)
{
// LOW 50us 확인
us_count = 0;
while(!((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM))
{
// LOW상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 70) // 여유둬서 70으로 check
{
state = TIMEOUT;
j = -1;
i = 5; // for문 두개를 한번에 빠져나가기 위해
break;
}
}
// state 확인 필수!
// HIGH가 몇 us인지 확인
if(state == OK)
{
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 90) // 70인데, 약간 여유주는것!
{
// HIGH상태가 90us가 지나도 안떨어지면 뭔가 문제!
state = TIMEOUT;
j = -1;
i = 5; // for문 두개를 한번에 빠져나가기 위해
break;
}
}
}
// '0' : HIGH 26~28us
// '1' : HIGH 70us
if(state == OK)
{
if(us_count < 40) // '0'
{
pulse[j] = 0;
}else if(us_count >= 40) // '1'
{
pulse[j] = 1;
}
}
}
// pulse를 가지고 data로 넣어주기!
if(state == OK)
{
data[i] = pulse[0] << 0 | pulse[1] << 1 | pulse[2] << 2 | pulse[3] << 3 |
pulse[4] << 4 | pulse[5] << 5 | pulse[6] << 6 | pulse[7] << 7;
}
}
// 5바이트 다 받아옴
// check sum 확인!!
if(state == OK)
{
if(data[4] != data[0] + data[1] + data[2] + data[3])
{
// check sum이 맞지 않는 상황
state = VALUE_ERROR;
}
}
_delay_us(60); // 제일 마지막 단계!! 50us LOW상태 유지
// 이 다음 HIGH를 유지해줘야함
/*
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 90)
{
// HIGH상태가 100us가 지나도 안떨어지면 뭔가 문제!
//printf("timeout\n");
state = TIMEOUT;
break;
}
}
if(us_count < 90)
{
// 데이터시트에는 안나와있는데
// HIGH를 90us동안 유지하지 않으면
// 뭔가 data가 계속 발생하고 있는것
state = TRANS_ERROR;
}*/
}
// 값 출력
if(state == OK)
{
printf("temp : %d.%d\n", data[2], data[3]);
printf("humidity : %d.%d\n", data[0], data[1]);
}else
{
printf("ERROR : %d\n", state);
}
_delay_ms(2000); // 2초정도 안정화 시간이 필요
}
}
<dht11.h>
/*
* dht11.h
*
* Created: 2025-03-18 오전 10:52:27
* Author: microsoft
*/
#ifndef DHT11_H_
#define DHT11_H_
#define F_CPU 16000000UL // 16MHZ
#include <avr/io.h>
#include <util/delay.h> // _delay_ms _delay_us
#include <avr/interrupt.h>
#include <stdlib.h>
#include <stdio.h> // printf
#define DHT_DDR DDRG
#define DHT_PORT PORTG
#define DHT_PIN PING
#define DHT_PIN_NUM 0
#define HIGH 1
#define LOW 0
uint8_t us_count = 0;
enum state_define {OK, TIMEOUT, VALUE_ERROR, TRANS_ERROR};
// #define 나열하는것보다 enum 쓰는게 더 깔끔할 수 있음
enum state_define state = OK; // 앞으로 관리할 state변수 생성 (초기값 OK)
#endif /* DHT11_H_ */
<실행 결과>
<dht11.c 함수 최적화>
/*
* dht11.c
*
* Created: 2025-03-18 오전 10:52:34
* Author: microsoft
*/
#include "dht11.h"
void init_dht11(void);
void dht11_main(void);
char * error_log = " ";
void init_dht11(void)
{
DHT_DDR |= 1 << DHT_PIN_NUM;
DHT_PORT |= 1 << DHT_PIN_NUM; // idle상태가 HIHG임
}
void signal_us_check(int duration, int binary_choice)
{
us_count = 0;
while(((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM) == binary_choice)
{
_delay_us(2);
us_count += 2;
if(us_count > duration)
{
state = TIMEOUT;
return;
}
}
}
int dht11_get_bit(void)
{
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
_delay_us(2);
us_count += 2;
if(us_count > 90)
{
state = TIMEOUT;
return -1;
}
}
if(us_count < 40) return 0;
else if(us_count >= 40) return 1;
}
void dht11_main2(void)
{
uint8_t data[5] = {0,}; // 온습도 데이터 5바이트를 저장할 공간
init_dht11();
while(1)
{
_delay_ms(1000);
memset(data, 0, sizeof(data)); // data 초기화
state = OK;
// ================ step 1 : start signal ======================
// idel상태인 HIGH를 100ms 유지 -> 이 후 LOW로 바꾸어 준다.
init_dht11();
_delay_ms(100);
DHT_PORT &= ~(1 << DHT_PIN_NUM);
_delay_ms(20); // LOW상태를 최소 18ms 유지해야함
DHT_PORT |= 1 << DHT_PIN_NUM; // start signal을 보낸 다음에는 HIGH로 유지해야함
DHT_DDR &= ~(1 << DHT_PIN_NUM); // input모드로 변경
_delay_us(1);
// response signal check
signal_us_check(50, HIGH);
if(state != OK)
{
error_log = "response signal check fail";
continue;
}
// ============= step 2 : response signal check =============
// step 2 실행 (정상적으로 DATA pin에 LOW가 감지된것)
signal_us_check(100, LOW);
if(state != OK)
{
error_log = "step 2, response signal low check fail";
continue;
}
// response high 체크
// LOW가 80us 정도 유지되고 (그니까 100us이내에) 잘 HIGH를 유지했는지 확인
signal_us_check(100, HIGH);
if(state != OK)
{
error_log = "step2, response signal high fail";
continue;
}
// 여기서 state가 OK면 hand shaking이 잘 마무리된것!!
// == DTAT LINE은 지금 LOW 상태임
// ============= step 3 : data bit receive from DHT11 =============
// 40개의 pulse를 count 한다
// -> 8비트식 한 바이트를 이루어 의미를 띄므로, 8비트씩 묶어야함
// '0' : LOW 50us, HIGH 26~28us
// '1' : LOW 50us, HIGH 70us
for(int i = 0; i<5; i++)
{
uint8_t pulse[8] = {0,}; // 1개의 pulse를 저장할 변수 (8비트 저장)
for(int j = 7; j>=0; j--)
{
// LOW 50us 확인
signal_us_check(70, LOW);
if(state == TIMEOUT)
{
i = 5;
j = -1;
error_log = "get bit, 50us low check fail";
}
// state 확인 필수!
// HIGH가 몇 us인지 확인
int dht11_bit = dht11_get_bit();
if(state == OK) pulse[j] = dht11_bit;
else error_log = "get bit, high fail";
}
// pulse를 가지고 data로 넣어주기!
if(state == OK)
{
data[i] = pulse[0] << 0 | pulse[1] << 1 | pulse[2] << 2 | pulse[3] << 3 |
pulse[4] << 4 | pulse[5] << 5 | pulse[6] << 6 | pulse[7] << 7;
}else{
error_log = "get bit fail";
}
}
// 5바이트 다 받아옴
// check sum 확인!!
if(state == OK)
{
if(data[4] != data[0] + data[1] + data[2] + data[3])
{
// check sum이 맞지 않는 상황
state = VALUE_ERROR;
}
}else{
error_log = "get bit fail 2";
}
_delay_us(60); // 제일 마지막 단계!! 50us LOW상태 유지
// 값 출력
if(state == OK)
{
printf("temperature : %d.%d\n", data[2], data[3]);
printf("humidity : %d.%d\n", data[0], data[1]);
}else
{
printf("ERROR CODE : %d\n", state);
}
_delay_ms(1500); // 2초정도 안정화 시간이 필요
}
}
void dht11_main(void)
{
uint8_t data[5] = {0,}; // 온습도 데이터 5바이트를 저장할 공간
init_dht11();
while(1)
{
memset(data, 0, sizeof(data)); // data 초기화
state = OK;
// ================ step 1 : start signal ======================
// idel상태인 HIGH를 100ms 유지 -> 이 후 LOW로 바꾸어 준다.
init_dht11();
_delay_ms(100);
DHT_PORT &= ~(1 << DHT_PIN_NUM);
_delay_ms(20); // LOW상태를 최소 18ms 유지해야함
DHT_PORT |= 1 << DHT_PIN_NUM; // start signal을 보낸 다음에는 HIGH로 유지해야함
DHT_DDR &= ~(1 << DHT_PIN_NUM); // input모드로 변경
_delay_us(1);
// response signal check
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태인지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 50)
{
// HIGH상태가 50us가 지나도 안떨어진다
// == response가 안들어 온거니까 문제가 생긴것
state = TIMEOUT;
break;
}
}
// ============= step 2 : response signal check =============
if(state == OK)
{
// step 2 실행 (정상적으로 DATA pin에 LOW가 감지된것)
us_count = 0;
while(!((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM))
{
// LOW상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 100)
{
// LOW상태가 100us가 지나도 HIGH로 안올라가면
// 뭔가 정상적인 반응이 되돌아온게 아닌것!!
state = TIMEOUT;
break;
}
}
}
// response high 체크
if(state == OK)
{
// LOW가 80us 정도 유지되고 (그니까 100us이내에) 잘 HIGH를 유지했는지 확인
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 100)
{
// HIGH상태가 100us가 지나도 안떨어지면 뭔가 문제!
state = TIMEOUT;
break;
}
}
}
// 여기서 state가 OK면 hand shaking이 잘 마무리된것!!
// == DTAT LINE은 지금 LOW 상태임
// ============= step 3 : data bit receive from DHT11 =============
// 40개의 pulse를 count 한다
// -> 8비트식 한 바이트를 이루어 의미를 띄므로, 8비트씩 묶어야함
// '0' : LOW 50us, HIGH 26~28us
// '1' : LOW 50us, HIGH 70us
if(state == OK)
{
for(int i = 0; i < 5; i++)
{
uint8_t pulse[8] = {0,}; // 1개의 pulse를 저장할 변수 (8비트 저장)
for(int j = 7; j >= 0; j--)
{
// LOW 50us 확인
us_count = 0;
while(!((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM))
{
// LOW상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 70) // 여유둬서 70으로 check
{
state = TIMEOUT;
j = -1;
i = 5; // for문 두개를 한번에 빠져나가기 위해
break;
}
}
// state 확인 필수!
// HIGH가 몇 us인지 확인
if(state == OK)
{
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 90) // 70인데, 약간 여유주는것!
{
// HIGH상태가 90us가 지나도 안떨어지면 뭔가 문제!
state = TIMEOUT;
j = -1;
i = 5; // for문 두개를 한번에 빠져나가기 위해
break;
}
}
}
// '0' : HIGH 26~28us
// '1' : HIGH 70us
if(state == OK)
{
if(us_count < 40) // '0'
{
pulse[j] = 0;
}else if(us_count >= 40) // '1'
{
pulse[j] = 1;
}
}
}
// pulse를 가지고 data로 넣어주기!
if(state == OK)
{
data[i] = pulse[0] << 0 | pulse[1] << 1 | pulse[2] << 2 | pulse[3] << 3 |
pulse[4] << 4 | pulse[5] << 5 | pulse[6] << 6 | pulse[7] << 7;
}
}
// 5바이트 다 받아옴
// check sum 확인!!
if(state == OK)
{
if(data[4] != data[0] + data[1] + data[2] + data[3])
{
// check sum이 맞지 않는 상황
state = VALUE_ERROR;
}
}
_delay_us(60); // 제일 마지막 단계!! 50us LOW상태 유지
// 이 다음 HIGH를 유지해줘야함
/*
us_count = 0;
while((DHT_PIN & 1 << DHT_PIN_NUM) >> DHT_PIN_NUM)
{
// HIGH상태가 얼마나 지속되는지 check한다
_delay_us(2);
us_count += 2;
if(us_count > 90)
{
// HIGH상태가 100us가 지나도 안떨어지면 뭔가 문제!
//printf("timeout\n");
state = TIMEOUT;
break;
}
}
if(us_count < 90)
{
// 데이터시트에는 안나와있는데
// HIGH를 90us동안 유지하지 않으면
// 뭔가 data가 계속 발생하고 있는것
state = TRANS_ERROR;
}*/
}
// 값 출력
if(state == OK)
{
printf("temperature : %d.%d\n", data[2], data[3]);
printf("humidity : %d.%d\n", data[0], data[1]);
}else
{
printf("ERROR CODE : %d\n", state);
}
_delay_ms(1500); // 2초정도 안정화 시간이 필요
}
}
<ComportMaster 결과>
<오실로스코프 파형 분석>
<Checksum 확인>
0001 0101
0000 0000
0001 1010
+ 0000 0111
------------------
0011 0110
I2C (Inter Intergrated Circuit)
통신
- 비동기식 : clock 신호에 무관하게 Data를 송수신하는 방식 예) CDMA, UART
- 동기식 : clock 신호에 맞춰서 Data를 송수신하는 방식 예) I2C, SPT
- SDA : 데이터를 주고 받기 위한 선 1가닥
- SCL : 송수신 동기화를 위한 선 1가닥
- 하나의 Master에 최대 127의 slave를 연결 가능
- I2C 통신은 동기식 통신 방식(클럭 신호를 이용해서 데이터의 전송 타이밍을 맞춤)으로 시리얼 통신 (UART)처럼 통신속도가 따로 정해져 있지 않다.
I2C 통신 타이밍 Sequence
1) SDA와 SCL 라인의 신호는 풀업 저항에 의해 Idle(평소)에는 High신호를 유지하다가 마스터가 슬레이브와 통신을 시도하기 위해서는 SDA신호를 Low로 떨어 트린다.
2) 그러면 Slave는 통신 시작 신호로 받아 들이고 Master는 SCL 라인으로 Clock신호를 만들어 낸다.
3) 클럭신호가 Low일때 SDA 신호를 비트 신호로 바꾸는 시간 (파란색) 이다. 4) 클럭신호가 High일때 SDA신호를 읽는 시간(녹색)이다.
3)와 4)를 반복하면서 1 클럭에 1byte씩 데이터 전송 한다.
5) 모든 비트의 전송이 끝난 후 SCL 신호가 High가 되면 SDA 신호도 High로 만들어 정지 신호 P(주황색)을 만든다.
Handshaking process in I2C
I2C protocol 오실로스코프 분석
'(Telechips) AI 시스템 반도체 SW 개발자 교육 > ATmega128A 마이크로컨트롤러 프로그래밍' 카테고리의 다른 글
13일차 (0) | 2025.03.20 |
---|---|
12일차 (0) | 2025.03.19 |
9일차 (0) | 2025.03.16 |
8일차 (0) | 2025.03.13 |
7일차 (0) | 2025.03.12 |