적외선 통신( IR ) - 리모컨 NFC format을 시리얼로 출력하는 코드AVR/Atmega128 강좌2023. 10. 13. 22:44
Table of Contents
반응형
LG에서 사용하는 NEC format을 시리얼로 출력해주는 소스코드입니다. 리모컨에서 버튼을 누르면 해당되는 값을 16진수로 변환하여 시리얼로 출력해줍니다.
2016. 6. 5 최초작성
실행화면입니다.
아래 주소에 있는 코드를 atmega128에서 동작하도록 수정하고 시리얼 통신으로 결과값을 받아볼 수 있도록 수정하였습니다.
http://extremeelectronics.co.in/code-libraries/using-ir-remote-with-avr-mcus/
10진수를 16진수로 변환하는 부분은 아래 사이트에 있는 코드를 사용했습니다.
https://dojang.io/mod/page/view.php?id=743
usart.h
#ifndef USART_H_ #define USART_H_ #include <avr/io.h> #include "serial.h" #define UBRR_ASYNC_NORMAL(br) ((F_CPU / (br * 16UL)) - 1) #define _BV(bit) \ (1 << (bit)) void serial_init(uint32_t baudrate) { // Set Baudrate UBRR0H = (UBRR_ASYNC_NORMAL(baudrate) >> 8); UBRR0L = UBRR_ASYNC_NORMAL(baudrate); // Enable RX and TX UCSR0B |= _BV(RXEN0) | _BV(TXEN0); // Set 8N1 Framing UCSR0C |= _BV(UCSZ00) | _BV(UCSZ01); } void serial_write(char c) { while ( !(UCSR0A & (1 << UDRE0)) ); UDR0 = c; } char serial_read() { while ( !(UCSR0A & (1 << RXC0)) ); return UDR0; } #endif /* USART_H_ */ |
main.c
#define F_CPU 16000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <stdlib.h> #include <util/delay.h> #include "usart.h" //States #define IR_VALIDATE_LEAD_HIGH 0 #define IR_VALIDATE_LEAD_LOW 1 #define IR_RECEIVE_BITS 3 #define IR_WAIT_STOP_BIT 4 //Others #define TOL 0.1 //Tollerence for timming #define QMAX 8 //Size of the Remote command buffer #define RC_NONE 255 //This val is returned by GetRemoteCmd when no key is pressed //Globals volatile unsigned int Time; //Main timer, stores time in 10us, //Updated by ISR(TIMER0_COMP) volatile unsigned char BitNo; //Pos of next BIT volatile unsigned char ByteNo; //Pos of current Byte volatile unsigned char IrData[4]; //The four data Bytes of Ir Packet //2-Byte Address 2-Byte Data volatile unsigned char IrCmdQ[QMAX];//Final Command Received (Buffer) volatile unsigned char PrevCmd; //Used for repeat //Variables used for start repeating only after a key is pressed for certain time volatile unsigned char Repeat; //1=yes 0=no volatile unsigned char RCount; //Repeat count volatile char QFront=-1,QEnd=-1; volatile unsigned char State; //State of receiver volatile unsigned char Edge; //Edge of interrupt [ RISING=1 OR FALLING=0 ] volatile unsigned int stop; /**********************************************************************************************/ /* F U N C T I O N S S T A R T S */ /**********************************************************************************************/ void RemoteInit() { char i; for(i=0;i<4;i++) IrData[i]=0; stop=0; State=IR_VALIDATE_LEAD_HIGH; Edge=0; Repeat=0; //Setup Timer0 //------------ TCCR0|=((1<<CS00)|(1<<WGM01)); //Prescaler : Fcpu Mode : CTC TIMSK|=(1<<OCIE0); //Enable Output Compare Interrupt OCR0=160; //Set Compare Value //Set Up INT0 //------------ EICRA |= (1<<ISC01); //INT ON Falling Edge EIMSK |= (1<<INT0); //Enable INT0 //Enable Interrupts //------------------- sei(); } ISR(TIMER0_COMP_vect) { Time++; } ISR(INT0_vect) { EIMSK&=(~(1<<INT0)); //Disable INT1 sei(); if(stop) return; unsigned int TempTime=Time; Time=0; TCNT0=0; switch(State) { case IR_VALIDATE_LEAD_HIGH: { if(Edge) { //Rising if((TempTime>(900-(900*TOL))) && (TempTime<(900+(900*TOL)))) { //Lead High Correct State=IR_VALIDATE_LEAD_LOW; //INT ON FALLING EDGE EICRA&=(~((1<<ISC01)|(1<<ISC00))); EICRA|=(1<<ISC01); Edge=0; } else { ResetIR(); } } else { //Falling EICRA|=((1<<ISC01)|(1<<ISC00)); //Set INT on Rising Edge Edge=1; } break; } case IR_VALIDATE_LEAD_LOW: { if((TempTime>(450-(450*TOL))) && (TempTime<(450+(450*TOL)))) { //Got a valid leader State=IR_RECEIVE_BITS; BitNo=0; ByteNo=0; EICRA|=((1<<ISC01)|(1<<ISC00)); //Set INT on Rising Edge Edge=1; } else if((TempTime>200) && (TempTime<245)) { if(Repeat) { //Got a repeat pulse if((QEnd==(QMAX-1) && QFront==0)||((QEnd+1)==QFront)) { QFront++; if(QFront==(QMAX)) QFront=0; } if(QEnd==(QMAX-1)) QEnd=0; else QEnd++; IrCmdQ[QEnd]=PrevCmd; if(QFront==-1) QFront=0; } else { RCount++; if(RCount==4) Repeat=1; } ResetIR(); }else { ResetIR(); } break; } case IR_RECEIVE_BITS: { if(Edge) { //Rising if((TempTime>50) && (TempTime<69)) { //Correct Beg of BIT found //INT ON FALLING EDGE EICRA&=(~((1<<ISC01)|(1<<ISC00))); EICRA|=(1<<ISC01); Edge=0; } else { ResetIR(); } } else { //Falling if((TempTime>41) && (TempTime<58)) { //We got a '0' here BitNo++; if(BitNo==8) { BitNo=0; ByteNo++; if(ByteNo==4) { State=IR_WAIT_STOP_BIT; } } EICRA|=((1<<ISC01)|(1<<ISC00)); //Set INT on Rising Edge Edge=1; }else if((TempTime>(169-(169*TOL))) && (TempTime<(169+(169*TOL)))) { //We Have got a '1' here IrData[ByteNo]|=(1<<BitNo); BitNo++; if(BitNo==8) { BitNo=0; ByteNo++; if(ByteNo==4) { State=IR_WAIT_STOP_BIT; } } EICRA |=((1<<ISC01)|(1<<ISC00)); //Set INT on Rising Edge Edge=1; }else { ResetIR(); } } break; } case IR_WAIT_STOP_BIT: { if(Edge) { //Check for integrity if(IrData[2]==((unsigned char)~IrData[3])) { //Now We Have Got a packet //Add its Cmd to Queue //Step1:Check of Q full if((QEnd==(QMAX-1) && QFront==0)||((QEnd+1)==QFront)) { QFront++; if(QFront==(QMAX)) QFront=0; } if(QEnd==(QMAX-1)) QEnd=0; else QEnd++; IrCmdQ[QEnd]=IrData[2]; PrevCmd=IrData[2]; if(QFront==-1) QFront=0; //Prevent repeating immediatly Repeat=0;//It will be enabled after 4 repeat pulses RCount=0; ResetIR(); } } } break; } EIMSK|=(1<<INT0); //Enable INT1 } void ResetIR() { char i; for(i=0;i<4;i++) IrData[i]=0; State=IR_VALIDATE_LEAD_HIGH; //INT ON FALLING EDGE EICRA &=(~((1<<ISC01)|(1<<ISC00))); EICRA |=(1<<ISC01); Edge=0; } unsigned char GetRemoteCmd(char wait) { unsigned char cmd; if(wait) while(QFront==-1); else if(QFront==-1) return (RC_NONE); cmd=IrCmdQ[QFront]; if(QFront==QEnd) QFront=QEnd=-1; else { if(QFront==(QMAX-1)) QFront=0; else QFront++; } return cmd; } void main() { uint8_t cmd=0; serial_init(9600); RemoteInit(); DDRD |= 1<< 3; while(1) { cmd=GetRemoteCmd(1); if ( cmd == 0xa5 ) continue; int decimal = cmd; char hexadecimal[20] = { 0, }; // 16진수로 된 문자열을 저장할 배열 int position = 0; while (1) { int mod = decimal % 16; // 16으로 나누었을 때 나머지를 구함 if (mod < 10) // 나머지가 10보다 작으면 { // 숫자 0의 ASCII 코드 값 48 + 나머지 hexadecimal[position] = 48 + mod; } else // 나머지가 10보다 크거나 같으면 { // 나머지에서 10을 뺀 값과 영문 대문자 A의 ASCII 코드 값 65를 더함 hexadecimal[position] = 65 + (mod - 10); } decimal = decimal / 16; // 16으로 나눈 몫을 저장 position++; // 자릿수 변경 if (decimal == 0) // 몫이 0이되면 반복을 끝냄 break; } // 배열의 요소를 역순으로 출력 for (int i = position - 1; i >= 0; i--) { serial_write(hexadecimal[i]); } serial_write('\r'); serial_write('\n'); } } |
반응형
'AVR > Atmega128 강좌' 카테고리의 다른 글
AVRISP mkII 및 Microchip Studio 사용법 (2) | 2024.08.17 |
---|---|
Atmel Studio 7.0에서 시뮬레이터 사용하기( Simulator ) (0) | 2023.10.18 |
Atmega128 기초 - SPI(Serial Peripheral Interface) (0) | 2023.10.13 |
Atmega128 기초 - 시리얼 통신( USART ) (0) | 2023.10.13 |
Atmega128 기초 – ADC(Analog to Digital) 변환 (0) | 2023.10.13 |
시간날때마다 틈틈이 이것저것 해보며 블로그에 글을 남깁니다.
블로그의 문서는 종종 최신 버전으로 업데이트됩니다.
여유 시간이 날때 진행하는 거라 언제 진행될지는 알 수 없습니다.
영화,책, 생각등을 올리는 블로그도 운영하고 있습니다.
https://freewriting2024.tistory.com
제가 쓴 책도 한번 검토해보세요 ^^
@webnautes :: 멈춤보단 천천히라도
그렇게 천천히 걸으면서도 그렇게 빨리 앞으로 나갈 수 있다는 건.
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!