Generalmente conduzco un LED de estado con varios patrones de parpadeo, dependiendo del estado del sistema. Cada patrón de parpadeo dura 1 segundo.
Para definir los patrones, rompo el intervalo de 1 segundo en segmentos de tiempo. Una máscara de bits en algún lugar define si el LED debe estar encendido o apagado para cada segmento de tiempo de cada patrón.
Esta no es una tarea crítica digna de usar interrupciones para. Mi módulo LED de estado estándar contiene una rutina que se puede llamar periódicamente. Mira el contador de tics actual de 1 ms y maneja todos los tiempos en consecuencia. Mientras esta rutina se llame a menudo en relación con los intervalos de tiempo de parpadeo, todo funciona a la perfección. Normalmente llamo a la rutina desde el bucle de eventos principal cuando no se procesaron otros eventos. En otras palabras, se trata de la prioridad más baja que hace el procesador. Eso es completamente opuesto a utilizar interrupciones.
Hago esto con la frecuencia suficiente para tener rutinas enlatadas para esto. En los procesadores dsPIC de Microchip, uso 48 cortes por patrón de parpadeo. Esto se debe a que las palabras de la memoria del programa tienen 24 bits de ancho, por lo que 48 bits provienen de usar dos palabras para definir cada patrón de parpadeo. Eso significa que cada rebanada tiene aproximadamente 21 ms de largo. El código enlatado utiliza tics ms completos por intervalo de tiempo, pero varía automáticamente entre 20 y 21 ms para mantener todo el patrón a 1 s a largo plazo.
Aquí está el código de plantilla para el módulo STAT en los procesadores dsPIC. Copias y renombras este módulo en tu proyecto. Las secuencias QQn se reemplazan con cadenas específicas del proyecto.
; ***************************************************************
; * Copyright (C) 2005, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; This module manages the status indicator LED.
;
; The status indicator LED is blinked with a pattern dependent on system
; status. This module determines the blink pattern from the system status,
; and performs the mechanics of blinking the LED accordingly.
;
; Exported routines:
;
; STAT_INIT
;
; Must be first call into this module.
;
; STAT_UPDATE
;
; Must be called periodically. It determines the system state, decides
; what pattern to display, tracks real time, and updates the LED
; accordingly. It is intended to be called from the main event loop as
; a low priority event.
;
; Configuration parameters:
;
; NAME
;
; Name of the /OUTBIT pin that controls the LED. Setting this line to ON
; is assumed to enable the LED, and OFF to disable it. The LED can be
; wired either way, as long as the polarity in the /OUTBIT command is set
; accordingly. The default is "ledstat".
;
; NSTBITS
;
; Number of bits in a pattern. The default is 48.
;
/include "qq2.ins.dspic"
;*******************************************************************************
;
; Configuration constants.
;
/const name string = "ledstat" ;name of output pin controlling the LED
/const nstbits integer = 48 ;number of slices in one-second display pattern
////////////////////////////////////////////////////////////////////////////////
//
// Macro PATTNUM
//
// Determine the number of the pattern to display. This macro leaves the 0-N
// pattern number in W0. W1-W3 may be trashed.
//
/macro pattnum
mov #0, w0
havepatt: ;W0 contains the 0-N number of the pattern to display
/endmac
//
////////////////////////////////////////////////////////////////////////////////
/include "(cog)src/dspic/stat.ins.dspic"
;*******************************************************************************
;
; Display patterns table.
;
; Each display pattern must be defined here. Patterns are defined
; sequentially starting with 0 at TBL_PATT.
;
; Each pattern is defined with the PATTERN macro. The parameter to this macro
; is a series of stars (*) or dashes (-). A star represents LED on, and a
; dash LED off. There must be exactly NSTBITS total characters in the
; pattern. Patterns are displayed in left to righ order as defined by the
; PATTERN macro parameter.
;
tbl_patt:
pattern ************************------------------------ ;0 - normal operation
.end
Este es el único código que requiere personalización. En general, solo necesita definir el nombre de la línea de salida que controla el LED, rellene el código que decide qué patrón mostrar dependiendo del estado del sistema y los patrones reales.
Tenga en cuenta el uso intensivo de mi preprocesador de ensamblador PIC. Por ejemplo, la macro PATRÓN utilizada en la parte inferior hace que la definición de patrones sea muy fácil. La macro genera las directivas .PWORD reales para definir los bits de patrón en la memoria del programa. Podría hacerlo directamente, pero la macro PATTERN proporciona una interfaz mucho más intuitiva para definir patrones de parpadeo.
Para completar, aquí está el código en el archivo de inclusión. Esto se trata como un archivo enlatado y no se modifica por aplicación:
; ***************************************************************
; * Copyright (C) 2005, Embed Inc (http://www.embedinc.com) *
; * *
; * Permission to copy this file is granted as long as this *
; * copyright notice is included in its entirety at the *
; * beginning of the file, whether the file is copied in whole *
; * or in part and regardless of whether other information is *
; * added to the copy. *
; * *
; * The contents of this file may be used in any way, *
; * commercial or otherwise. This file is provided "as is", *
; * and Embed Inc makes no claims of suitability for a *
; * particular purpose nor assumes any liability resulting from *
; * its use. *
; ***************************************************************
;
; Canned code for the STAT module. See the header comments in the
; QQQ_STAT.DSPIC file for a description of the possible configuration
; parameters.
;
;*******************************************************************************
;
; Configuration constants.
;
/if [not [exist "name"]] then
/const name string = "ledstat"
/endif
/if [not [exist "nstbits"]] then
/const nstbits integer = 48
/endif
;
; Derived constants.
;
/block
/var local ii integer
/var local r real
/var local s string
/const npattw integer = [div [+ nstbits 23] 24] ;N prog mem words per pattern
/set r [/ 1000 nstbits] ;ms ticks per display pattern slice
/const add1ms integer = [rnd [/ 65536 r]] ;accumulator increment per ms
/endblock
;*******************************************************************************
;
; Variables.
;
;*******************
;
; Global state.
;
.section .stat, bss
;*******************
;
; Local state.
;
alloc lastclock ;last 1 ms clock value updated to
alloc accslice ;overflows when time for next display slice
alloc slice ;0-N current display slice number
alloc pattn ;0-N number of pattern being displayed
.section .stat_code, code
;*******************************************************************************
;
; Subroutine STAT_INIT
;
; Initialize the hardware and software state managed by this module.
;
glbsub stat_init, regf0
mov tick1ms, w0
mov w0, lastclock ;init last clock value current with
mov #65535, w0
mov w0, accslice ;force slice update next STAT_UPDATE
mov w0, pattn ;init current pattern number to invalid
mov #[- nstbits 1], w0
mov w0, slice ;first update will start at start of pattern
leaverest
;*******************************************************************************
;
; Subroutine STAT_UPDATE
;
; This routine is intended to be called periodically by the main event loop.
; It determines the current system state, where it is within the current
; display pattern, and updates the display accordingly.
;
; Timing for the display is derived here from the global TICK1MS clock
; variable. This routine need not be called with any particular timing.
; Since elapsed time is detected in whole ms, calling it faster than that has
; no benefit, although it does no harm other than to take more excution
; cycles. Calling it less often than that will not cause time to be lost, but
; will cause the display to be updated in bursts so as to appear to "stutter"
; if too slow. Roughly calling this routine every 1 to 5 ms is recommended.
;
glbsub stat_update, regf0 | regf1 | regf2 | regf3
stupd_recheck: ;back here after a clock tick was processed
mov lastclock, w0 ;get last clock value updated to
mov tick1ms, w1 ;get the current clock
cp w0, w1
bra z, stupd_leave ;no new tick, nothing more to do ?
;
; A new clock tick has occurred.
;
add #1, w0 ;update last clock value we are now current with
mov w0, lastclock
mov accslice, w0 ;update slice time accumulator to this new tick
mov #[v add1ms], w1
add w0, w1, w0
mov w0, accslice
bra nc, stupd_recheck ;no new display slice this tick ?
;
; Advance to next display slice.
;
mov slice, w0 ;get the current 0-N slice number
add #1, w0 ;increment it
mov #[- nstbits 1], w1 ;get max slice number
cp w0, w1
skip_leu ;still within valid range ?
mov #0, w0 ;no, wrap back to 0
mov w0, slice
;
; The display will be updated.
;
; Determine the pattern to display.
;
pattnum ;set W0 to the 0-N number of pattern to display
;
; W0 contains the 0-N number of the pattern to display.
;
mov pattn, w1 ;get number of pattern currently displaying
mov w0, pattn ;update number of pattern to display now
cp w0, w1 ;compare new pattern to previous
bra z, stupd_hpatsl ;same pattern as last time ?
;
; The display pattern has changed. Reset to displaying the start of
; the pattern.
;
mov #0, w0
mov w0, slice ;set to first slice in pattern
mov w0, accslice ;set to start of this slice
stupd_hpatsl: ;PATTN and SLICE all set
;
; Update the display. PATTN is the number of the pattern to display, and
; SLICE is the 0-N slice to display within the pattern.
;
;
; Init W3:W2 to point to the start of the patterns table in program
; memory.
;
mov #tbloffset(tbl_patt), w2 ;init W3:W2 pointing to start of table
mov #tblpage(tbl_patt), w3
and #0xFF, w3
;
; Update W3:W2 to point to the start of the selected pattern.
;
mov pattn, w0 ;get 0-N pattern number
mov #[* npattw 2], w1 ;get program memory addresses per pattern
mul.uu w0, w1, w0 ;make address offset for start of pattern
add w2, w0, w2 ;make start address of this pattern
addc w3, w1, w3
;
; Skip over whole program memory words of the pattern to point W3:W2
; to the program memory word containing the bit to display.
;
mov slice, w0 ;get 0-N slice number within this pattern
stupd_pwslice: ;back here to skip whole prog mem words
cp w0, #24 ;compare to number of bits in a prog mem word
bra ltu, stupd_dpwslice ;done finding prog mem word of this slice ?
sub #24, w0 ;no, make 0-N number of bit within next word
add #2, w2 ;update address to next word
addc #0, w3
jump stupd_pwslice ;back to check slice within word again
stupd_dpwslice: ;W0 is 0-N bit within word at W3:W2
;
; W3:W2 is the address of the whole program memory word that contains
; the bit to display. W0 is the 0-23 number of the bit within that
; word.
;
mov w3, Tblpag ;set high bits of prog mem address to read from
cp w0, #16
bra geu, stupd_hword ;bit is in the high word ?
tblrdl [w2], w1 ;no, read the low word
jump stupd_hbits ;have bit pattern
stupd_hword: ;the bit is in the high word
tblrdh [w2], w1 ;read the high word
sub #16, w0 ;make bit number within this part of the word
stupd_hbits:
;
; W0 is the 0-N number of the bit within W1 to display.
;
lsr w1, w0, w1 ;move the selected bit into LSB of W1
btsc w1, #0 ;bit is off ?
jump stupd_don ;no, the bit is on
set_ledstat_off ;display off this slice
jump stupd_recheck
stupd_don: ;display on this slice
set_ledstat_on
jump stupd_recheck
stupd_leave:
leaverest
////////////////////////////////////////////////////////////////////////////////
//
// Macro PATTERN patt
//
// Create the table entry for one status display pattern. PATT must be a
// sequence of "*" and "-" characters. "*" lights the LED for that time slice
// and "-" makes it dark. There must be exactly NSTBITS characters in PATT.
//
// Patterns are displayed from left to right with a complete sequence lasting
// one second.
//
// This macro will emit .PWORD directives to define the data for the pattern
// in program memory.
//
/macro pattern
/var local patt string = [qstr [arg 1]] ;get the pattern string
/var local ind integer = 1 ;1-N index into pattern string
/var local pchar string ;single character extracted from PATT
/var local word integer ;current program memory word being built
/var local nbits integer ;number of bits set within program memory word
/var local ii integer ;scratch integer
/set nbits 0 ;init to no bits set in current word
/set word 16#FFFFFF ;init bits in current program memory word
/loop ;back here each new bit in the pattern
/if [> ind nstbits] then ;done all bits ?
/quit
/endif
/set pchar [sindx ind patt] ;get the pattern character for this bit
/set ind [+ ind 1] ;update PATT index for next time
/if [not [or [= pchar "*"] [= pchar "-"]]] then
/show 'Invalid character "' patt '" in display pattern'
.error "Patt char"
.end
/stop
/endif
/if [= pchar "-"] then ;set this bit to off ?
/set ii [shiftl 1 nbits] ;make mask for this bit within word
/set ii [~ ii] ;make AND mask for turning off this bit
/set word [and word ii] ;apply the mask to turn off this bit within word
/endif
/set nbits [+ nbits 1] ;count one more bit done in current word
/if [>= nbits 24] then ;have a whole word to write out ?
.pword 0x[chars [int word "fw 6 lz base 16 usin"]]
/set nbits 0 ;reset to start of new word
/set word 16#FFFFFF ;reset word to all bits on
/endif
/endloop ;back to do next input pattern bit
/if [> nbits 0] then ;there are unwritten bits in WORD ?
.pword 0x[chars [int word "fw 6 lz base 16 usin"]]
/endif
/endmac