Consultar ensayos de calidad


El protocolo de los controles remotos: Philips RC-5



El protocolo de los controles remotos: Philips RC-5
A menudo en la etapa de desarrollo de algún proyecto pensamos en que seria útil la utilización de un control a distancia. El control de este tipo mas comúnmente utilizado es el control remoto mediante infrarrojos, como el usado en cualquier televisor o equipo de audio. 
Tenemos dos alternativas: o desarrollamos desde cero nuestro protocolo de comunicaciones (y el hardware del emisor) o bien adoptamos alguno de los existentes en el mercado.
Quizás el más difundido y sobre el que más información se puede encontrar es el empleado por Philips, llamado 'RC-5'. Este protocolo ha sido adoptado por muchos otros fabricantes, por lo que es posible encontrar controles remotos 'genéricos' por muy poco dinero.
Este documento contiene la información necesaria para que podamos decodificar los mensajes enviados por estos controles remotos en nuestros proyectos. |


ÍNDICE:
> Introducción
> Características
> El protocolo
> Comandos pre-definidos
> Link externo: receptor de comandos Philips RC-5 con PIC16F84A
 
> Características:
Las características mas sobresalientes de este protocolo están resumidas en las siguientes líneas:
- 5 bits de dirección y 6 bits para el comando (7, en el caso del RC5X)
- Codificación tipo Manchester (Bi-phase coding)
- Frecuencia portadora de 36KHz.
- Tiempo constante para cada bit, de 1.778ms (64 ciclos a 36KHz.)

La mayoría de los controles remotos implementan este protocolo.
 
[Volver al Índice]
> El protocolo:
El protocolo consiste en un tren de pulsos cuadrados de 36Khz (la denominada 'portadora'). Cada '1' esta codificado como 889 microsegundos de pulsos, y 889 microsegundos de 'silencio'. El '0' se codifica como 889 microsegundos de 'silencio' y 889 microsegundos de pulsos. La longitudtotal del '0' y del '1' es idéntica, y son 1778 microsegundos (o 1,778 milisegundos). El grafico siguiente ilustra claramente esto:

Dentro de un bit 'caben' exactamente 64 pulsos, si la portadora es de 36KHz. Es decir, el periodo de una señal de 36KHz es de 1/36.000 = 27.78125 us, que multiplicado por 64 da exactamente 1778 us. Este es un buen dato para tener en cuenta el diseño del software de nuestro receptor.
Para que el receptor sepa que le esta 'diciendo' el emisor remoto, debe poder interpretar las 'tramas' de ceros y unos que este le envía. Cada trama es un comando, y esta compuesto por 14 bits (15 en el caso del RC5X). De esos 14 bits, los primeros 2 bits son de 'start' (arranque): siempre son '1'. El tercer bit se invierte cada vez que una tecla se pulsa y se suelta nuevamente, para poder distinguir si una tecla permanece presionada o se ha presionado mas de una vez. Los siguientes 5 bits corresponden a la dirección del dispositivo receptor, y los últimos 6 al comando trasmitido. Esto permite utilizar un mismo control remoto para comandar diferentes equipos, simplemente asignando a cada uno un código de dirección diferente.

Una trama RC5 completa.
Hay una variación del código RC5 llamada RC5X que dispone de 7 bits para determinar el comando (lo que permite 128 comandos diferentes vs. los 64 comandos del RC5 tradicional). La forma de la trama es la misma, pero el segundo bit de start (S2) es utilizado como el bit 7 del comando.
 
Tanto en la dirección como en el comando, primero se transmite el bit mas significativo (MSB) y por ultimo el menos significativo (LSB)
La longitud completa de la trama es igual a 14 * 1.778 us = 24.892 us. Si la tecla se mantiene presionada, la trama se reenvía continuamente, pero con una pausa de equivalente a 50 bits ( 50 x 1.778 us = 88.900us) entreuna y otra transmisión. Como dijimos antes, viendo el estado del tercer bit podemos determinar si se trata de pulsaciones sucesivas de la misma tecla (el bit cambiaria) o de una misma pulsación 'larga' (el bit permanece en el mismo estado)

Diagramas de tiempo para una transmisión completa.
[Volver al Índice]
> Comandos pre-definidos
Si estamos creando nuestro propio control remoto, podemos adoptar cualquier dirección y comando para las funciones que implementemos. Pero lo más posible es que queramos utilizar un control remoto de algún aparato en desuso o incluso un control remoto 'genérico' nuevo, que seguramente nos costara menos que armarnos uno.
En ese caso, deberíamos consultar las siguientes tablas para saber cuales son los comandos pre-definidos por Philips:

Direcciones. Las que figuran en blanco no están asignadas, y es buena idea
utilizarlas para nuestros proyectos.
 

Lista de comandos asignados para TV y VCR por Philips.

Receptor de códigos de control remoto RC5 de Philips

RC5 es la norma universal de Philips Electronics para sus mandos a distancia por IR (controles remotos) ya sean para equipos de audio, TV's, videocaseteras, etc. La idea es utilizar un mismo circuito integrado emisor para todos los equipos y modificar solo el dato a enviar. Este circuito permite ver sobre una pantalla de LCD los códigos de control RC5 generados por un control remoto.

El circuito es bien simple y se reduce a un microcontrolador PIC (con su respectivo programa cargado), una pantalla LCD de 2 líneas x 20 caracteres y un receptor IR estándar de TV. La alimentación del circuito es de 5V y consume poco menos de 200mA como máximo. El preset de 10K permite ajustar el contraste de la pantalla.
; ** ** ** ** ** ** ** ** ** ** *******;
; This program reads the Philips RC5 remote control codes from a
; handheld infrared remote control, and displays the decoded
; data words on an LCD.
;
; IMPORTANT NOTE: This code may be used for private purposes only.
; Anyone contemplating commercial use of this code should check
; with Philips Corporation for possible limitations and
; restrictions on the use of their RC5 remote control code format.
;
; The interface works with a Hitachi HD66702- or 44780-based LC-Display
; This is a 2 line * 20 characters display module.
;
; Program READRC5.ASM
; Last update SEPT. 15, 1996
; Author Brian Aase
; Thanks to Peer Ouwehand for the enhanced LCD driver routines and demo code.
;
; ** ** ** ** ** ** ** ** ** ** *******
;Mod info: This version assumes RA3 idling at high level so that Sharp
;IR pickup can be connected directly.
;
; ** ** ** ** ** ** ** ** ** ** *******
; Fosc = 4MHz
; Cycle_time = 1/Fosc / 4
; = 1/(4*10^6) / 4
; = 1uSec
; ** ** ** ** ** ** ** ** ** ** *******

LIST P=16C84

__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON
RADIX DECinclude <c:mplabp16c84.inc>

; ** ** ** ** ** ** ** ** ** ** *******
; Equates, I/O, vars
; ** ** ** ** ** ** ** ** ** ** *******
RESET_V EQU 0x0000 ; Address of RESET Vector
ISR_V EQU 0x0004 ; Address of Interrupt Vector
OSC_FREQ EQU D'4000000' ; Oscillator Frequency is 4 MHz

LCD_DATA EQU PORTB ; LCD data lines interface
LCD_DATA_TRIS EQU TRISB
LCD_CTRL EQU PORTA ; LCD control lines interface

LCD_LINE0 EQU 0x000
LCD_LINE1 EQU 0x040
LCD_LINE2 EQU 0x014
LCD_LINE3 EQU 0x054

; PORTA bits
DATA_IN EQU 3 ; Input data from IR pickup
LCD_E EQU 2 ; LCD Enable control line
LCD_RW EQU 1 ; LCD Read/Write control line
LCD_RS EQU 0 ; LCD Register-Select control line

; PORTB bits
DB7 EQU 7 ; LCD dataline 7 (MSB)
DB6 EQU 6 ; LCD dataline 6
DB5 EQU 5 ; LCD dataline 5
DB4 EQU 4 ; LCD dataline 4
DB3 EQU 3 ; LCD dataline 3
DB2EQU 2 ; LCD dataline 2
DB1 EQU 1 ; LCD dataline 1
DB0 EQU 0 ; LCD dataline 0 (LSB)

; misc.

#DEFINE RAMstart 0x0C ; For 16C84

LCD_TEMP EQU RAMstart ; LCD subroutines internal use
COUNT EQU RAMstart+1 ; A counter, used multiple places
DELAY EQU RAMstart+2 ; Used in DELAYxxx routines
X_DELAY EQU RAMstart+3 ; Used in X_DELAYxxx routines
TOGGLE EQU RAMstart+4 ; The RC5 Toggle bit
SYSTEM EQU RAMstart+5 ; The RC5 System word
COMND EQU RAMstart+6 ; The RC5 Command word
MZDATA EQU RAMstart+7 ; The RC5 extra Data word
POINTER EQU RAMstart+8 ; Used in TABLE_MSG subroutine
ASCII_O EQU RAMstart+9 ; ASCII One's digit to print
ASCII_T EQU RAMstart+10 ; ASCII Ten's digit to print
ASCII_H EQU RAMstart+11 ; ASCII Hundred's digit to print
BIT_COUNT EQU RAMstart+12 ; Counter for incoming bits
BYTE_COUNT EQU RAMstart+13 ; Counter for buffer bytes
TEMP EQU RAMstart+14 ; Used by PARSE to hold the 2-bit pattern
SERIAL_BUF EQU RAMstart+15 ; Buffer for incoming bitstream
SERIAL_2 EQU RAMstart+16
SERIAL_3 EQU RAMstart+17
SERIAL_4 EQU RAMstart+18
SERIAL_5 EQU RAMstart+19SERIAL_6 EQU RAMstart+20
FIELD EQU RAMstart+21 ; Temporary storage for field bit
PARSE_FLAGS EQU RAMstart+22 ; DECODE returns its data in this
MZ_FLAG EQU RAMstart+23 ; Set if there is an extra data word
; in the bitstream

w EQU 0
f EQU 1
ONE EQU B'00000001' ; 2-bit incoming pattern matches
ZERO EQU B'00000010'
; ** ** ** ** ** ** ** ** ** ** *******
; Program start
; ** ** ** ** ** ** ** ** ** ** *******
ORG RESET_V ; RESET vector location
RESET GOTO START


; ** ** ** ** ** ** ** ** ** ** *******
; This is the Periperal Interrupt routine. Should NOT get here
; ** ** ** ** ** ** ** ** ** ** *******
ORG ISR_V ; Interrupt vector location
INTERRUPT BCF STATUS, RP0 ; Select bank 0
GOTO INTERRUPT

;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; Table message to display: kept right up front to avoid crossing 0xff boundary
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==

TABLE_ST MOVWF PCL
MSG_T RETLW 'T'
RETLW 'O'RETLW 'G'
RETLW ' '
RETLW '='
RETLW ' '
RETLW 0x00
MSG_S RETLW 'S'
RETLW 'Y'
RETLW 'S'
RETLW 'T'
RETLW 'E'
RETLW 'M'
RETLW ' '
RETLW '='
RETLW ' '
RETLW 0x00
MSG_C RETLW 'C'
RETLW 'O'
RETLW 'M'
RETLW 'N'
RETLW 'D'
RETLW ' '
RETLW '='
RETLW ' '
RETLW 0x00
MSG_D RETLW 'D'
RETLW 'A'
RETLW 'T'
RETLW 'A'
RETLW ' '
RETLW '='
RETLW 0x00
MSG_Y RETLW 'D' ; Place your debug messages here
RETLW 'E'
RETLW 'B'
RETLW 'U'
RETLW 'G'
RETLW ' '
RETLW 'M'
RETLW 'E'
RETLW 'S'
RETLW 'S'
RETLW 'A'
RETLW 'G'
RETLW 'E'
RETLW ' '
RETLW '1'
RETLW 0x00
MSG_Z RETLW 'M'
RETLW 'E'
RETLW 'S'
RETLW 'S'
RETLW 'A'
RETLW 'G'
RETLW 'E'
RETLW ' '
RETLW '2'
TABLE_END RETLW 0X00

IF( (TABLE_ST & 0x0FF) >= (TABLE_END & 0x0FF) )
MESSG 'Warning - Message table 'TABLE_ST' crosses page boundary'
ENDIF

; ** ** ** ** ** ** ** ** ** ** *******
; Initialize processor registers
; ** ** ** ** ** ** ** ** ** ** *******
START ; POWER_ON Reset (Beginning of program)
CLRF STATUS ; Do initialization, Select bank 0
CLRF INTCON ; Clear int-flags, Disable interrupts
CLRF PCLATH ; Keep in lower 2KByte

CLRF PORTA ; ALL PORT outputs should output Low.
CLRF PORTB
BSF STATUS, RP0 ; Select bank 1
MOVLW 0x0F8 ; RA2-0 outputs, RA5-3 inputs
MOVWF TRISA
MOVLW 0x000 ; RB7-0 outputs
MOVWF TRISB
MOVLW B'11010001' ; Option register setup:
; No RB Pullups
; TMR0 fed from internal clock
; Assign prescaler to TMR0
; use 1:4 prescaling ratio
MOVWF OPTION_REG

BCF STATUS, RP0 ; Select bank 0
CALL LCDINIT ; Initialize LCDisplay

; ** ** ** ** ** ** ** ** ** ** *****
; Look at RA4 to invoke debug routine instead of regular program; ** ** ** ** ** ** ** ** ** ** *****

POLL_RA4 BTFSS PORTA,4
GOTO POLL_RA3 ; Start regular program if RA4 is low
MOVLW LCD_LINE0 ;
CALL LCDSDDA ; Set to first line
MOVLW MSG_Y ; Point to first message string
CALL TABLE_MSG ; Display it
MOVLW LCD_LINE1 ;
CALL LCDSDDA ; Set to second line
MOVLW MSG_Z ; Point to next message string
CALL TABLE_MSG ; Display it
DB_LOOP GOTO DB_LOOP ; Hang here forever

; ** ** ** ** ** ** ** ** ** ** *****
; When power is applied, wait for data on RA3 before proceeding
; Remember the Sharp IR pickup has an active-low output
; ** ** ** ** ** ** ** ** ** ** *****

POLL_RA3 BTFSC PORTA, DATA_IN ; The pickup module has inverse logic
GOTO POLL_RA3 ; High is idle, low is active
MOVLW D'147' ; Found data, load timer for 444 uS
; minus 11 overhead = 433 cycles
; 255-147=108 counts x 4 prescaled
MOVWF TMR0 ; Which creates a 1/4 bit wait
BCF INTCON,T0IF ; Clear timer overflow flag
BCF STATUS,C ; Initialize the carry flag
CALL READ ; Read the data stream
BTFSC STATUS,C ; Carry flag set means bogus data
GOTO POLL_RA3 ; Start over if bad datastream
CALL PARSE ; Parse the data
BTFSC STATUS,C ; Carry flag set means no successGOTO POLL_RA3 ; Start over if bad parse

; ** ** ** ** ** ** ** ** ** ** *******
; Display the data we gathered
;
; ** ** ** ** ** ** ** ** ** ** *******

MOVLW LCD_LINE0 ; 0x00
CALL LCDSDDA ; Position cursor leftmost on first line
MOVLW MSG_T ; Point to Toggle message
CALL TABLE_MSG ; Display message
MOVF TOGGLE,w ; Load the toggle bit to display
MOVWF ASCII_O ; Send data to conversion routine
CALL HEX_TO_ASC ; Convert to ascii
MOVF ASCII_O,w ; Ones digit is in ascii_o
CALL LCDPUTCHAR ; Display toggle data
MOVLW LCD_LINE0 + 0x009 ; Position 9
CALL LCDSDDA ; Position cursor
MOVLW MSG_S ; Point to System message
CALL TABLE_MSG ; Display message
MOVF SYSTEM,w ; Load the system byte to display
MOVWF ASCII_O ; Send data to conversion routine
CALL HEX_TO_ASC ; Convert to ascii
MOVF ASCII_T,w ; Tens digit
CALL LCDPUTCHAR ; Display it
MOVF ASCII_O,w ; Ones digit
CALL LCDPUTCHAR ; Display it

MOVLW LCD_LINE1 ; 0x40
CALL LCDSDDA ; Set cursor leftmost on line 2
MOVLW MSG_C; Point to Command message
CALL TABLE_MSG ; Display the message
MOVF COMND,w ; Load the command byte to display
MOVWF ASCII_O ; Send data to conversion routine
CALL HEX_TO_ASC ; Convert to ascii
MOVF ASCII_H,w ; Hundreds digit
CALL LCDPUTCHAR ; Display it
MOVF ASCII_T,w ; Tens digit
CALL LCDPUTCHAR ; Display it
MOVF ASCII_O,w ; Ones digit
CALL LCDPUTCHAR ; Display it
MOVLW LCD_LINE1 + 0x00C ; Position 12
CALL LCDSDDA ; Set cursor
MOVLW MSG_D ; Point to Data message
CALL TABLE_MSG ; Display the message

BTFSS MZ_FLAG,0 ; Is there a data word to display?
GOTO NO_DATA ; No

MOVF MZDATA,w ; Load the data byte to display
MOVWF ASCII_O ; Send data to conversion routine
CALL HEX_TO_ASC ; Convert to ascii
MOVF ASCII_T,w ; Tens digit
CALL LCDPUTCHAR ; Display it
MOVF ASCII_O,w ; Ones digit
CALL LCDPUTCHAR ; Display it
GOTO POLL_RA3 ; Wait for incoming again

NO_DATA MOVLW ' ' ; Print spaces instead of data value
CALL LCDPUTCHAR
MOVLW ' '
CALL LCDPUTCHAR
GOTO POLL_RA3 ; Wait for incoming again; ** ** ** ** ** ** ** ** ** ** *******
; Main program ends here
;
; ** ** ** ** ** ** ** ** ** ** *******


; ** ** ** ** ** ** ** ** ** ** *******
; Send a message using a table to output the message
;
; ** ** ** ** ** ** ** ** ** ** *******
TABLE_MSG
MOVWF POINTER ; Point to the first char. we want
LOOP_WR
MOVFW POINTER ; Renew the pointer
CALL TABLE_ST ; Initiate table lookup
XORLW 0x00 ; Is this the terminating char?
BTFSC STATUS,Z
GOTO END_WR
CALL LCDPUTCHAR ; Actually put the char on display
INCF POINTER,f ; Point to the next char
GOTO LOOP_WR ; Do next character
END_WR
RETURN

; ** ** ** ** ** ** ** ** ** ** *******
; LCD Module Subroutines
; ** ** ** ** ** ** ** ** ** ** *******
;
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDINIT
; Initilize LC-Display Module
; This code sets up the Optrex DMC50218 (2x20)
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==LCDINIT
; Busy-flag is not yet valid
CLRF LCD_CTRL ; ALL PORT output should output Low.
; power-up delay
MOVLW 0x01E
CALL X_DELAY500 ; 30 * 0.5mS = 15mS
; Busy Flag should be valid from here
MOVLW 0x038 ; 8-bit-interface, 2-lines
CALL LCDPUTCMD
MOVLW 0x000 ; disp.off, curs.off, no-blink
CALL LCDDMODE
CALL LCDCLEAR
MOVLW 0x004 ; disp.on, curs.off
CALL LCDDMODE
MOVLW 0x002 ; auto-inc (shift-cursor)
CALL LCDEMODE
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCD_ENABLE
; Pulses LCD enable pin
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCD_ENABLE
BSF LCD_CTRL, LCD_E ; LCD E-line High
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDBUSY
; Returns when LCD busy-flag is inactive
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDBUSY
BSF STATUS,RP0 ; Select Register page 1
MOVLW 0x0FF ; Set PORTB for input
MOVWF LCD_DATA_TRIS
BCF STATUS, RP0 ; Select Register page 0BCF LCD_CTRL, LCD_RS; Set LCD for command mode
BSF LCD_CTRL, LCD_RW; Setup to read busy flag
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_DATA, W ; Read busy flag + DDram address
BCF LCD_CTRL, LCD_E ; LCD E-line Low
ANDLW 0x80 ; Check Busy flag, High = Busy
BTFSS STATUS, Z
GOTO LCDBUSY
LCDNOTBUSY BCF LCD_CTRL, LCD_RW
BSF STATUS, RP0 ; Select Register page 1
MOVLW 0x000
MOVWF LCD_DATA_TRIS ; Set PORTB for output
BCF STATUS, RP0 ; Select Register page 0
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDCLEAR
; Clears display and returns cursor to home position (upper-left corner).
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDCLEAR
MOVLW 0x001
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDHOME
; Returns cursor to home position.
; Returns display to original position (when shifted).
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDHOME
MOVLW 0x002
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDEMODE; Sets entry mode of display.
; Required entry mode must be set in W
; b0 : 0 = no display shift 1 = display shift
; b1 : 0 = auto-decrement 1 = auto-increment
; b2-7 : don't care
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDEMODE
ANDLW 0x003 ; Strip upper bits
IORLW 0x004 ; Function set
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDDMODE
; Sets display control.
; Required display mode must be set in W
; b0 : 0 = cursor blink off 1 = cursor blink on
; b1 : 0 = cursor off 1 = cursor on
; b2 : 0 = display off 1 = display on (display data remains in DDRAM)
; b3-7 : don't care
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDDMODE
ANDLW 0x007 ; Strip upper bits
IORLW 0x008 ; Function set
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDSCGA
; Sets Character-Generator-RAM address. CGRAM is read/written after
; this setting.
; Required CGRAM address must be set in W
; b0-5 : required CGRAM address
; b6-7 : don't care;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDSCGA
ANDLW 0x03F ; Strip upper bits
IORLW 0x040 ; Function set
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDSDDA
; Sets the Display-Data-RAM address. DDRAM data is read/written after
; this setting.
; Required DDRAM address must be set in W
; b0-6 : required DDRAM address
; b7 : don't care
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDSDDA
IORLW 0x080 ; Function set
CALL LCDPUTCMD
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDGADDR
; Returns address counter contents, used for both DDRAM and CGRAM.
; RAM address is returned in W
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDGADDR
BSF STATUS,RP0 ; Select Register page 1
MOVLW 0x0FF ; Set PORTB for input
MOVWF LCD_DATA_TRIS
BCF STATUS, RP0 ; Select Register page 0
BCF LCD_CTRL, LCD_RS; Set LCD for command mode
BSF LCD_CTRL, LCD_RW; Setup to read busy flag
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_DATA, W ; Read busy flag + RAM address
BCF LCD_CTRL, LCD_E ; LCD E-line LowANDLW 0x07F ; Strip upper bit
BCF LCD_CTRL, LCD_RW
BSF STATUS, RP0 ; Select Register page 1
MOVLW 0x000
MOVWF LCD_DATA_TRIS ; Set PORTB for output
BCF STATUS, RP0 ; Select Register page 0
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDPUTCHAR
; Sends character to LCD
; Required character must be in W
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDPUTCHAR
MOVWF LCD_TEMP ; Character to be sent is in W
CALL LCDBUSY ; Wait for LCD to be ready
BCF LCD_CTRL, LCD_RW; Set LCD in read mode
BSF LCD_CTRL, LCD_RS; Set LCD in data mode
BSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_TEMP, W
MOVWF LCD_DATA ; Send data to LCD
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
; LCDPUTCMD
; Sends command to LCD
; Required command must be in W
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==
LCDPUTCMD
MOVWF LCD_TEMP ; Command to be sent is in W
CALL LCDBUSY ; Wait for LCD to be ready
BCF LCD_CTRL, LCD_RW; Set LCD in read mode
BCF LCD_CTRL, LCD_RS; Set LCD in command modeBSF LCD_CTRL, LCD_E ; LCD E-line High
MOVF LCD_TEMP, W
MOVWF LCD_DATA ; Send data to LCD
BCF LCD_CTRL, LCD_E ; LCD E-line Low
RETURN

; ** ** ** ** ** ** ** ** ** ** *******
; Delay_time = ((DELAY_value * 3) + 4) * Cycle_time
; DELAY_value = (Delay_time - (4 * Cycle_time)) / (3 * Cycle_time)
;
; i.e. (@ 4MHz crystal)
; Delay_time = ((32 * 3) + 4) * 1uSec
; = 100uSec
; DELAY_value = (500uSec - 4) / 3
; = 165.33
; = 165
; ** ** ** ** ** ** ** ** ** ** *******
DELAY500 MOVLW D'165' ; +1 1 cycle
MOVWF DELAY ; +2 1 cycle
DELAY500_LOOP DECFSZ DELAY, F ; step 1 1 cycle
GOTO DELAY500_LOOP ; step 2 2 cycles
DELAY500_END RETURN ; +3 2 cycles
;
;
X_DELAY500 MOVWF X_DELAY ; +1 1 cycle
X_DELAY500_LOOP CALL DELAY500 ; step1 wait 500uSec
DECFSZ X_DELAY, F ; step2 1 cycle
GOTO X_DELAY500_LOOP ; step3 2 cycles
X_DELAY500_END RETURN ; +2 2 cycles

;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==; HEX_TO_ASC .. Converts a hex digit to three ASCII characters
; Enter with the hex digit in ASCII_O
; Exit with Hundreds ascii digit in ASCII_H,
; Tens ascii digit in ASCII_T,
; and Ones ascii digit in ASCII_O.
; The incoming byte is not preserved.
;= == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == ==

HEX_TO_ASC MOVLW '0' ; Preload a zero into 10's & 100's
MOVWF ASCII_T
MOVWF ASCII_H

DO_100s MOVLW D'100'
SUBWF ASCII_O,w ; Subtract 100 to test size
BNC DO_10s ; It's less than 100, so branch

MOVWF ASCII_O ; It was bigger, so decrement it
INCF ASCII_H,f ; Bump up the 100's digit
GOTO DO_100s ; Loop again till < 100

DO_10s MOVLW D'10'
SUBWF ASCII_O,w ; Subtract 10 to test size
BNC ADJUST ; It's less than 10, so branch

MOVWF ASCII_O ; It was bigger, so decrement it
INCF ASCII_T,f ; Bump up the 10's digit
GOTO DO_10s ; Loop again till < 10

ADJUST MOVLW '0' ; The # in ASCII_O is now < 10
ADDWF ASCII_O,f ; Turn it into an ASCII character

BLANK_ZEROSMOVLW '0'
XORWF ASCII_H,w ; Is the 100's char a 0?
BTFSS STATUS,Z
GOTO HEX_DONE ; No.
MOVLW ' ' ; Yes,
MOVWF ASCII_H ; So replace it with a space.

MOVLW '0'
XORWF ASCII_T,w ; Is the 10's char a 0?
BTFSS STATUS,Z
GOTO HEX_DONE ; No.
MOVLW ' ' ; Yes,
MOVWF ASCII_T ; So replace it with a space

HEX_DONE RETURN

; ** ** ** ** ** ** ** ** ** ** ******
;READ .. reads the incoming data stream and saves it into a 6-byte buffer
; Remember again that the IR pickup output is active low
; ** ** ** ** ** ** ** ** ** ** ******

READ ; First, zero all storage
MOVLW SERIAL_BUF ; Start of RAM buffer
MOVWF FSR ; Load indirect register
RD_LOOP1 CLRF INDF ; Zero out the buffer
INCF FSR,f ; Increment to next byte
MOVLW SERIAL_BUF+6 ; Test for 6 bytes done
XORWF FSR,w
BTFSS STATUS,Z
GOTO RD_LOOP1 ; Loop till done

CLRF BIT_COUNT
CLRF BYTE_COUNT
MOVLW SERIAL_BUF ; Reset the indirect pointer back
MOVWF FSR ; to the start of the buffer space

RD_LOOP2 BTFSS INTCON, T0IF ; Wait till timer goes444 Usec
GOTO RD_LOOP2
CALL RESTART_TMR0 ; Reset timer for 888 uSec
BTFSC PORTA,3 ; Check RA3 signal (i.e. debounce)
GOTO BAD_DATA ; If it's high (logic 0), bail out

RD_LOOP3 BTFSS INTCON, T0IF ; Wait till timer goes 888 uSec
GOTO RD_LOOP3

CALL RESTART_TMR0 ; Restart 888 uSec timer
INCF BIT_COUNT,f
MOVLW D'43' ; See if we've done all 42 bits
XORWF BIT_COUNT,w
BTFSC STATUS,Z
GOTO RD_FINISH ; We've done all 42 bits
BSF STATUS,C ; Preset the carry bit
BTFSC PORTA,3 ; Test RA3
BCF STATUS,C ; Input bit is high (logic 0) so change carry
; Now the input bit is in the carry flag
RLF INDF,f ; Rotate it into the buffer
INCF BYTE_COUNT,f ;
BTFSC BYTE_COUNT,3 ; See if all 8 bits are filled
CALL NEXT_BYTE ; Yes, use next buffer byte
GOTO RD_LOOP3 ; Loop back & do the rest of the bits

RD_FINISH BCF STATUS,C ;
RLF INDF,f ; The last buffer byte has only 2
RLF INDF,f ; bits loaded.
RLF INDF,f ; So we shift them up to the top
RLF INDF,f ; the hard way.
RLF INDF,f
RLF INDF,f
BCF STATUS,C ; Clear carry to show a successful capture

RETURN

; ** ** ** ** ** ** ** ** ** ** ******;NEXT_BYTE .. Increment the FSR and clear the counter
;
; ** ** ** ** ** ** ** ** ** ** ******

NEXT_BYTE INCF FSR,f
CLRF BYTE_COUNT
RETURN

; ** ** ** ** ** ** ** ** ** ** ******
;RESTART_TMR0 .. Restart the timer with an 888 uSec delay
; and refresh the overflow flag.
; MPLAB stopwatch says there is a loop overhead of
; 14 cycles, thus we need it to run for 888-14=874 uSec
; ** ** ** ** ** ** ** ** ** ** ******

RESTART_TMR0
BCF INTCON, T0IF ; Clear the overflow flag
MOVLW D'37' ; 255 - 37 = 218 x 4 = 872 uSec
MOVWF TMR0
RETURN

; ** ** ** ** ** ** ** ** ** ** ******
;PARSE .. decodes the saved datastream into the various
; RC5 words and flags.
; ** ** ** ** ** ** ** ** ** ** ******

PARSE
MOVLW SERIAL_BUF ; Put buffer start address into
MOVWF FSR ; the FSR
CLRF TEMP ; Initialize variables
CLRF BYTE_COUNT ;
CLRF MZ_FLAG ;
CLRF FIELD ;
CLRF TOGGLE ;
CLRF SYSTEM ;
CLRF COMND ;
CLRF MZDATA ;; First one is the field bit
RLF INDF,f ; First bit into carry
RLF TEMP,f ; Put it into TEMP for decoding
RLF INDF,f ; Second bit
RLF TEMP,f ; ditto
INCF BYTE_COUNT,f ; Start keeping track of INDF bit position
CALL DECODE
BTFSC PARSE_FLAGS,2 ; Illegal pattern found
GOTO BAD_DATA
; Must have found a good bit
RRF PARSE_FLAGS,f ; Put field bit into Carry
RLF FIELD,f ; Move it into FIELD

CLRF TEMP ; Next one is the toggle bit
RLF INDF,f ; First bit into carry
RLF TEMP,f ; Put it into TEMP for decoding
RLF INDF,f ; Second bit
RLF TEMP,f ; ditto
INCF BYTE_COUNT,f ; keep track of INDF bit position
CALL DECODE
BTFSC PARSE_FLAGS,2 ; Illegal pattern found
GOTO BAD_DATA
; Must have found a good bit
RRF PARSE_FLAGS,f ; Put toggle bit into Carry
RLF TOGGLE,f ; Move it into TOGGLE


MOVLW 0x05 ; Next one is the system byte, 5 bits
MOVWF COUNT
SYS_1 CLRF TEMP
RLF INDF,f ; First bit into carry
RLF TEMP,f ; Put it into TEMP for decoding
RLF INDF,f ; Second bit
RLF TEMP,f ; ditto
INCF BYTE_COUNT,f ; keep track of INDF bit position
BTFSC BYTE_COUNT,2 ; (there are two rotates per count)
CALL NEXT_BYTE ; Go to nextbuffer byte when count=4
CALL DECODE
BTFSC PARSE_FLAGS,2 ; Illegal pattern found
GOTO BAD_DATA
; Must have found a good bit
RRF PARSE_FLAGS,f ; Put bit into Carry
RLF SYSTEM,f ; Move it into SYSTEM
DECFSZ COUNT,f ; Have we done all 5 bits?
GOTO SYS_1 ; No, not yet

; Here we test for the two spaces
; present in the extended data format.
; If they appear, we set a flag
; and skip over them to the command
; word.

MOVLW B'11000000' ; Mask for 2nd buffer byte
ANDWF SERIAL_2,w ; Are the 2 top bits zero?
BTFSS STATUS,Z ;
GOTO PHILIPS ; No space found

CALL NEXT_BYTE ; Skip over first space
RLF INDF,f ; Skip over second space
RLF INDF,f ;
INCF BYTE_COUNT,f
MOVLW 0x01
MOVWF MZ_FLAG ; Set the flag


PHILIPS MOVLW 0x06 ; Next one is the command byte, 6 bits
MOVWF COUNT
CMD_1 CLRF TEMP
RLF INDF,f ; First bit into carry
RLF TEMP,f ; Put it into TEMP for decoding
RLF INDF,f ; Second bit
RLF TEMP,f ; ditto
INCF BYTE_COUNT,f ; keep track of INDF bit position
BTFSC BYTE_COUNT,2 ; (there are two rotates per count)
CALL NEXT_BYTE ; Go to next buffer byte when count=4CALL DECODE
BTFSC PARSE_FLAGS,2 ; Illegal pattern found
GOTO BAD_DATA
; Must have found a good bit
RRF PARSE_FLAGS,f ; Put bit into Carry
RLF COMND,f ; Move it into COMND
DECFSZ COUNT,f ; Have we done all 6 bits?
GOTO CMD_1 ; No, not yet

BTFSS FIELD,0 ; If field bit=0 then comnd=comnd+64
BSF COMND,6

BTFSC MZ_FLAG,0 ; Test for extra data word
GOTO MDAT_1 ; Parse extra data word
RETURN ; Finish here if Philips format

MDAT_1 MOVLW 0x06 ; Next one is the data byte, 6 bits
MOVWF COUNT
MDAT_2 CLRF TEMP
RLF INDF,f ; First bit into carry
RLF TEMP,f ; Put it into TEMP for decoding
RLF INDF,f ; Second bit
RLF TEMP,f ; ditto
INCF BYTE_COUNT,f ; keep track of INDF bit position
BTFSC BYTE_COUNT,2 ; (there are two rotates per count)
CALL NEXT_BYTE ; Go to next buffer byte when count=4
CALL DECODE
BTFSC PARSE_FLAGS,2 ; Illegal pattern found
GOTO BAD_DATA
; Must have found a good bit
RRF PARSE_FLAGS,f ; Put bit into Carry
RLF MZDATA,f ; Move it into MZDATA
DECFSZ COUNT,f ; Have we done all 6 bits?
GOTO MDAT_2 ; No, not yet

PARSE_DONE RETURN; ** ** ** ** ** ** ** ** ** ** ******
; DECODE .. enter with two-bit data in TEMP
; return with result code in PARSE_FLAGS, thus
; PARSE_FLAGS<0> = valid data, one or zero
; PARSE_FLAGS<1> = unused
; PARSE_FLAGS<2> = set if data is invalid
; ** ** ** ** ** ** ** ** ** ** ******

DECODE
CLRF PARSE_FLAGS
MOVLW ONE
XORWF TEMP,w ; Compare to bit pattern '01'
BZ ONE_EXIT

MOVLW ZERO
XORWF TEMP,w ; compare to bit pattern '10'
BZ ZERO_EXIT

BAD_EXIT BSF PARSE_FLAGS,2 ; bit pattern neither 01 nor 10
RETURN

ONE_EXIT BSF PARSE_FLAGS,0 ; Return with valid data in LSB
ZERO_EXIT RETURN ; of the PARSE_FLAGS variable

; ** ** ** ** ** ** ** ** ** ** ******
; BAD_DATA .. Exit if Read or Parse doesn't like what it finds.
; The Carry flag is set as an error message.
; ** ** ** ** ** ** ** ** ** ** ******

BAD_DATA
BSF STATUS,C ; Set the carry flag to show error
RETURN

; ** ** ** ** ** ** ** ** ** ** ******

END ; End of program

Using The PIC Microcontroller Hardware PWM Feature& Infrared Communications Links

Based on feedback on this article, we now have a new 8-pin custom programmed PIC designed for infrared serial communications & remote control applications. Click HEREfor details.
Parts Kits now in stock for this application HERE.
Many applications can benefit from an infrared communications link.  This article willhopefully shed some light on how to send & receive serial data between microcontrollers such as the BASIC Stamp, or PICMicro programmed with PicBasic.
Note: You can build these simple circuits, cut & paste the code into the PicBasic Pro compiler, and have a full-blown serial infrared communications network operating between several PICMicro's or even a BASIC Stamp. You do not need the PicBasic compiler to do this. If you can program a PIC, we have sample code at the end of this article for an 8-pin PIC that will generate the 38KHz carrier for this application instead of using the hardware PWM feature of the more expensive PICMicro.
Now - let's dive right in to the code.
PicBasic Pro Code:
' Setting up hardware PWM for 38KHz operation.


DEFINE LOADER_USED 1'Setup for boot-loader programming

TRISC.2 = 0 ' CCP1 (PortC.2 = Output)
PR2 = 25 ' Set PWM Period for approximately 38KHz
CCPR1L = 13 ' Set PWM Duty-Cycle to 50%
CCP1CON = %00001100 ' Select PWM Mode
T2CON = %00000100 ' Timer2 = ON + 1:1 prescale
TRISB.0 = 0

ADDRESS VAR BYTE
DAT VAR BYTE
ID VAR BYTE
ADDRESS = 10
ID = 25

BEGIN:
FORDAT = 0 TO 255
SEROUT PORTB.0,4,[ID,ADDRESS,DAT]
PAUSE 100
NEXT
GOTO BEGIN
The hardware PWM is configured in the beginning of our code. After we define the PWM frequency, and duty cycle, our code can proceed to performing other tasks while the hardware continues to operate in the background. Notice how program execution falls into a tight loop once it reaches the routine BEGIN. Even though we stay within this loop sending serial data continuously, the PWM signal continues without the need for software intervention to generate the 38KHz carrier.
Hardware peripherals offer true multi-tasking not available otherwise. Yes - you'll hear some people boasting of using interrupts or 'C' for multi-tasking, but it's still a far cry far from the real thing. Background hardware operation is the 'real deal' -- period.
How it works:
This example was tested on the FLASH-Lab 77 development board with PicBasic Profor rapid development. The FLASH-Lab 77 boards use a boot-loader program. If you're not using the boot-loader, just strip the line DEFINE LOADER_USED 1 line from the code above, and proceed as normal.
PortC.2 on the PIC16F877 also functions as the hardware PWM output pin (CCP1) when not being used for normal I/O operations. Several registers need to be configured to use the PWM feature.
Timer2 (TMR2), and PR2 (timer2 module's period register) are used to establish the period. Figure 1 shows a graphical representation of how this works.

Figure 1:  PWM Output
As shown in the previous code segment, we first have to load the timer2 period register (PR2) to setup the period for our required frequency (38KHz) output. A PWM output (Figure 1) has a time base (period) and a time that the output stays high (duty cycle). Thefrequency of the PWM is the inverse of the period - which is (1/period).
Figure 1 shows the period from TMR2 = PR2 to TMR2 = PR2. This represents one complete cycle. To determine the period required to generate a frequency of 38KHz, simply take 1/38KHz, or 1/38,000. The result is 1/38,000 = 0.000026316 (26.3uS). We know that in order to generate our 38KHz frequency, we'll need each period to be approximately 26 microseconds. A duty cycle of 50% would need 13uS high, and 13uS low on the I/O-pin to generate our required frequency of 38KHz at a duty cycle of 50%.
Frequency ( f ) and period ( P ) are inversely proportional. f = 1/P, & P = 1/f.
To calculate the value to be loaded into PR2:
(4MHz / (4 * TMR2 prescale value * 38KHz)) - 1= PR2.
We'll use a prescale value of 1 for timer2.
4 * 1 * 38,000 = 152,000
4,000,000 / 152,000 = 26.315
26.315 - 1 = 25.315
We'll load 25 into PR2, and accept the minimal error.

Figure 2:  Finding Our Resolution
Figure 2 shows how to find the maximum PWM resolution (in bits) for a given PWM frequency, with our selected oscillator frequency. This application uses the PIC16F877 with a 4MHz oscillator, so we need to calculate: Log (4MHz/38KHz) / Log(2) to find our maximum resolution in bits.
Log (4,000,000/38,000 ) = 2.022
Log(2) = .301
Our maximum resolution is found to be 2.022/.301 = 6.7-bits
Note: Resolution refers to the resolution of the duty cycle, and not the actual frequency of the PWM signal.

I randomly chose a duty cycle of 50% for this application. To setup the duty cycle, there are two registers that need to be configured.
CCPRL1  contains the eight (most significant bits), and CCP1CON <4:5> (CCP1CON bits 4 and 5) contain the two (least significant bits). Since we will only have a maximum of 6-bits resolution, we only need to load theCCPR1 register. CCP1CON bits 4 & 5 will be loaded with 0's.
To figure the value to load into CCPRL1 for 38KHz @ 4MHz with a 50% duty cycle:
(PR2 + 1) * TMR2 prescale * 50% Duty Cycle = value for CCPRL1, or
(25 + 1) * 1 * 0.50 = 26 * 0.50 = 13
TRISC.2 = 0        ' CCP1 (PortC.2 = Output)
PR2 = 25            ' Set PWM Period for approximately 38KHz
CCPR1L = 13      ' Set PWM Duty-Cycle to 50% 
CCP1CON = %00001100  ' Mode select = PWM
T2CON = %00000100       ' Timer2 ON + 1:1 prescale
Above is the code we use. Notice register CCP1CON is loaded with a binary value that sets bits 2 and 3. These are CCP1M3 and CCP1M2, and set the PWM mode. Timer2 T2CON bit 2 is set to start the timer. Bits 1 and 0 are left clear for a prescaler of 1. TRISC.2 sets up portC.2 as an output which is necessary to have portC.2 output the 38KHz carrier (PWM) frequency.

Now that we have our 38KHz carrier with a ~50% duty cycle setup, we'll need a circuit that will combine our carrier and serial data signal.
Note: We are actually just controlling the carrier frequency with our serial data-stream by turning the carrier ON/OFF for the duration of each data-bit.
Using the 74HCT132 NAND Schmitt trigger as shown below in Figure 6, simplifies the procedure. One input will be connected directly to PortC.2 which will generate our 38KHz carrier using the PIC hardware PWM feature. The remaining input will connect to PortB.0 which will be used to output our serial data-stream.
The NAND output (pin #3) will only go to logic 0 when both inputs 1 & 2 are at logic 1. This effectively holds the PNP drive transistor OFF until both inputs are at logic 1. Since the carrier frequency is 38KHz, and considerably faster than our serial data, the serial data will cause the transistor to turn ON during each logic 1 data-bit.
Tofurther explain what's happening, think of it as the serial data just turning the carrier ON/OFF for the same bit-time as each data-bit in the serial data-stream.
This combination of both inputs to the NAND will give us the 38KHz modulated datasignal on the output pin of the NAND.
Here's what both signals being applied to inputs 1 & 2 of the NAND gate look like when connected to an O-scope.

Figure 3  Serial data & PWM carrier fed to NAND gate inputs
Figure 3 shows the two separate signals being applied to the two inputs (1 & 2) of the NAND Schmitt Trigger. Trace A is the actual serial data being sent out from the PIC on PortB.0. Trace B is the 38KHz PWM carrier being generated by the PIC hardware, and output on PortC.2 to the input of the NAND gate.
Now look at the modulated data signal on (Trace A) coming out of the NAND gate on pin #3.

Figure 4 NAND output to PNP drive transistor.
Notice from trace A (signal being fed to the base of the PNP drive transistor) that the base of the transistor & our serial data is now modulated at 38KHz, and inverted. Trace B still shows the 38KHz carrier from portC.2 into pin 1 of the NAND gate.
Figure 5 (shown below) shows our serial data being input to the NAND (trace B), and the actual output of data from the PNA4602M 38KHz IR detector module (trace A).
Notice how the output signal from the detector (trace A) has the 38KHz carrier stripped from the incoming data-signal. The detector module removes the carrier (38KHz), and outputs the data (minus) the 38KHz carrier.
The slight phase shift you see below is due to the response times of the infrared detector module, drive transistor, and NAND gate combined.

Figure 5 Serial signal on pin #2 of NAND & data out from IR detector module.
The Transmitter:
Below is the simple transmittercircuit. To use the circuit below, just connect CCP1 of the PIC you use (PortC.2 for the PIC16F877) to one of the two inputs to the NAND gate. Use any other I/O-pin you want to send serial data to the other input of the NAND gate.
Tip: Don't substitute another NAND gate for this project. The 74HCT132 is a NAND Schmitt Trigger. The Schmitt Trigger function helps to stabilize circuit oscillation.

Figure 6  IR LED Drive + NAND Circuit
A simple two input NAND Schmitt Trigger is used to combine the two incoming signals into an output data signal modulated at 38KHz.

The receiver is very simple. Just take the serial data directly from the data output pin of the detector module as shown in figure 7.

Figure 7 Receiver circuit.
For the receiver, I used the BASIC Stamp II for rapid testing & verification of operation. Converting this code to PicBasic is simple. Here's the BS2 code.
' BS2 program to test IR communication program
' using the PIC16F877 hardware PWM.

SYNCH CON 25 'Establish synchronization byte
BAUD CON 396 'NON INVERTED 2400 baud (MAX)
DAT VAR byte 'Data storage variable
DIRH = %11111111 'All outputs
ADDRESS VAR BYTE

START:

SERIN 0,BAUD,[WAIT(SYNCH),ADDRESS,DAT]
OUTH = dat
GOTO START
Notice how the Stamp waits until it receives the SYNCH byte first before accepting the remaining data. This helps to synchronize the receiver to the transmitter. The address byte shows one method of talking to multiple receivers by using addressing. This is only an example. You can use the address byte to force the program to only respond if it receives itsown unique address first, or ignore the technique altogether.
DAT is the data (byte) that will be transferred to the Stamp port pins P8 to P15. Connect 8 LEDs to the Stamp I/O-pins P8 to P15. Use 470 ohm series resistors for each LED to limit current to acceptable levels. When IR data is received, you can verify reception visibly by watching the LED's count from 0 to 255.
Note: Due to the limited response time of the detector module, the maximum baud-rate is normally around 2400. If you experiment with this project - you'll see first-hand how increasing the baud-rate will degrade data.

The simple infrared transmitter circuit shown above in Figure 6 can also be used with various encoder ICs such as the Holtek 4-bit HT-12E encoder, and even the 8-bit versions as well. The only requirement is that you have a stable oscillator such as the PIC using hardware PWM, a 555 timer circuit, or another oscillator source capable of providing a stable carrier frequency.
The data output pin of the encoder provides the serial data on the transmitter. Use the circuit shown below in Figure 8 when using the Holtek decoder IC's instead of serial data with a microcontroller.
The circuit shown below is a simple inverter circuit, and necessary for use with the HT-12D and other decoders. If you prefer, you can use this receiver circuit for serial as well. Either one will work with serial data, but use the one below for the HT-12D decoder IC.

Figure 8: Circuit for use with Holtek decoder ICs.
Tip: The PNA4602M output has an internal pull-up resistor. This causes the output to hold a logic 1 (high) on the base of the NPN transistor. The HT-12D decoder IC will go into low power or sleep mode when the data input pin is at ground conserving power in the receiver circuit until data is being received.

If you don'town PicBasic, or simply don't wish to commit a large PIC such as the PIC16F877 or F876 to this simple task, you can easily use the smaller 8-pin version (PIC12C508) to generate the 38KHz carrier.
Here's a short code-sample for generating a 38KHz frequency using the small 8-pin PIC12C508. It's not hardware PWM, but it works very well, and it's cheap.
Note: For higher precision, use an external crystal or ceramic resonator. The internal oscillator for the PIC12C508 is a low precision oscillator. For most instances - the internal oscillator works fine, but increased precision of the carrier frequency will increase receiver sensitivity - and hence increase the overall operating range.
*** NEW ***
We have sample code for using the hardware PWM module on the 18-pin PIC16F628 now as well, and it works quite nice for this project. Click HERE to see how to do this with a $4.00 PIC..
To use an external oscillator with the sample code below - replace IntRC_OSC with XT_OSC before assembling the code, and burning the PIC12C508.
Assembled with MPASMWIN V03.30  Download the .HEX file in .txt format HERE Just save the file, then re-name it with the .hex file extension.

PROCESSOR 12c508
#include 'p12c508.inc'
__CONFIG _MCLRE_OFF & _CP_OFF & _WDT_OFF & _IntRC_OSC
#DEFINE PORT B'11111101'
MOVF OSCCAL
MOVLW PORT
TRIS GPIO

BEGIN
BCF GPIO, 1 ;1uS
NOP ;2uS each nop is 1uS long
NOP ;3uS
NOP ;4uS
NOP ;5uS
NOP ;6uS
NOP ;7uS
NOP ;8uS
NOP ;9uSNOP ;10uS
NOP ;11uS
NOP ;12uS
NOP ;13uS
NOP ;14uS
NOP ;15uS
NOP ;16uS
NOP ;17uS
NOP ;18uS
NOP ;19uS
BSF GPIO, 1 ;1uS Begin HIGH duty cycle
NOP ;2uS
NOP ;3uS
NOP ;4uS
NOP ;5uS
GOTO BEGIN ;2uS (26uS total for 38KHz)
END


The tiny 8-pin PIC12C508 can easily be programmed to output a steady 38KHz carrier. If you just need the 38KHz oscillator for this project - this PIC is very inexpensive, and works quite well.
The assembly code shown above will provide a duty cycle of approximately 27%. Adjusting the time between the BCF and BSF commands, will adjust the duty cycle. Be sure to maintain an overall time (period) of 26uS to keep the frequency stable at 38KHz.
Tip #1: Try swapping the BCF & BSF instructions around - or just split the difference between each command to set & clear the I/O-pin GPIO.1.
Tip #2: If you really want to crank power to the LED, try reducing the duty-cycle of the carrier to around 1uS, and using a very small (or no) current limiting resistor for the IR LED. You'll want to replace the 2N4403 LED drive transistor with one that can handle this power level.
Port-pin GPIO.1 is simply connected to one of the NAND inputs, and will replace the larger PIC used in this application. The serial data can then come directly from a PIC or BASIC Stamp I/O-pin, and you're ready to go with infrared data communications.
We have a component parts KIT for this application in stock. The KIT includes the following components:
| [1] 38 to 40KHz (Programmable)PIC frequency generator with resonator. |
| [1] 74HCT132 Quad 2-Input NAND Schmitt trigger. |
| [1] Panasonic PNA4602M infrared detector module. |
| [2] Lumex OED-EL-8L, High-Power 180mW, 940nm Infrared LEDs. |
| [1] 2N4403 PNP LED drive transistor. |
| [1] 5.1-Ohm LED current limiting resistor. |
| [1] 330-Ohm PNP drive transistor base resistor. |

Philips RC-6 Protocol |
RC-6 is, as may be expected, the successor of the RC-5 protocol. Like RC-5 the new RC-6 protocol was also defined by Philips. It is a very versatile and well defined protocol. Because of this versatility its original definition is many pages long. Here on my page I will only summarize the most important properties of this protocol.
Features |
* Different modes of operation, depending on the intended use
* Dedicated Philips modes and OEM modes
* Variable command length, depending on the operation mode
* Bi-phase coding (aka Manchester coding)
* Carrier frequency of 36kHz
* Manufacturer Philips
Modulation |
RC-6 signals are modulated on a 36 kHz Infra Red carrier. The duty cycle of this carrier has to be between 25% and 50%.
Data is modulated using Manchester coding. This means that each bit (or symbol) will have both a mark and space in the output signal. If the symbol is a '1' the first half of the bit time is a mark and the second half is a space. If the symbol is a '0' the first half of the bit time is a space and the second half is a mark. 
Please note that this is the opposite of the RC-5 protocol!
The main timing unit is 1t, which is 16 times the carrier period (1/36k * 16 = 444µs).
With RC-6 a total of 5 different symbols are defined:
* The leader pulse, which has a mark time of 6t (2.666ms) and a space time of 2t (0.889ms). This leader pulse is normally used to setthe gain of the IR receiver unit. 

* Normal bits, which have a mark time of 1t (0.444ms) and space time of 1t (0.444ms). A '0' and '1' are encoded by the position of the mark and space in the bit time. 

* Trailer bits, which have a mark time of 2t (0.889ms) and a space time of 2t (0.889ms). Again a '0' and '1' are encoded by the position of the mark and space in the bit time. 

The leader and trailer symbols are only used in the header field of the messages, which will be explained in more detail below.
RC-6 Mode 0 |
I can only describe operation mode 0 because I have never actually seen other modes in use than the one my Philips TV understands. The way I understand it the other modes can vary extremely from mode 0.
Mode 0 is a dedicated Philips Consumer Electronics mode. It allows control of up to 256 independent devices, with a total of 256 commands per device.

The command is a concatenation of different information. I will cover these different components from left to right.
Header field
The Header field consists of 3 different components.
* First the leader symbol LS is transmitted. Its purpose is to adjust the gain of the IR receiving unit.
* This leader symbol is followed by a start bit SB which always has the value '1'. Its purpose is to calibrate the receiver's timing.
* The mode bits mb2 mb0 determine the mode, which is 0 in this case, thus all three bits will be '0'.
* Finally the header is terminated by the trailer bit TR. Please note that the bit time of this symbol is twice as long as normal bits! This bit also serves as the traditional toggle bit, which will be inverted whenever a key is released. This allows the receiver to distinguish between a new key or a repeated key.
Control Field
This field holds 8 bits which are used as address byte.This means that a total of 256 different devices can be controlled using mode 0 of RC-6. 
The msb is transmitted first.
Information Field
The information field holds 8 bits which are used as command byte. This means that each device can have up to 256 different commands. 
The msb is transmitted first.
Signal Free Time
The Signal Free time is a period in which no data may be transmitted (by any device). It is important for the receiver to detect the signal free time at the end of a message to avoid incorrect reception. 
The signal free time is set to 6t, which is 2.666ms.

Schematic For Transmitter |

Schematic For Receiver |

Parts |

Part | Total Qty. | Description | Substitutions |
R1 | 1 | 22K 1/4W Resistor
R2 | 1 | 1 Meg 1/4W Resistor
R3 | 1 | 1K 1/4W Resistor
R4, R5 | 2 | 100K 1/4W Resistor
R6 | 1 | 50K Pot
C1, C2 | 2 | 0.01uF 16V Ceramic Disk Capacitor
C3 | 1 | 100pF 16V Ceramic Disk Capacitor
C4 | 1 | 0.047uF 16V Ceramic Disk Capacitor
C5 | 1 | 0.1uF 16V Ceramic Disk Capacitor
C6 | 1 | 3.3uF 16V Electrolytic Capacitor
C7 | 1 | 1.5uF 16V Electrolytic Capacitor
Q1 | 1 | 2N2222 NPN Silicon Transistor | 2N3904 |
Q2 | 1 | 2N2907 PNP Silicon Transistor
Q3 | 1 | NPN Phototransistor
D1 | 1 | 1N914 Silicon Diode
IC1 | 1 | LM308 Op Amp IC
IC2 | 1 | LM567 Tone Decoder
LED1 | 1 | Infa-Red LED
RELAY | 1 | 6 Volt Relay
S1 | 1 | SPST Push Button Switch
B1 | 1 | 3 Volt Battery | Two 1.5V batteries in series |
MISC | 1 | Board, Sockets For ICs, Knob For R6, Battery Holder
RELAY | 1 | 6 Volt Relay


Notes |
1. To adjust the circuit, hold down S1 while pointing LED1 at the receiver. Adjust R6 until you hear the relay click.
2.You can increase range by using a high output LED for LED1.
3. Bright light will stop the receiver from responding to the transmitter.
4. There is an error in the schematic. There shuold be a 1 megaohm resistor between pin 3 of IC1 and ground. This provides a 0 volt reference to bias the IC.
5. FPRC5RX V0.9
6. - field programmable RC5/Sony infrared remote receiver/decoder.
7. construction of a 16 bit parallel output learning Phillips RC5/Sony Sircs infrared decoder based on a 16F873 PIC processor in which IR codes are defined at run-time with a remote control.
0 Introduction |
1 Field programming |
2 Modes & Codes |
3 IR Standards |
4 Schematic & PCB |
5 First run |
6 Downloads |
7 Contact & Links |
8.
| 0 | Introduction | Top |
9. There exists a lot of very fine infrared receiver/decoder d.i.y. projects on the internet, so when I needed one for a homebuilt preamp, the obvious solution was to design yet another one. At least this increases the d.i.y. IR projects population by one :-) Since the project has matured it is probably also a candidate for simple home automation tasks and the like, but time will tell what it can actually be used for, if anything
10. Initially I believed this project to be fairly innovative, but that only proves that I'm too naive :-) At a stage where this project is pretty stable I did the extremely stupid move to search for 'learning ir decoder' on Google. Big mistake ! The number one hit were a pretty much similar project at MP3 IR Decoder/Remote Control made several years ago for a MP3 player control using a PIC16F84 So while I don't knowingly have stolen ideas and such (unless I write that I have) then I very likely haven't made - anything - neweither Please check the MP3 page, because they cirtainly were here first. But I still think this is a nice project though :-)
11.
12.
|
13. Figure 0 : Test setup on experimental PCB with two output pins, the signal LED and the IR receiver connected. If you are able to program a 16F873 and have a suitable crystal and a IR receiver at hand you can be up and running in half an hour from - now - :-) Note : The PIC on the picture is an ancient prototype and it uses a another pin layout on the processor than is used below.
14. Supported standards
15. The decoder handles both Phillips RC5 and Sony Sircs formats out-of-the-box and with some limitations also Panasonic REC-80.
IR Standard | Format | Supported |
Phillips RC5 | 14 bit standard | Yes |
| 14 bit extended | Yes |
Sony Sircs | 12 bit | Yes |
| 15 bit | Yes |
| 20 bit | No (note 1) |
Panasonic REC-80 | 48 bit | Limited. (note 2) |
16.
|
17. Table 1. FPRC5RX decoder.
18.
19. Note 1 : Newer seen one, thats why :-)
20. Note 2 : Only the least 16 bits are used (i.e. stored in the PIC). I haven't found any REC80 protocol specs and perhaps the last 16 are not the most interesting bits at all. Obviously there is a risk of incorrect detections when only part of the code is verified.
21. The results from a web search regarding the Sony and Panasonic IR formats are quite inconsistent regarding timing specs. If people are right, then this construction is bound to come into trouble 'somewhere'. The timing schemes used are solely based on monitoring the remotes i have at hand with an oscilloscope.
22.
23. Features
24. What makes this decoder perhaps a bit different from others is that it has 16 ready-to-use digital outputs which in total can be assigned to up to more than 16 differentIR codes (see downloads for actual capacity). It is therefore possible to have more than one IR code activating a given output pin, for instance when using several remotes. It is also possible to have a individual IR code assigned to multiple output pins if that can be used for anything meaningfull..
25. Another feature is the programming of the IR codes, which takes place with the decoder at run-time and shooting at it with the remote controller(s) it is supposed to understand. All that is needed is physical access to the PIC as the programming is initiated by shorting pins on the processor. There are thus no IR remote codes hardcoded in the PIC from scratch, and you don't need to know the actual codes involved when pressing a given button on the remote. This is possible due to the non-volatile eeprom and flash memory in the 16F873 PIC processor.
26. It is possible to select how the output mode should be for each IR code programmed. (The normal high pulse while a key is pressed, a toggle mode, ).
27. Actually the field programming capability is a idea I have stolen from an existing receiver chip. Unfortunately I don't remember who the manufacturer is, only that it was featured in a Elektor magazine. I'll have to check that out. Or perhaps it wasn't really that programmable, and what I saw was a construction using the infamous SAA3049 ?
28. (Update v0.5 : Its Elektor allright and it is 'Learning RC5 Control Decoder 01 - 16' from January 2001. Found at https://www.elektor-electronics.co.uk/ln/ln.htm)
29. At present there is no possibility to get a readout of the assignment table if (when) you loose track of which channels go where allthough you can erase all asignments made to the individual output pins. Or you can reprogram the PIC to wipe it completely clean.
30. Theserial I2C port available on the PIC processor is used for broadcasting information about pin number and new level whenever a output level changes.
31. Vocabulary
32. Pin : Or channel or output pin, one of the 16 output pins on the PIC. Each pin can have multiple IR codes assigned.
33. Assignment : An assignment is a link between a given IR code and a given pin the code corresponds to.
34. Mode : An assignment has a mode, which is how the output pin works. (pulse, toggle etc)
35. Programming : Obviously the PIC processor has to be programmed on its own with a dedicated program. This program is the one that can be found under downloads. Note that when the term programming is used on this page, it most likely refers to the process of getting the IR codes beamed into the PIC (which is done at run-time).
36. Future
37. The project here is currently on hold, replaced by other interesting projects, so right now nothing new is likely to happen. I have got some requests though, and that obviously feels nice, so keep them coming :-)
38. #1. Request for a audible 'beep' on recognized IR code. This would probably be a new mode to program on a output pin.
39. #2. Request for a standby mode where one pin would be the master controlling wether the rest of the decoder were in standby or active. This pin would then control the main power supply as well.
40. #3. Why not use the AUX pin (RA4) to something ??!??
41. Recent changes
42. V0.8 – april 9, 2004. Added a little more info about LEDs.
43. V0.9 – april 18, 2005. Feedback on a IR reciever and a link corrected..
44.
| 1 | Field programming | Top |
45. Actually a more appropiate title would have been 'Learning' as this is the term used for intelligent remotes, but for now I'll stick to my initialterm field programming.
46. The programming is quite simple, all you need is a piece of wire hooked up to Vcc and a suitable Phillips, Sony or Panasonic remote. If you really dislike shortcircuiting a PIC output pin like this then try to replace the wire with a 22 ohms resistor. It seems to work. Remember that in order to program you will need a power supply capable of supplying more than a PIC output can sink. 100mA or above should be fine.
47. A supplying note on this output pin shortening method for user inputs might be in place. What happens (if the PIC is running as it should) is that whenever a output pin is read by the software, then the output pin will change output level to the one currently present regardless of what was actually programmed by the software. This is due to the hardware design of a PIC I/O port. What it means is that the idle loop that runs continuesly in the software will automatically remove the shortcircuit condition inflicted by the user whenever it get around to scan the ports for user interactions. The good news is that this happens 'very often', so the warnings below about beeing quick to remove the shortcircuiting wire are just a precaution in case the PIC for some reason has gone heywire.
48. All notions of a flashing LED assume that a standard LED is connected to the LEDA output.
49. Adding an IR code
50. ◊ 1 Turn on power.
51. Briefly let the +5V wire touch the signal LEDA output (i.e. directly at pin 28) and LEDA will flash wildly in about 2 seconds - the PIC is now in programming mode (as opposed to normal run mode). All 16 outputs are now driven active low. See Note1
52. ◊ 2 Connect the output pin (one of 16) to be programmed to Vcc, and the signal LED turns on.
53. This procedure effectively shortcircuits a low driven output pin tothe positive supply. Don't panic, but at the other hand, don't leave the short on :-)
54. ◊ 3 Select mode.
55. You are now in a endless loop where you can select the mode you want for the assignment in progress. You change mode in the 'shortly short a pin' fashion. See Output pin mode tables. Step to point '4' below once you have selected the mode you want or just to accept the default mode right away (most likely just a monostable output pin).
56. ◊ 4 Press the key on the remote that should activate this pin in the current mode.
57. If the signal LEDA starts to flash very slowly and newer stops again then see error codes section below. The normal behaviour is a quick LEDA flashing with a frequency of about 'now I recieve a code that I recognize' Hz. If no flashes are seen, then the most likely cause is that the remote is a not a RC5 or Sony type after all.
58. ◊ 5 Release remote, the signal LED turns off, and the programming is complete.
59. The above sequence can be executed for all channels and more than one time for a single channel as well. A new assignment is stored in the flash right after point '5' above, meaning that you can just remove/apply power as you please, and still keep on adding new assignments whenever you feel for it. You only need to execute '1' once when programming a bunch of codes in one session. Not surprisingly you leave programming mode by removing the power again.
60.
61. Note1. Extended pins. Since the pin number associated with a IR code is transmitted in the serial I2C packets (see below) it actually makes some kind of sense to extend the pin range to include extended pins 17-32 as well. If you let the Vcc wire touch the signal LEDA after the point ◊1 (i.e. a second time) then you still can use the pins 1-16 during steps ◊2-◊5 asprogrammming inputs, but the pin numbers saved internally will now be called 17-32. That is, they will not affect the physical pins 1-16 when running in normal mode, but they will get their state transmitted over the I2C bus to an external listener. When you enter the extended pin range there will be another run of wild flashing LED, only this time it takes approx. 4 seconds. The extended mode were introduced in order to control the stepper motor volume control (see links) via the i2c bus, i.e. without using any of the 16 output pins.
62.
63. Deleting a channel
64. ◊ 1 Turn on power.
65. Do this while the signal LEDA is shorted to the PIC Vcc (+5V) line. This is a pretty mean way to power up a PIC since it is trying to drive the same line low, so remove the short after power on. The signal LED will flash in about 5 seconds and the PIC is now in delete mode.
66. ◊ 2 Connect a output pin (one of 16) to be deleted to Vcc.
67. All IR codes assigned to the channel will be purged. Repeat this step for the channels to cleaned up, you get a few signal LED flashes as an confirmation after each delete.
68. ◊ 3 Turn off power.
69.
70. Delete everything
71. ◊ 1 Turn on power.
72. See description under 'Deleting a channel'.
73. ◊ 2 Connect signal LED output to Vcc.
74. I.e. a second time. All user data in the PIC are deleted and the PIC will act as if it had just been programmed. Since this is point of no return the signal LED will just enter a infinite flashing loop until you remove power again.
75. ◊ 3 Turn off power.
76.
77. Error codes
78. Some erroneous situations are signalled by the PIC entering an infinite loop with the following number of flashes of the LEDA spaced by a space. The only recovery is to flip the power off and then onagain after which everything is as it was before the error occured. The blinking rate is slow enough to be seen with the eye.
79.
Flashes | Meaning |
3 | Recieved IR code allready assigned to this pin |
4 | No room left, all available assignment slots occupied. (see downloads for actual capacity) |
80. Table 1.1. Error table.
81. Backup
82. Just upload the entire eeprom and flash from the PIC and save it.
83.
84.
| 2 | Modes & Codes | Top |
85.
86. Modes
87. These are the current library of available output modes available for each of the pins on the PIC processor. Note however that it is a build time decision which of these will actually be included in a binary release, see Output pin mode tables.
88. Notice that the output levels during normal use are saved in eeprom on the fly and restored at power up. (relevant to all but normal mode pins).
89. Normal :
90. The output pin is high only while the remote is transmitting the matching code, else its low. (ex : 'turn motor up'). Also known as monostable or non-latching mode. In order not to get a series of pulses while a keycode is repeated from a depressed key, a timeout slight larger than the largest expected pulse to pulse time must expire before the output goes low (i.e. > 113.8 millisecs as found in RC5)
91. Toggle :
92. The output changes state every time the remote starts transmitting the matching code. (ex : 'lamp on' 'lamp off' “lamp ). Also known as bistable or latching mode.
93. Radio :
94. This mode only gives sense when applied to two or more pins. The name is taken from a radio with pushbuttons in the channel preselector, where only one output at a time will be high. Once a new button (pin) is selected the previously selected pops out again. (Note thatthere is a small overlap in time from the newly selected pin goes high to the previous high pin goes low in order to get make-before-break when using relays to switch audio paths). There is only one common radiogroup available. Also known as a 1-of-N decoder. During normal run mode the radio group can also be controlled by shorting radio pins to +5V, just as it was done during programming mode. An example of a small radio group wiring can be seen here.
95. BiToggle :
96. This is a genuine bastard mode, so if you expect the above modes to be enough then just skip this chapter. This mode was needed in order to have a fprc5rx controlling an audio preamplifier. What is provided is a normal run mode where a toggle output pin can be set both electrically and from a recieved IR code, just as for the radio mode above. The problem is however how to make a push button both drive the pin low and high for release and activate respectively. The solution here is to use two pins, called master and slave. The masters are the toggle output pins which have to be one of output pins 9-12. They toggle as would be expected from matching assigned IR codes just as normal toggle mode pins. The slave pin for a master is the pin 4 counts higher, i.e. pins 13-16. These are configured as inputs in normal run mode and should have a pull up (v0.6) resistor connected. A master will now also toggle each time its slave input gets a low (v0.6) pulse. To make it more hairy and more phrone to complete chaos, it is still possible to assign modes to the slave inputs. The state of these will only by transmitted over the I2C serial wire for (relatively) obviously reasons. An example of an BiToggle master/slave wiring can be seen here.
97. When programming a bi-toggle pin-pair then use the master pins (9 to 12) for the programming.If you try to assign a bi-toggle mode to another pin than 9 to 12 then please tell me what happens :-)
98.
99. BiToggleDelayed :
100. The BiToggleDelayed mode is a preamplifier requirement for controlling output mute relay(s) if installed. Please notice that the phase of this mode means that it should be interpreted as high level = play and not as high level = mute.
101. It is equal to the BiToggle above except for a 3 second (or thereabout) delay at power up where the output is forced low regardless of the last active level retrieved from eeprom. So if the PIC were powered off while a pin in this mode were high, then this pin will go high after a 3 second delay at power up. If you interact with a BiToggleDelayed pin in the delay time after power on, then the delayed setting stuff is cancelled.
102.
103. You can basically have all modes on all pins, but I will leave it up to you to keep the system sane For example you can have a toggle mode mixed with an radio mode on the same pin. This makes it possible to have two selected pins in the radio group (the correct one, and a subsequent toggle in one of those that were off), both of which will go low when the next radio pin is selected. This at least makes sense to me :-) Said in another way : when a code/pin combination is discovered to run in radio mode, then all other pins with radio functionality are affected (i.e. cleared), where as for normal and toggle mode it is only the individual pin that is modified. Hmm.
104.
105. Output pin mode tables
106. The idea with 'output pin mode tables' is that such a table becomes one of the ingredients in a build. As there are only one table in play at the moment this concept is pretty thin :-)
'Standard' |
Mode | LED pulses (off blinks) |
Monostable 'Normal' | '1' |Bistable 'Toggle' | '2' |
Radio button | '3' |
BiToggle | '4' |
BiToggleDelayed | '5' |
107. Table 2.1. Output pin mode table 'Standard'.
108.
109. Serial I2C
110. The serial I2C port from the PIC is used for broadcasting levelchanges on the output pins. The PIC acts as I2C master and transmits 3 bytes (address/command/data) on a output level change, see the following table. The speed is 400 kbit/sec which probably makes the I2C bus as implemented here unreliable for other purposes than local talk in closed environments (i.e. Enclosures).
111.
Address | Command | Data |
FPRC5RX broadcast (7bit) : 0x34 | 0 - Level went low | Pin number minus one, 0..15 + 16-31 |
- | 1 - Level went high | - |
112. Table 2.2. Serial I2C 3 bytes package.
113.
114.
115.
| 3 | IR Standards | Top |
116. This section is meant as an introduction into the Phillips, Sony and Panasonic IR standards, without even attempting to write everything there is to write. If I tried I would fail anyway. If you want to know more I recommend the internet and/or the link section at buttom.
117. Please note that the figures, values and everything else here is lifted from other diy pages and/or comes directly from an oscilloscope.
118.
119. RC5 - PHILLIPS
120. The following figure shows the format of the 14 bit biphase RC5 code. The toggle bit is what makes the RC5 really neat. It changes value whenever a button is pressed down, meaning for instance that a TV set won't go to channel 11 if you press 1, and while it is still depressed, let your hand briefly interrupt the IR. The toggle bit will be the same in both instances and a clever decoder will ignore the second sequence. (Currently the decoder described on this page is then - not - clever by this definition:-)
121.
122. As it can be seen the RC5 code is transmitted with MSB first with a data payload of 11 bits. Actually the start bits can be binary 10 as well as 11 shown in the figure above. It is then called an extended RC5 code.
123. Timing values :
124. The base clock for RC5 is 36kHz and a total of 64 counts is used per bit giving a bit time = 1.78 msec. The duration of the RC5 code is then 14 times this = 24.9 msec and the overall RC5 period is 64 bit periods = 113.8 msec.
125.
126. SIRCS - SONY
127. The Sony IR data is transmitted LSB first, probably since it gives no meaning to transmit the code from top and downwards. (bad joke :-). The format is pulse length modulation. There can be 12 or 15 databits of which the standard code seems to be the one af 12 bit in length, with a 5 bit device id and then a 7 bit button id. I don't know the rationale/meaning of the additional 15 bit code length, but the decoder accepts this as well as the 12 bit code. Contrary to the Phillips code the start sequence before a Sony sequence is not regarded as a part of the bit count.
128.
129. Timing values :
130. The sync in a Sony transmission is a 2.4 msec burst followed by 0.6 msec silence. The base clock for Sony is 40kHz and a total of 24 counts is used per bit element (with a bit consisting of 2 or 3 elements) giving a bit time = 1.2 msec or 1.8 msec respectively. The teoretical duration of the Sony code is minimum 3.0 + 12*1.2 = 17.4 msec and maximum 3.0 + 15*1.8 = 30 msec (*note) and the overall Sony period is allways fixed at approx 45 msec which equals nothing ?
131. (*note) My personal highscore is approx. 26 msec (on a stop button with remote in TV mode) !
132.
133. REC-80 - Panasonic
134. The Panasonic REC-80 (or RECS-80 ?) uses pulse-spacemodulation. The code is 48 bits long not counting a single trailing end-of-transmission bit (logic '0') and is based on a 32kHz clock. Please find more elsewhere :-)
135.
136. SAMPLING - software
137. The sampling of the IR signals as done by the PIC processor is made very strict concerning the format. The drawback from this is that codes containing quirks from the devices of the real-world will be ignored. If this seems to be the problem then the consistency checking obviously should be relaxed. So far all bits are sampled twice in the case of RC5 to verify the biphase, and two or three times on the Sony/Panasonic to verify a high-low or high-high-low sequence. After the code is completed it is verified that there is a few msecs with no signal before the code is accepted. This will obviuosly be a problem if a remote transmits codes with bitlengths different from the bitlengths mentioned above.
138. Another design issue is whether or not to require that two or more equal receptions of a code has been made before acknowledging it. Not surprisingly this will have effect on the latency of the system. Currently just a single code is needed, as it seems that the 'strict sampling' as described above effectively kills all junk transmissions. This number of matches needed might be subject to change
139.
140.
| 4 | Schematic & PCB | Top |
141.
142. Schematic
143.
144. Figure 4.1. Schematic.
145. Click to enlarge or download .pdf
146. PCB
147. See under downloads to get a readable version. All resistors and capacitors are 1206 size SMD (or 0805). If you think this pcb has a strange mix of component casings, then you're right !
148.
149. Figure 4.2. Printed circuit board.
150. Click to enlarge or download .pdf
151.
152.Tested IR receivers :
153. Ideally the IR receiver should have a center frequency of 36 kHz for RC5 and 40 kHz for Sony and 32 kHz for Panasonic.
154. Vishay TFMM 5380 : Output active low, 38 kHz. Icc,typ 0.5 mA. Very good. (RC5 and Sony). This receiver were taken from a old VCR, and I actually don't expect it is possible to find it as it have been replaced by the TSOPxxx device line.
155. Sharp IS1U60 : Output active low, 38 kHz. Icc,typ 2.8 mA. Either unusable or perhaps my sample is just slightly defective ? The device I have (bought from RS-components) is extremely sensitive to 'light-bulb-light' and on top it thrashes a RC5 code real badly (v0.6) Mikkel complained and told me he uses this type and it works fine for him :-). (V0.9) If this continues then I might have to surrender, now also John tells me that the IS1U60 rocks
156. Vishay 1138 : Output active low, 38 kHz. Icc,typ 1,2 mA. Very good. According to Vishay then the TSOP11/21 series actually would be a good compromise for covering all the 3 IR standards used here (noting the different carrier frequencies!).
157.
158. If you have experiences with any of these or other IR receivers, good as well as bad, then you are most welcome to mail me.
159.
160. I/O connectors :
161. CON100. PIC programming, IR receiver and LEDs. The connector has a twofold purpose as it can be used for both normal use (IR receiver and LEDs) and for incircuit programming of the PIC. The intention is that the IR receiver chip and the LEDs are mounted off-pcb, or with a little ingenuity directly into the connector holes, letting the possibility for incircuit programming go.
162. CON100 – LED(S). The LEDA is the 'normally turned off' / 'flashing if active' output and this is the output to use if you want to connect asingle standard LED. The LEDB output is just LEDA driven in antiphase in order to make it easy to use a bicolor LED instead. Since it is not obvious to everyone what is meant by this, you can have a look here. Consider to at least start with a ground referenced standard LED connected to LEDA while you are programming the PIC as this is easier to monitor.
163. CON101. Serial I2C output.
164. CON102. The 16 output pins. Drive sink/source in the order of 20 mA.
165. CON103. Power. Idle consumption is approx. 6 mA. At least 100 mA should be available when programming.
166.
167.
| 5 | First run | Top |
168.
169. This table might be of use as a checklist at the first power on.
Action | Response | No response ! |
Apply power | Short led flash. (Normal mode) | Check everything (again!) |
Let +5V touch LEDA (PIC pin 28/RB7) | LEDA flashes. (Programming mode) | Are you sure ????? |
Let +5V touch a output pin X | Single LEDA flash (Mode 0)
Press a key on remote | The signal led flashes. | Verify the output from the receiver with a oscilloscope |
Release the key | The signal led turns off.
Remove and re-apply power again | Short led flash. (Normal mode)
Measure output pin X | 0V
Press the remote key again | 5V on pin X and the signal LED flashes rapidly. | |
170. Table 5.1. First run.
171. You can use a DMM instead of an oscilloscope if you don't have one. You should see some voltage fluctuations whenever the receiver is active as opposed to a steady reading when there is no IR present.
172.
173. If it doesn't work :
174. From the email correspondances done so far then the majority of the fails people have had with this project boils down to remotes that turns out not to be transmitting one of the 'supported standards' afterall. A few fails have been (unoriginal) remotes that transmitted with an okay standard but were found to have a timing that were slightly off. Then there are the expected ones such as using a 4 Mhz xtal instead of a 20 Mhz xtal and so on. A few problems were so exotic that nobody probably know what it was all about - the only comfort should be that so far I don't know of any that newer got the decoder to work in the end.
175.
176.
| 6 | Downloads | Top |
177. Software for 16F873
178. The downloads are .hex files only, no source files. Please note that since the software can go into a 16F873 it fits nicely into a 16F876 as well, and it will also be happy in the 40 pin versions.
179. Software with build versions less than one are development. (Everything is in, and at least basic functionality has been verified.)
180. Active low output IR receiver (TFM5380 / 1138 style)
181. 20 MHz xtal - 32 assignments - 'Standard' mode table.
182. Build 0.34 - 28aug2003. Fixed bi-toggle mode on pins 10-12. Fixed radio-mode in general. Reworked channel delete part. - Download
IR Controller, Control the MP3 Player From a IR Remote
This cool project was contributed by Todd Elliot (see below for email address). It's a receiver for IR remote controls. It can learn the codes from buttons on multiple types of remotes and send the command strings understood by the player. Very cool, and it's GPL'd!
|
Schematic in PDF format
ir_schem.pdf
Project Files
irdecoder_r2.tgz
Documentation
The IR decoder is designed to work with Paul's MP3 player to allow use of any IR controller you may have by 'learning' up to 32 buttons. It only learns enough of the code to distinguish between buttons. It is a generic enough scheme that it can learn a variety of remote controllers. It has beentested with 5 different remotes so far. Probably need to try some more Once a button is 'learned', pressing the button will produce a command string on the serial output. The codes are stored in the interal EEPROM memory. Once they are learned, you don't have to do it again for this remote.
The Decoder serial port runs at 19200 baud 8,n,1
It should be connected to the 4-pin serial port on the MP3 player
To initiate the learn function press the ] key followed by 01,02,03,31 while running the MP3 Player connected to a terminal emulator. This will generate a 'Press XX' message. You can then press the corresponding button on your IR remote. Don't hold the remote too close to the decoder board. I have best results at least 2 or 3 feet away. After learning the button code, the IR decoder will output a ascii/visual representation of the key-code. Now pressing the button on the remote should produce the corresponding command string for control of the MP3 player on the serial port output.
Sample output:

IR DECODER

PRESS 10
|
|
|
|
|
|





DONE

End sample output
Now pressing the button on your remote control will produce the string 'play' on the serial portoutput.
ï‚· X=00 -> '0'
ï‚· X=01 -> '1'
ï‚· X=02 -> '2'
ï‚· X=03 -> '3'
ï‚· X=04 -> '4'
ï‚· X=05 -> '5'
ï‚· X=06 -> '6'
ï‚· X=07 -> '7'
ï‚· X=08 -> '8'
ï‚· X=09 -> '9'
ï‚· X=10 -> 'PLAY'
ï‚· X=11 -> 'NEXT'
ï‚· X=12 -> 'PREVIOUS'
ï‚· X=13 -> 'RANDOM'
ï‚· X=14-31 -> Unused at this point
Codes 14-31 could be things like GOTOXXXX, BANDXXXX,NEXTBAND,NEXTALB,ETC.
Obviously, this hardware/software could be used to control other serial devices. It is hoped that making this design Free will inspire other uses and designs, just as Paul's enormous contribution with the MP3 player has inspired me to contribute this small project.
TODO:
ï‚· There are plenty of I/O pins left. The learn function could 
be initiated by pressing buttons instead of using a terminal emulator?
ï‚· The free I/O pins could also be used to control some other logic 
instead-of/in-addition-to outputing a serial command

R-related ASCII Schematics V1.00
These materials are provided as-is, with no support. They are not being maintained. At present they are being kept available because we're aware people still refer to them - but we reserve the right to remove this archive, without notice, at any time.

Contents:
* Infra Red Remote Transponder
* Cheap 40KHz clock
* A very STABLE 40khz generator
* Minimizing SUN's noise in IR reception
* Build an Infrared night scope
* Decoding IR Remote Controls
* IR 'slotted switch' sensor

Infra Red Remote Transponder
From: squish@endor.uucp (Shishin Yamada)
[] I built a remote-transponder, which lets me send signals from a small receiver into closed (opaque door) cabinets, and around corners, etc. Anyways, the cheif problem is just stray environmental noise with any slowly changing amplitude modulated IR signal (lotsof 60 Hz noise, and sunlight noise). Most IR remotes work around a 40KHz carrier, so that they can just pulse this digitally, and just bandpass filter it at the receiving end. This boosts the range of unfocused IR remotes to tens of feet (around 20-30 feet). Adding two IR Leds helps alot, by sending out more IR signals.
Anyways, the following is a cutout from the group sci.electronics. Most of which had been posted in the past month (I guess many news-servers might not go back one month, so I re-posted. Hope nobody minds). There is included transmitter and receiver modules. Personally, I find the Sharp IR Receiver module (avaiable at Radio Shack) to be the easiest darn thing to use. You just pop in +5V and ground, and you get the demodulated signal out (a high/low version of whatever was riding on the 40KHz IR signal). It comes with simple application notes. Hope this info helps you out.
Oh, lastly, if you're looking for ANALOG transmitters, I would look into Radio-Electronics recently for posts about their 'Air-Hop' voice transmitter, or into Forrest Mims III 'Circuit Cookbook.' They both show how to do FM modulation onto IR (much, much better than AM).
IR DETECTOR CIRCUIT
30Hz BANDPASS FILTER gain = 1
Q = 4

+5V .1uF
| 330K
+-------||----+-------///--------+
/ |
100K |
/ |
|
.1uF | ___ |
| 39K | ___|
+----//---+-------||----+----|- ___ |
IR | |
Detector | LM3900 >--+---+
| ___/ |
||---+ +----|+ ___/ |
|| / ___/ |
||---+ 5.6K |
| / / |
| 1M |
/ |
|
GND GND
+5V |
|
|
|
+-------- ----- ------ -------------+
|
|
|
|
|
| ___
| 120K | ___
+-------//-----|- ___
SCHMITT TRIGGER |
| LM3900 >--+------ Vout
| ___/ |
+----|+ ___/ |
___/ |


1.1M | 1.1M |
+5V --//-----+---------//------+
|----- 1uF
-----
|
|
GND

Notes
* The LM3900 is a quad unipolar op-amp IC. Vcc of this chip must be on +5V DC.
* I found that the 100K pull-up resistor on the IR detector provided the optimum sensor performance. Any increase or decrease in the resistance caused a decrease in the signal quality from the IR detector.
* The 0.1uF capacitors that are part of the filter eliminate the effects of DC light, such as direct sunlight, something that causes an unfiltered IR passive detector to become swamped.
* The H->L and L->H threshold voltages in the Schmitt trigger can be changed by adjusting the 120K and 1.1M resistors.
* The 1uF capacitor was added to eliminate voltage spikes at the H->L and L->H trasitions.
* Vout is a TTL/CMOS level signal that outputs a logical high 30 times/second when an object has gotten within 6-12 inches of the IR detector.

IR EMITTER CIRCUIT
+5V 555 +5V
| TIMER |
/ +-----------+ |
18 |
/ 10ohms GND -----|GND Vcc|-----+

/ /
| 3 2.2K
+----- ----- ---------|OUT | /
|7
DISCH|-----+
| 4|- |
IR LED ||--+ +5V -----|R | /<| | 200K
||--+ /
| 26
| +---|TRIG THRES|-----+------+

+-----------+
GND ----- .1uF
-----
+----- ----- -----------+ |
|
GND

Notes:
* Adding more IR LED's will increase the range of the IR detector.
* The signal on pin 3 of the 555 is 30Hz and has a duty cycle of 50%
* Due to the very small pull-up resistor the 555 sinks about 109mA. The specs say the 555 can sink up to 225mA so it's well below the danger level.

Cheap 40KHz clock
(From Sebastian Filzek)
Use a 40KHz Xtal and a 74C14 schmitt trigger:
________ <----- ----- ------ 2.2 M resistor
___| 2M2 |___
________


|
|
+-----| O------+--------> Output 40KHz
/
/ gate 1 of 74C14
|
|
--+--
XXX 40KHz Xtal
--+--
|
|
-----
---
-

This circuit has worked for me in many applications. (it might be an idea to buffer the signal befor using it. (There are still 5 unused gates in the 'C14.. :-)

A very STABLE 40khz generator
(From Rodney Radford)
A circuit that I have used before is based on the CD4060 (14stage binarycounter) and a 640Khz ceramic resonator. The CD4060 is basically an oscillator and a ripple counter to divide the 640khz down to something more usable.
Here is the pinout of the CD4060 (frequencies are assuming a 640khz input signal into pins 10/11/12 - circuit shown below):
+-/-+
160hz 1 16 Vcc
80hz 2 15 625hz
40hz 3 14 2.5khz
10khz 4 13 125hz
20khz 5 12
5khz 6 11 >---- see sub-circuit below
40khz 7 10 /
GND 8 9 NC
+----+

Sub-circuit for a 640khz ceramic resonator:
12 >----- ----- ------------+
740pf | (you may be able to obtain
11 >-------+----+---|(----+ a resonator with builtin
| capacitors and three leads)
640khz --- |
res. O / 1Mohm |
--- |
|
10 >-------+----+---|(----+
740pf |
GND >----- ----- ------------+


A nice part about this circuit is that it delivers a STABLE 40khz signal, as well as delivering several other frequencies that can be used to modulate the 40khz carrier. For example, the person that designed this circuit (Ken Boone, member of Triangle Amateur Robotics) used it to build several beacons in his yard to serve as navigation points for a robotic lawnmower. By diode-OR'ing the results of the 40khz carrier and one of the lower frequencies (such as the 125Hz) line to drive a ring of IR-LEDs, he could locate the beacon and tell which, of several, beacons he had found.
This circuit has proven to be VERY stable, and is fairly inexpensive (about $1.50 for the CD4060and 640Khz ceramic resonator).

Minimizing SUN's noise in IR reception
(From jrm@gnv.ifas.ufl.edu)
A 'baffle' is a perforated disk or disks spaced inside your 'shade tube'. The idea is to trap all reflections, leaving only the light coming in on the exact axis of the tube to strike the IR Detector.
__________ ______ ____ ___

DET <--- IR LIGHT

-------- ----- ------ -

^Baff ^Baff ^Baff

Off-axis light, 'noise', will be caught by the baffles and dissipated through reflection between the baffles. Paint the inside of your tube black in fact, check into what paints/coatings are 'black' to IR wavelenghts. Just because a paint LOOKS black does not mean it won't reflect IR.
Check into an astronomy or optics group to get the formula for the ideal spacing of the baffles and how big a hole should be in them. Getting this right will improve your system performance.

Build an Infrared night scope
(From -=-= Wes =-=-)
Building a night scope is easy if you have the heart of it which is the image intensifier part. I would recommend using the PVS-5 module which uses 'MCP' or Micro Channel Plate technology. This is a U.S. 2nd generation device and is rated at 15,000 times light gain. The resolution is one of the best on the market. It was used in Desert Storm and released to the surplus market about 2 1/2 years ago. However, it can't be exported out of the U.S. :-( The device can be found for between $350 to $700 depending on the quality you want in terms how new it is or if it used. I will list a couple of vendors at the end.
I have built several of these scopes with and without targeting lasers. The laser will kill your battery in no time and Irecommend not using one for normal use as the PVS-5 has excellent response without it (unless you want to scare the crap out of someone in total darkness running around your yard. Just put a laser dot on his forehead and let him figure out where it came from and what is at the end of it.like a 30.30 :-) Anyway, you will need the following:
* 10' length of 1 3/4' PVC plastic pipe (thinwall)
* 6' length of 3/4' PVC pipe and end caps (thinwall)
* 1- 35mm lens with shutter
* 1- eyepiece (see text)
* 1- lens mount (I use Minolta lens adaptors and lenses which I pick up at pawn shops dirt cheap)
* 1- 3/4' washer
* 1- small spring
* 1- micro pushbutton switch
* 1- 3 volt lithium battery (I use the DL123A which Radio Shaftahhh..Shack sells for $7.99)
* 1- tube of silicon rubber (black)
* And of course, one PVS-5 MCP module

When you receive your module do not pull on the power wires or they will break off inside of the power supply and you now have a several hundred dollar paper weight! Do no handle the front screen if possible. If you do, wipe it clean with a optical lens cleaner. DO NOT TWEEK THE TWO POTS IN THE POWER SUPPLY!! These pots adjust the ABC (Automatic Brightness Control) and AGC (Automatic Gain Control). If the pots are set too high, a flashover will occur in the Micro Channel Plates and burn out one or more which means that part of the display is dead. This is noticed by a black spot on the display when the PVS-5 is turned on. With that out of the way, lets continue
Using fine sandpaper or cheesecloth, smooth out the inside surface of the larger PVC pipe. Test fit the PVS-5 module by sliding it into the PVC pipe. It should fit snug but not tight. Continue sanding until the fit is snug. Next, remove the module and wipe down the inside of thepipe. Spray the inside flat black and let it dry. Once its dry, mount the front lens mount to the PVC pipe and mount the lens. Slide the PVS-5 into the other end and slide it to about 2'>from the lens. Focus the lens to infinity and close the shutter all the way so that only a pinhole is open. Point it towards an object 10 feet or better away. Apply 3 volts to the PVS-5 and slide it back and forth until the clearest image can be seen on the display screen. Move the focus on the lens in and out and insure the image remains clear. Secure the PVS-5 into the housing with the silicon rubber. DO NOT GET IT ON THE DISPLAY OR THE FRONT SCREEN! In case you are wondering why you can use the PVS-5 in normal lighting (like a shop or lab) its because of the automatic brightness function. The PVS-5 was designed to eliminate blooming problems with muzzle flash and bright light sources such as gun fire and explosions. Just don't open the shutter all the way (though it wouldn't hurt it).
After the silicon rubber is cured, we now start on the 'fun' (ugh !) part. This is time consuming (about an hour) and requires a little patience. The eyepiece that I use is a 35mm lens that is 'reversed' I.E. you look through the front of it rather than the back. The reason I do this is to eliminate the pincushion effect of the PVS-5's concave screen. But you can use anything that will magnify the image (even a 8X jeweler's eye loupe which I used on my first one with 'passable' results). Anyway, if you choose to use a 35mm lens like I did, then we have to rework the lens. First unscrew the whole body of the lens. Most will have a small screw stop that won't allow you to unscrew it completely unless the screw is removed. Once the lens is separated from the shutter and rear optic, clean the grease off of the threads. Next, try a fittest into the PVC housing. If the lens is too tight, grind the threads down until the lens fits snug, but not overly tight. Next, drill a small hole 1/2' from the rear of the PVS-5 at the top to pass the power wires through. Now, put the lens onto the PVC and press it as far in as it will go. Now apply power to the PVS-5. The image will be blurred. Here is the fun part. Remove power and the lens and using a hacksaw or bandsaw, cut 1/2' off of the PVC pipe and try it again. Continue doing this until it 'starts' to come into focus. Once it starts to come into focus, saw the PVC in 1/8' sections. Continue until the display is crystal clear. This has to be done whether you use a 35mm lens or not. Whatever you choose, the housing has to be cut to focus the eyepiece correctly. At this point, you need to remove the eyepiece, front lens mount and front lens. Cover the front and rear of the housing with paper and masking tape. Now you can spray paint the housing whatever color you choose. I do mine in flat satin black and they come out great ! Set it aside to dry. After its dry, remove the paper and masking tape. Blow out any particles. Insure that the PVS-5 is secure with silicon rubber. Touch up any scrapes of the flat black paint on the inner surface to eliminate reflections. Clean the front and back of the PVS-5 with optical lens cleaner. Re-assemble the front lens mount and front lens. Insert eyepiece. Drill two 1/16' hole about 1/2' from the rear of the housing on either side of the eyepiece. Secure the eyepiece with two small 2-56 screws. Apply power and insure all is well so far.
Now for the battery holder. This is what the 3/4' PVC pipe and end caps are for. Put an end cap on one end and place it on the main housing so that the front end cap is against the front lens mount. Measure back from theeyepiece about 3/4' and put a mark on the small PVC pipe. Cut the pipe on the mark and place the other end cap on the small pipe. Put the whole thing on the main housing and check the fit. If it is to close to the eyepiece, mark and cut it where it is at a suitable distance. Next, mark exactly where the wires are coming out of the housing on the bottom of the battery holder pipe and drill a small hole there so that the wires go straight into the battery holder. Next, drill a hole for the pushbutton about 1/2' from the end of the front end cap. Remove both caps and set aside for now. Measure 1 1/2' from the rear of the battery holder and place a mark here. Now saw with a hacksaw about 3/4 of the way through the battery holder to form a slot. Grind the washer so it fits flush into the slot (I.E. the round top is even with the round top of the battery holder). Next nip a small slot out of the side of the washer so that the ground wire can pass through it. Insert the washer into the slot and insure it is flush then epoxy it into place by putting a dab of epoxy OPPOSITE the slotted side inside of the battery holder. Next, take a small piece of insulated hookup wire and strip one end. Form a loop that will let a 4-40 screw pass through it and solder the loop. Next place a 4-40 flat head screw into the hole in the center of the washer with the head pointing towards the battery. Place the loop of the wire on the other side and secure it with a 4-40 nut. Solder the other end to one side of the pushbutton switch. Connect the positive wire from the PVS-5 to the other side of the switch. Route the ground wire from the PVS-5 through the slot in the washer and out the back of the housing. Next we make the rear battery connection by using a spring secured into the rear end cap. I used a spring from a 'D' cell batteryholder and secured it into place with a 2-56 screw and nut. I also soldered the ground wire to the spring after I determined the length so that the cap would just come off and let the battery slide free. But use your ingenuity on this. Install the battery with the positive side pointing towards the front of the scope and put on the rear end cape. Press the button and viola, check for a working scope.
Finally (whew) install the front end cap and secure the battery housing to the main housing with a bead of silicon rubber along both sides of the battery housing. Smooth the silicone down so it looks like it was made like that. Let the silicon dry. Next, paint the housing whatever color you want. Again, I used flat satin black.
DO not point your scope at the sun or other really bright light source. Even though the scope has automatic gain control, a bright IR source could burn the MCP.
One reason for using the lens adaptor was so that a telephoto lens could be used or just a standard 35mm lens. Also, the 35mm eyepiece lens makes it nice for mounting to other devices like a camera (with a 80mm extension) with the threaded lens front. I have built maybe 14 of these and they are great scopes. Far better than the Russian stuff in terms of resolution and clarity. Below is the vendors for the MCP modules:
MWK Industries
1269 W. Pomona
Corona, CA 91720
1-800-356-7714
1-909-278-0563
Cost: $395 item number NIGTU2 (ask for Martin)
Meredith Instruments
P.O. Box 1724
5035 N. 55th Ave. #5
Glendale, AZ 85301
1-800-722-0392
1-602-934-9387
Have fun with it and let me know how it goes :-) (particularly if you get some foxy lady that likes nude moonbathing and you get some nice 8 x 11's :-) My e-mail is wellison@kuhub.cc.ukans.edu.

And if you need an IR filter for that spotlight so you can use it to 'helpout' the above project, here's a little something:
(From William J. Beaty)
The large amounts of IR plastic filter sheet are no longer available, but here's a hint.
Go to a theatrical lighting supplier and buy two filter gels, one for 'congo blue' and one for primary red. Overlap them and you get black. However, these dyes are transparent to IR. Lay them between thin plexi for a big filter sheet. They aren't entirely black, you can see the sun through them. for darker filtering, overlap more sheets. The standard sheet is 18' x 24' (I think) and costs $3 to $5.
and (From John De Armond)
Edmund Scientific sells surplus sniperscope illuminator IR filters for about $20. This is a glass filter that can stand the heat of a large lamp.

Decoding IR Remote Controls
(From Juergen Putzger)
The origin of this posting was the question what to do with an old TV. I suggested to use the infrared remote control as an input keyboard for a microcontroller board and mentioned a piece of code I had written for the 8052 microcontroller. I was asked by some people to share my information about remote controls, so here it is:
There are at least two international standards which are used by remote controls to encode the commands, the RC5 and RECS 80 code. The RECS 80 code uses pulse length modulation. Each bit to be transmitted is encoded by a high level of the duration T followed by a low level of duration 2T representing a logical '0' or 3T representing a logical '1'.
T 2T T 3T T 2T
_ _ _

________
0 1 0

Notice that a '1' takes more time to be transmitted than a '0'. The RC 5 code instead has a uniform duration of all bits. A transition in the middle of the time interval assigned to each bit encodes the logical value. A '0' is encoded by a high to lowtransition and a '1' by a low to high transition. Therefore we need additional transitions at the beginning of each bit to set the proper start level if a series of equal bits is sent. We don't need this additional transition if the next bit has a different value. This is also called a 'biphase' code.
|1.Bit|2.Bit|3.Bit|4.Bit|
__ __ __ __

|_________|
0 0 1 1

Instead of being fed direct into the IR emitter, most remote controls modulate a 20-30 kHz carrier with this signal. A logic one is represented by a burst of oscillations.
______////_______////________
0 1 0 1 0

The reason is, that you can use a filter tuned to the carrier frequency to distinguish the signal from noise in the ambient light. Fluorescent lamps are the main source of such noise. Photodiodes behind an optical filter which transmits infrared light but blocks visible light are used as detectors. The signal from the photodiode is fed through a filter tuned to the carrier fequency and then amplified. The amplified signal is demodulated just like the carrier is demodulated in any AM radio receiver.
+
|
_|_ photodiode
/_ demodulator

_|_ ____| _______ __||___ ____ L and C form a
| / / signal circuit resonant
| / |/ _|_ | out to the carrier
= == amplifier /_ = ==
|C / L
|___|_________________|________|____

It can be a lot of pain to design a sensitive receiver that does'nt start to oscillate. It is also necessary to have some automatic gain control to avoid overload of the amplifier at close distance to the emitter. It is easier to use some integratedcircuit that does all of the job. The best i have ever seen (and used) is the SFH505A manufactured by SIEMENS (no, I don't work for this company). It looks like one of this three legged voltage regulators and uses a single 5V supply. It incorporates an optical filter, the photodiode, a filter tuned to about 30 kHz , the amplifier with automatic gain control and the demodulator.
If you don't know which code your remote control is transmitting you can identify it by viewing the output of your receiver with an oscilloscope. The RECS 80 code uses high pulses of uniform length while the low pulses differ in length. If there are high and low pulses of two different lengths it might be RC5 code. Note that your receiver may invert the levels.
How are commands like volume control or channel selction encoded? In the case of the RC5 code there is an international standard. Every command is encoded by 14 bits. The first two bits S are startbits to allow the receiver to adjust the automatic gain control and to synchronize. Next a bit T follows, that toggles with every new keystroke. Next is the address A of the device which shall respond to the command. At last the command itself follows.
| S | S | T | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 |

Some important addresses and commands:
Address: Device: Command:
0 TV1 09 Numbers 09 (channel select)
1 TV2 12 Standby
5 VCR1 16 Master Volume +
6 VCR2 17 Master Volume -
17 Tuner 18 Brightness +
18 Audio Tape 19 Brightness -
20 CD Player 50 Fast rewind
52 Fastrun forward
53 Play
54 Stop
55 Recording

There are integrated decoder circuits which have inputs to select the device address and parallel outputs activated by the commands. Since this is comp. robotics the devices you wish to control will have a microcontroller on board which can do all the decoding. Here is an input routine I have written for the 8052 microcontroller family to receive RC5 codes. My cousin has written a similar routine for the RECS80 code which i will try to make available also. Perhaps we can start a collection of such routines and archive them somewhere.
; ---------= == == == == =----------= == == == == =---------= == == == ==---------
; Interrupt Driven Receiving Routine for RC5 code
; written by Juergen Putzger (juergen.putzger@physik.uni-regensburg.de)
; ---------= == == == == =----------= == == == == =---------= == == == ==---------

$MOD52

INPUT EQU P3.2 ; Port3,Bit2 is used as input. The demodulated signal
; with active low level is connected to this pin
LF EQU 0AH ; Linefeed
CR EQU 0DH ; Carriage return
SPC EQU 20H ; Space
RB0 EQU 000H ; Select Register Bank 0
RB1 EQU 008H ; Select Register Bank 1 poke to PSW to use

DSEG ; This is internal data memory
ORG 20H ; Bit adressable memory

FLAGS: DS 1
CONTROL BIT FLAGS.0 ; toggles with every new keystroke
NEW BIT FLAGS.1 ; Bit set when a new command has been received

COMMAND: DS 1 ; Received command byte
SUBAD: DS 1 ; Device subaddress
BUFFER: DS 30 ; Buffer to store length of transmitted pulses
STACK: DS1 ; Stack begins here

CSEG ; Code begins here

;---------= == == == == =----------= == == == == =---------= == == == ==---------
; PROCESSOR INTERRUPT AND RESET VECTORS
;---------= == == == == =----------= == == == == =---------= == == == ==---------

ORG 00H ; Reset
JMP MAIN

ORG 0003H ; External Interrupt0
JMP RECEIVE

; ---------= == == == == =----------= == == == == =---------= == == == ==---------
; Output routines
; DonB4t forget to set up the serial port and Baud rate !
; ---------= == == == == =----------= == == == == =---------= == == == ==---------

N_OUT: ADD A,#30H ;Convert BCD number to ASCII
C_OUT: JNB TI,$ ;Wait until transmission completed.
CLR TI ;Clear interrupt flag.
MOV SBUF,A ;Write out character to serial port.
RET

BIN2BCD: ;Convert 8 bit value in Acc to 3 digit BCD
MOV B,#100
DIV AB
CALL N_OUT
XCH A,B
MOV B,#10
DIV AB
CALL N_OUT
XCH A,B
CALL N_OUT
RET

; ---------= == == == == =----------= == == == == =---------= == == == ==---------
; Interrupt routine is entered by the first high to low transition
; at Port3-Bit2. Stores the length of all pulses occuring at this
; pin in buffer. Analyzes the timing of the startbits to calculate
; a threshold between short and long pulses. This routine is
; independent of CPU speed. The device address and command are
; extracted from the bit stream. Two flags are set upon exit,
; the control bit which toggles with every new keystroke and the
; NEW bit indicating that a new command has been received.
;---------= == == == == =----------= == == == == =---------= == == == ==---------

RECEIVE:
PUSH PSW ; save current registerset
MOV PSW,#RB1
PUSH ACC
MOV R0,#BUFFER
REC: MOV A,#0
REC0: INC A ; Measure duration of low-level
NOP
NOP ; Delay
NOP
NOP
JZ TIMEOUT ; End of transmission if duration exeeds 256 counts
JNB INPUT,REC0
MOV @R0,A
INC R0
MOV A,#0
REC1: INC A ; Measure duration of high-level
NOP
NOP ; Delay
NOP
NOP
JZ TIMEOUT ; End of transmission
JB INPUT,REC1
MOV @R0,A
INC R0
JMP REC
TIMEOUT:
MOV A,BUFFER ; calculate threshold between short and long pulses
INC R0 ; length of first low-pulse
ADD A,BUFFER+1 ; plus length of first high-pulse
CLR C
RRC A ; divided by two
MOV R1,A
CLR C
RRC A ; plus half of the time
ADD A,R1
MOV R5,A ; yields threshold
MOV R0,#BUFFER
MOV R1,#1 ; initial value
MOV R2,#13 ; Number of bits to decode
DECODE: MOV A,@R0
INC R0
CLR C
SUBB A,R5 ; compare length with threshold
MOV A,#0
CPL C ; short=1
RLC A
JNZ NOSKIP
INC R0 ; if short skip over next pulse
NOSKIP: XRL A,R1 ; new bit is calculated by XOR with previous bit
MOV R1,A ; Store new bit
RRC AMOV A,R3 ; Store new Bit in R3/R4 by rotating
RLC A
MOV R3,A
MOV A,R4
RLC A
MOV R4,A
DJNZ R2,DECODE
MOV A,R3
ANL A,#00111111B ; extract command from R3
MOV COMMAND,A
MOV A,R3
RLC A ; do some rotating to extract
XCH A,R4
RLC A ;device address
XCH A,R4
RLC A
XCH A,R4
RLC A
CLR CONTROL
JNB ACC.5,TZ ; Check control bit
SETB CONTROL
TZ: ANL A,#00011111B ; mask device address
MOV SUBAD,A
POP ACC ; Restore old registerset
POP PSW
SETB NEW ; Set flag to indicate the new command
RETI


; ---------= == == == == =----------= == == == == =---------= == == == ==---------
; Main routine. Program execution starts here. Don't forget to add
; code to initialize the serial port and Baud rate if your monitor
; program doesn't do that for you. The Main loop waits until a command
; has been received. Then the control bit, subaddress and command byte
; are printed separated by spaces. Leading zeroes are not suppressed.
; When a standby command (12) has been received, the main loop is
; terminated and the program returns to the monitor.
; ---------= == == == == =----------= == == == == =---------= == == == ==---------


MAIN: MOV TCON,#00H ; MAKE SURE TIMERS ARE SHUT DOWN.
MOV PSW,#RB0 ; Select register bank 0
MOV SP,STACK
SETB EX0 ; Enable external Interrupt0
CLR IT0 ; triggered by a high to low transition
SETB EA
CLR NEWLOOP: JNB NEW,LOOP ; Wait until a command has been received
MOV A,#CR
CALL C_OUT ; Ouput carriage return and linefeed
MOV A,#LF
CALL C_OUT
MOV A,FLAGS
ANL A,#00000001B
CALL BIN2BCD ; Output control Bit
MOV A,#SPC
CALL C_OUT
MOV A,SUBAD
CALL BIN2BCD ; Output subaddress
MOV A,#SPC
CALL C_OUT
MOV A,COMMAND
CALL BIN2BCD ; Output command
MOV A,COMMAND
CLR C
SUBB A,#0CH ; compare for standby command
CLR NEW
JNZ LOOP ; go on receiving
CLR EX0 ; stop receiving
CLR EA ; and
JMP 8000H ; return to monitor which has its entry point at 8000H

END

Also see https://www.awi-bremerhaven.de/~cdodge/PCIR/

IR 'slotted switch' sensor
(From Paul Hitchcock)
There is a type of detector known as a 'slotted switch' that consists of a phototransistor/LED pair mounted on a solid frame with a small air gap between the two elements. A typical circuit might be:
o +5v o +5v



220 ohms / / 4.7K

/ /

| +-------> Vout
_|_ /
/ |/
----- | NPN
|



GND GND

| air gap |

When the air gap is unobstructed, the transistorsaturates, pulling Vout to ground; when the gap is blocked, the transistor cuts off and Vout is +5 volts.

This article compiled by <filipg@paranoia.com>. The most recent version is available on

Conversor RS232 a TTL sin MAX232

Todos sabemos que a la hora de conectar un PIC a la PC utilizar el MAX232 es el paso mas directo y fácil. Sólo cinco capacitores y éste integrado estará funcionando bien. Pero tomando en cuenta que hoy por hoy un MAX232 puede salirnos incluso mas caro que el mismísimo PICmicro decidimos desarrollar una alternativa válida que lo reemplace.
 
|
El circuito de arriba utiliza la propia corriente del puerto COM de la PC para generar los símbolos del RS232. Los pines marcados como TxD, RxD y Gnd corresponden al conector RS232 de la PC (ver conexionado) mientras que los pines marcados como RD y TD van directamente a microcontrolador. Podemos observar el pinout de los transistores.
Este tipo de interface es muy vista en mouses o elementos de control de punteo en PC. Los puntos de alimentación son de 5V (los mismos que del micro).
Amplifier Thermal Protection
Rod Elliott (ESP)
Share|

Introduction
The thermal protection of amplifiers is always a concern, since overheating is a sure way to reduce the life of semiconductors and other components.  Where you don't want to use a fan (such as in Project 42 - Thermo-Fan for Amplifier Cooling), then a complete shutdown can be performed.
This project is really a mixture of ideas, some simple, and others even simpler.  The system I have installed in my biamp unit is fan cooling.  Once a preset temperature is reached, the fans start, and remain on until the amp is turned off again.  This is crude, but very effective.  It only operates if I am listening LOUD on a very hot day, which means that the fans have probablyonly operated about 5 times in their life.  I do know about it when they operate because they are fairly noisy (although I have reduced the operating voltage which quietens them down a bit), but at least I know that the amp is protected.
Even simpler is to just switch off the power when the amp overheats.  I would use this as a backup to the thermo-fan or fan controller if I left the amp powered on all the time.  While I don't do this, a lot of people do, and although it does waste a certain amount of electricity, the greatest concern is fire.
At least a simple precaution or two should be taken to ensure that one does not come home to a pile of ashes that used to be a home - this actually happened to a friend of mine, and from what I saw, there is not a lot to recommend it.
| WARNING.  This project relies on your ability to wire mains voltage circuits.  Do not attempt construction unless you are confident that your efforts will not result in death or injury. |
Because I use Australian conventions for mains (Active, Neutral and Earth), you might need to translate these to the conventions where you live.  They are sometimes referred to as Line, Neutral and Earth (UK), or Line-Hot, Line-Cold and Ground (one - of many - US conventions I have seen).
Basically, the active is the lead that will kill you, the Neutral is the lead that MIGHT kill you (if the plug or socket is wired incorrectly), and Earth is the safety grounding lead (Green-Yellow nearly everywhere for new equipment).

Thermal Switches
The simplest of all is the thermal switch.  These are used in washing machines, dish washers, microwave ovens, and many other appliances, and can be obtained from an appliance repairer for less than $10 (they are generally about AU$4.50 or so).  The switches need to be screwed down to heatsinks usingthermal compound, but should be glued to transformers using a suitable adhesive (see below).  Make certain that the tags are properly insulated to prevent electrocution - this is VITALLY important.
 
Thermal Switch
Figure 1 shows the connections for the type of unit I refer to.  These switches are available in a variety of temperatures, normally open, normally closed, etc.  For amplifier protection, you need up to three normally closed thermal switches (TS1 to TS3), rated at no more than 80 degrees Celcius.  These are for the power transformer, and one for each heatsink.  The incoming mains (after the power switch and fuse) is routed as shown through each of the thermal switches, and finally to the transformer primary.
 
Figure 1 - Thermal Switch, And Wiring Diagram For Three Switches
Should any of the protected items exceed the switch temperature, the amplifier will be turned off.  It will turn back on again when it cools enough for the switch to reset.  In the case of a fault, the amp will turn off and back on again until the problem is rectified, but at least there is protection.
Where it is not possible to screw the switch to the item (such as a transformer), a high temperature epoxy can be used.  Do not use Super-Glue or similar, as it is unsuited to the task.  Likewise, don't use the 5-Minute 'epoxies'.  They are not true epoxies, and cannot tolerate the sustained heat.  True epoxy adhesives take about 24 hours to cure properly, and once cured are extremely robust.  At the risk of an unpaid advertisment, I would suggest the 24 hour cure Araldite - NOT the 5-Minute one.  Clamp the switch to the surface until the adhesive has cured - this can be done easily with painters' masking tape for awkward shapes.
Use the adhesive sparingly - some of these switches are open at the contact face, andif epoxy enters the internals of the switch it may ruin it.

Thermal Fan
For a thermal fan, a simple detector using a thermistor (or a number of thermistors) senses that the temperature is above a preset limit.  Once this is reached, the fan(s) start, and will then run until the temperature is below the threshold again.  This is an updated version of the system I am using at present.  The main problem is the general unavailability of thermistors!  As a result, two circuits are shown.  Select the one you want based on whether you can get the thermistors or not.
The simplest AC switch is a TRIAC, which will turn on if the gate voltage exceeds the internal trigger current.  As long as the current remains, the TRIAC will continue to conduct.  TRIACs can be irksome to drive with DC, so the MOC3021 opto isolator provides excellent electrical isolation, and ideal TRIAC triggering.  This way, we can use mains voltage fans using AC, rather than the Thermo-Fan project, which needs DC fans and runs off the main amplifier power supply.
Although DC fans are cheap and easily obtained, they are not as powerful as most AC fans, and are generally fairly low quality - although there are many computers out there that have been running for years, and the fans are still fine.
AC fans can be made quieter by reducing their voltage, and the easiest is to use a resistor.  This will need to be a high power wirewound type, and make sure that the terminations are properly insulated.  I will have to leave it to you to experiment to find a suitable value resistor.
 
Figure 2 - AC Fan Controller
This circuit is based on the thermo-fan design, but now switches a TRIAC, using an opto isolator specially designed for the purpose.  I experimented with simpler circuits, but was highly unimpressed with the results, so in theinterests of making a reliable and predictable protection unit, decided on the slightly more complex solution.  See Figure 4 for the pinouts for the opto-coupler and TRIAC.  To calculate the value of R5, use the formula for the thermistor version (substitute R5 for R3, otherwise the formula is the same).

If You Can Get Thermistors
The simplest way of all is to use a thermistor, which can be almost anything you can get hold of, but in Australia, none of the popular retail suppliers has any thermistors that I have found, and they are not at all common any more.  Pity, because they are very easy to use.  If you can get them, Figure 3 is by far the simplest way to control the fans, but it will require some degree of experimentation, since I cannot predict what sort of thermistors may be available where you live.
The NTC (Negative Temperature Coefficient) thermistors are RT1 to RT3, but you can add more or use fewer than this as needed.  The trimpots make it easy to make fine adjustments for each thermistor.  If you can, try to get thermistors with a nominal value of about 10k (at 20 degrees C).  A trimpot and diode is needed for each thermistor to prevent interaction between the sensing circuits.
 
Figure 3 - Thermistor Version
I still used the TRIAC isolator / trigger IC, as this is the easiest way to trigger the TRIAC reliably and maintain safety.  The thermistors supply the bias to Q1 as the resistance of any one of the thermistors falls with increasing temperature.  Q1 turns on Q2, which supplies LED current to the MOC3021.
The zener current needs to be about 20mA.  Knowing this, R3 can be calculated -
R3 = (+Ve - 12) / 0.02   where +Ve is the amplifier supply
As an example, assume that your amp has +/-50V supply rails.  We will also calculate the power rating for R3 -
R3 = (50 - 12) / 0.02 =38 / 0.02 = 1900 Ohms (use 1k8)

R3 = V² / R = 38² / 1800 = 1444 / 1800 = 0.8W   (use at least 2W)

Electrical Wiring
Electrical safety is (as always) critical.  There should be no track material between the pins of the MOC3021, and a completely bare section of board (whether PCB, perforated or Veroboard) must be left between all low voltage circuits and high voltage circuits.  This safety zone must 5mm MINIMUM. Likewise, there should be 5mm minimum between any live (mains) board wiring and chassis. All mains wiring should be shrouded with heatshrink tubing or plastic insulating sheet to ensure that human contact is not possible.
The TRIAC and MOC3021 (US readers can use the lower voltage MOC3020) are shown in Figure 4.
 
Figure 4 - MOC3021 and TRIAC Connections
The terminal marked * must not be connected on the MOC3021.  Unlike transistors or FETs, TRIACs do not have a sensible designation for the main terminals, and they are referred to simply as MT1 and MT2.

Airflow
The direction of airflow is important to ensure maximum cooling.  Computers do it the wrong way around, by sucking air across the power supply.  This was done for aesthetic reasons, and has nothing to do with efficiency.  Someone decided (perhaps not unwisely) that air coming through disk drive slots and other orifices in the computer cases would be annoying to users, so the fans were reversed.
If you want to cool a heatsink - blow air onto the surface.  This creates turbulence that disrupts the laminar airflow, and allows cooler air to come into direct contact with the surface of the heatsink.  If air is sucked past the heatsink, this is nowhere near as effective.  If your spoonful of soup is too hot, do you blow or suck air across the spoon?  I rest my case.


Política de privacidad