Questo articolo della Rubrica Firmware Reload descrive come implementare via software un blocco che effettua un ritardo su PIC10F322 e utilizzarlo come anti-rimbalzo per interruttori.
INTRODUZIONE
L’obiettivo è realizzare un blocco di attesa che accetti valori tra 2μs e 193μs. L’intento è quello di sfruttarlo come discriminatore del rumore o come anti-rimbalzo per un interruttore. Utilizzato come ritardo, può essere usato dall’applicazione per effettuare operazioni sui segnali a basso livello ad un determinato intervallo, utilizzato per il “debouncing” invece può agire su un interruttore meccanico per ripulire il segnale o alimentare qualsiasi altra circuiteria elettronica. Per la realizzazione si utilizza la periferica CLC (Configurable Logic Cell) per realizzare una commutazione veloce in uscita, se ciò non fosse indispensabile si possono utilizzare solamente delle porte logiche, in tal caso più cicli di istruzioni devono essere elaborati prima che l’uscita commuti in funzione dell’ingresso. Utilizzando il CLC il segnale viene pilotato direttamente e ha solo il ritardo di propagazione tra il segnale di entrata e quello di uscita. Per velocizzare ulteriormente e ottenere la massima performance, il codice viene scritto in assembly. Il codice viene scritto in-line, senza subroutine per ottimizzare le performance durante i salti di codice. Il codice occupa solo 43 locazioni sulle 512 disponibili di flash e solo un byte di RAM. L’applicazione è stata sviluppata sulla scheda demo PIC10F322 (AC103011). Le versioni degli strumenti utilizzati sono le seguenti: MPASMWIN.exe v5.45, mplink.exe v4.43, mplib.exe v4.43.
GENERAZIONE DEL RITARDO
Come detto, il ritardo può essere impostato tra 2μs e 193μs per incrementi discreti di 750ns (in base al clock interno a 16MHz e alle 3 istruzioni necessarie per eseguire un loop di attesa). Ovviamente, la dimensione massima del ritardo può essere aumentata, o riducendo la frequenza di clock oppure aumentando il numero di cicli del loop di ritardo. I ritardi sono sincronizzati sui fronti di salita o di discesa del segnale in esame, tramite due #define si possono abilitare:
;; 2 lines below enable rising and falling edge delays #defi ne RISING_EDGE_DELAY #defi ne FALLING_EDGE_DELAY ;; specify length of falling and rising edge below RISE_EDGE_DELAY equ 0x01 FALL_EDGE_DELAY equ 0x01 ;#defi ne MS_DELAY
o disabilitare, due ulteriori righe consentono di definire il valore del ritardo, che verrà calcolato in base alla definizione o meno di MS_DELAY, nel caso sia definita, il ritardo viene considerato in millisecondi, oppure in alternativa se la #define è commentata in step da 750ns. Se la situazione è quella del codice riportato in precedenza, allora il valore di ritardo si ottiene come: delay = 2μs + (delay_value x 750ns). Attivando il ritardo su entrambi i fronti, la situazione è quella di Figura 1.
Il segnale di uscita viene sfasato rispetto al segnale d’ingresso, a seconda dei ritardi impostati per i due fronti. Se analizziamo un singolo fronte, quello di discesa, dei segnali in ingresso e in uscita, possiamo ottenere il ritardo di propagazione, approssimativamente intorno ai 50ns, vedi Figura 2.
REALIZZAZIONE DEL RITARDO CON CLC
In Figura 3 è possibile vedere lo schema a blocchi del blocco di ritardo realizzato utilizzando la periferica CLC.
Se il blocco viene configurato per non generare un ritardo, un sotto-blocco dedicato di pass-through realizzato tramite la periferica CLC, permette di portare il segnale d’ingresso direttamene all’uscita. In alternativa, il segnale del mix di uscita viene preso dal canale alternativo dove il PIC Device Core genera l’attesa. Per realizzare il pass-through l’unico blocco CLC disponibile nel PIC10F322 viene configurato come in Figura 4.
Viene utilizzata la TAB logica dedicata all’AND. Come si può vedere dalla Figura 4 nella prima porta OR abbiamo il segnale d’ingresso che è l’unica entrata del GATE1. Le restanti porte logiche OR (GATE2, GATE3 e GATE4) non collegate sono invertite in uscita in maniera che presentino un livello logico alto all’ingresso della porta logica AND. Infine, il segnale risultante va in uscita dopo essere stato bufferizzato con un buffer non invertente. Se ci fosse l’esigenza di invertire il segnale in uscita, sarebbe sufficiente far diventare il buffer invertente come in Figura 9, per ottenere un segnale in uscita speculare a quello in ingresso (vedi Figura 6).
IL SOFTWARE
Il software che realizza il blocco di ritardo può essere scaricato dal sito Microchip dal link dedicato [2]. Di seguito riportiamo il file DELAY.ASM proposto da Microchip per far vedere come è realizzato il loop di ritardo.
;/******************************************************************** ;* FileName:delay.asm ;* Dependencies: ;* Processor:PIC10F322 ;* Hardware: ;* Compiler:MPASM 5.45 or later ;* Company:Microchip Technology, Inc. ;* ;* Copyright © 2007-2012 Microchip Technology Inc. All rights r eserved. ;* ;*/ #include <p10f322.inc> list p=p10f322 ;; Defi ne parameters here ;; 2 lines below enable rising and falling edge delays #defi ne RISING_EDGE_DELAY #defi ne FALLING_EDGE_DELAY ;; specify length of falling and rising edge below RISE_EDGE_DELAY equ 0x05 FALL_EDGE_DELAY equ 0x04 #defi ne MS_DELAY ;; Confi guration Fuses __confi g _FOSC_INTOSC & _BOREN_OFF & _WDTE_OFF & _PWRTE_OFF & _MCLRE_O FF & _CP_OFF & _WRT_OFF ;; pin-out ;; 1 - RA0 - pin available for use as scope trigger. ;; 2 - VSS ;; 3 - RA1 - Data Out / CLC1 ;; 4 - RA2 - Data In / CLC1IN2 ;; 5 - VDD ;; 6 - MCLR #defi ne input_signal PORTA,2 #defi ne output_signal LATA,1 ; single RAM location used for countdown_timer countdown_timer equ 0x51 ;; additional RAM location required if millisecond delay is ena bled. #ifdef MS_DELAY ms_timer equ 0x52 ; delay counter for specifying time delay in milliseconds. #endif org 0x00 start bcf TRISA,0 ; RA0 output - this can be used as a scope trigger. bcf TRISA,1 ; RA1 output clrf ANSELA ; all pins are digital. movlw 0x70 movwf OSCCON ; 16 MHz clock - change this value for longer dela ytimes ; and to lower current consumption. ;; CLC is set up here with the following include: #include “CLC_pass_through.inc” ; Confi gure CLC for falling edge. ; bsf CLC1POL,LC1POL; option to invert signal through CLC block . ;; input level test btfss input_signal ; What is the current value of my input sign al? goto signal_low ; Low. goto signal_high ; High. ;; ===== This is the start of my main loop signal_high ; Signal just transitioned high. #ifdef RISING_EDGE_DELAY ; If I have rising edge delay, movlw RISE_EDGE_DELAY movwf countdown_timer ; load countdown timer with rising edge d elay. rising_edge_delay_loop ; insert ‘nop’s’ below this line to incr ease delay. #ifdef MS_DELAY ; option for millisecond delay call millisecond_delay #endif #ifndef MS_DELAY decfsz countdown_timer,1 ; Has countdown timer expired? goto rising_edge_delay_loop; no, continue delay loop #endif bsf output_signal ; and drive pin high. #endif #ifdef FALLING_EDGE_DELAY bsf output_signal ; drive latch high bcf CLC1CON,LC1OE ; PORT -> pin #endif #ifndef FALLING_EDGE_DELAY bsf CLC1CON,LC1OE ; CLC -> pin #endif wait_for_falling_edge btfsc input_signal goto wait_for_falling_edge signal_low ; Signal just transitioned low. #ifdef FALLING_EDGE_DELAY movlw FALL_EDGE_DELAY movwf countdown_timer ; load countdown timer with falling edge delay. #endif falling_edge_delay_loop ; insert ‘nop’s’ below this line to inc rease delay. #ifdef MS_DELAY ; option for millisecond delay call millisecond_delay #endif #ifndef MS_DELAY decfsz countdown_timer,1 ; Has countdown timer expired? goto falling_edge_delay_loop ; no, continue delay loop #endif bcf output_signal ; and drive pin low. #ifdef RISING_EDGE_DELAY bcf output_signal ; drive latch low bcf CLC1CON,LC1OE ; PORT -> pin #endif #ifndef RISING_EDGE_DELAY bsf CLC1CON,LC1OE ; CLC -> pin #endif wait_for_rising_edge btfss input_signal goto wait_for_rising_edge goto signal_high ;;;;;; end of main loop #ifdef MS_DELAY millisecond_delay movlw .250 ; 250 loops x 16 cycles per loop = 4000 Tcy = 1 ms movwf ms_timer millisecond_delay_loop nop nop nop nop nop nop nop nop nop nop nop nop nop decfsz ms_timer ; has countdown timer reached 0? goto millisecond_delay_loop; No. continue looping decfsz countdown_timer ; Do I need to have another millisecond delay? goto millisecond_delay ; Yes. retlw 0x00 ; No - done. #endif end