¿Cómo implementar el LED de estado en un sistema? [cerrado]

2

Esta pregunta está relacionada con la práctica general del sistema integrado de software. Quiero tener un led parpadeante como un led de estado para mi MCU.

¿Qué tan correcto es implementarlo con la interrupción del temporizador? Con eso dado la prioridad más baja.

¿Qué hay de usar un PWM con cierta frecuencia establecida? ¿Qué método puede tener ventajas sobre el otro?

¿Cuál es el método general que utilizan los ingenieros de la industria para mostrar el estado del sistema / unidad-mcu usando un led?

    
pregunta AmyM

2 respuestas

6

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
    
respondido por el Olin Lathrop
5

La ventaja de usar un periférico de hardware, como PWM o un temporizador, es que realiza parte del trabajo en hardware y libera a la MCU de tener que hacer el trabajo con las instrucciones.

La desventaja de usar un periférico de hardware para indicar el estado del software es que el periférico de hardware puede seguir funcionando después de que el software haya dejado de funcionar y luego el indicador de estado impulsado por hardware indicaría un estado engañoso.

Por ejemplo, después de configurar el PWM, un LED parpadeará sin intervención del software. Eso es bueno porque ahora el software puede ser más simple porque no necesita controlar el LED. Pero el periférico de hardware PWM continuará funcionando mientras se obtenga un reloj. No importa si el software se está ejecutando o se ha bloqueado. Por lo tanto, este LED controlado por PWM es un mal indicador de si el software se está ejecutando.

Al alternar el LED en una interrupción del temporizador de hardware, se simplifica el software porque el software no tiene que realizar un seguimiento del tiempo. Pero ahora el LED parpadeante solo indica si la interrupción del temporizador de hardware está funcionando. El bucle principal del software o una tarea podrían estar bloqueados, pero si la interrupción aún se está reparando, el LED continuará parpadeando. Por lo tanto, este LED controlado por interrupción no es un buen indicador de si el software se está ejecutando.

Si desea que el LED parpadeante sea como un latido que indica que el software se está ejecutando correctamente, debe controlar el flash LED desde el software. Y si tiene un sistema multitarea con múltiples tareas, entonces el software probablemente debería verificar el estado de cada tarea para determinar si el LED debe estar encendido.

He utilizado PWM o temporizadores de hardware para destellar los LED que indican las condiciones (como los umbrales de alarma), donde el parpadeo indica la presencia de la condición y el apagado indica la ausencia de la condición. El software aún determina la presencia o ausencia de la condición y pone el hardware en el modo correcto, pero luego el hardware controla el patrón de destello del LED mientras la condición está presente.

Considere usar un reinicio de vigilancia para no solo reiniciar el software en caso de una falla, sino también reiniciar los indicadores controlados por hardware.

    
respondido por el kkrambo

Lea otras preguntas en las etiquetas