반응형

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');
    }
}




반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts