Come continuare ad utilizzare una vecchia e costosa stampante non più compatibile con Windows 7/8/10

La stampante è uno di quei strumenti che cambi solo quando si rompe oppure… quando non è più compatibile con l’ultimo aggiornamento di Windows.

Ma spesso è frustrante dover cambiare una stampante solo perchè non più supportata dal nuovo sistema operativo, soprattutto se la stampante in questione possiede queste caratteristiche:

  1. funziona ed ha funzionato sempre benissimo
  2. è costata parecchio
  3. è di ottima qualità
  4. consuma poco inchiostro

Nel mio caso ho avuto a che fare con una stampante professionale da ufficio Develop 1650D. La stampante ha sempre funzionato egregiamente con WindowsXP, funzionava in alcuni casi ristretti su Windows7 ed un bel giorno ha smesso del tutto di funzionare dopo l’ultimo aggiornamento del suddetto sistema operativo.

529ef87ed1beb529d4026ee8ed4ab96c33430541

La stampante non ha porte Ethernet o Wifi. Ha una singola porta USB ed una porta parallela: ciò significa che deve essere collegata direttamente ad un computer.

Soluzione “semplice” è buttare la stampante da 2000 e rotti euro e comprarne una nuova: non ci piace.

 

Tentativo: utilizzo di un print server commerciale

Acquistare un printserver commerciale sembrerebbe la soluzione ottimale: il print server funge da ponte tra la stampante e la rete LAN dell’ufficio scavalcando del tutto il problema del sistema operativo.

71YFJAkgaTL._SL1280_

Purtroppo però tutti i print server in circolazione supportano solo alcuni modelli specifici di stampanti ed in genere solo quelle più recenti. Non era la soluzione ideale per questa stampante ma potrebbe esserlo per la vostra, quindi lo consiglio vivamente per evitare inutili grattacapi

 

Tentativo: Macchina XP dedicata e condivisione stampante

Una soluzione alternativa è collegare un PC WindowsXP direttamente alla stampante e condividerla in rete. Questa soluzione non ha funzionato in quanto, sebbene la stampante fosse perfettamente visibile in rete dagli altri PC Windows7, le stampe non partivano a causa dell’incompatibilità tra i driver XP  e i PC utilizzatori (Windows7).

 

Soluzione finale: print server ad-hoc

La soluzione è consistita nel disaccoppiare utenti Windows7 e stampante tramite l’utilizzo di una stampante virtuale PDF. Un PC WindowsXP dedicato gestisce la stampante reale via USB e al tempo stesso condivide in rete una stampante virtuale PDF. I PDF (le stampe degli utenti) vengono creati sul disco della macchina XP all’interno di una directory specifica che funge da coda di stampa. Un programma ad-hoc realizzato in .NET C# (printserver.exe) e residente nella macchina XP provvede a scodare i file PDF dalla directory e a stamparli sulla stampante reale.  Il programma è avviato automaticamente e non richiede alcun intervento manuale per funzionare.

Screen shot 2015-11-02 at 5.38.30 PM

Lato utente il meccanismo è del tutto trasparente: in rete è visibile solo la stampante virtuale. Ogni comando di stampa verso la stampante virtuale si traduce in una stampa vera e propria sulla Develop 1650D.

Screen shot 2015-11-02 at 5.38.15 PM

Il tutto realizzato su un comunissimo PC desktop privo di mouse, tastiera e schermo. L’unica cosa da ricordare è accendere il printserver la mattina prima di utilizzare la stampante!

printserver

 

Aspetti interessanti della soluzione

Allo stato attuale i PDF vengono scodati, stampati e quindi cancellati; Nessuno però vieta di copiare i PDF in una ulteriore cartella di backup in modo da mantenere uno storico digitale delle stampe.

E’ possibile estendere il meccanismo ad altre stampanti obsolete e collegarle tutte alla stessa macchina XP; l’unico limite è il numero di porte USB e parallele disponibili (di solito 4 o 6 USB e 1 o 2 parallele).

La stampante funzionerà anche con Windows 8, Windows 10 e anche sistemi Linux e Mac.

Clicca qui per andare alla pagina di download di printserver

Telecomando universale per apricancelli a 433.92 MHz

Di recente ho dovuto comprare un set di telecomandi  (parlo del telecomando universale, quelli ad autoapprendimento) per i cancelli di casa. La procedura di solito è semplice, si prende il telecomando originale, lo si affianca a quello universale e si clona il segnale. Purtroppo nel mio caso non ha funzionato, probabilmente per una incompatibilità a livello di frequenze (433.92MHz degli universali e 433 MHz del’originale o viceversa). Il modello del telecomando originale è Elvox ET2 ZX03.

Siccome i telecomandi originali Elvox sono alquanto costosi, una soluzione è stata quella di realizzare un circuito in grado di rendere comunque compatibili i cancelli con i telecomandi universali o qualsiasi altra marca di telecomandi. Questa soluzione richiede però la realizzazione di un circuito e non necessariamente potrebbe funzionare con altri tipi di telecomandi.

Ho trovato online invece un’altra soluzione interessate, per chi non avesse il tempo di realizzare il circuito da solo e che risolve in modo definitivo il problema legato alla duplicazione del telecomando, si chiama SHEDU

shedu

Si tratta di un prodotto che permette di usare lo smartphone in alternativa al telecomando.
Visto il costo equiparabile a quello di un paio di telecomandi e l’indubbia praticità, è una soluzione interessante sia per un uso personale che per le aziende.
Molto interessanti anche alcune funzioni aggiuntive come l’apertura per prossimità e la possibilità di condividere l’accesso ad altri utenti tramite l’app stessa in tutta sicurezza (utile ad esempio per concedere ai familiari la possibilità di aprire il cancello senza acquistare nuovi telecomandi).
Attualmente è in corso una promozione che permette di ottenere degli sconti sull’acquisto per chi si registra e condivide sui social tramite il link che vi viene inviato

SHEDU è sicuramente la soluzione più pratica e risolve definitivamente il problema; per quanto riguarda invece la realizzazione di un circuito ad-hoc, occorrerà prendere un modulo ricevitore da collegare elettricamente al telecomando Elvox originale: il circuito riceve il segnale dai telecomandi universali e comanda il telecomando originale. Il telecomando originale a sua volta emette il segnale per i cancelli che quindi si aprono/chiudono come di consueto.

Il circuito scelto è RKAU2, un ricevitore con attacco molex in auto-apprendimento a 2 canali; è dotato di due relè non polarizzati (quindi semplici contatti) ideali per essere collegati ai 2 pulsanti del telecomando originale.

ricevitore

Il circuito ricevitore deve essere alimentato a 12V e non include l’antenna. L’alimentatore è facilmente reperibile, qualsiasi 12V ad almeno 500mA va bene. Per l’antenna è sufficiente un filo elettrico lungo esattamente 17.3 cm (la lunghezza d’onda a 433Mhz è 69.3 cm, quindi 1/4 di lunghezza d’onda è all’incirca 17.3 cm).

Questi sono i contatti del circuito ricevitore:

ricevitore_schema

I pulsanti P1 e P2 servono per la programmazione.

Ho quindi collegato il circuito ricevitore al telecomando, collegando tra loro i contatti dei 2 relè (CN1 e CN2) ai due pulsanti del telecomando Elvox originale. Sia il circuito ricevitore che il telecomando vengono alimentati dallo stessa fonte a 12V. Questo lo schema elettrico finale:

remote

Il circuito finale, una volta realizzati i collegamenti, si presenta cosi’:

20141002_084354

Il cavetto nero è l’alimentazione, il filo in alto l’antenna. Il circuito a sinistra è il telecomando Elvox originale, quello a destra il circuito ricevente.

Tutto l’insieme è stato inserito in una cassetta plastica per esterni opportunamente alimentata. Programmando il circuito ricevente è possibile aprire/chiudere i cancelli utilizzando qualsiasi telecomando (ovviamente compatibile con il ricevitore), da quelli universali ai cloni più economici.

In questo modo è possibile comandare i cancelli sia con gli eventuali altri telecomandi originali (ne abbiamo sacrificato solo uno) che con i nuovi. In più non abbiamo dovuto modificare o sostituire i circuiti dei singoli motori dei cancelli.

LED Cube 3x3x3 PIC16F84 con microfono incorporato

Un LED cube 3x3x3 costruito completamente a mano!

I LED cube sono matrici LED a tre dimensioni in grado di illuminarsi nelle più complesse animazioni; ne esistono di numerosi tipi tra cui 3x3x3, 4x4x4 e addirittura 8x8x8. Alcuni sono comandati via PC, altri sono provvisti di microcontrollore e quindi completamente autonomi.

Nel mio caso ho dotato il cubo di microfono e amplificatore per lampeggiare a tempo di musica (una specie di VU meter tridimensionale). L’ho realizzato con un semplice PIC micro 16F84, un amplificatore MAX9812, microfono e pochi altri componenti.

DSCN4392

Multiplexing

La griglia LED è composta da 3 piani di 9 LED ciascuno per un totale di 27 LED (3x3x3). Il micro prevede solo 13 GPIO, ovviamente non sufficienti a pilotare tutti e 27 i LED singolarmente; ho quindi realizzato un indirizzamento del singolo LED secondo la coppia piano/colonna. In questo modo per accendere un LED e’ sufficiente specificare il piano (uno di tre, quindi 3 GPIO) e la colonna di afferenza (una di nove, quindi altri 9 GPIO) per un totale di 12 GPIO. Elettricamente cio’ si traduce nel collegare tra loro i catodi dei LED di ogni piano e tutti gli anodi secondo le colonne.

Questa particolare configurazione purtroppo ci costringe ad accendere un solo piano alla volta: abilitare piu’ di un piano contemporaneamente comporterebbe l’accensione di LED non desiderati. E’ comunque possibile risolvere il problema avvicendando i 3 piani molto velocemente tra loro (tecnica display multiplexing): in sostanza il micro seleziona il primo piano, ne accende opportunatamente i nove LED, spegne il primo piano, accende il secondo, accende i nove LED del secondo piano, spenge il secondo piano, accende il terzo e cosi’ via in loop il più velocemente possibile. L’occhio umano non e’ in grado di percepire questo veloce cambiamento e la percezione finale e’ quella di avere tutti i LED accesi contemporaneamente. Nel mio caso ho programmato il multiplexing ad una frequenza di circa 100Hz ottenendo cosi’ un frame rate dell’intero pattern LED di circa 33,3Hz. Nell’immagine qui sotto mostro i collegamenti tra i GPIO del micro con alla griglia LED 3x3x3.

multiplex

Luminosita’ variabile dei LED

In aggiunta al multiplex, il micro alimenta i LED tramite PWM cosi’ da poterne modificare la luminosità. Il pic 16F84 non prevede hardware dedicato per il PWM ma e’ comunque possibile realizzarlo via software togglando molto velocemente on/off i GPIO opportuni.

Animazioni

Il cubo e’ in grado di mostrare fino ad 8 animazioni differenti, ognuna composta da un certo numero di frame (un frame è semplicemente una configurazione ON/OFF dei 27 LED). Le animazioni sono codificate nella flash del micro come semplici tabelle retwl di lookup.

Sincronizzazione con musica esterna

Ho dotato il cubo di un microfono amplificatore integrati. In questo modo e’ in grado di mostrare le animazioni LED andando piu’ o meno a tempo di musica. Il segnale analogico captato dal microfono viene amplificato, filtrato da un filtro RC passa basso e poi squadrato in un segnale TTL 0-5V. Il segnale cosi’ ottenuto passa al piedino RB0/INT del micro. Il filtro RC è dimensionato per far in modo che passino solo le basse frequenze ad esempio la batteria di una musica o simili. Ogni volta che il microfono capta un segnale a bassa frequenza il piedino RB0 viene portato a livello logico alto il che scatena un interrupt nel microcontrollore. Il micro quindi seleziona casualmente una animazione (dalle 8 disponibili) e la sulla griglia LED, un frame dopo l’altro (e’ possibile impostare da software la velocita’ delle animazioni).

Schema elettrico

Questo lo schema elettrico completo:

ledcube - schematic

Il pic 16F84 è nella sua classica configurazione con oscillatore esterno da 4MHz e circuito di reset. I pin da RB1 a RB7 e RA2,RA3 indirizzano le 9 colonne LED tramite apposite resistenze limitatrici, i pin RA0,RA1 e RA4 attivano rispettivamente il piano alto, di mezzo e il basso tramite i 3 FET di potenza (2N7000). La sezione audio analogica è composta da microfono, integrato amplificatore MAX9812, filtro passa basso (R17,C7) e squadratore di segnale (i due BC547 a valle). Notare il pullup di 4.7K per il pin RA4: RA4 e’ l’unico pin del 16F84 ad essere open-collector, occorre quindi il pull-up.

DSCN4394 DSCN4399

DSCN4397 DSCN4396

Il MAX9812 non viene commercializzato nel classico package DIL ma solo su TSOP: essendo un package estremamente miniaturizzato ho dovuto realizzare una basetta adapter apposita (vedi foto in basso a destra) sulla quale saldare a parte l’integrato.

Codice sorgente

Il codice sorgente è scritto interamente in assembler in quanto sia per il multiplexing dei 3 layer che per il PWM occorre un timing particolarmente accurato, dell’ordine dei microsecondi. Il codice si compone di tre sezioni principali:

  • Inizializzazione
  • Idle routine
  • ISR (Interrupt Service Routine)

Al power on viene eseguita l’inizializzazione delle varie parti del micro (direzioni dei GPIO, timer interno, variabili di programma etc…). Immediatamente dopo il cubo entra nella idle routine nella quale parte la modalità glowing (tutti e 27 i LED rimangono accesi e si aumenta e diminuisce ciclicamente la luminosità. Il cubo permane in questa modalità fino a che non subentra un interrupt esterno (dal pin RB0) corrispondente ad un beat del segnale sonoro captato dal microfono (una musica, un battito di mani, etc…). L’interrupt viene immediatamente servito dalla routine ISR: viene impostata la luminosità massima e viene scelta una animazione casuale (fra 8 disponibili) che viene mostrata sulla griglia led. L’animazione è mostrata sulla griglia LED un frame dopo l’altro, cicliclamente. Ad ogni giro viene decrementata la luminosità di un fattore 1. Quando la luminosità raggiunge lo zero il micro esce dalla ISR e si riporta in modalità attesa (cubo glowing).

Ecco il flowchart completo del programma:

flowchart

Dettaglio codice sorgente

Il sorgente si compone di un singolo file .asm. Per la compilazione e programmazione del micro e’ sufficiente l’ambiente MPLab e apposito programmatore, ad esempio il pickit 3

ICSP40PICkit3PG

Download codice sorgente: ledcube

Nella prima parte del codice indichiamo il micro che andremo ad utilizzare (16F84) e la base per le costanti (base 16, hex):

;directives

PROCESSOR 16F84A
RADIX HEX

passiamo poi a creare i define dei registri principali del micro

;defs

PCL EQU 0x02
OPTREG EQU 0x01
TMR EQU 0x01
INTCON EQU 0x0B
TMR0 EQU 0x01
TRISB EQU 0x06
TRISA EQU 0x05
PORTA EQU 0x05
PORTB EQU 0x06
STATUS EQU 0x03
FSR EQU 0x04
INDF EQU 0x00
Z EQU 2        ; Z flags
GIE EQU 7      ; GIE bit
INTF EQU 1     ; INTF flag

infine definiamo le variabili (parliamo sempre di locazioni a 8bit) del nostro programma, in particolare i 3 layer (LOWL, MIDL e HIGL) e il layer “extra” EXTL che andrà a contenere tutti i noni LED dei layer (useremo quindi solo 3 bit in EXTL). TIME sarà la velocità delle animazioni e BRIG il livello di luminosità:


LOWL EQU 0x20   ; bottom layer (8 bit pattern)
MIDL EQU 0x21   ; middle layer (8 bit pattern)
HIGL EQU 0x22   ; upper layer (8 bit pattern)
EXTL EQU 0x23   ; extra layer (9th led for each layer)
TIME EQU 0x24   ; current frame speed
TCONT EQU 0x25  ; frame speed counter
LSEL EQU 0x26   ; layer selector
BCONT EQU 0x27  ; brightness counter
BRIG EQU 0x28   ; brightness
CURL EQU 0x29   ; current layer

La primissima istruzione (locazione 0x0000) è un semplice goto alla routine di inizializzazione. Occorre mettere il goto in quanto il micro richiede che all’indirizzo 0x0004 parta la routine di gestione interrupt.

ORG 0x0000              ; start from address 0x0000
goto Init

A questo punto osserviamo il codice di inizializzazione:

Init:                   ; initialization
bsf     STATUS,5        ; select RAM bank 1
movlw   b'00000001'
movwf   TRISB
movlw   b'00000000'
movwf   TRISA
bcf     OPTREG,5        ; start the TMR module in counter mode
bcf     STATUS,5        ; select RAM bank 0
movlw   0x00            ; all leds off
movwf   PORTA
movwf   PORTB
clrf    LSEL            ; no layer selected
call    IdleCube

molto semplicemente impostiamo tutti i GPIO come output (bit di TRISB e TRISA a zero) tranne il primo bit di PORTB (RB0) che ci servirà invece come ingresso per triggerare l’interrupt (RB0 è collegato all’amplificatore audio esterno). Avviamo il timer interno in modalità conteggio ciclico, resettiamo gli output ed infine saltiamo alla funzione IdleCube.

Passiamo ora ad analizzare la funzione IdleCube:

per prima cosa impostiamo il pattern “full 27 led” ossia tutti e 27 i led accesi. Da notare che i noni LED di ogni layer sono mappati rispettivamente nel primo, secondo e quinto bit di EXTL (RA0, RA1 e RA4): osservare lo schematico per vedere questa corrispondenza.

;******** IDLECUBE ***********************************
;
; The cube is glowing and ready to trigger...
;
;*****************************************************

IdleCube:

movlw   b'11111111'
movwf   LOWL
movlw   b'11111111'
movwf   MIDL
movlw   b'11111111'
movwf   HIGL
movlw   b'00010011'
movwf   EXTL

settiamo al minimo luminosità e velocità di animazione:

movlw   0x01
movwf   BRIG      ; smallest brightness
movlw   0x02
movwf   TIME      ; smallest pattern duration

Abilitiamo poi l’interrupt esterno dal pin RB0

bcf   INTCON,INTF
bsf   INTCON,4     ; enabling the interrupt from the RB0/INT pin
bsf   INTCON,GIE   ; enabling the interrupt service

passiamo poi ciclicamente a fare fadein e fadeout del ful-27-led pattern:

IdleCube_fadein:          ; fade in loop
callShowCube
incfsz	BRIG
goto	IdleCube_fadein
IdleCube_fadeout:         ; fade out loop
call	ShowCube
decfsz	BRIG
goto	IdleCube_fadeout
incf	BRIG,1
goto	IdleCube_fadein

Il micro rimane in questa condizione indefinitamente. Ecco il cubo durante la fase idle:

Non appena la sezione microfono/amplificatore emette un segnale sul pin RB0, viene triggerato un interrupt gestito immediatamente dal micro. Il micro inizia quindi ad eseguire il codice alla locazione 0x0004 (inizio della nostra routine ISR). La routine è abbastanza semplice e si compone di tre parti principali:

  • disabilitazione interrupt
  • selezione di un valore random da 0 a 7
  • jump table per lanciare uno di 8 animazioni led

Per il valore random viene campionato il valore corrente del timer (un valore compreso tra 0 e 255) e viene messo in AND con la maschera 0x07 per prelevarne solo i 3 bit meno significativi. Questi 3 bit sono il nostro valore casuale 0-7 e vengono sommati al program counter per chiamare la funzione animazione corrispondente.

Interrupt:              ; interrupt service routine
bcf    INTCON,INTF      ; disable the interrupt service
bsf    INTCON,GIE
movf   TMR,0            ; pick a pattern at random
andlw  0x07
addwf  PCL,1            ; jump into jump table
goto   Pattern_treble
goto   Pattern_updown
goto   Pattern_twobars
goto   Pattern_buildframe
goto   Pattern_rotplane
goto   Pattern_rlplane
goto   Pattern_snake
goto   Pattern_fourface

Analizziamo ora la funzione principale, ossia ShowCube. ShowCube mostra sulla griglia led un singolo frame dell’animazione prescelta. Il frame è codificato nei 24 bit di LOWL, MIDL, HIGL e nei 3 bit aggiuntivi di EXTL per un totale di 27 bit (i 3x3x3 led della griglia). Il pattern completo è mostrato sulla griglia accendendo un layer alla volta ad una frequenza di circa 100Hz. I bit RA0, RA1 e RA4 abilitano il layer corrispondente (controllare lo schematico per le corrispondenze). Il singolo layer è mostrato invocando la funzione ShowLayer.

;******** ShowCube ***********************************
;
; Shows the cube pattern for 0.01 * TIME sec using
; brightness level BRIG. The refresh rate is 100Hz.
;
;*****************************************************

ShowCube:

; setup counter
movf    TIME,0
movwf   TCONT           ; TCONT 0
decfsz  TCONT,1
goto    ShowCube_loop
return

Per finire ecco la funzione ShowLayer utilizzata per illuminare un singolo layer della griglia. La funzione implementa un classico PWM per settare la luminosità del singoli LED ad un valore prescelto (variabile BRIG): per un tempo pari a (BRIG/255)% il layer rimane acceso, per un tempo pari a ((255-BRIG)/255)% il layer rimane spento. In sostanza la variabile BRIG codifica il duty cycle del PWM.

;******** ShowLayer **********************************
;
; Shows the layer encoded in W and EXTL for x msec.
; (BRIG/255)% of the time the layer is ON, the
; remaining (255-BRIG)/255)% of the time the layer
; is OFF. (this is a PWM controlled brightness)
;
;*****************************************************

ShowLayer:
; layer on for (255/BRIG)*x msec
; layer off for (255/(255-BRIG))*x msec
; where x depends on the osc used

; set the first seven leds (bit0 of PORTB is used to receive interrupts!)
movwf   PORTB           ; PORTB
; set/clear the 8th led
btfsc   CURL,0
bsf     PORTA,2

; test the 9th bit of the current layer and set
; the 9th led accordingly (9th led = bit3 of PORTA)
movf    EXTL,0
andwf   LSEL,0          ; W btfss   STATUS,Z        ; is the 9th bit clear (9th led off)?
bsf     PORTA,3         ; no, set the 9th bit

; set the 9th bit of the current layer and turn on
; the entire layer
movf    LSEL,0
xorwf   PORTA,1         ; PORTA
; wait (BRIG/255)%
movf    BRIG,0
movwf   BCONT
ShowLayer_loop_layeron:
decfsz  BCONT
goto    ShowLayer_loop_layeron

; turn off the entire layer
clrf    PORTA

; wait ((255-BRIG)/255)%
movf    BRIG,0
movwf   BCONT
decf    BCONT,1
ShowLayer_loop_layeroff:
incfsz  BCONT
goto    ShowLayer_loop_layeroff

return

Ecco il cubo all’opera: