PIC: Controle Remoto IR - Protocolo NEC
Esse é um decodificador de controle remoto infravermelho, para o protocolo NEC.
A decodificação do sinal funciona da seguinte maneira:
O sinal é conectado ao pino de interrupção externa. Quando ocorre o primeiro pulso do sinal, uma interrupção é gerada. Após isso, o código entra em loop e a cada novo pulso, é calculado o tempo desse pulso ( através da contagem da variável 'timer' ) e é salva na variável 'timerBuffer'. Após o fim do sinal, o código sai do loop. Depois, vem a decodificação. Ele faz a comparação do tempo de cada pulso (salvo na variavel 'timerBuffer' ), com os tempos padronizado do protocolo NEC.
No código, o loop dentro da rotina de interrupção ocorre a cada +-55us (por causa do delay). Então o valor de tempo da variável 'timerbuffer' é igual ao valor verdadeiro do tempo dividido por 55.
No código, o loop dentro da rotina de interrupção ocorre a cada +-55us (por causa do delay). Então o valor de tempo da variável 'timerbuffer' é igual ao valor verdadeiro do tempo dividido por 55.
O sensor utilizado é um módulo receptor infravermelho, pode ser o IRM2638.
DOWNLOAD:
Firmware: NEC_ir_pic18f4550.hex
Projeto: NEC_Ir_pic18f4550.rar
O código abaixo está configurado para utilizar o PIC18F2550/4550 com clock de 16Mhz. Para utilizar em outros PICs, verifique o datasheet e substitua os registros de interrupção( INT0IF_Bit e INT0IE_Bit ) e veja qual é o PINO de entrada da interrupção.
CÓDIGO
// LCD module connections sbit LCD_RS at RD0_bit; sbit LCD_EN at RD3_bit; sbit LCD_D4 at RD4_bit; sbit LCD_D5 at RD5_bit; sbit LCD_D6 at RD6_bit; sbit LCD_D7 at RD7_bit; sbit LCD_RS_Direction at TRISD0_bit; sbit LCD_EN_Direction at TRISD3_bit; sbit LCD_D4_Direction at TRISD4_bit; sbit LCD_D5_Direction at TRISD5_bit; sbit LCD_D6_Direction at TRISD6_bit; sbit LCD_D7_Direction at TRISD7_bit; // End LCD module connections bit decoded_flag; #define DEBUG #define PINO RB0_Bit //Estados #define _IDLE 0 #define _MARK 1 #define _SPACE 2 #define _STOP 3 // (tempo / 55.5) //NEC Protocol #define NEC_HDR_MARK 162 //9000us #define NEC_HDR_SPACE 81 //4500us #define NEC_BIT_MARK 10 //560us #define NEC_ONE_SPACE 29 //1600us #define NEC_ZERO_SPACE 10 //560us #define NEC_RPT_SPACE 41 //2250us #define NEC_TIME_EXCESS 4 struct irParam { char length; char timer; char state; char timerBuffer[75]; } IrRecv = {0, 0, 0}; unsigned long value; void interrupt() { volatile char pinValue = 0; if(INT0IF_Bit) { while(1) { pinValue = PINO; //PINO DE INTERRUPÇÃO INT0 IrRecv.timer++; if(IrRecv.length > 99) { IrRecv.state = _STOP; } if(IrRecv.state == _IDLE)//Estado inicial { if(pinValue == 1) //Mark { IrRecv.length = 0; IrRecv.timerBuffer[IrRecv.length++] = IrRecv.timer; IrRecv.timer = 0; IrRecv.state = _MARK; } } else if(IrRecv.state == _MARK)//Estado em nivel logico alto { if(pinValue == 0)//Space { IrRecv.timerBuffer[IrRecv.length++] = IrRecv.timer; IrRecv.timer = 0; IrRecv.state = _SPACE; } } else if(IrRecv.state == _SPACE)//Estado em nivel logico baixo { if(pinValue == 1)//Mark { IrRecv.timerBuffer[IrRecv.length++] = IrRecv.timer; IrRecv.timer = 0; IrRecv.state = _MARK; } else { if(IrRecv.timer > 100) IrRecv.state = _STOP; } } else if(IrRecv.state == _STOP)//Fim do sinal { decoded_flag = 1; IrRecv.timer = 0; break; } delay_us(49); } INT0IF_Bit = 0;//reseta a flag de interrupção } } //prepara a proxima decodificacao void Resume() { IrRecv.state = _IDLE; IrRecv.length = 0; } char DecodeNEC() { char offset = 1;//o primeiro pulso é ignorado char i=0; if(!decoded_flag) return 0; //compara com o tempo de SPACE do sinal de start if((IrRecv.timerBuffer[offset] < (NEC_HDR_SPACE - NEC_TIME_EXCESS)) || (IrRecv.timerBuffer[offset] > (NEC_HDR_SPACE + NEC_TIME_EXCESS))) { #ifdef DEBUG lcd_out(2, 1, "start erro"); #endif decoded_flag = 0; Resume(); return 0; } //Tamnho do buffer é 2 * 32(nBits) + 4 if(IrRecv.length < 68) { decoded_flag = 0; Resume(); return 0; } offset++; //Recupera o valor transmitido pelo sinal for(i=0;i < 32;i++) { if((IrRecv.timerBuffer[offset] < (NEC_BIT_MARK - NEC_TIME_EXCESS)) || (IrRecv.timerBuffer[offset] > (NEC_BIT_MARK + NEC_TIME_EXCESS))) { #ifdef DEBUG lcd_out(2,1," bit error "); #endif decoded_flag = 0; Resume(); return 0; } offset++; if((IrRecv.timerBuffer[offset] > (NEC_ONE_SPACE - NEC_TIME_EXCESS)) && (IrRecv.timerBuffer[offset] < (NEC_ONE_SPACE + NEC_TIME_EXCESS))) { value <<= 1; value |= 1; #ifdef DEBUG lcd_out(2,1,"data ok "); #endif } else if((IrRecv.timerBuffer[offset] > (NEC_ZERO_SPACE - NEC_TIME_EXCESS)) && (IrRecv.timerBuffer[offset] < (NEC_ZERO_SPACE + NEC_TIME_EXCESS))) { value <<= 1; #ifdef DEBUG lcd_out(2,1,"data ok "); #endif } else { #ifdef DEBUG lcd_out(2,1,"data error"); #endif decoded_flag = 0; Resume(); return 0; } offset++; } #ifdef DEBUG lcd_out(2,1," value ok "); #endif decoded_flag = 0; Resume(); return 1; } void main() { char msg[16]; TRISB.F0 = 1; TRISB.F6 = 0; TRISB.F7 = 0; GIE_Bit = 1;//habilita interrupção global //PEIE_Bit = 1;//habilita interrupção dos perifericos ADCON1 = 0x0F; //desativa a entrada analogica do pino RB0 //Pode-sedesativar a entrada analogica do pino RB0, configurando os fusíveis lcd_init(); lcd_cmd(_LCD_CURSOR_OFF); lcd_out(1,1,"VALOR:"); delay_ms(100); INT0IE_Bit = 1;//habilita interrupção externa while(1) { if(DecodeNEC()) { longwordtohex(value, msg);//converte o valor para hexadecimal lcd_out(1, 8, msg); if(value == 0x807608f7) PORTB.F6 = ~PORTB.F6; if(value == 0x80768877) PORTB.F7 = ~PORTB.F7; } } }
Boa Tarde companheiro. Estou tendo seguinte problema, tanto com o MPLab quanto para o CCS:
ResponderExcluirError 128 "arquivo.c" Line(1,1): A #device required before this line
Teriam como me ajudar?
Abraços
Yuri
O código está escrito para MikroC.
ExcluirComo adaptar esse circuito para o pic16f628a
ResponderExcluirPor gentileza teria o msm código para CCS compiler?
ResponderExcluirTem o código para CCS?
ResponderExcluirTeria o código para C18? só uso esse
ResponderExcluirOLA
ResponderExcluirBom trabalho ! eu usei o hexa que compilado por você e funcionou de primeira
Porem tentei montar um projeto e compilar no Mikroc e deu dois erros na linha 2
" ; expected but LCD_RS found e internal error " por que será não manjo bem do mikroc
talvez ele considerou sbit como sendo final da linha ????
abs
consegui montar todo o código no MikroC e configurar para o MCU PIC16F628A para testar.
ResponderExcluirporém não decodifica, provávelmente porque estou usando uma frequencia de 4MHz.
***Teria como usar assim? se eu mudar a divisão do tempo de 55,5us seria o suficiente?
pq tbm não sei calcular qual seria a divisão correta a colocar nesse caso.
Vc poderia dizer como vc chegou no 55,5us de divisão nesse projeto?
Vlw obrigado.
Ola teria como passar o codigo que foi adaptado para 16f628a
ExcluirPoderia por gentileza passar o código adaptado para MikroC
ExcluirCom esse condigo da para clonar o sinal de controle remoto de um ar condicionado.
ResponderExcluir