BASIC4MCU | 질문게시판 | Atmega128 광센서,스위치 를 이용한 led 제어
페이지 정보
작성자 pupuro 작성일2021-10-27 14:46 조회9,018회 댓글6건본문
Atmega128 광센서를 이용한 led 제어+외부인터럽트 스위치 답변글이 작동하지 않아서 그 코드를 참고해 다시 코드를 짜보았습니다.
광센서를 가리면 불이 꺼지고 광센서를 가리지 않으면 불이 켜지는 것까진 되지만스위치 입력을 받으면 광센서를 안가리면 불이 꺼지고 광센서를 가리면 불이 켜져야하는것이 되지 않습니다.새로 광센서를 읽는 함수를 만들어 보았습니다(readlight 2)#define F_CPU 16000000L#include <avr/io.h>#include <util/delay.h>#include <stdio.h>#include "UART1.h"#include <avr/interrupt.h>volatile int state =1; //led켜진상태로 시작void readLight(INT0_vect) //광센서 가리면 꺼짐{if(read_ADC()>980){state=0;}else{state=1;}}void readLight2(INT0_vect){if(read_ADC()>980){state=1;}else{state=0;}}void INIT_PORT(void){DDRD=0x00;PORTD=0x01;DDRB=0x01;PORTB=0x00;}void INIT_INTO(void){EIMSK |=(1<<INT0);EICRA |=(1<<ISC01);sei();}FILE OUTPUT=FDEV_SETUP_STREAM(UART1_transmit,NULL,_FDEV_SETUP_WRITE);FILE INPUT=FDEV_SETUP_STREAM(NULL,UART1_receive,_FDEV_SETUP_READ);void ADC_init(unsigned char channel){ADMUX |=(1<<REFS0);ADCSRA |=0x07;ADCSRA |=(1<<ADEN);ADCSRA |=(1<<ADFR);ADMUX = ((ADMUX&0xE0)|channel);ADCSRA |=(1<<ADSC);}int read_ADC(void){while(!(ADCSRA&(1<<ADIF)));return (ADC);}int main(void){int read;char dir; //스위치 변수stdout = &OUTPUT;stdin= &INPUT;UART1_init();ADC_init(0);INIT_PORT();INIT_INTO();while(1){read= read_ADC();_delay_ms(1000);readLight();if(state==1){PORTB=0x01;}else{PORTB=0x00;}if(DDRD & 0x00) //스위치 누르면{if(dir==0) //dir=0이 1로바뀜dir=1; PORTB=0x00; readLight2();} //led 켜지고 광센서 가리면 켜짐else { //스위치 안누르면if(dir==1) //dir=1이 0으로 바뀜dir=0; readLight(); }//광센서 가리면 꺼짐}return 0;}
댓글 6
조회수 9,018master님의 댓글
master 작성일
if(DDRD & 0x00)
이(어떤 값에 0을 & 시키는) 연산은 아무런 의미가 없습니다.
또, PIND가 아닌 DDRD 레지스터를 왜 연산에 사용하고 있는지도 모르겠습니다.
PIND를 사용했더라도 인터럽트 함수를 사용하고 있다면, 동시에 메인에서 인터럽트 핀을 체크할 필요가 없겠죠
master님의 댓글
master 작성일
인터럽트0 함수를 2개씩 왜 만드는지도 모르겠고
인터럽트 함수를 메인에서 호출하는 것도 처음봅니다.
인터럽트가 무엇인지, 어떤 경우에 어떻게 사용하는지 전혀 모르시나봅니다.
master님의 댓글
master 작성일
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//
volatile int dir=1,read;
//
void readLight(INT0_vect){ dir^=1; }
//
int main(void){
DDRB=0x01; PORTD=0x01;
ADMUX=0x40; ADCSRA=0xE7;
EIMSK=0x01; EICRA=0xAA; sei();
while(1){
_delay_ms(1000);
read=ADCW;
if(dir){ if(read>980)PORTB=0; else PORTB=1; }
else { if(read>980)PORTB=1; else PORTB=0; }
}
}
master님의 댓글
master 작성일
UART1을 코드에 추가하고 싶은 것 같은데요
추가해드리죠
헤더파일이나 번거로운 코드를 사용하지 않아도 됩니다.
물론, 추가한 코드는 메인에서 사용하지 않으므로 불필요한 코드입니다.
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
//
volatile int dir=1,read;
//
char U1_RX(void){ while(!(UCSR1A&0x80)); return UDR1; }
void U1_TX(char c){ while(!(UCSR1A&0x20)); UDR1=c; }
void U1_STR(char *s){ while(*s)U1_TX(*s++); }
//
void readLight(INT0_vect){ dir^=1; }
//
int main(void){
DDRB=0x01; PORTD=0x01;
UCSR0B=0x18; UBRR0L=103; //9600
ADMUX=0x40; ADCSRA=0xE7;
EIMSK=0x01; EICRA=0xAA; sei();
while(1){
_delay_ms(1000);
read=ADCW;
if(dir){ if(read>980)PORTB=0; else PORTB=1; }
else { if(read>980)PORTB=1; else PORTB=0; }
}
}
master님의 댓글
master 작성일
read=ADCW;
AVRStudio 버전에 따라서 위 코드가 적용되지 않는 경우에는 아래 코드를 사용하세요
read=ADC;
나중버전이 아래 코드를 사용해야 합니다.
ADC 및 ADCW는 16비트 레지스터명입니다.
pupuro님의 댓글
pupuro
감사합니다 올려주신 코드 참고하고 공부해서 약간 수정 했더니 해결했습니다