적외선(IR) 프로그램 수정
1. 적외선(IR) 신호 읽기 - ATmega8 개선하기
2019/10/22 - [AVR/작품] - 적외선(IR) 신호 읽기 - ATmega8에서 IR 리모콘에서 오는 신호의 low 길이와 high 길이를 측정하는 프로그램을 만들었습니다. 이 프로그램은 Input Capture로 들어오는 의미 없는 첫 데이터를 그대로 표시한다는 문제점을 가지고 있었습니다. 이 문제점을 개선해 봤습니다.
////////////////////////////////////////////////// // __TIMER1_CAPT (timer1 capture interrupt service routine) // PARAM NONE // RETURN NONE // CHANGED AL ////////////////////////////////////////////////// __TIMER1_CAPT: PUSH AL IN AL,SREG PUSH AL PUSH AH PUSH ZL PUSH ZH IN AL,ICR1L IN AH,ICR1H LDI ZL,0 OUT TCNT1H,ZL OUT TCNT1L,ZL IN ZL,TCCR1B SBRC ZL,ICES1 RJMP __TIMER1_CAPT_SET_FALLING SBR ZL,(1 << ICES1) OUT TCCR1B,ZL CPI IR_STATE,IR_STANDBY // skip first useless data BREQ __TIMER1_CAPT_QUIT LDI ZL,LOW(IR_QUEUE_HIGH) LDI ZH,HIGH(IR_QUEUE_HIGH) ADD ZL,IR_QUEUE_HEAD_L ADC ZH,IR_QUEUE_HEAD_H ST Z+,AL ST Z,AH // MOVW ZL,IR_QUEUE_DATA_L // data++; // ADIW ZL,1 // MOVW IR_QUEUE_DATA_L,ZL MOVW ZL,IR_QUEUE_HEAD_L ADIW ZL,2 LDI AL,LOW(IR_QUEUE_SIZE) // head %= IR_QUEUE_SIZE; LDI AH,HIGH(IR_QUEUE_SIZE) CP ZL,AL CPC ZH,AH BRLO __TIMER1_CAPT_STORE_QUEUE_HEAD CLR ZL CLR ZH __TIMER1_CAPT_STORE_QUEUE_HEAD: MOVW IR_QUEUE_HEAD_L,ZL __TIMER1_CAPT_QUIT: LDI IR_STATE,IR_DATA_IN POP ZH POP ZL POP AH POP AL OUT SREG,AL POP AL RETI __TIMER1_CAPT_SET_FALLING: CBR ZL,(1 << ICES1) OUT TCCR1B,ZL LDI ZL,LOW(IR_QUEUE_LOW) LDI ZH,HIGH(IR_QUEUE_LOW) ADD ZL,IR_QUEUE_HEAD_L ADC ZH,IR_QUEUE_HEAD_H ST Z+,AL ST Z,AH RJMP __TIMER1_CAPT_QUIT ////////////////////////////////////////////////// // __TIMER1_COMPA (timer1 output1A compare interrupt service routine) // PARAM NONE // RETURN NONE // CHANGED AL ////////////////////////////////////////////////// __TIMER1_COMPA: PUSH AL IN AL,SREG CPI IR_STATE,IR_DATA_IN BRNE __TIMER1_COMPA_QUIT LDI IR_STATE,IR_NO_MORE __TIMER1_COMPA_QUIT: OUT SREG,AL POP AL RETI
두 개의 함수를 수정합니다.
첫번째로 Input Capture 인터럽트 서비스인 __TIMER1_CAPT를 수정합니다. 위 소스에 표시는 하지 않았지만 프로그램 시작시 각 종 변수들을 초기화하는 함수 VARIABLES_INIT 함수에서 IR_STATE에 IR_STANSBY 값을 넣습니다. 첫 데이터가 들어올 때에 __TIMER1_CAPT 함수에서 IR_STATE의 값을 검사해서값이 IR_STANDBY이면 현재 카운터 값은 의미없는 데이터이기 때문에 IR_QUEUE에 넣지 않고(24, 25행), IR_STATE 변수에 IR_DATA_IN을 넣고 인터럽트 서비스를 종료합니다. 이렇게하여 첫 데이터는 버리고, 두번째 데이터부터 IR_QUEUE에 넣을 수 있습니다.
두번째로 TIMER1 Compare match 인터럽트 서비스인 __TIMER1_COMPA를 수정합니다. IR_STATE 변수가 IR_DATA_IN인 상태에서 이 인터럽트가 걸렸을 때에만 데이터 입력이 종료되었다는 의미로 IR_STATE 변수에 IR_NO_MORE 값을 갖도록 합니다(75, 76, 77행).
이렇게 수정한 후에 MAIN_LOOP에서 IR_STATE의 값이 IR_NO_MORE가 될 때까지 대기합니다. IR_STATE의 값이 IR_NO_MORE가 되면 IR_QUEUE의 값을 모두 표시한 다음에 IR_STATE에 IR_STANDBY를 넣고, 다시 IR_STATE의 값이 IR_NO_MORE가 될 때까지 대기합니다.
2. 적외선 리모콘(IR remocon) 신호 분석 - ATmega8 개선하기
이전 글 2019/10/28 - [AVR/작품] - 적외선 리모콘(IR remocon) 신호 분석 - ATmega8을 두가지 사항을 개선합니다. 첫째는 위의 1. 적외선(IR) 신호 읽기 - ATmega8 개선하기에서와 마찬가지로 첫 데이터를 취합하지 않는 것입니다. 위의 예에서와 같이 __TIMER1_CAPT와 __TIMER1_COMPA 인터럽트 서비스 루틴을 수정합니다.
두번째는 IR 신호 분석 루틴인 ANALYZE_REMOCON 함수를 수정하는 것입니다. 이전의 글 2019/10/28 - [AVR/작품] - 적외선 리모콘(IR remocon) 신호 분석 - ATmega8에서 세 가지 IR 프로토콜(NEC 프로토콜, TC9012 프로토콜, SAMSUNG 하우젠 천정형 에어콘 프로토콜)의 신호를 분석했습니다. 이 세 프로토콜은 LEADER 신호의 길이는 모두 달랐습니다. low(0)과 high(1)의 길이는 NEC 프로토콜과 TC9012 프로토콜은 같았으나, 삼성 하우젠 천정형 에어콘 프로토콜은 다른 두 프로토콜보다 짧았습니다. 사실은 삼성 하우젠 천정형 에어콘의 리모콘 프로토콜의 사양을 모르기 때문에, 2019/10/22 - [AVR/작품] - 적외선(IR) 신호 읽기 - ATmega8에서 작성한 프로그램으로 측정한 값을 기초로 어림잡아 사용했습니다. 그러던 중에 2019/11/02 - [AVR/작품] - 적외선 리모콘(IR Remocon) 신호 보내기 - ATmega8에서 삼성 천정형 에어콘에 low(0)과 high(1)의 신호 길이를 NEC 프로토콜이나 TC9012 프로토콜과 같이 보내도 동작한다는 사실을 발견했습니다.
그래서 이전의 글에서는 NEC 프로토콜과 TC9012 프로토콜은 같은 루틴을 사용하고 삼성 하우젠 천정형 에어컨은 별도의 루틴으로 처리했던 것을 모두 하나의 루틴에서 처리하도록 개선했습니다. 이 때에 삼성 하우젠 천정형 에어콘 리모콘의 신호 길이가 다른 두 프로토콜 신호의 길이보다 조금 짧기때문에 low 값과 high 값의 신호 길이 범위를 정하는 매크로 MIN_0_LENGTH, MAX_0_LENGTH, MIN_1_LENGTH, MAX_1_LENGTH의 값을 조금 조정했습니다.
수정한 LengthIR_M8.asm과 RecieveIR_M8의 소스 프로그램을 첨부합니다.