BASIC4MCU | 질문게시판 | atmega128 인터럽트 입력을 통한 모드 변경
페이지 정보
작성자 수제비성애자 작성일2021-12-20 11:10 조회2,989회 댓글6건본문
질문 드리고 혼자 생각해서 코드는 원하던 동작은 만들었습니다.
#define F_CPU 16000000
#define STOP 0
#define START 1// switch(state)를 정의해준다.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> // 여러 함수를 사용하기 위해 헤더함수 선언
unsigned char count_int=0;
char count=0;
void Show4Digit(int number); // Show4Digit
void ShowDigit(int i, int digit);
void Run(void);
void mode_1_Stop_Watch();
void mode_2_Stop_Alarm();
void mode_3_Free_Topic();
int mode_state = mode_1_Stop_Watch();
while(1)
{
switch(mode_state)
{
case 1:
mode_1_Stop_Watch;
break;
case 2:
mode_2_Stop_Alarm();
break;
case 3:
mode_3_Free_Topic();
}
}
const unsigned char Segment_Data[] =
{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F};
char COLUMN[4]={0,0,0,0};
// Default SHOW_NUMBER12=0, SHOW_NUMBER34=0
int SHOW_NUMBER=0, SHOW_NUMBER12=0, SHOW_NUMBER34=0; //세그먼트는 0000으로 시작한다.
int state=STOP; // 시작 state는 STOP이다.
ISR(TIMER0_OVF_vect) // TIMER0 has overflowed
{
if(state==START){
count_int++; // count_int값이 하나 증가
// 244번에 한번씩 seconds를 하나 증가 즉, 244.14 Hz / 244 = 1Hz, 즉 1초임.
if(count_int == 244){
PORTG ^= 0x03; //G포트 다이오드 on
SHOW_NUMBER34++; //1초가 지날 때 Seconds를 1씩 올린다.
count_int=0; //다시 count는 0부터 세어진다.
}
}
}
ISR(INT0_vect) {
if(state==STOP) state=START; // state가 STOP으로 시작되고, INT0을 누르면 state는 START로 바뀐다. 따라서 INT0을 1번 누르면 START가 된다.
}
ISR(INT1_vect) {
if(state==START) state=STOP; // state가 start일 때 INT1을 누르면 state는 START로 바뀐다.
}
ISR(INT2_vect) {
if(mode_state==2) mode_state=1;
else mode_state==2;
}
ISR(INT3_vect) {
if(mode_state==3) mode_state=1;
else mode_state==3;
}
int main(void) {
DDRC = 0xff; DDRA = 0xff; //출력으로 사용합니다.
EICRA = 0x0F; // Rising Edge detection on INT0 & INT1
EIMSK = 0x03; // Set INT0 & INT1
SREG |= 0x80; // Global Interrupt Enable
TCCR0 = 0x06; // Normal mode, prescale 256, 16M/256=62500Hz
TCNT0 = 0x00; // n=0, 256 count, 62500Hz/256=244.14Hz
TIMSK = 0x01; // timer0 OVERFLOW interrupt enable
PORTC = 0x00;
state=STOP; //시작 state는 stop
while (1) {
Run();
SHOW_NUMBER=SHOW_NUMBER12*100+SHOW_NUMBER34;
Show4Digit(SHOW_NUMBER);
} //Show_NUMBER는 세븐세그먼트 순서대로 천의자리부터 일의자리까지 각 숫자가 값을 가지는 천의자리 숫자입니다.
}
void Show4Digit(int number) {
COLUMN[0] = number/1000; //천의자리 표시
COLUMN[1] = (number%1000)/100; //백의자리 표시
COLUMN[2] = (number%100)/10; //십의자리 표시
COLUMN[3] = (number%10); //일의자리 표시
for(int i=0;i<4;i++) {
ShowDigit(COLUMN[i],i); //한 자릿수씩 숫자를 표현합니다.
_delay_ms(2); // wait for a second
}
}
void Run(void) {
switch(state) {
case STOP : break; // state가 STOP일 때 멈춘다.
case START: TIMER0_OVF_vect;
if(SHOW_NUMBER34>59){
SHOW_NUMBER12++;
if(SHOW_NUMBER12>59) SHOW_NUMBER12=0;
SHOW_NUMBER34=0; // state가 STATRT일 때 34자리는 1씩 올라가고, 34가 59보다 클 때, 12는 1씩 증가한다. 12가 59보다 크게되면 00.00이 된다.
}
break;
}
}
void ShowDigit(int i, int digit) {
PORTC=~(0x01<<digit);
if(digit==1)
PORTA = Segment_Data[i]|0x80; // 두 번째 세븐세그먼트의 dp포인트에 LED가 들어오게 함
else
PORTA = Segment_Data[i];
}
이 상태에서 어떤 모드에서든 int2를 누르면 알람모드로 변경해서 int0을 눌렀을 때 모드에 맞는 기능 수행,int2를 다시 누르면 모드 1로 변경.어떠 모드에서든 int3을 누르면 자유주제로 변경해서 int0을 눌렀을 때 모드에 맞는 기능 수행을 하려고 하는데 모드 변경이 안됩니다.int3을 다시 누르면 모드1로 변경case를 사용해서 모드에 값을 입력해주려고 했는데 아무래도 while, swicth를 잘못 쓴것으로 보이는데 어디를 수정하면 모드를 변경할 수 있을까요?
댓글 6
조회수 2,989master님의 댓글
master 작성일
뭘 하려는지 이해가 안됩니다.
제가 적어드린 답변코드를 수정해서 다시 만들어보시고
뭘 원하는지 명확하게 작성해보세요
수제비성애자님의 댓글
수제비성애자
첫 실행모드에서는 다음과 같이 작동하고
INT3을 누르면 다른 모드로 변경하여 INT0을 눌렀을 때 첫 모드와 다른 기능을 수행하고
INT4를 누르면 또 다른 모드로 변경하여 INT0을 눌렀을 때 또 다른 기능을 수행하게 하고 싶습니다.
#define F_CPU 16000000
#define STOP 0
#define START 1
#define INIT 2 // switch(state)를 정의해준다.
#define mode_0_Stop_Watch 3
#define mode_1_Alarm 4
#define mode_2_Free_Topic 5
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> // 여러 함수를 사용하기 위해 헤더함수 선언
unsigned char count_int=0;
char count=0;
void Show4Digit(int number); // Show4Digit
void ShowDigit(int i, int digit);
void Run(void);
const unsigned char Segment_Data[] =
{0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x6F};
char COLUMN[4]={0,0,0,0};
// Default SHOW_NUMBER12=0, SHOW_NUMBER34=0
int SHOW_NUMBER=0, SHOW_NUMBER12=0, SHOW_NUMBER34=0; //세그먼트는 0000으로 시작한다.
int state=STOP; // 시작 state는 STOP이다.
int mode=mode_0_Stop_Watch;
ISR(TIMER0_OVF_vect) // TIMER0 has overflowed
{
if(state==START){
count_int++; // count_int값이 하나 증가
// 244번에 한번씩 seconds를 하나 증가 즉, 244.14 Hz / 244 = 1Hz, 즉 1초임.
if(count_int == 244){
PORTG ^= 0x03; //G포트 다이오드 on
SHOW_NUMBER34++; //1초가 지날 때 Seconds를 1씩 올린다.
count_int=0; //다시 count는 0부터 세어진다.
}
}
}
ISR(INT0_vect) {
if(state==STOP) state=START; // state가 STOP으로 시작되고, INT0을 누르면 state는 START로 바뀐다. 따라서 INT0을 1번 누르면 START가 된다.
}
ISR(INT1_vect) {
if(state==START) state=STOP; // state가 start일 때 INT1을 누르면 state는 START로 바뀐다.
}
ISR(INT2_vect) {
if(state==START) state==STOP;
if(mode==mode_1_Alarm)
mode=mode_0_Stop_Watch;
else mode==mode_1_Alarm;
}
ISR(INT3_vect) {
if(state==START) state==STOP;
if(mode==mode_2_Free_Topic)
mode==mode_0_Stop_Watch;
else mode==mode_2_Free_Topic;
}
int main(void) {
DDRC = 0xff; DDRA = 0xff; //출력으로 사용합니다.
EICRA = 0xFF; // Rising Edge detection on INT0 & INT1
EIMSK = 0x0F; // Set INT0 & INT1
SREG |= 0x80; // Global Interrupt Enable
TCCR0 = 0x06; // Normal mode, prescale 256, 16M/256=62500Hz
TCNT0 = 0x00; // n=0, 256 count, 62500Hz/256=244.14Hz
TIMSK = 0x01; // timer0 OVERFLOW interrupt enable
PORTC = 0x00;
state=STOP; //시작 state는 stop
while (1) {
Run();
SHOW_NUMBER=SHOW_NUMBER12*100+SHOW_NUMBER34;
Show4Digit(SHOW_NUMBER);
} //Show_NUMBER는 세븐세그먼트 순서대로 천의자리부터 일의자리까지 각 숫자가 값을 가지는 천의자리 숫자입니다.
}
void Show4Digit(int number) {
COLUMN[0] = number/1000; //천의자리 표시
COLUMN[1] = (number%1000)/100; //백의자리 표시
COLUMN[2] = (number%100)/10; //십의자리 표시
COLUMN[3] = (number%10); //일의자리 표시
for(int i=0;i<4;i++) {
ShowDigit(COLUMN[i],i); //한 자릿수씩 숫자를 표현합니다.
_delay_ms(2); // wait for a second
}
}
void Run(void)
{
switch(state)
{
case STOP : break; // state가 STOP일 때 멈춘다.
case START: TIMER0_OVF_vect;
if(SHOW_NUMBER34>59)
{
SHOW_NUMBER12++;
if(SHOW_NUMBER12>59) SHOW_NUMBER12=0;
SHOW_NUMBER34=0; // state가 STATRT일 때 34자리는 1씩 올라가고, 34가 59보다 클 때, 12는 1씩 증가한다. 12가 59보다 크게되면 00.00이 된다.
}
break;
case INIT : SHOW_NUMBER12=0, SHOW_NUMBER34=0, state=STOP; //state가 INIT일 때 모두 0000으로 초기화하고 state=STOP으로 돌아간다.
break;
}
}
void ShowDigit(int i, int digit) {
PORTC=~(0x01<<digit);
if(digit==1)
PORTA = Segment_Data[i]|0x80; // 두 번째 세븐세그먼트의 dp포인트에 LED가 들어오게 함
else
PORTA = Segment_Data[i];
}
INT3을 누르면 stop이 되어야 하는데 안되는 상황입니다. 이해 가실까요?
mode가 stopwatch,freetopic일 때, INT2를 누르면 alarm으로 가고, mode가 alarm일 때 INT2를 다시 누르면 stopwatch.
mode가 stopwatch,alarm일 때, INT3를 누르면 freetopic으로 가고, mode가 freetopic일 때 INT3를 다시 누르면 stopwatch.
다음과 같이 작동하기 위해 INT2, INT3에 If를 다음과 같이 넣어준 것 입니다.
master님의 댓글
master 작성일
ISR(INT3_vect) {
if(state==START) state==STOP;
if(mode==mode_2_Free_Topic)mode==mode_0_Stop_Watch;
else mode==mode_2_Free_Topic;
대입은 == 가 아니고 = 입니다.
한 두군데가 아니군요
수제비성애자님의 댓글
수제비성애자
진짜 기본적인 실수를 하고 있었네요.. 바쁘신 와중에 감사합니다.
master님의 댓글
master 작성일
EIMSK = 0x1F; // Set INT0 & INT1
INT4를 이네이블 시켰는데 INT4 함수는 안보입니다.
이네이블 시키고 함수가 없는 경우 엉뚱하게 동작하거나 먹통이 될 수도 있습니다.
수제비성애자님의 댓글
수제비성애자
방금 확인해서 수정했습니다.. INT4도 쓰려다가 안쓰기로 바꿔서 실수한 것으로 보입니다. 친절한 답변 감사합니다.