August 24, 2019

디바이스마트 미디어:

[20호]DIY 프로젝트 공모전 입선작 – EVALARM 물체회피 기능을 가진 알람카

20Feadiym

작품설명

제작 동기

293260

일반시계와 알람시계의 가장 큰 차이점은 알람기능 수행 여부의 차이입니다. 그 중 알람기능은 정해진 시간에 맞추어 사용자가 일어날 수 있도록 도와주는 것이 가장 큰 핵심이라고 할 수 있습니다. 하지만 기존의 알람시계는 소리를 잘 듣기위해 곁에 두고 자게 되고, 이로 인해 사용자가 무의식중에 알람을 꺼버려서 지각을 하거나 그 기능을 상실해 버리는 경우가 대부분입니다. 그렇기 때문에 저희 Evalam은 소리가 잘 들리게 끔 곁에 두지만 일어나지 않으면 꺼지지 않게 끔 설계되어 있어 가장 중요하고 큰 기능이 상실되는 것을 막고 이를 재미와 접목시켜 상쾌한 아침을 맞을 수 있도록 만들어졌습니다.

유사 작품 | 클로키로보틱 알람시계

20diy클로키로보틱
유동성을 가진다는 측면에서 본 아이디어와 유사한 장점을 가졌지만 가격이 너무 비싸고 장애물들을 피할 수 없기 때문에, 자칫 장롱 밑 등의 폐쇄된 장소에 들어갈 시 분실의 위험이 따른다는 큰 단점이 있습니다.
아이디어는 클로키로보틱 알람시계와 비슷하지만 클로키로보틱 알람시계의 단점인 장애물을 피할 수 없다는 점과 폐쇄된 장소에 들어갈 시 분실의 위험이 따른 점을 개선하도록 설계되어 있습니다. 적외선 센서을 통한 물체 회피와 리모컨 센서를 통한 RC카 제어 등으로 실용성을 높이는 것과 더불어 재미를 위해 제작하게 되었습니다.

작품 기능 및 설명

20Feadiym0 (6)
동작은 RC카와 시계의 기능을 합쳐 놓은 작품입니다.
RC카는 물체 회피(모터), 조정기(수신부), 움직임(거리센서)으로 구성되어 있고, 시계에서는 일반적인 알람과 시계로 구성되어 있습니다. 서로 다른 두 작품을 합쳐 알람이 울릴 경우에 알람을 꺼버리려는 행동을 방지할 수 있도록 설계했습니다.
또한 4개의 센서를 통해 벽이나 물건을 회피하여 작품과 물건을 보호하도록 설계했습니다. 이에 대한 자세한 설명은 후에 하겠습니다.

 

주요 동작 및 특징

알람이 울릴 시 전체 시나리오

20Feadiym0

4개의 거리 측정 센서로 물체에 감지하는 상황은 총 7가지 경우로 생각해 보았습니다. 그리고 그 상황에 따라 동작은 5가지로 구성했습니다. 먼저 주요 동작 조건을 사진으로 확인해 보겠습니다.

20diy평지 1. 평지에서 사진 : 단순히 알람이 시끄럽게 울리도록 설계했습니다.
20diy앞에서 알람잡 2. 앞에서 Evalarm을 잡으려고 할 때 : 앞에서 Evalarm을 잡으려고 할 때 뒤로 움직이도록 설계했습니다.
20diy뒤에서 알람잡 3. 뒤에서 Evalarm을 잡으려고 할 때 : 앞으로 움직이도록 설계했습니다.
20diy앞뒤에서 알람잡 4. 앞뒤에서만 물체가 감지 될 때 : 좌측으로 회전하도록 설계했습니다.
네방향 5. 네 방향에서 물체가 감지 될 때 : 빠져나갈 수 있는 틈새를 찾도록 설계했습니다.
앞뒤랑 좌측 6. 앞뒤 그리고 좌측에서 물체가 감지 될 때 :우측으로 회전하도록 설계했습니다.
앞뒤 우측 7. 앞뒤 그리고 우측에서 물체가 감지 될 때 : 좌측으로 회전하도록 설계했습니다.

설정 시 전체 시나리오 : 시간 수정, 알람 설정, 알람 시간

20Feadiym0 (1)
위와 같은 표처럼 알람 시간과 알람 설정 그리고 시간을 4개의 스위치로 설정할 수 있도록 설계되어 있습니다.

메인 알람 끔
메인화면 알람이 꺼진 화면
알람킴 시간십초변화
알람이 켜진 화면 시간을 10초로 설정한 화면
시간십분변화 시간열시간변화
시간을 10분으로 설정한 화면 시간을 10시간으로 설정한 화면

위와 같은 표처럼 알람 시간과 알람 설정 그리고 시간을 4개의 스위치로 설정할 수 있도록 설계되어 있습니다.

전체 시스템 구성

하드웨어 구성

20Feadiym0 (2)

TEXT LCD는 7비트로 제어가 가능하도록 설계했으며, 스위치 외부 인터럽트를 사용하여 제어하도록 했습니다. 리모컨 센서는 외부 인터럽트와 타이머 카운트로 인식 받도록 설계했습니다. 적외선 센서는 AD변환을 통해 거리를 측정하도록 설계했습니다.

적외선 센서(L298)

20diyL298데이터시트
L298 데이터시트
20fediy03
모터 입력(설정)에 대한 움직임의 방향
20diyL298데이터시트2
L298의 데이터시트
20diyL298데이터시트3
L298N 부품

사용시스템

1) 리모컨 관련 시스템 및 설명
리모컨의 데이터 형식은 아래 그림과 같습니다. 처음에 리더 펄스가 나옵니다. D6121(구 삼성, 구 LG) 형식은 리더 펄스의 길이가 13.5msec이고 TC9012(삼성. LG) 형식은 리더 펄스의 길이가 9msec 입니다.
다음에 32 비트의 데이터가 따라 오는데, 처음 2바이트는 커스텀 코드이고, 다음 1바이트는 데이터, 마지막 바이트는 데이터 1의 보수입니다.

20fediy04
리모컨의 데이터 형식

각 비트는 1 또는 0을 나타내는데 펄스 폭의 길이로 구별합니다. (아래 그림 참조) 즉, 펄스 폭이 긴 것(A)이 1을 나타내고, 짧은 것(B)은 0을 나타냅니다. 시간은 각각 0.5625 msec와 1.6875 msec입니다.

20fediy005
데이터 펄스폭의 길이

아래에 삼성 리모컨(TV, VCR)의 코드 값을 예로 들었습니다. 우리는 이 코드표를 사용하는 것이 아니라, 프로그램을 통해서 이 코드 값을 알아내고(표와 일치하는지에 대한 확인), 알아낸 코드 값을 이용해서 LCD를 제어하도록 하겠습니다. 삼성 리모컨뿐만 아니라 TC9012나 D6121 형식의 리모컨은 어떤 것이나 코드 값을 알아내서 사용하는 것이 목적입니다.

2) 삼성리모컨에 대한 전반적인 데이터 표

20Feadiym0 (4)

3) rc카 시스템

20diY RC카 rc카 윗부분
rc카 뒷부분 rc카 옆부분(왼)
20fediy006 ※ 볼게이트의 사용은 무게중심에 의해 앞으로 본체가 쏠리는 것을 방지하는데 도움을 주기 위해 장착하였습니다.

 

단계별 제작 과정
단순히 시계에 필요한 시간 변경 그리고 알람 등의 기능을 업그레이드하여 제작했습니다. 그리고 RC카에 필요한 모터 제어와 리모컨 수신 센서 제어를 포함하여 RC카를 제작했습니다. 적외선 센서를 제어하고 기존의 RC카에서 물체를 회피하는 기능을 연구하고 제작했습니다. 마지막으로 물체 회피와 RC카 그리고 시계 이 모든 것을 합친 Evalarm이 제작됐습니다.

 기타(회로도, 소스코드, 참고문헌 등)

소스코드보기

#include <avr/io.h>
#include <avr/interrupt.h>

#define ir_ready 0
#define ir_lead 1
#define ir_data 2
unsigned char ir_rx_data[4];
//voliate
unsigned char ir_state;
unsigned char ir_timer_cnt;
unsigned char ir_bit_cnt;
unsigned char ir_rx_flag=0;
unsigned char ir_rx_temp;

void clock_data_m_change();
void clock_data_p_change();
void alarm_data_m_change();
void alarm_data_p_change();
void ir_car_run();

char moter_data;

void delay_us(unsigned int us)
{
unsigned int i;

for(i=0;i<us;i++){
asm(“PUSH R0″);
asm(“POP R0″);
asm(“PUSH R0″);
asm(“POP R0″);
asm(“PUSH R0″);
asm(“POP R0″);
}
}

void delay_ms(unsigned int ms)
{
unsigned int i;
for(i=0;i<ms;i++){
delay_us(1000);
}
}

#define CUR11 0×02 /* 커서 홈에 위치시키는 명령어 값 */
#define CUR21 0xC0 /* 커서 2라인 1열에 위치시키는 명령어 값 */
#define LCDON 0x0C /* LCD ON 명령어 값 */
#define LCDOFF 0×08 /* LCD OFF 명령어 값 */
#define MODE4 0×20 /* 4비트 인터페이스 설정 */
#define FSET 0×28 /* 기능설정, 4비트 인터페이스, NF=10 : 2행 5×7 폰트 */
#define LCDCLR 0×01 /* LCD 클리어 */
#define MODENT 0×06 /* 엔트리모드 설정, 표시는 이동 않고, AC 증가, 커서 우측 이동 */

typedef unsigned char byte;

void lcd_cmd(unsigned char ch){ /LCD에 명령어값 1바이트 쓰는 서브루틴, ch는 명령어 값 /
unsigned char temp0, temp1;
delay_ms(1); / 약 15msec delay /
DDRA = 0xff; // 포트C를 출력으로
temp0 = ch & 0xf0; / 상위4비트 마스크 /
temp1 = temp0 | 0×04; / 하위 4비트에 0100b(RS=R/W=0, E=1) 써넣기 /
PORTA = temp1; / LCD에 명령어값의 상위 4비트 써넣기 /
temp1 = temp0 & 0xf0; / 하위 4비트에 0000b(RS=R/W=0, E=0) 써넣기 /
PORTA = temp1; / LCD에 입력 불허 /
delay_us(10); / 약 0.01 msec 시간지연 /
temp0 = (ch << 4) & 0xf0 ; / 하위4비트를 상위로 옮기고 마스크 /
temp1 = temp0 | 0×04 ; / 하위 4비트에 0100b(RS=R/W=0, E=1) 써넣기 /
PORTA = temp1; / LCD에 명령어값의 하위 4비트 써넣기 /
temp1 = temp0 & 0xf0; / 하위 4비트에 0000b(RS=R/W=0, E=0) 써넣기 /
PORTA = temp1; / LCD에 입력 불허 /
}

void lcd_ln11(void){ /* LCD의 1행1열에 커서를 위치시키는 서브루틴 */
lcd_cmd(CUR11);
}

void lcd_dat(unsigned char ch){ /* LCD에 1글자 쓰는 서브루틴, ch는 글자의 아스키 코드 값 */
unsigned char temp0, temp1;
delay_ms(1); /* 약 15msec delay */
DDRA = 0xff; // 포트C를 출력으로
temp0 = ch & 0xf0; /* 상위4비트 마스크 */
temp1 = temp0 | 0×05; /* 하위 4비트에 0101b(RS=1, R/W=0, E=1) 써넣기 */
PORTA = temp1; /* LCD에 DATA값의 상위 4비트 써넣기 */
temp1 = temp0 | 0×01; /* 하위 4비트에 0001b(RS=1, R/W=0, E=0) 써넣기 */
PORTA = temp1; /* LCD에 입력 불허 */
delay_us(10); /* 약 0.01 msec 시간지연 */
temp0 = (ch << 4) & 0xf0 ; /* 하위4비트를 상위로 옮기고 마스크 */
temp1 = temp0 | 0×05; /* 하위 4비트에 0101b(RS=1, R/W=0, E=1) 써넣기 */
PORTA = temp1; /* LCD에 DATA값의 하위 4비트 써넣기 */
temp1 = temp0 | 0×01; /* 하위 4비트에 0001b(RS=1, R/W=0, E=0) 써넣기 */
PORTA = temp1; /* LCD에 입력 불허 */
}

void lcd_init(void){ /* LCD 초기화 서브루틴 */
delay_ms(15); /* 약 15msec delay */
delay_ms(5);
lcd_cmd(MODE4);
delay_ms(5);
delay_ms(5); /* 약 5msec delay */
lcd_cmd(MODE4); delay_us(100);
delay_ms(5);
lcd_cmd(MODE4);
delay_ms(5);
lcd_cmd(FSET); /* 기능설정, 4비트 인터페이스, NF=10 : 2행 5×7 폰트 */
delay_ms(5);
lcd_cmd(LCDON); /* LCD ON 명령어 값 */
delay_ms(5);
lcd_cmd(LCDCLR); /* LCD Clear 명령어 값 */
delay_ms(5);
lcd_cmd(MODENT); /* 엔트리모드 설정, 표시는 이동 않고, AC 증가, 커서 우측 이동 */
delay_ms(5);
}

void lcd_str(char *str){ /* LCD에 flash에 저장된 문자열을 출력하는 함수 */
unsigned int i=0;
for(i=0;str[i] != 0; i++)
lcd_dat(str[i]);
}

//시간 관련 소스
char s,m,h;
char as,am,ah;
char a_on;//알람

//키관련 소스
char key;
char key_on;
char key_mode;
char key_count;
char key_buffer;

//1s
int us100;
char count_on;

//시간 변경 함수
void clock_count(){
if(key_mode==1){
}else if(key_mode==11){
}else{
if(count_on==1){
s++;
if(s==60){
m++;
s=0;
}
if(m==60){
h++;
m=0;
}
if(h==60){
h=0;
}
count_on=0;
}
}
}

void key_data(){
if(key_on==1){
//일반 모드
if(key_mode==0){
if(key==4){
key_mode=1;//시간 변경 모드
}else if(key==5){
key_mode=2;//알람 시간 변경 모드
}else if(key==6){
key_mode=3;//알람 설정 모드
}else if(key==7){
key_mode=0;
key_count=0;
}
//시간 시분초 결정
}else if(key_mode==1){
if(key==4){
key_count=(key_count+1)%6;//시분초
}else if(key==5){
key_count=(key_count+5)%6;//시분초
}else if(key==6){//시분초 변경 결정
key_mode=11;
key_buffer=key_count;
}else if(key==7){
key_mode=0;
key_count=0;
}
//시간 시분초 변경
}else if(key_mode==11){
if(key==4){
clock_data_p_change();
}else if(key==5){
clock_data_m_change();
}else if(key==6){
key_mode=1;
}else if(key==7){
key_mode=0;
key_count=0;
}
}else if(key_mode==2){
if(key==4){
key_count=(key_count+1)%6;//시분초
}else if(key==5){
key_count=(key_count+5)%6;//시분초
}else if(key==6){//시분초 변경 결정
key_mode=21;
}else if(key==7){
key_count=0;
key_mode=0;
}
//시간 시분초 변경
}else if(key_mode==21){
if(key==4){
alarm_data_p_change();
}else if(key==5){
alarm_data_m_change();
}else if(key==6){
key_mode=2;
}else if(key==7){
key_mode=0;
key_count=0;
}
}else if(key_mode==3){
if(key==4){
a_on=1;
}else if(key==5){
a_on=0;
}else if(key==6){
key_mode=0;
key_count=0;
}else if(key==7){
key_mode=0;
key_count=0;
}
}
key_on=0;
}
}

//시간 시분초 변경
void clock_data_p_change(){
if(key_count==0){
if((s%10)==9){
s=s-9;
}else{
s=s+1;
}
}else if(key_count==1){
if((s/10)==5){
s=s-50;
}else{
s=s+10;
}
}else if(key_count==2){
if((m%10)==9){
m=m-9;
}else{
m=m+1;
}
}else if(key_count==3){
if((m/10)==5){
m=m-50;
}else{
m=m+10;
}
}else if(key_count==4){
if((h/10)==2){
if((h%10)==3){
h=h-3;
}else{
h=h+1;
}
}else{
if((h%10)==9){
h=h-9;
}else{
h=h+1;
}
}
}else if(key_count==5){
if((h%10)<4){
if((h/10)==2){
h=h-20;
}else{
h=h+10;
}
}else{
if((h/10)==1){
h=h-10;
}else{
h=h+10;
}
}
}
}

//시간 시분초 변경
void clock_data_m_change(){
if(key_count==0){
if((s%10)==0){
s=s+9;
}else{
s=s-1;
}
}else if(key_count==1){
if((s/10)==0){
s=s+50;
}else{
s=s-10;
}
}else if(key_count==2){
if((m%10)==0){
m=m+9;
}else{
m=m-1;
}
}else if(key_count==3){
if((m/10)==0){
m=m+50;
}else{
m=m-10;
}
}else if(key_count==4){
if((h/10)==2){
if((h%10)==0){
h=h+3;
}else{
h=h-1;
}
}else{
if((h%10)==0){
h=h+9;
}else{
h=h-1;
}
}
}else if(key_count==5){
if((h%10)<4){
if((h/10)==0){
h=h+20;
}else{
h=h-10;
}
}else{
if((h/10)==0){
h=h+10;
}else{
h=h-10;
}
}
}
}

//시간 시분초 변경
void alarm_data_p_change(){
if(key_count==0){
if((as%10)==9){
as=as-9;
}else{
as=as+1;
}
}else if(key_count==1){
if((as/10)==5){
as=as-50;
}else{
as=as+10;
}
}else if(key_count==2){
if((am%10)==9){
am=am-9;
}else{
am=am+1;
}
}else if(key_count==3){
if((am/10)==5){
am=am-50;
}else{
am=am+10;
}
}else if(key_count==4){
if((ah/10)==2){
if((ah%10)==3){
ah=ah-3;
}else{
ah=ah+1;
}
}else{
if((ah%10)==9){
ah=ah-9;
}else{
ah=ah+1;
}
}
}else if(key_count==5){
if((ah%10)<4){
if((ah/10)==2){
ah=ah-20;
}else{
ah=ah+10;
}
}else{
if((ah/10)==1){
ah=ah-10;
}else{
ah=ah+10;
}
}
}
}

//시간 시분초 변경
void alarm_data_m_change(){
if(key_count==0){
if((as%10)==0){
as=as+9;
}else{
as=as-1;
}
}else if(key_count==1){
if((as/10)==0){
as=as+50;
}else{
as=as-10;
}
}else if(key_count==2){
if((am%10)==0){
am=am+9;
}else{
am=am-1;
}
}else if(key_count==3){
if((am/10)==0){
am=am+50;
}else{
am=am-10;
}
}else if(key_count==4){
if((ah/10)==2){
if((ah%10)==0){
ah=ah+3;
}else{
ah=ah-1;
}
}else{
if((ah%10)==0){
ah=ah+9;
}else{
ah=ah-1;
}
}
}else if(key_count==5){
if((ah%10)<4){
if((ah/10)==0){
ah=ah+20;
}else{
ah=ah-10;
}
}else{
if((ah/10)==0){
ah=ah+10;
}else{
ah=ah-10;
}
}
}
}

void lcd_display(){
if(key_mode==0){
lcd_cmd(0×80);
if(a_on==1){
lcd_str(“a_on s]”);
}else{
lcd_str(“a_off s]”);
}
lcd_dat(ah/10+0×30);
lcd_dat(ah%10+0×30);
lcd_dat(‘:’);
lcd_dat(am/10+0×30);
lcd_dat(am%10+0×30);
lcd_dat(‘:’);
lcd_dat(as/10+0×30);
lcd_dat(as%10+0×30);
PORTC=0X00;
lcd_cmd(0xc0);
lcd_str(“time] “);
lcd_dat(h/10+0×30);
lcd_dat(h%10+0×30);
lcd_dat(‘:’);
lcd_dat(m/10+0×30);
lcd_dat(m%10+0×30);
lcd_dat(‘:’);
lcd_dat(s/10+0×30);
lcd_dat(s%10+0×30);
}else if(key_mode==1){
lcd_cmd(0×80);
lcd_str(“time setting “);
PORTC=0X00;
lcd_cmd(0xc0);
lcd_dat(h/10+0×30);
lcd_dat(h%10+0×30);
lcd_dat(‘:’);
lcd_dat(m/10+0×30);
lcd_dat(m%10+0×30);
lcd_dat(‘:’);
lcd_dat(s/10+0×30);
lcd_dat(s%10+0×30);
lcd_dat(‘ ‘);
if(key_count==0){
lcd_str(“1s “);
}else if(key_count==1){
lcd_str(“10s “);
}else if(key_count==2){
lcd_str(“1m “);
}else if(key_count==3){
lcd_str(“10m “);
}else if(key_count==4){
lcd_str(“1h “);
}else if(key_count==5){
lcd_str(“10h “);
}
}else if(key_mode==11){
lcd_cmd(0×80);
if(key_count==0){
lcd_str(“time(1s) change “);
}else if(key_count==1){
lcd_str(“time(10s) change “);
}else if(key_count==2){
lcd_str(“time(1m) change “);
}else if(key_count==3){
lcd_str(“time(10m) change “);
}else if(key_count==4){
lcd_str(“time(1h) change “);
}else if(key_count==5){
lcd_str(“time(10h) change “);
}
PORTC=0X00;
lcd_cmd(0xc0);
lcd_dat(h/10+0×30);
lcd_dat(h%10+0×30);
lcd_dat(‘:’);
lcd_dat(m/10+0×30);
lcd_dat(m%10+0×30);
lcd_dat(‘:’);
lcd_dat(s/10+0×30);
lcd_dat(s%10+0×30);
lcd_str(” “);
}else if(key_mode==2){
lcd_cmd(0×80);
lcd_str(“alarm setting “);
PORTC=0X00;
lcd_cmd(0xc0);
lcd_dat(ah/10+0×30);
lcd_dat(ah%10+0×30);
lcd_dat(‘:’);
lcd_dat(am/10+0×30);
lcd_dat(am%10+0×30);
lcd_dat(‘:’);
lcd_dat(as/10+0×30);
lcd_dat(as%10+0×30);
lcd_dat(‘ ‘);
if(key_count==0){
lcd_str(“1s “);
}else if(key_count==1){
lcd_str(“10s “);
}else if(key_count==2){
lcd_str(“1m “);
}else if(key_count==3){
lcd_str(“10m “);
}else if(key_count==4){
lcd_str(“1h “);
}else if(key_count==5){
lcd_str(“10h “);
}
}else if(key_mode==21){
lcd_cmd(0×80);
if(key_count==0){
lcd_str(“alarm(1s) change “);
}else if(key_count==1){
lcd_str(“alarm(10s) change “);
}else if(key_count==2){
lcd_str(“alarm(1m) change “);
}else if(key_count==3){
lcd_str(“alarm(10m) change “);
}else if(key_count==4){
lcd_str(“alarm(1h) change “);
}else if(key_count==5){
lcd_str(“alarm(10h) change “);
}
PORTC=0X00;
lcd_cmd(0xc0);
lcd_dat(ah/10+0×30);
lcd_dat(ah%10+0×30);
lcd_dat(‘:’);
lcd_dat(am/10+0×30);
lcd_dat(am%10+0×30);
lcd_dat(‘:’);
lcd_dat(as/10+0×30);
lcd_dat(as%10+0×30);
lcd_str(” “);
}else if(key_mode==3){
lcd_cmd(0×80);
lcd_str(“alarm setting “);
PORTC=0X00;

lcd_cmd(0xc0);
if(a_on==0){
lcd_str(“alarm off “);
}else if(a_on==1){
lcd_str(“alarm on “);
}
}
}

char buzzer=0;
char ir_go=0;
void alarm_oper(void){
if(a_on==1){
if(h==ah){
if(m==am){
if(s==as){
buzzer=1;
ir_go=1;
}
}
}
}
if(buzzer==1){
PORTD|=0X02;
}else{
PORTD&=0Xfd;
}

delay_ms(1);

if(ir_go==1){
ir_car_run();
}
}

char sr,sl,sf,sb;
char ad_data;

void senser(){
ADMUX=0X60; //어느핀 변화시킬건지
ADCSRA=0XC7; //ad 변환 시작
while((ADCSRA&0×10)==0); //변수=AD값 걸림
ad_data=ADCH; //변수값에 저장
if(ad_data<100){
sf=1;
}else{
sf=0;
}
delay_ms(1);
ADMUX=0X61; //어느핀 변화시킬건지
ADCSRA=0XC7; //ad 변환 시작
while((ADCSRA&0×10)==0); //변수=AD값 걸림
ad_data=ADCH; //변수값에 저장
if(ad_data<100){
sb=1;
}else{
sb=0;
}
delay_ms(1);

ADMUX=0X62; //어느핀 변화시킬건지
ADCSRA=0XC7; //ad 변환 시작
while((ADCSRA&0×10)==0); //변수=AD값 걸림
ad_data=ADCH; //변수값에 저장
if(ad_data<100){
sr=1;
}else{
sr=0;
}
delay_ms(1);

ADMUX=0X63; //어느핀 변화시킬건지
ADCSRA=0XC7; //ad 변환 시작
while((ADCSRA&0×10)==0); //변수=AD값 걸림
ad_data=ADCH; //변수값에 저장
if(ad_data<100){
sl=1;
}else{
sl=0;
}
delay_ms(1);
}

void ir_car_run(){
senser();
//전방 물체 감지
if(sf==0){
//전후방 물체 감지
if(sb==0){
//오른쪽 물체 감지
if(sr==0){
//오른쪽으로 회전 7
PORTC=0X9C;
}else{
//왼쪽으로 회전 6 5 4
PORTC=0X6C;
}
}else{
//후방으로 전진 3 0
PORTC=0X5C;
}
}else{
//후방 물체 감지
if(sb==0){
//전방으로 전진 2 0
PORTC=0XAC;

}else{
//오른쪽 물체 감지
if(sr==0){
//전방으로 전진 1
PORTC=0XAC;
}else{
//왼쪽 물체 감지
if(sl==0){
//전방으로 전진 1
PORTC=0XAC;
}else{
//정지 0
PORTC=0X00;
}
}
}
}
}

void putch(unsigned char ch){ /* 한개의 문자를 pc로 송신한다. */
while((UCSR0A & 0×20) == 0);
UDR0 = ch;
UCSR0A |= 0×20; // 문자 송신준비완료
}

char ir_oper;

void ir_remote(){
//RC카
if(ir_rx_flag == 1){//데이터 전송
ir_rx_flag =0;
putch(ir_rx_data[0]);
putch(ir_rx_data[1]);
putch(ir_rx_data[2]);
putch(ir_rx_data[3]);
ir_oper=1;
//rc_data=ir_rx_data[2];
}
if(ir_oper==1){
if(ir_rx_data[2]==0×05){
//전방
PORTC=0XAC;
}else if(ir_rx_data[2]==0×08){
//왼쪽
PORTC=0X9C;
}else if(ir_rx_data[2]==0x0a){
//오른쪽
PORTC=0X6C;
}else if(ir_rx_data[2]==0x0d){
//뒤로
PORTC=0X5C;
}else if(ir_rx_data[2]==0×04){
ir_go=1;
}else{
PORTC=0X00; }
ir_oper=0;
}
}

int main(void){
DDRA = 0Xff; //LCD
DDRC = 0Xff; //모터 구동
DDRD = 0×02; //리모컨 소자
DDRE = 0X0f; //스위치
DDRF = 0X00; //거리 측정 센서

//외무 인터럽트
EICRB = 0XFF;//상승 에지
EICRA = 0XFF;//상승 에지
EIMSK = 0Xf1;//0-초음파,1-리모컨
UBRR0H = 0;
UBRR0L = 103; // baud rate 9600
UCSR0A = 0;
UCSR0B = 0×98;
UCSR0C = 0×06;
//타이머 카운트 100us
TIMSK = 0X02;
TCCR0 = 0X0A;
OCR0 = 200;
SREG = 0X80;
putch(0×03);
lcd_init();
//lcd_ln11();
//lcd_str(“COME ON”);
delay_ms(10);
while(1){
//물체 회피 및 부저
alarm_oper();
//리모컨 컨트롤
ir_remote();
//키스위치
key_data();
//LCD
lcd_display();
//시간 카운터
clock_count();
delay_ms(10);
}
}

SIGNAL(INT4_vect){
// lcd_cmd(0×80);
// lcd_str(“adfag”);
// delay_ms(3000);
key_on=1;
key=4;
buzzer=0;
ir_go=0;
PORTC=0X00;
}
SIGNAL(INT5_vect){
key_on=1;
key=5;
buzzer=0;
ir_go=0;
PORTC=0X00;
}
SIGNAL(INT6_vect){
key_on=1;
key=6;
buzzer=0;
ir_go=0;
PORTC=0X00;
}
SIGNAL(INT7_vect){
key_on=1;
key=7;
buzzer=0;
ir_go=0;
PORTC=0X00;
}
SIGNAL(TIMER0_COMP_vect){
ir_timer_cnt++;
us100=us100+1;
if(us100==10000){
us100=0;
count_on=1;
}
}

SIGNAL(INT0_vect){
switch(ir_state){
case ir_ready : //오류 데이터
ir_state = ir_lead;
break;
case ir_lead ://시작 관련 데이터
//리드 펄스 데이터가 오면 4.5ms과 0.5ms의 합의 구간인 5ms
//0×30=48, 0×35=53이다
if((ir_timer_cnt>=0×30) && (ir_timer_cnt<0×35)){
ir_state = ir_data;
}else{
ir_state = ir_state;
}
ir_bit_cnt = 0;
ir_rx_temp = 0;
break;

case ir_data ://진짜 데이터 3번 데이터 활용
if((ir_timer_cnt>=8) && (ir_timer_cnt<15)){ //0데이터
}else if((ir_timer_cnt>=19) && (ir_timer_cnt<30)){//1데이터
ir_rx_temp = ir_rx_temp|0×80;
}else { //에러 데이터
ir_state = ir_lead;
break;
}
ir_bit_cnt++;
////8개의 비트가 다 들어 올 경우 데이터화 시킴
if((ir_bit_cnt%8)==0){
ir_rx_data[(ir_bit_cnt/8)-1] = ir_rx_temp;
ir_rx_temp = 0;
if(ir_bit_cnt >= 32){//모든 데이터 다 들어 올 경우
ir_state = ir_ready;
ir_bit_cnt = 0;
ir_rx_flag = 1;//새로운 데이터 인식 변수
}
}
ir_rx_temp = ir_rx_temp>>1;//데이터화 하는 과정
break;
default: break;
}
ir_timer_cnt = 0;
}

입선을 수상하신 경성대학교 김가희님 외 3분께 진심으로 축하의 말씀을 드립니다.
수상하신 팀에게는 적립금 10만원과 함께 (주)칩센에서 제공해드리는 소정의 경품이 제공되었습니다.
다음호에는 경성대학교 전력 실험실 김민욱 외 4명이 수상한 ‘천지인 스위치 광고판’이 소개될 예정입니다.

 

 

Leave A Comment

*