- 센서에 입력되는 신호가 임계값을 넘으면 Low/High를 출력하는 센서 모듈
- Low/High를 출력하는 센서 모듈 예
- PIR(인체 감지) 센서모듈(HC-SR501)
- Sound 센서모듈(SZH-EK033)
- 홀 센서(Hall Sensor) WSH131
- Low/High를 출력하는 센서 모듈을 제어하는 구성도
- Low/High를 출력하는 센서 모듈을 제어하는 프로그램 예
- Analog 전압을 출력하는 센서 모듈
- ADC(Analog to Digital Conversion) object(class ADC)
- Analog 전압을 출력하는 센서 모듈 예
- 물 수위 센서(Water Level Sensor)
- 포토 센서(GL5516)
- 온도 센서(LM35DZ)
- Analog voltage를 출력하는 센서 모듈을 사용하는 구성도
- Analog voltage를 출력하는 센서 모듈을 사용하는 프로그램 예
- 펄스폭(Pulse width) 출력 모듈
- Single-Wire 통신을 사용하는 센서
- I2C 통신을 사용하는 모듈
- AVR(Atmega128) 센서(Sensors)와 센서 모듈(Sensor Modules) 관련 페이지 보기
- Low/High를 출력하는 센서 모듈 예
- Low/High를 출력하는 센서 모듈을 사용하는 구성도
- Low/High를 출력하는 센서 모듈을 제어하는 프로그램 예
- Input port의 값을 이용하는 예
- PIR 센서모듈(HC-SR501)의 상태를 LED에 표시하는 프로그램 예(Atmel Studio 7): sensor_handler.zip
아래 사진은 자주 자용하는 Low/High를 출력하는 센서 모듈의 예 이다. 아래 예의 센서는 입력 신호가 미리 정해진 임계치를 넘으면 Low 상태에서 High 상태(or High 상태에서 Low 상태)로 천이(Rising edge or Falling edge)하기 때문에 External Interrupt 처리 방식으로 제어 할 수 있다.
윗 예의 센서 모듈은 입력 신호가 임계치를 넘기면 Low 상태에서 High 상태(or High 상태에서 Low 상태)로 천이하기 때문에 Input port의 값(또는 변동)을 이용하여 센서의 상태를 입력 받을 수 있다.
PIR 센서모듈(HC-SR501)은 제어 기능(인체가 감지되면 일정시간 동안 High 상태를 유지하는 기능, High 상태에서 Low 상태로 천이하면 일정시간 신호를 감지하지 않는 기능 등)을 내장하고 있기 때문에 마이크로 콘트롤러를 사용하지 않아도 대부분의 용도에 사용할 수 있다. 아래 프로그램은 PIR 센서모듈의 출력을 LED에 보여 주는 간단한 프로그램 예 이다.
// Target : Atmega128
// Crystal: 16Mhz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
void port_init(void)
{
	// Sensor의 출력신호를 PE4에 연결 하고 다른 한 단자는 GND에 연결한다.
	DDRE &= (~0x10);	// PORTE의 PE4를 Input Port로 설정
	PORTF = 0x00;		// PORTF의 초기값 설정(PORTF의 LED가 꺼진 상태)
	DDRF  = 0xff;		// PORTF를 Output Port로 설정
}
// Initialize all peripherals
void init_devices(void)
{
	cli();         // Disable all interrupts
	port_init();   // I/O Port init
	sei();         // Re-enable interrupts
}
int main (void)
{
	init_devices();
	
	// Infinite loop
	while(1){
		// PE4 가 Low인 경우
		if((PINE & 0x10) == 0){
			PORTF &= ~0x01;		// LED(PF0): Turn off
		}
		// PE4 가 High인 경우
		else {
			PORTF |= 0x01;		// LED(PF0): Turn on
		}
	}
	return 0;
}
          - Atmega128 개발보드와 센서 모듈 연결
- Atmega128 개발보드 PE4 <-> 센서의 Output pin
- Atmega128 개발보드 VDD(5V) <-> 센서의 Power pin.
- Atmega128 개발보드 GND <-> 센서 GND
- Output port(PF0)에 LED 연결
- PF0에 저항(330Ω)과 LED를 직열로 연결한다.
- sensor_handler.zip 파일을 Download하여 압축을 해제한다.
- sensor_handler.hex를 개발 보드에 Upload 한다.
- 실험:
- 개발 보드의 프로그램(sensor_handler)을 실행한다.
- Atmega128 개발보드의 프로그램을 실행하고 PIR(인체 감지) 센서모듈(HC-SR501) 앞에 손(인체)을 가까이 접근 시킨다.
- 센서모듈(HC-SR501)이 인체를 감지하면 일정 시간(센서 모듈에서 설정된 시간) 동안 LED가 Turn on 상태를 유지한다.
- Sound 센서와 홀 센서 응용을 위한 프로그램 예(Atmel Studio 7): sensor_event_one_short.zip
Sound 센서와 홀 센서는 입력 신호의 크기가 일정한 값을 초과하면 출력이 High 상태에서 Low 상태로 천이한다. 아래 예는 입력 신호의 크기가 일정한 값을 초과하면 일정 시간 동안(4초) LED가 Turn on 되는 프로그램 예이다.
// Sound 센서 모듈(SZH-EK-33), 홀센서(WSH131)
// 입력 신호가 일정 기준을 초과한 경우(센서 High -> Low) LED를 4초동안 Turn on 한다.
// PE4(외부 Interrupt 4번)를 이용 하여 High/Low를 출력하는 센서(Sensor) 신호를 받는다.
// 4초 Delay을 구현하가 위하여 Timer1의 Compare Match A Interrupt를 이용한다.
// Target : Atmega128
// Crystal: 16Mhz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
void port_init(void)
{
	// PE4(INT4)를 이용 하여 Sensor의 출력신호(High/Low)를 입력 받는다.
	// Sensor의 출력신호를 PE4(External Interrupt)에 연결 하고 다른 한 단자는 GND에 연결 하여야 한다.
	DDRE &= (~0x10);	// PORTE의 PE4를 Input Port로 설정
	PORTF = 0x00;		// PORTF의 초기값 설정(PORTF의 LED가 꺼진 상태)
	DDRF  = 0xff;		// PORTF를 Output Port로 설정
	// External Interrupt 4, Falling edge interrupt.
	EICRB = 0x02;
	// External Interrupt 4, Rising edge interrupt.
	//EICRB = 0x03;
	// External Interrupt 4 enable
	EIMSK |= (1 << INT4);
}
// Timer1의 Output Compare Interrupt A를 이용하여 4Sec Time delay를 구현한다.
#define DELAY_SEC (62500)    //  64uSec * 62500 = 4000000uSec = 4Sec
void timer_init(void)
{
	// (0 << WGM13) | (0 << WGM12)(0 << WGM11) | (0 << WGM10) : Normal port operation.
	// (1 << CS12) | (0 << CS11) | (1 << CS10) : 101  prescale clk/1024, Clock 주기 : 64uSec
	TCCR1B = ((1 << CS12) | (0 << CS11) | (1 << CS10));
	// 이 예에서는 Output Compare Interrupt A를 사용하기 때문에 4Sec 시간 지연을 얻기 위하여는
	// OCR1A의 값을 TCNT1 + DELAY_SEC로 설정하여야 한다.
	// OCR1A = TCNT1 + DELAY_SEC;
	TIMSK &= ~(1 << OCIE1A);     // Output Compare A Match Interrupt Disable
}
// Initialize all peripherals
void init_devices(void)
{
	cli();         // Disable all interrupts
	port_init();   // I/O Port initialized
	timer_init();  // Timer1 initialized
	sei();         // Re-enable interrupts
}
// External Interrupt 4가 발생 하였을 때 실행되는 함수
SIGNAL (INT4_vect)
{
	EIMSK &= ~(1 << INT4);  // External Interrupt 4 Disable
	PORTF |= 0x01;			// LED(PF0): Turn on
	OCR1A = TCNT1 + DELAY_SEC;	//4 Sec Delay(Timer1 output compare A match)
	TIMSK |= (1 << OCIE1A);		// Output Compare A Match Interrupt Enable
}
// Timer1 Output Compare A Match Interrupt가 발생 하였을 때 실행되는 함수
SIGNAL (TIMER1_COMPA_vect)
{
	TIMSK &= ~(1 << OCIE1A);	// Output Compare A Match Interrupt Disable
	PORTF &= ~0x01;				// LED(PF0): Turn off
	EIFR |= (1 << INTF4);       // Clear External Interrupt Flag
	EIMSK |= (1 << INT4);		// External Interrupt 4 enable
}
int main (void)
{
	init_devices();
	
	// Infinite loop
	while(1){
	}
	return 0;
}
          - Atmega128 개발보드와 센서 모듈 연결
- Atmega128 개발보드 PE4 <-> 센서의 Output pin
- Atmega128 개발보드 VDD(5V) <-> 센서의 Power pin.
- Atmega128 개발보드 GND <-> 센서 GND
- 홀 센서인 경우에는 전원과 센서의 Output pin 사이에 약 4.7K 부하 저항을 연결한다.
- Output port(PF0)에 LED 연결
- PF0에 저항(330Ω)과 LED를 직열로 연결한다.
- sensor_event_one_short.zip 파일을 Download하여 압축을 해제한다.
- sensor_event_one_short.hex를 개발 보드에 Upload 한다.
- 실험:
- Atmega128 개발보드의 프로그램을 실행한다.
- 프로그램이 실행되면 센서에 임계치 이상의 신호를 인가 한다.
- 센서에 임계치 이상의 신호를 인가되면 LED가 지정된 시간(4Sec) 동안 Turn on 된다.
- 센서에 임계치 이상의 신호를 인가하는 방법 예
- Sound 센서모듈(SZH-EK033): 센서에 큰 소음이나 진동(입으로 후하고 마이크에 진동)을 가한다.
- 홀 센서(Hall Sensor) WSH131: 먼저 홀 센서 회로를 구성하고 홀 센서 앞에 자성체(자석)를 접근 시킨다.
참고자료: 홀 센서 회로 예
- Analog 전압을 출력하는 센서 모듈 예
- Analog voltage를 출력하는 센서 모듈을 사용하는 구성도
- Analog voltage를 출력하는 센서 모듈을 사용하는 프로그램 예
- Atmega128 개발보드를 사용하여 Analog voltage를 주기적으로 측정하여 출력하는 프로그램 예(Atmel Studio 7): sensor_analog_interrupt_uart.zip
아래 사진은 자주 자용하는 Analog 전압을 출력하는 센서 모듈의 예 이다. 아래 예 센서는 입력 신호의 크기에 따라 출력 전압이 변동하기 때문에 센서 모듈의 출력 전압을 디지털 값으로 변환하는 A/D 변환기를 사용하여야 한다.
윗 예의 센서 모듈은 모두 Analog voltage 신호를 출력하기 때문에 ADC를 사용하여야 한다.
아래 프로그램 예는 sensor_analog_interrupt_uart 프로그램 중 Timer를 이용하여 측정 주기를 발생하고 ADC로 Analog voltage를 측정하는 프로그램 예이다. 전체 프로그램은 sensor_analog_interrupt_uart.zip에 포함되어 있다.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "gnu_sciutil.h"
#include "adc.h"
unsigned short int adcResult;
void init_port(void)
{
	DDRF &= ~(1 << PF0);	// PF0 : Input Port
}
#define ADC_PERIOD 1562		// 1562 * 64uSec = 0.1Sec
void timer3_init(void)
{
	// Timer3를 Normal Mode로 설정 한다.
	// ADC 변환 주기: OC3A Rg의 Compare match Interrupt를 이용 하여 0.1 Sec 주기의 
	//  Interrupt를 발생 시키고, 이 주기를 ADC 변환 주기로 이용 한다.
	// (0 << WGM33) | (0 << WGM32)  | (0 << WGM31) | (0 << WGM30) : Normal mode
	// (0 << COM3A1) | (0 << COM3A0) : Normal port operation, OCnA disconnected.
	TCCR3A = (0 << COM3A1) | (0 << COM3A0) | (0 << WGM31) | (0 << WGM30);  
	// (1 << CS32) | (0 << CS31) | (1 << CS30) : 101  prescale clk/1024, Clock 주기 : 64uSec
	TCCR3B = (0 << WGM33) | (0 << WGM32) | (1 << CS32) | (0 << CS31) | (1 << CS30);  
	TCNT3 = 0x0000;			// Timer3 Counter Register 초기화
	// OCR3A 값 설정 : 1562 * 64uSec = 0.1Sec
	OCR3A = TCNT3 + ADC_PERIOD;
	// Timer/Counter3, Output Compare A Match(ADC 변환 Start) Interrupt Enable
	ETIMSK |= (1 << OCIE3A);
}
void adc_init(void){
//	(0 << REFS1) | (0 << REFS0) ; AREF, Internal Vref turned off
//	(0 << ADLAR)  ; ADLAR: ADC Right Adjust Result
//	MUX4:0 <= 00000 ;  ADC0, Single Ended Input
	ADMUX = 0x00;	// Ch 0 사용
//	(1 << ADEN)  ; ADC Enable
//	(0 << ADSC)  ; ADC Start Conversion, 0 : Stop Convertion , 1 Start Convertion 
//	(0 << ADFR)  ; Single Convertion mode
//	(1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) ; Prescaler Select Bits, Division Factor ; 128
//     ADC의 Clock frequency: 16M /128 = 125KHz
//	(0 << ADIE)  ; ADC Interrupt Disable
	ADCSRA = (1 << ADEN) | (0 << ADSC) | (0 << ADFR) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (0 << ADIE);
}
void init_adc(void){
	init_port();
	timer3_init();
	adc_init();
}
SIGNAL(TIMER3_COMPA_vect)
{ 
	ETIMSK &= ~(1 << OCIE3A);      // Timer3, Output Compare A Match Interrupt Disable
	OCR3A = TCNT3 + ADC_PERIOD;    // Output Compare A Match Interrupt 주기 설정
    // A/D 변환
	ADCSRA |= (1 << ADSC)  ;       // ADC Start Conversion
	ADCSRA |= (1 << ADIE);         // ADC Interrupt Ensable
	ETIMSK |= (1 << OCIE3A);       // Timer3, Output Compare A Match Interrupt Enable
}
SIGNAL(ADC_vect)
{ 
	ADCSRA &= ~(1 << ADIE);        // ADC Interrupt Disable
	// ADC의 출력을 부호없는 10진수로 출력한다.
	// 센서의 종류에 따라 출력 값을 조정하는 코드가 필요하다.
	adcResult = ADC;
	// A/D 변환 결과를 모니터에 출력 한다.
	SCI_OutChar(CR);
	SCI_OutString("    ");
	SCI_OutChar(CR);
	// ADC의 출력을 부호 없는 10진수로 출력한다.
	// 센서의 종류에 따라 출력 값을 조정하는 프로그램이 필요하다.
	SCI_OutUDec(adcResult);
}
        - PC와 AVR 사이에 UART 통신선을 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Atmega128의 GND를 연결한다.
- Atmega128 개발보드와 센서 모듈 연결
- Atmega128 개발보드 ADC0를 입력 단자(PF0) <-> 센서의 Analog output pin
- Atmega128 개발보드 VDD(5V} <-> 센서 Vdd pin(센서의 종류에 따라 공급 전압을 확인 할 것)
- Atmega128 개발보드 GND <-> 센서 GND
주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.
참고자료: USB - Serial 변환 모듈
- sensor_analog_interrupt_uart.zip 파일을 Download하여 압축을 해제한다.
- sensor_analog_interrupt_uart.hex를 개발 보드에 Upload 한다.
- 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
- 모니터 프로그램에서 필요한 설정(Serial Port와 Baudrate(19200) 등을 설정)을 한다.
- 실험:
- 개발 보드의 Reset SW를 누르면 모니터에 "ADC Testing." 메세지가 출력된다.
- 0.1 Sec 주기로 ADC0(PF0)의 전압 값이 A/D 변환되어 모니터에 출력된다.
- 센서에 신호(센서의 종류에 따라)를 가하고 Console에 출력되는 측정 값과 비교한다.
- 초음파 거리 센서(HC-SR04)
- 초음파 거리 센서(HC-SR04) 모듈을 제어하는 프로그램 예
- 초음파 거리 센서(HC-SR04) 모듈을 제어하는 프로그램 예(Atmel Studio 7): sensor_pulse_width_HC_SR04.zip
초음파 거리 센서(HC-SR04) 모듈을 사용하는 구성도 예
초음파 거리 센서(HC-SR04) 모듈은 초음파를 반사하는 물체까지의 거리에 비례한 Pulse 폭을 출력한다.
아래 프로그램 예는 sensor_pulse_width_HC_SR04 프로그램 중 Timer를 이용하여 Trigger 신호를 출력하고 펄스폭을 측정하는 프로그램 예이다. 전체 프로그램은 sensor_pulse_width_HC_SR04.zip에 포함되어 있다.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "gnu_sciutil.h"
#include "timer1_input_capture_pulse_width_measure.h"
#define TRIGER_PORT PORTE
#define TRIGER_DDR DDRE
#define TRIGER_BIT 3
#define CAPTURE_PORT PORTE
#define CAPTURE_DDR DDRE
#define CAPTURE_PORT_BIT 7
#define MEASURE_PERIOD 6250		// 0.1Sec <- 16uSec * 6250
#define TRIGER_WIDTH 3			// 12uSSec <- 4uSec * 3
volatile unsigned short int oldICR;
unsigned short int pulseWidth, distance;
unsigned long int long_dist;
void init_port(void)
{
	TRIGER_DDR |= (1 << TRIGER_BIT);	// Triger 출력 Port를 Output port로 설정한다.
	TRIGER_PORT &= ~(1 << TRIGER_BIT);	// Triger 출력 Port를 초기화(0)
	CAPTURE_DDR &= ~(1 << CAPTURE_PORT_BIT);  // ICP1(PD4 : J2 --> 16번)을 
	CAPTURE_PORT &= ~(1 << CAPTURE_PORT_BIT); // ? Input Capture Register Tregger 신호의 입력 단자로 사용 한다.
}
// Timer1A의 Output Compare Register(OCR1A)는 측정 주기 발생을 위하여 사용 한다.
//   측정주기 0.1Sec <- 16uSec * 6250
// Prescale clk/256, Clock 주기 : 16uSec
void timer1_init(void)
{
	// (0 << WGM13) | (0 << WGM12)  | (0 << WGM11) | (0 << WGM10) : Normal mode
	// (0 << COM1A1) | (0 << COM1A0) : Normal port operation, OCnA disconnected.
	// (1 << CS12) | (0 << CS11) | (0 << CS10) : 100  prescale ck/256, Clock 주기 : 16uSec
	TCCR1B = (1 << CS12) | (0 << CS11) | (0 << CS10);  
	TCNT1 = 0x00;			//Timer/Counter1 Register 초기화
	OCR1A = TCNT1 + MEASURE_PERIOD;	// 0.1Sec <- 16uSec * 6250
	// OCIE1A : Output Compare A Match Interrupt Enable.
	TIMSK = (1 << OCIE1A);
}
// Timer3A의 Output Compare Register(OCR3A)는 HC-SR04의 Trigger pulse를 발생을 위하여 사용 한다.
// Timer3A의 Input Capture Register는 펄스 폭을 측정 하기 위한 Rg로 사용 한다.
// 펄스 폭(High 상태) 측정 : Timer3, ICR3를 사용 한다.
// Prescale clk/64, Clock 주기 : 4uSec
void timer3_init(void)
{
	// (0 << WGM33) | (0 << WGM32)  | (0 << WGM31) | (0 << WGM30) : Normal mode
	// (0 << COM3A1) | (0 << COM3A0) : Normal port operation, OCnA disconnected.
	// TCCR3A = (0 << COM3A1) | (0 << COM3A0);
	// ICNC3: Input Capture Noise Canceler.
	// ICES3: Input Capture Edge Select. One : Rising edge, Zero : Falling edge.
	// (1 << CS32) | (0 << CS31) | (0 << CS30) : 100  prescale ck/64, Clock 주기 : 4uSec
	TCCR3B = (1 << ICNC3) | (1 << ICES3) | (0 << CS32) | (1 << CS31) | (1 << CS30);
	TCNT3 = 0x00;			//Timer/Counter1 Register 초기화
	// TICIE3 ; Input Capture Interrupt Disable.
	// OCIE3A : Output Compare A Match Interrupt Disable.
	ETIMSK &= ~(1 << OCIE3A);
	ETIMSK &= ~(1 << TICIE3);
}
void init_timer(void){
	init_port();
	timer1_init();
	timer3_init();
}
// 측정 주기를 발생
SIGNAL(TIMER1_COMPA_vect)
{ 
	// OCIE1A : Output Compare A Match Interrupt Disable.
	TIMSK &= ~(1 << OCIE1A);
	// 측정 주기
	OCR1A = TCNT1 + MEASURE_PERIOD;	// 0.1Sec <- 16uSec * 6250
	// Triger 신호를 출력한다. Triger Port <- High
	TRIGER_PORT |= (1 << TRIGER_BIT);
	// Triger 신호 폭 설정(12uSec <- 4uSec * 3)
	OCR3A = TCNT3 + TRIGER_WIDTH;
	// Trigger pulse clear를 위한 Timer3 interrupt enable 
	ETIMSK |= (1 << OCIE3A);
	// 측정 주기 발생 Timer interrupt enable.
	TIMSK |= (1 << OCIE1A);
}
// HC-SR04의 Trigger pulse를 Low로 하고 Echo 신호의 펄스폭 측정을 Enable 한다.
SIGNAL(TIMER3_COMPA_vect)
{
	// OCIE1B : Output Compare B Match Interrupt Disable.
	ETIMSK &= ~(1 << OCIE3A);
	// Triger Port <- Low
	TRIGER_PORT &= ~(1 << TRIGER_BIT);
	// Input Capture Interrupt가 Rising edge에서 발생 하도록 설정 한다.
	// ICES3: Input Capture Edge Select. One : Rising edge, Zero : Falling edge.
	TCCR3B |= (1 << ICES3);
	// TICIE3: Input Capture Interrupt Enable.
	ETIMSK |= (1 << TICIE3);
}
// HC-SR04의 Echo 펄스폭을 측정하고 결과를 출력한다. 
SIGNAL(TIMER3_CAPT_vect)
{ 
	ETIMSK &= ~(1 << TICIE3);  // TICIE3 ; Input Capture Interrupt Disable.
	// 만약 현재 Rising edge에서 Input Capture Interrupt가 발생된 경우
	if((TCCR3B & (1 << ICES3)) != 0){
		// 펄스 폭 측정을 위하여 현재 Capture된 ICR3 값을 저장 한다.
		oldICR = ICR3;
		// 다음 Interrupt는 Falling edge에서 발생 하도록 설정 한다.
		// ICES3: Input Capture Edge Select. One : Rising edge, Zero : Falling edge.
		TCCR3B &= ~(1 << ICES3);  
		// TICIE3 ; Input Capture Interrupt Enable.
		ETIMSK |= (1 << TICIE3);
	}
	// 만약 현재 Falling edge에서 Input Capture Interrupt가 발생된 된 경우
	else{
		// 펄스 폭을 측정(계산) 한다.
		pulseWidth = ICR3 - oldICR;
		// pulseWidth를 uSec(*4)로 변환한 다음 거리(cm)로 변환한다.
		// 거리 cm <- (pulseWidth * 4(uSec)) / 58 <- ((pulseWidth * 4(uSec)) * 17) / 1000
		// 거리 cm <- (pulseWidth * 17) / 250
		long_dist = ((unsigned long)pulseWidth * 17) / 250;
		distance = long_dist;
		// 측정 된 펄스 폭 값을 모니터에 출력 한다.
		SCI_OutChar(CR);
		SCI_OutString("    ");
		SCI_OutChar(CR);
		// 거리(cm)를 부호 없는 10진수로 출력한다.
		SCI_OutUDec(distance);
	}
}
          - PC와 AVR 사이에 UART 통신선을 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Atmega128의 GND를 연결한다.
- Atmega128 개발보드와 센서 모듈 연결
- Atmega128 개발보드 Trigger output pin(PE3) <-> HC-SR04 센서의 Trig pin
- Atmega128 개발보드 Pulse input pin(PE7) <-> HC-SR04 센서의 Echo pin
- Atmega128 개발보드 VDD(5V} <-> HC-SR04 센서 Vdd pin
- Atmega128 개발보드 GND <-> HC-SR04 센서 GND
주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.
- sensor_pulse_width_HC_SR04.zip 파일을 Download하여 압축을 해제한다.
- sensor_pulse_width_HC_SR04.hex를 개발 보드에 Upload 한다.
- 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
- 모니터 프로그램에서 필요한 설정(Serial Port와 Baudrate(19200) 등을 설정)을 한다.
- 실험:
- 개발 보드의 Reset SW를 누르면 모니터에 "Pulse width output sensor testing." 메세지가 출력된다.
- 0.1Sec 주기로 거리가 측정되어 모니터에 출력된다.
- 초음파 거리센서 앞에 반사체의 위치를 변경하며 실험한다.
- 온도/습도 센서(DHT11/DHT22) 모듈
- 온도/습도 센서(DHT11/DHT22) 모듈을 제어하는 프로그램 예
- 온도/습도 센서(DHT11) 모듈을 제어하는 프로그램 예(Atmel Studio 7): single_wire_comm_DHT11.zip
DHT11/DHT22 센서 모듈을 사용하는 구성도 예
DHT11 센서 모듈에 따른의 Pin 배치 예
주: 위 예와 같이 DHT11 센서 모듈의 제작 회사에 따라 Pin 배치와 Pull-up 저항의 내장여부가 다르기 때문에 주의를 요함. 2번 모듈인 경우에는 10K Pull-up 저항이 내장되어 있다.
온도/습도 센서(DHT11/DHT22) 모듈은 측정한 온도/습도 값을 디지털 데이터로 변환하여 Single-Wire 통신 프로토콜로 출력한다.
DHT11 센서의 Data signal timming diadram 예. 더 자세한 자료는 DHT11 Data sheet에서 확인하기 바람.
아래 프로그램 예는 single_wire_comm_DHT11 프로그램 중 측정 결과를 읽는 함수와 결과를 모니터에 출력하는 함수 예이다. 전체 프로그램은 single_wire_comm_DHT11.zip에 포함되어 있다.
#include <avr/io.h>
#include "timer0_clock.h"
#include "gnu_sciutil.h"
// DEFINE SETUP
#define SENSOR_DDR				DDRC
#define SENSOR_PORT				PORTC
#define SENSOR_PIN				PINC
#define SENSOR_PIN_BIT			PC5
// GLOBAL VARIABLES
uint8_t DHT11Data[5] = {0};
static uint8_t DHT11Init = 0;
// DHT11 초기화
void DHT11Setup(){
	// Power on 후 DHT11 이 안정화(사용 가능한 상태)되는데 약 1초 정도가 필요하다.
	delay(2000);
	// SENSOR_PORT를 output port로 설정한다.
	SENSOR_DDR |= 1 << SENSOR_PIN_BIT;
	// Set setup flag
	DHT11Init = 1;
}
// 온도를 출력하는 함수
void DHT11DisplayTemperature(){
		    SCI_OutString("온도: ");
		    SCI_OutUDec(DHT11Data[2]);
		    SCI_OutChar('.');
		    SCI_OutUDec(DHT11Data[3]);
			SCI_OutChar('C');
}
// 습도를 출력하는 함수
void DHT11DisplayHumidity(){
		    SCI_OutString("습도: ");
		    SCI_OutUDec(DHT11Data[0]);
		    SCI_OutChar('.');
		    SCI_OutUDec(DHT11Data[1]);
		    SCI_OutChar('%');
}
// DHT11의 습도와 온도 값을 읽는 함수
int8_t DHT11ReadData(){
	uint8_t sensor_bytes, bits, buffer=0, timeout = 0, checksum;
	
	// 만약  DHT11 초기화가 실행되지 않은 경우  DHT11를 초기화한다.
	if(DHT11Init == 0) DHT11Setup();
	
	// START signal을 Sensor에 Send 한다.
	//   SENSOR_PORT를 output port로 설정한다.
	SENSOR_DDR |= (1 << SENSOR_PIN_BIT);
	SENSOR_PORT &= ~(1 << SENSOR_PIN_BIT);	// Pin에 LOW를 출력한다.
	delay(20);	// Pin의 LOW 상태를 최소 18 mSec 동안 유지한다.
	// SENSOR_DDR을 Input port(high Z)로 설정한다.
	// Data line에 신호가 없는 경우 Pull-up 저항에 의하여 Data line은  HIGH 상태가된다.
	SENSOR_DDR &= ~(1 << SENSOR_PIN_BIT);
	delayMicroseconds(32); // Wait for 20-40 us
	
	// Sensor 응답 신호를 Check 한다. 80us LOW -> 80us HIGH signal
	// 만약 신호가 HIGH 이면(Sensor didn't respond) Error code를 Return 한다.
	if(SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
		return 0; // Error code
	}
	
	// Sensor가 LOW signal을 Send 한 경우 HIGH 신호를 기다린다.
	delayMicroseconds(82);
	
	// 만약 HIGH인 경우 Sensor는 Data를 Send 할 준비가 된 상태이다.
	if(SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
		delayMicroseconds(82); // HIGH 신호가 종료되기를 기다린다.
		// 만약 HIGH 상태가 계속되면 Error 가 발생한 것이기 때문에 0를 Return 한다.
		if(SENSOR_PIN & (1 << SENSOR_PIN_BIT)) return 0;
	}else{
		return 0; // Error code
	}
	
	// Sensor로 부터 Data(5 Byte)를 읽는다.
	for(sensor_bytes = 0; sensor_bytes < 5; sensor_bytes++){
		// Sensor로 부터 수신한 Bit Data를 Byte Data로 변환하는 값을 저장하는 buffer를 초기화한다.
		buffer = 0;
		// 8 Bits를 수신하여 Byte로 변환한다.	
		for(bits = 0; bits < 8; bits++){
			// 각 Bits를 수신할 때 마다 Signal이 Low인 상태를 50uSec 동안 기다린다.
			while(~SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
				// Signal Low 상태를 기다리는 시간을 최대 80uSec로 제한한다.
				// Signal이 Low인 상태를 80uSec 이상 지속하면 Error code(Return 0)를 Return한다.
				timeout++;
				if(timeout > 8) break;
				delayMicroseconds(10);
			}
			timeout = 0;
			
			// Signal이 HIGH 이면 Bit 값을 읽는다.
			if(SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
				// bit 값이 0인 경우 26-28 us 동안 HIGH 이고, bit 값이 1인 경우 70uSec 동안 High이다.
				delayMicroseconds(40);
				// 만약 Signal이 HIGH 상태이면 buffer의 bits 위치를 1로 Set 한다.
				if(SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
					// buffer의 bits 위치를 1로 Set 한다.
					// Sensor는 MSB 먼저 송신한다.
					buffer |= 1 << (7 - bits);
				}
				
				// Signal의 HIGH 상태가 종료되기를 80uSec 동안 기다린다.
				while(SENSOR_PIN & (1 << SENSOR_PIN_BIT)){
					// Signal High 상태를 기다리는 시간을 최대 80uSec로 제한한다.
					timeout++;
					if(timeout > 8) break;
					delayMicroseconds(10);
				}
				timeout = 0;
			}else{
				// Signal LOW 인 상태를 지속하면 0를 Return(Error response) 한다.
				return 0;
			}
		}
		
		// 수신한 Byte data를 DHT11Data[sensor_bytes]에 저장한다.
		DHT11Data[sensor_bytes] = buffer;
	}
	
	// Data transmision 이 조료되기를 기다린다. Sensor는 50uSec 동안 LOW를 출력하고,
	// 다음 START command 이 있을 때까지 Low-power consumption mode가 된다.
	// Sensor 가 안정되어 다음 측정이 가능한 상태까지 약 1Sec 정도의 시간이 필요하다.
	delayMicroseconds(60);
	
	// Idle 상태일 때 Sensor DATA line은 HIGH 상태를 유지하여야 한다.
	// 아래와 같이 AVR에서 High를 출력 할 수도 있지만 더 좋은 방법은 
	// Idle 상태(high Z)에서는 Pull-up 저항으로 High 상태가 되도록 하는 방법이다.
	// Pull-up 저항으로 High 상태가 되도록 하기 위하여는 적당한 값의 Pull-up 저항을 사용하여야 한다.
	// AVR에서 High를 출력하는 코드 예
	//   SENSOR_DDR |= 1 << SENSOR_PIN_BIT;
	//   SENSOR_PORT |= 1 << SENSOR_PIN_BIT;
	
	// Data transmission errors를 check 한다.
	checksum = DHT11Data[0] + DHT11Data[1] + DHT11Data[2] + DHT11Data[3];
	if(checksum != DHT11Data[4]){
		return -1; // Checksum error code
	}	
	// OK return code
	return 1;
}
          - PC와 AVR 사이에 UART 통신선을 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 RXD와 Atmega128의 TXD0(PE1)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 TXD와 Atmega128의 RXD0(PE0)를 연결한다.
- 컴퓨터(USB --> UART(RS232) 변환 모듈)의 GND와 Atmega128의 GND를 연결한다.
- Atmega128 개발보드와 센서 모듈 연결
- Atmega128 개발보드 Data pin(PC5) <-> DHT11 센서의 Data pin
- Atmega128 개발보드 VDD(5V} <-> DHT11 센서 Vcc pin
- Atmega128 개발보드 GND <-> DHT11 센서 GND
주: 컴퓨터에 Serial Port가 없는 경우 "USB --> UART(RS232) 변환 모듈"를 사용(USB Port를 Serial Port로 변환)하여 연결한다. 개발보드에 따라서는 "USB --> UART(RS232) 변환 모듈"을 내장하고 있는 경우가 많기 때문에 본인이 사용하는 개발보드에서 확인 하여야 한다.
- single_wire_comm_DHT11.zip 파일을 Download하여 압축을 해제한다.
- single_wire_comm_DHT11.hex를 개발 보드에 Upload 한다.
- 모니터 프로그램(예: OC-Console, Tera Term)을 설치(이미 설치되어 있는 경우에는 실행만 하면됨)하고 실행 한다.
- 모니터 프로그램에서 필요한 설정(Serial Port와 Baudrate(19200) 등을 설정)을 한다.
- 실험:
- 개발 보드의 Reset SW를 누르면 모니터에 "DHT11 Testing" 메세지가 출력된다.
- 약 2초 주기로 DHT11 센서의 측정 결과(온도와 습도)가 Console에 출력된다.
- 센서의 온도와 습도를 변경하며 결과를 관측한다.
- 디지털 출력 온도 센서(DS1621)
- 디지털 출력 온도 센서(DS1621)를 제어하는 프로그램 예
- AVR(Atmega128) 센서(Sensors)와 센서 모듈(Sensor Modules) 관련 페이지 보기
I2C 통신을 이용한 측정 과 제어 시스템 구성도
주: AVR 보드 또는 센서 모듈에 Pull-Up 저항이 내장되지 않은 경우 I2C Pull-Up 저항(데이터 선의 길이에 따라 1K - 10K 저항을 사용)이 필요하다. 아래 프로그램 예에서 링크되는 TWI 통신 예제 페이지에 회로 예가 있다.
디지털 출력 온도 센서(DS1621)를 사용하는 시스템 구성과 프로그램 예는 "TWI 통신을 사용한 응용 프로그램 예: DS1621을 사용한 온도 측정 프로그램 예"에서 설명하였으니 참고하기 바람.
 














