Controllo da telecomando

SOMMARIO

Si propone di realizzare un controllo remoto per piccoli elettrodomestici (luci, ventilatori da soffitto, TV, ecc.) con un assorbimento massimo di circa 5A (cioè circa 1kWatt), utilizzando un telecomando ad Infrarossi, di cui si memorizza un comando (per esempio il POWER ON/OFF). La soluzione si caratterizza per i minimi ingombri e per costi e consumi irrisori.

PRINCIPALI MATERIALI UTILIZZATI

PIC16F684-I/P Microchip - MCU 8 Bit, Flash, 20 MHz, 3.5 KB, 256 EEPROM
MOC3020 Fotoaccoppiatore, Uscita Triac, DIP, Non Zero Crossing, 400 V
PE014F24 Relè di Alimentazione, 24 VDC, 5A, PE Series, Bistabile
IR Receiver Infrared Radiation Module 38KHz

Con riferimento alla Fig.2 del il post Alimentazione e controllo senza trasformatore di tensione, opportunamente modificato, si propone lo schema del Ricevitore ad Infrarossi di Fig.1.

Fig.1

A partire dallo schema di Fig.1, si è cercato di realizzare un layout di ingombri particolarmente contenuti, giungendo a due soluzioni che possono essere integrate in una presa Schuko (vedere Fig.2) o in modulo di una presa elettrica generica (vedere Fig.3 formata da due semi-circuiti da alloggiare uno sull'altro).

Fig.2 Fig.3

Il circuito di Fig.2 ha un diametro di circa 41mm, mentre il circuito di Fig.3 è formato da due sottocircuiti di misure 41 x 20,5 mm. Il circuito di Fig.3 è particolarmente interessante, perchè può avere la realizzazione di Fig.4 o di Fig.5,   integrandosi quest'ultima negli ingombri di un frutto di una presa elettrica.

Fig.4


Fig.5

DISCUSSIONE

Il microcontrollore possiede una memoria EEPROM nella quale memorizzare la sequenza del comando infrarosso di un telecomando generico con portante a 38kHz. Il ricevitore mantiene la sua uscita nello stato HIGH in assenza di segnale. Quando viene illuminato da un telecomando con portante a 38kHz (frequenza comune, per esempio i telecomandi di un TV Samsung, di un lettore DVD United e di una lampada ventilatore di design lo pilotano tranquillamente) registra un segnale binario, in cui l'informazione è memorizzata nella durata temporale del segnale (generalmente nello stato LOW). Quando la sequenza è inviata, continuando a premere il pulsante del telecomando, il segnale viene ripetuto o viene ripetuta una sequenza non significativa.
Il software riconosce la partenza del segnale da acquisire quando il sensore riceve la prima transizione da HIGH a LOW (per minimizzare i consumi il microcontrollore è posto nella condizione di stand-by con l'istruzione sleep e il piedino di lettura del sensore Infrarosso è collegato all'ingresso RA2 su cui è abilitato la funzione di interrupt).
Con la transizione HIGH-LOW che "sveglia" il Ricevitore, parte una sequenza di LOW e HIGH (che nel seguito chiameremo impropriamente Bit), nella cui durata è codificato il codice del tasto del telecomando, differente per ogni tasto. Ad ogni Bit è assegnata una locazione di memoria nella RAM del microcontrollore da h'22' a h'7F' per un totale di 94 Bit (dovrebbero essere sufficienti per discriminare il tasto di un qualunque telecomando). Il Microcontrollore conta per quanto tempo dura il Bit (nelle locazioni di indirizzo pari nello stato LOW, nelle locazioni di indirizo dispari nello stato HIGH); alcuni conteggi (generalmente i fine sequenza) possono genrare un overflow , cioè un conteggio maggiore di 255. Di solito, ciò non pregiudica il riconoscimento del tasto. Per telecomandi con Bit di durata lunga può essere necessario di ridefinire il contatore della routine PAUSE, per aumentare il tempo di campionamento del conteggio temporale.

MODALITA' DI FUNZIONAMENTO

Se si alimenta il circuito con il tasto di programmazione (Butt sul pin RA0 di Fig.1) premuto, il microcontrollore entra nella modalità di programmazione e attende di leggere il tasto del telecomando da memorizzare (per esempio il POWER ON/OFF del televisore), facendo lampeggiare il led di programmazione. A questo punto si può rilasciare il tasto di programmazione e si deve illuminare il sensore Infrarosso con il segnale del tasto da memorizzare. Alla ricezione del segnale, il led si spegne per riaccendersi una volta in modo prolungato al completamento della procedura di acquisizione del tasto di comando. Il relay è posto nella condizione di contatto aperto e il microcontrollore va nello stato di stand-by, attendendo comandi dal telecomando. Se la memorizzazione del comando è corretta, solo premendo il tasto memorizzato si ha una breve accensione del led e una commutazione del relay alternativamente aperto/chiuso, mentre tutti gli altri tasti non danno luogo ad alcuna azione.

APPLICAZIONI

Un'applicazione classica di questo dispositivo è l'alimentazione/disalimentazione del televisore (ed altri accessori multimediali, come decoder, lettori DVD, ecc. collegati alla stessa presa) con il comando POWER ON/OFF del telecomando del televisore, eliminando i consumi di stand-by di questi elettrodomestici (in stand-by il dispositivo consuma poco più di 1 milliWatt).
Un'altra applicazione è quella, per esempio, di accendere luci, ventilatori da soffitto o qualunque altro elettrodomentico che singolarmente assorbano meno di 1kWatt, con lo stesso telecomando del televisore, adibendo a tale scopo dei tasti altrimenti non usati (ce n'è sempre qualcuno che è non mai usato per comandare il televisore).

PROGRAMMAZIONE E TEST

A partire dal codice proposto nel post  Alimentazione e controllo senza trasformatore di tensione, opportunamente modificato, si ottiene una versione funzionante, per lo schema di Fig.1, qui di seguito mostrata.

;**********************************************************************
; Controllo Relay - Versione telecomando                              *
;**********************************************************************
;                                                                     *
;    Filename:	    P16F684_Telec_ac.asm                              *
;    Date:                                                            *
;    File Version: 1.00                                               *
;                                                                     *
;    Author: InTeAS WebMaster                                         *
;    Company: https://www.inteas.it                                   *
;                                                                     * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files Required: P16F684.INC                                      *
;                                                                     *
;**********************************************************************
;
    list p=16f684 ; list directive to define processor
    #include <P16F684.inc> ; processor specific variable definitions	
__CONFIG _CP_OFF & _CPD_OFF & _BOD_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_ON & _FCMEN_OFF & _IESO_OFF
;
; '__CONFIG' directive is used to embed configuration word within .asm file.
; The lables following the directive are located in the respective .inc file. 
; See respective data sheet for additional information on configuration word.
;
;***** EEPROM MAP
;
; 00-5D 	Sequenza contatori durata tasto di comando 
; 5E-FE 	Non usati
; FF		Stato del Relay (OFF=0, ON=1)
;
;
;***** LOCAL VARIABLE DEFINITIONS
;
; 0x20 - 0x7F: Bank 0 
;
VALFL         EQU  0x20
PCOUNT1       EQU  0x21
;
; 0x22 - 0x7F: Sequenza Comando
;
; 0xA0 - 0xBF: Bank 1
;
COUNT1        EQU  0xBF
COUNT2        EQU  0xBE
ITERAZ        EQU  0xBD
BYTVAL        EQU  0xBC
CONFR         EQU  0xBB
;
;**********************************************************************
; PROGRAM AREA
;**********************************************************************
;
	ORG 0x000 ; processor reset vector
  	goto INIT ; go to beginning of program
;
	ORG 0x004 ; interrupt vector location
	goto INTERRUPT
;
INIT:
;
; OPTION Register, on reset all bits = 1
;
	; bit 7 (NOT_RAPU) Weak Pull-Ups (Enabled=0)	
	; bit 6 (INTEDG) Interrupt Edge Select on RA2(Falling Edge=0)
	; bit 5 (T0CS) Timer0 Source Selection: 
;           1= T0CKI Transition (default)
;           0= Internal Instruction (CLKOUT) 
	; bit 4 (T0SE) Timer0 Source Edge Selection: 1 = H-to-L (default), 0= L-to-H  
	; bit 3 (PSA) Prescaler Assignment: 1= to WDT (default), 0= to Timer0	
	; bits 2:0 (PS2,PS1,PS0) Prescaler Rate Selection: 1:128 default
	movlw b'00011111' ; T0CS= 0 : Internal Timer0
	bsf STATUS,RP0 ; Bank 1		
	movwf OPTION_REG
;
; INTCON: INTERRUPT CONTROL REGISTER
;
	; bit 7 (GIE) Global Interrupt Enable bit (Enabled=1)
	; bit 6 (PEIE) Peripheral Interrupt Enable bit (Disabled=0)
	; bit 5 (T0IE) Timer0 Overflow Interrupt Enable bit (Disabled=0)
	; bit 4 (INTE) RA2/INT External Interrupt Enable bit (Disabled=0)
	; bit 3 (RAIE) PORTA Change Interrupt Enable bit (Disabled=0)
	; bit 2 (T0IF) Timer0 Overflow Interrupt Flag bit (not used)
	; bit 1 (INTF) RA2/INT External Interrupt Flag bit (used:Active on 1)
	; bit 0 (RAIF) PORTA Change Interrupt Flag bit (not used)
	movlw b'10000000'
	movwf INTCON
;
; I/O Summary
;
; PORTA,5 INPUT  (pin  2) : NC
; PORTA,4 INPUT  (pin  3) : NC 
; PORTA,3 INPUT  (pin  4) : NC
; PORTA,2 INPUT  (pin 11) : Infra Red Interrupt (attivo su 0)
; PORTA,1 INPUT  (pin 12) : NC
; PORTA,0 INPUT  (pin 13) : Programming Input (attivo su 0)
;
; PORTC,5 OUTPUT (pin  5) : Power Supply Control (attivo su 0)
; PORTC,4 INPUT  (pin  6) : NC
; PORTC,3 INPUT  (pin  7) : AC Signal
; PORTC,2 OUTPUT (pin  8) : Program Led (attivo su 1)
; PORTC,1 INPUT  (pin  9) : NC
; PORTC,0 INPUT  (pin 10) : NC
;
; *******************************
; Set of the PORTA I/O (bit 5:0)
; *******************************
;
	bcf STATUS,RP0 ; Bank 0	
	movlw h'07' ; Set RA<2:0> and RC<4,1:0> to digital I/O
	movwf CMCON0
	bsf STATUS,RP0 ; Bank 1
	clrf ANSEL ; Digital I/O
; 1=input 0=output	
	movlw b'11111111'
	movwf TRISA ; write in TRISA register
;
; *******************************
; Set of the PORTC I/O (bit 5:0)
; *******************************
;
; 1=input 0=output
	movlw b'11011011'
	movwf TRISC ; write in TRISC register
	bcf STATUS,RP0 ; Bank 0
	bsf PORTC,5 ; inattiva Power Supply 
	bcf PORTC,2 ; spegne Probe Led
;
	btfss PORTA,0 ; salta se non c'è Programming Input
	goto PROGRAM ; va alla Programming routine
;
; Va in stand-by
;
STAND_BY:
	bsf INTCON,4 ; abilita l'interrupt su RA2
	sleep
;
;***********************************************
; INTERRUPT: routine di interrupt
;***********************************************
;
INTERRUPT:
	bcf STATUS,RP0 ; Bank 0
	bcf INTCON,1 ; spegne il flag di interrupt
	bcf INTCON,4 ; disabilita l'interrupt
	btfss PORTA,0 ; salta se non c'è Programming Input
	goto PROGRAM ; va alla Programming routine
;
; Acquisizione comando
;
	call ACQUISIZIONE
;
; Verifica di comando completo (FSR=h'80')
;
	btfss FSR,7 ; salta se FSR=80 
	goto STAND_BY; comando incompleto
;
; Analisi comando
;
	movlw h'22'
	movwf FSR ; Inizializzazione puntatore sequenza
	bsf STATUS,RP0 ; Bank 1
	clrf CONFR ; inizializza a zero flag
	clrf EEADR ; Inizializzazione puntatore EEPROM
CmdAnLoop: 	
	call EEREAD ; valore corrente in w
	subwf INDF,0 ; esegue w = f - w 	
	btfsc STATUS,Z ; salta se f diverso da w (Z=0)
	goto EndCmdAn ; f=w (Z=1)
	btfsc STATUS,C ; salta se w maggiore di f (C=0)
	goto PosDiff ; w minore di f 
; Risultato negativo
	addlw h'05' ; massima differenza accettabile
	btfsc STATUS,C ; salta se C=0 cioè diff. NON accettabile
   	goto EndCmdAn ; C=1 differenza accettabile
	incf CONFR ; 
	goto EndAnalysis
; Risultato positivo
PosDiff:
	sublw h'05'
	btfsc STATUS,C ; salta se C=0 cioè diff. accettabile
   	goto EndCmdAn ; C=1 differenza NON accettabile	
	incf CONFR ; 
	goto EndAnalysis
;
EndCmdAn:
	incf EEADR,1
	incf FSR,1
	btfss FSR,7 ; salta se FSR=80
	goto CmdAnLoop
;
; Fine Analisi
;
EndAnalysis:
	btfsc CONFR,0; salta se CONFR=0 (comando valido)
	goto STAND_BY ; comando NON valido
;
; Comando valido
;
  	movlw h'FF'
	movwf EEADR
	call EEREAD ; valore attuale relay in w (0=OFF 1=ON)
	bcf STATUS,RP0 ; Bank 0	
	movwf VALFL ; salva valore attuale in VALFL
;
	movlw b'00000001'
	xorwf VALFL,f ; salva lo stato opposto del relay
	call ACTCNT ; attuazione sul relay del nuovo stato
	movf VALFL,w 
	bsf STATUS,RP0 ; Bank 1	
	call STATUS_SAVE ; memorizza in EEPROM il nuovo stato 	 	
	bcf STATUS,RP0 ; Bank 0
	bsf PORTC,2 ; accende Probe Led
	bsf STATUS,RP0 ; Bank 1
	call DELAY_MAX	
	bcf STATUS,RP0 ; Bank 0
	bcf PORTC,2 ; spegne Probe Led
	bsf STATUS,RP0 ; Bank 1
	call DELAY_MAX
	goto STAND_BY
;
;***********************************************
; PROGRAM: routine di programmazione comando
;***********************************************
;
PROGRAM:
; Lampeggio d'attesa (16 cicli max,)	
	bsf STATUS,RP0 ; Bank 1
	movlw h'10'
	movwf ITERAZ
PrgLoop:
	bcf STATUS,RP0 ; Bank 0
	bsf PORTC,2 ; accende Probe Led
	bsf STATUS,RP0 ; Bank 1
	movlw h'FF'
	movwf COUNT2
PrgDly2:
	movlw h'FF'
	movwf COUNT1
PrgDly1:
	bcf STATUS,RP0 ; Bank 0
	btfss PORTA,2 ; salta se non c'è comando
	goto COMMAND_ACQ
	bsf STATUS,RP0 ; Bank 1	
	decfsz COUNT1,1
	goto PrgDly1
	decfsz COUNT2,1
	goto PrgDly2
	bcf STATUS,RP0 ; Bank 0
	bcf PORTC,2 ; spegne Probe Led
	bsf STATUS,RP0 ; Bank 1
PrgDly4:
	movlw h'FF'
	movwf COUNT1
PrgDly3:
	bcf STATUS,RP0 ; Bank 0
	btfss PORTA,2 ; salta se non c'è comando
	goto COMMAND_ACQ
	bsf STATUS,RP0 ; Bank 1	
	decfsz COUNT1,1
	goto PrgDly3
	decfsz COUNT2,1
	goto PrgDly4
	decfsz ITERAZ,1
	goto PrgLoop
;
;  Tempo scaduto
;
	goto STAND_BY
;
; Acquisizione Comando
;
COMMAND_ACQ:
	bcf PORTC,2 ; spegne Probe Led
	call ACQUISIZIONE
;
; Verifica di comando completo (FSR=h'80')
;
	btfss FSR,7 ; salta se FSR=80 
	goto PROGRAM; comando incompleto	
;
; Salvataggio comando in EEPROM
;	
	bsf STATUS,RP0 ; Bank 1		
	call INTEE_WR
;
; Memorizzazione stato OFF del relay   
;
	movlw h'00'
	call STATUS_SAVE	
	bcf STATUS,RP0 ; Bank 0	
	clrf VALFL
	call ACTCNT ; attuazione sul relay dello stato OFF
;
; Segnalazione avvenuta memorizzazione
;
	bsf PORTC,2 ; accende Probe Led
	bsf STATUS,RP0 ; Bank 1
;
	movlw h'10'
	call LDELAY
;
	bcf STATUS,RP0 ; Bank 0	
	bcf PORTC,2 ; spegne Probe Led
	bsf STATUS,RP0 ; Bank 1
;
	movlw h'10'
	call LDELAY
;	
	goto STAND_BY
;
;
;###############################################
;#                 ROUTINES   	               #
;###############################################
;
;
;***********************************************
; ACQUISIZIONE
;***********************************************
;
ACQUISIZIONE:
	movlw h'22'
	movwf FSR ; inizializzazione puntatore sequenza
ZeroCount:
	clrf INDF ; azzera contatore corrente
ZeroLoop:	
	call PAUSE	
	btfsc PORTA,2 ; salta se IR = 0
	goto EndZeroCount
	incf INDF ; incrementa contatore corrente	
	btfss STATUS,Z ; salta se Z=1 (>255)	
	goto ZeroLoop ; Z=0 (<256)
;
; Overflow on Zero
;
ZOLoop:
	btfss PORTA,2 ; salta se IR = 1
	goto ZOLoop ; aspetta fino a che IR=0
;
EndZeroCount:
	incf FSR,1 
;	
OneCount:
	clrf INDF ; azzera contatore corrente
OneLoop:
	call PAUSE
	btfss PORTA,2 ; salta se IR = 1	
	goto EndOneCount
	incf INDF ; incrementa contatore corrente
	btfss STATUS,Z ; salta se Z=1 (>255)	
	goto OneLoop ; Z=0 (<256)
;
; Overflow on One
;
; Se il comando si interrompe a metà, va a 1
; per impedire che il software rimanga all'infinit oin loop
; va definito un Tempo max. di attesa e poi fine comando
;
	movlw h'FF'
	movwf COUNT2
OODly:
	movlw h'FF'
	movwf COUNT1
OOLoop:
	btfss PORTA,2 ; salta se IR = 1
	goto EndOneCount ; IR=0
	decfsz COUNT1,1
	goto OOLoop
	decfsz COUNT2,1
	goto OODly	
;
; Comando incompleto: fine prematura
;
	return
;
EndOneCount:
	incf FSR,1 
	btfss FSR,7 ; salta se FSR=80 
	goto ZeroCount	
	return
;
;***********************************************
; PAUSE
;***********************************************
;
PAUSE:
	movlw h'01' ; può essere aumentato 
; se troppi overflow in sequenza (intervalli lunghi)
	movwf PCOUNT1
Pse1:
	decfsz PCOUNT1,1
	goto Pse1
	return
;
;***********************************************
; DELAY Routine max 196,65 msec, min 0,771 msec
;***********************************************
;
DELAY_MAX:
	movlw h'FF'
DELAY:
	movwf COUNT2
Dly2:
	movlw h'FF'
	movwf COUNT1
Dly1:
	decfsz COUNT1,1
	goto Dly1
	decfsz COUNT2,1
	goto Dly2	
	return
;
;****************************************************
; LDELAY Routine lungo ritardo 1 ciclo circa 196 msec; max 49.8 sec circa
;****************************************************
;
LDELAY_STD:
	movlw h'02'
LDELAY:
	movwf ITERAZ
Dly3:
	call DELAY_MAX
	decfsz ITERAZ,1
	goto Dly3
	return
;
;*****************
; ACTUATOR CONTROL
;*****************
;
ACTCNT:
;
;	Syncronization	VALFL=0 Negative Polarity (Status Off)
;					VALFL=1 Positive Polarity (Status On)
;
	btfsc VALFL,0
	goto Syncr2 
; Negative Polarity
Syncr1:
	btfss PORTC,3
	goto Syncr1 ; waiting for AC=1
	goto LdPr
; Positive Polarity
Syncr2:
	btfsc PORTC,3
	goto Syncr2 ; waiting for AC=0
;
; Loading procedure
;
LdPr:
	call TRANSDET ; 0-->1
	call PWSPCNT
	return
;
; **********************
; Transition Detection
; **********************
;
TRANSDET:
	btfsc PORTC,3
	goto Tr10 ; jump if AC Signal=1
; AC Signal=0
Tr01:
	btfss PORTC,3	 
	goto Tr01 ; waiting for AC=1
	return
Tr10:
	btfsc PORTC,3
	goto Tr10 ; waiting for AC=0
	return
;
; **************************
; Power Supply Control Signal
; **************************
;
PWSPCNT:
	movlw h'FF'
	movwf PCOUNT1
PDly1:
	decfsz PCOUNT1
	goto PDly1
;	
;	Spike Emission
;
	bcf PORTC,5 ; Signal Active	
	movlw h'10' ; durata spike
	movwf PCOUNT1
Spk1:
	decfsz PCOUNT1
	goto Spk1
	bsf PORTC,5 ; Signal Inactive	
	return
;
;******************************************
; GESTIONE EEPROM INTERNA (256 BYTE)
;******************************************
;
;******************************************
; EEREAD Routine: indirizzo in EEADR
;******************************************
;
EEREAD:
	bsf EECON1,RD ;EE Read
	movf EEDAT,W ;risultato in w
	return
;
;*************************************************************
; EEWRITE Routine: byte in EEDAT, indirizzo in EEADR  
;*************************************************************
;
EEWRITE:
	bsf EECON1,WREN ;Enable write
	movlw h'55' ;Unlock write
	movwf EECON2
	movlw h'AA'
	movwf EECON2
	bsf EECON1,WR ;Start the write
	movlw h'0A' ; 06 è il minimo
	call DELAY
	return
;
;********************************************************************************
; INTEE_WR ROUTINE da RAM a EEPROM
;********************************************************************************
;
INTEE_WR:
	movlw h'22'
	movwf FSR ; inizializzazione puntatore di sequenza
	clrf EEADR ; inizializzazione puntatore EEPROM 
IntEEWrLoop:
	movf INDF,w
	movwf EEDAT
	call EEWRITE	
	incf EEADR,1
	incf FSR,1 
	btfss FSR,7 ; salta se FSR=80
	goto IntEEWrLoop
	return
;
; ************************************************************
; STATUS_SAVE: Memorizzazione in EEPROM; stato del relay in w  
;*************************************************************
;
STATUS_SAVE:	
	movwf EEDAT
  	movlw h'FF'
	movwf EEADR
	call EEWRITE ; salva lo stato relay in EEPROM
	return
;
;******************************************************************************
		END ; directive 'end of program'
;******************************************************************************