May 17, 2024, 02:48:58 AM

News:

Got VSA?  Want to use your Prop-SX?  Now you can!  See the VSA section of the Library forum for Prop-SX code that works with VSA.


SX Timer/Stopwatch

Started by chuck, July 22, 2008, 04:16:35 AM

Previous topic - Next topic

chuck

As an add-on to the BMX Random Gate controller in the Prop-1 forum, I would like to include a timer/stopwatch. The timer starts when the gate drops and stops whaen the cyclist rides over a floor switch, the time would be displayed an a LCD and would remian for several seconds. The time would need to show seconds/10th's and 100th's and would only need to go to a maximum of 10 seconds.

If someone could direct my reading to appropriate documents so I can have a go I would be greatful.

JonnyMac

If you download the SX-Key IDE (programming software for the SX) you'll see that the help file includes a simple stopwatch example.  In your case the timing elements of the interrupt would need to support serial communications as well since you're using a AP-8 to do the audio annunciation and a serial LCD to display lane timing.  This means that your interrupt needs to be running a timer VP as well as two transmit UART VPs.

This is not trivial stuff.  Over the next couple days I'll start folding some code together to show you how it's done.
Jon McPhalen
EFX-TEK Hollywood Office

chuck

Thanks Jon, I'll start reading at once

JonnyMac

July 22, 2008, 10:19:01 AM #3 Last Edit: July 22, 2008, 10:24:42 AM by JonnyMac
I like to start my day with a bit of a programming exercise to wake my brain (with an assist from Starbucks, of course).  So... to demonstrate that what you're getting into isn't trivial, I've knocked up this framework that supports simultaneous transmit on two pins (AP-8 and LCD) and maintains a high-resolution timer that can go from zero to 255.9999 seconds.  I think most of the support functions are there, the rest would be the body (we'll work on that when you actually have a Prop-SX in hand).

In case you're wondering, no, I didn't write this from scratch -- I do a lot of Prop-SX programming and had most of the bits on hand (only the timer part is new, and I've done that before).  I ran the program through the SX simulator to check for any timing issues; as I expected, everything is fine.


' =========================================================================
'
'   File...... BMX_Stopwatch.SXB
'   Purpose...
'   Author.... Jon Williams, EFX-TEK
'              Copyright (c) 2008 EFX-TEK
'              Some Rights Reserved
'              -- see http://creativecommons.org/licenses/by/3.0/
'   E-mail.... jwilliams@efx-tek.com
'   Started...
'   Updated... 22 JUL 2008
'
' =========================================================================


' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Conditional Compilation Symbols
' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

DEVICE          SX28, OSCXT2, TURBO, STACKX, OPTIONX, BOR42
FREQ            50_000_000
ID              "BMXTimer"


' -------------------------------------------------------------------------
' I/O Pins
' -------------------------------------------------------------------------

TX2             PIN     RC.7 OUTPUT             ' P15 for LCD
TX1             PIN     RC.6 OUTPUT             ' P14 for AP-8


' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

' Bit dividers for 3.255 uS interrupt
' -- interrupt actually runs at 3.333 uS for timing precision

Baud2400        CON     128
Baud4800        CON     64
Baud9600        CON     32
Baud19K2        CON     16
Baud38K4        CON     8

Baud1x0a        CON     Baud38K4                ' 1 bit period (ISR counts)
Baud1x5a        CON     Baud1x0a * 3 / 2        ' 1.5 bit periods

Baud1x0b        CON     Baud19K2
Baud1x5b        CON     Baud1x0a * 3 / 2


Yes             CON     1
No              CON     0


' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

flags           VAR     Byte
isrFlag        VAR     flags.0                 ' isr has started
tmrRun         VAR     flags.1                 ' to enable/disable timer

tmpB1           VAR     Byte                    ' for subs/funcs
tmpB2           VAR     Byte
tmpW1           VAR     Word
tmpW2           VAR     Word


tx1Serial       VAR     Byte (16)               ' tx1 serial data (AP-8)
tx1Buf         VAR     tx1Serial(0)            ' eight-byte buffer
tx1Count       VAR     tx1Serial( 8 )          ' tx1 bit count
tx1Divide      VAR     tx1Serial(9)            ' bit divisor timer
tx1Lo          VAR     tx1Serial(10)           ' holds start bit
tx1Hi          VAR     tx1Serial(11)           ' tx1 output reg
tx1Head        VAR     tx1Serial(12)           ' buffer head (write to)
tx1Tail        VAR     tx1Serial(13)           ' buffer tail (read from)
tx1BufCnt      VAR     tx1Serial(14)           ' # bytes in buffer

tx2Serial       VAR     Byte (16)               ' tx2 serial data (LCD)
tx2Buf         VAR     tx2Serial(0)            ' eight-byte buffer
tx2Count       VAR     tx2Serial( 8 )          ' tx2 bit count
tx2Divide      VAR     tx2Serial(9)            ' bit divisor timer
tx2Lo          VAR     tx2Serial(10)           ' holds start bit
tx2Hi          VAR     tx2Serial(11)           ' tx2 output reg
tx2Head        VAR     tx2Serial(12)           ' buffer head (write to)
tx2Tail        VAR     tx2Serial(13)           ' buffer tail (read from)
tx2BufCnt      VAR     tx2Serial(14)           ' # bytes in buffer

hrTimer         VAR     Byte (5)
tix            VAR     hrTimer(0)
tmr100us       VAR     hrTimer(1)
tmr1ms_LSB     VAR     hrTimer(2)
tmr1ms_MSB     VAR     hrTimer(3)
tmrSecs        VAR     hrTimer(4)

rider1          VAR     Byte(3)
r1ms_LSB       VAR     rider1(0)
r1ms_MSB       VAR     rider1(1)
r1Secs         VAR     rider1(2)

rider2          VAR     Byte(3)
r2ms_LSB       VAR     rider2(0)
r2ms_MSB       VAR     rider2(1)
r2Secs         VAR     rider2(2)

rider3          VAR     Byte(3)
r3ms_LSB       VAR     rider3(0)
r3ms_MSB       VAR     rider3(1)
r3Secs         VAR     rider3(2)

rider4          VAR     Byte(3)
r4ms_LSB       VAR     rider4(0)
r4ms_MSB       VAR     rider4(1)
r4Secs         VAR     rider4(2)


' =========================================================================
  INTERRUPT NOCODE 300_000                      ' 3.333 uS
' =========================================================================

Mark_ISR:
  \ BANK  flags                                 ' (1)
  \ SETB  isrFlag                               ' (1)


' --------------
' TX UART - AP-8
' --------------
'
Transmit1:
  ASM
    BANK  tx1Serial                             ' (1)
    TEST  tx1Count                              ' (1)   transmitting now?
    JZ    TX1_Buffer                            ' (2/4) if tx1Count = 0, no
    DEC   tx1Divide                             ' (1)   update bit timer
    JNZ   TX1_Done                              ' (2/4) time for new bit?
    MOV   tx1Divide, #Baud1x0a                  ' (2)   yes, reload timer
    STC                                         ' (1)   set for stop bit
    RR    tx1Hi                                 ' (1)   rotate TX1 buf
    RR    tx1Lo                                 ' (1)
    DEC   tx1Count                              ' (1)   update the bit count
    MOVB  TX1, tx1Lo.6                          ' (4)   output the bit
    JMP   TX1_Done                              ' (3)

TX1_Buffer:
    TEST  tx1BufCnt                             ' (1)   anything in buffer?
    JZ    TX1_Done                              ' (2/4) exit if empty
    MOV   W, #tx1Buf                            ' (2)   point to buffer tail
    ADD   W, tx1Tail                            ' (1)
    MOV   FSR, W                                ' (1)
    MOV   tx1Hi, IND                            ' (2)   move byte to TX1 reg
    CLR   tx1Lo                                 ' (1)   clear for start bit
    MOV   tx1Count, #10                         ' (2)   start + 8 + 1 stop
    INC   tx1Tail                               ' (1)   update tail pointer
    CLRB  tx1Tail.3                             ' (1)   keep 0..7
    DEC   tx1BufCnt                             ' (1)   update buffer count

TX1_Done:
    BANK  $00                                   ' (1)
  ENDASM


' -------------
' TX UART - LCD
' -------------
'
Transmit2:
  ASM
    BANK  tx2Serial                             ' (1)
    TEST  tx2Count                              ' (1)   transmitting now?
    JZ    TX2_Buffer                            ' (2/4) if tx2Count = 0, no
    DEC   tx2Divide                             ' (1)   update bit timer
    JNZ   TX2_Done                              ' (2/4) time for new bit?
    MOV   tx2Divide, #Baud1x0b                  ' (2)   yes, reload timer
    STC                                         ' (1)   set for stop bit
    RR    tx2Hi                                 ' (1)   rotate TX2 buf
    RR    tx2Lo                                 ' (1)
    DEC   tx2Count                              ' (1)   update the bit count
    MOVB  TX2, tx2Lo.6                          ' (4)   output the bit
    JMP   TX2_Done                              ' (3)

TX2_Buffer:
    TEST  tx2BufCnt                             ' (1)   anything in buffer?
    JZ    TX2_Done                              ' (2/4) exit if empty
    MOV   W, #tx2Buf                            ' (2)   point to buffer tail
    ADD   W, tx2Tail                            ' (1)
    MOV   FSR, W                                ' (1)
    MOV   tx2Hi, IND                            ' (2)   move byte to TX2 reg
    CLR   tx2Lo                                 ' (1)   clear for start bit
    MOV   tx2Count, #10                         ' (2)   start + 8 + 1 stop
    INC   tx2Tail                               ' (1)   update tail pointer
    CLRB  tx2Tail.3                             ' (1)   keep 0..7
    DEC   tx2BufCnt                             ' (1)   update buffer count

TX2_Done:
    BANK  $00                                   ' (1)
  ENDASM


' -----
' Timer
' -----
'
HR_Timer:
  ASM
    JNB   tmrRun, Timer_Exit                    ' (2/4) abort if disabled
    BANK  hrTimer                               ' (1)
    INC   tix                                   ' (1)
    CJB   tix, #30, Timer_Exit                  ' (4/6) 100 us?
    CLR   tix                                   ' (1)   yes, clear tix
    INC   tmr100us                              ' (1)   and increment
    CJB   tmr100us, #10, Timer_Exit             ' (4/6) 1 ms?
    CLR   tmr100us                              ' (1)
    INC   tmr1ms_LSB                            ' (1)
    ADDB  tmr1ms_MSB, Z                         ' (2)
    CJNE  tmr1ms_LSB, #$E8, Timer_Exit          ' (4/6) 1 second?
    CJNE  tmr1ms_MSB, #$03, Timer_Exit          ' (4/6)
    CLR   tmr1ms_LSB                            ' (1)
    CLR   tmr1ms_MSB                            ' (1)
    INC   tmrSecs                               ' (1)

Timer_Exit:
    BANK  $00                                   ' (1)
  ENDASM


  RETURNINT


' =========================================================================
  PROGRAM Start
' =========================================================================


' -------------------------------------------------------------------------
' Subroutine / Function Declarations
' -------------------------------------------------------------------------

DELAY_MS        SUB     1, 2                    ' replaces PAUSE
RANDOMIZE       FUNC    2, 1, 2                 ' replaces RANDOM

TX1_BYTE        SUB     1                       ' transmit byte on TX1
TX1_STR         SUB     2                       ' transmit string on TX1

TX2_BYTE        SUB     1
TX2_STR         SUB     2


' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  PLP_A = %0000
  PLP_B = %00000000
  PLP_C = %00000000


Main:

  GOTO Main


' -------------------------------------------------------------------------
' Subroutine / Function Code
' -------------------------------------------------------------------------

' Use: DELAY_MS duration
' -- replaces PAUSE
' -- assumes 3.333 uS interrupt rate

SUB DELAY_MS
  IF __PARAMCNT = 1 THEN
    tmpW1 = __PARAM1
  ELSE
    tmpW1 = __WPARAM12
  ENDIF
  DO WHILE tmpW1 > 0
    tmpW2 = 300
    DO WHILE tmpW2 > 0
      \ CLRB isrFlag
      \ JNB  isrFlag, $
      DEC tmpW2
    LOOP
    DEC tmpW1
  LOOP
  ENDSUB

' -------------------------------------------------------------------------

' Use: result = RANDOMIZE value
' -- replaces RANDOM

FUNC RANDOMIZE
  IF __PARAMCNT = 1 THEN
    tmpW1 = __PARAM1
    RANDOM tmpW1_LSB                            ' use byte algorithm
  ELSE
    tmpW1 = __WPARAM12                          ' use word algorithm
    RANDOM tmpW1
  ENDIF
  RETURN tmpW1
  ENDFUNC

' -------------------------------------------------------------------------

' Use: TX1_BYTE aByte
' -- moves "aByte" to 8-byte circular buffer (when space is available)
' -- will wait if buffer is presently full
' -- tx1BufCnt holds byte count of transmit buffer ( 0 to 8 )

SUB TX1_BYTE
  ASM
    BANK  tx1Serial                             ' point to tx vars
    JB    tx1BufCnt.3, $                        ' prevent buffer overrun
    MOV   W, #tx1Buf                            ' point to buffer head
    ADD   W, tx1Head
    MOV   FSR, W
    MOV   IND, __PARAM1                         ' move byte to tx buf
    INC   tx1Head                               ' update head pointer
    CLRB  tx1Head.3                             ' keep 0..7
    INC   tx1BufCnt                             ' update buffer count
    BANK  $00
  ENDASM
  ENDSUB

' -------------------------------------------------------------------------

' Use: TX1_STR [String | Label]
' -- pass embedded string or DATA label

SUB TX1_STR
  tmpW1 = __WPARAM12                            ' get offset/base

  DO
    READINC tmpW1, tmpB1                        ' read a character
    IF tmpB1 = 0 THEN EXIT                      ' if 0, string complete
    TX1_BYTE tmpB1                              ' send the byte
  LOOP
  ENDSUB

' -------------------------------------------------------------------------

' Use: TX2_BYTE aByte
' -- moves "aByte" to 8-byte circular buffer (when space is available)
' -- will wait if buffer is presently full
' -- tx2BufCnt holds byte count of transmit buffer ( 0 to 8 )

SUB TX2_BYTE
  ASM
    BANK  tx2Serial                             ' point to tx vars
    JB    tx2BufCnt.3, $                        ' prevent buffer overrun
    MOV   W, #tx2Buf                            ' point to buffer head
    ADD   W, tx2Head
    MOV   FSR, W
    MOV   IND, __PARAM1                         ' move byte to tx buf
    INC   tx2Head                               ' update head pointer
    CLRB  tx2Head.3                             ' keep 0..7
    INC   tx2BufCnt                             ' update buffer count
    BANK  $00
  ENDASM
  ENDSUB

' -------------------------------------------------------------------------

' Use: TX2_STR [String | Label]
' -- pass embedded string or DATA label

SUB TX2_STR
  tmpW1 = __WPARAM12                            ' get offset/base

  DO
    READINC tmpW1, tmpB1                        ' read a character
    IF tmpB1 = 0 THEN EXIT                      ' if 0, string complete
    TX2_BYTE tmpB1                              ' send the byte
  LOOP
  ENDSUB

' -------------------------------------------------------------------------


' -------------------------------------------------------------------------


' -------------------------------------------------------------------------
' User Data
' -------------------------------------------------------------------------
Jon McPhalen
EFX-TEK Hollywood Office

chuck

I have had a go at amending the help file timer code to what I would like, I know there are lines of code relating to a 7-segment LED but is this on the right lines.

' =========================================================================
'
' File...... STOPWATCH.SXB
' Purpose... Digital Stopwatch
' Author.... (c) Parallax, Inc. -- All Rights Reserved
' E-mail....
' Started...
' Updated... 05 JUL 2006
'
' =========================================================================
' -------------------------------------------------------------------------
' Program Description
' -------------------------------------------------------------------------
'
' Displays running timer on LCD display.

' -------------------------------------------------------------------------
' Device Settings
' -------------------------------------------------------------------------

      
FREQ       4_000_000
ID       "STOPWATCH"

' -------------------------------------------------------------------------
' IO Pins
' -------------------------------------------------------------------------

TmrMode    PIN    RC.6          ' mode: 0 = mmss, 1 = hhmm
TmrEnable    PIN    RC.7          ' enable input, 1 = run

' -------------------------------------------------------------------------
' Constants
' -------------------------------------------------------------------------

Yes       CON    1
No       CON    0
MaxDigit    CON    4          ' 4-digit display
DecPnt       CON    %10000000       ' decimal point mask
TmrSSTH    CON    1          ' show MM.SS (no blink)
TmrRun       CON    1          ' run timer
TmrHold    CON    0          ' hold timer
MaxSecs      CON    10          ' counts upto 10 seconds
                  

' -------------------------------------------------------------------------
' Variables
' -------------------------------------------------------------------------

ms       VAR    Word          ' milliseconds
clock       VAR    Byte(3)       ' clock array
hundths      VAR    clock(0)       ' hundredth's
tenths       VAR    clock(1)       ' tenth's
secs       VAR    clock(2)      ' seconds
blink       VAR    secs.0          ' DP blink control bit
display    VAR    Byte(MaxDigit)       ' multiplexed segments
digPntr    VAR    Byte          ' digit pointer
tmpB1       VAR    Byte
tmpB2       VAR    Byte

' -------------------------------------------------------------------------
INTERRUPT 1000
' -------------------------------------------------------------------------

' The ISR is called every millisecond using the Rate parameter of the
' INTERRUPT instruction. With a 4 MHz clock, the prescaler will be set
' 1:16 and the ISR will run every 250 RTCC cycles.
'
' If the timer is enabled (TmrEnable pin = 1), the timer values will be
' updated every millisecond, otherwise only the display will be refreshed
' (one digit per interrupt).

ISR_Start:
  IF TmrEnable = TmrHold THEN Next_Digit    ' skip clock update if 0
Update_Timer:
  INC ms ' update ms counter
  IF ms = 10 THEN             ' check for 1 second
    ms = 0
    INC hundths
    IF hundths = 10 THEN          ' check for new minute
      hundths = 0
      INC tenths
      IF tenths = 10 THEN          ' check for new hour
        tenths = 0
        INC secs
        IF secs = MaxSecs THEN
          secs = 0
        ENDIF
      ENDIF
    ENDIF
  ENDIF

Next_Digit:
  INC digPntr                ' point to next digit
  IF digPntr = MaxDigit THEN '          check pointer
    digPntr = 0             ' wrap if needed
   ENDIF

Update_Segs:
  Segs = %00000000             ' blank segments
  READ DigMap + digPntr, DigCtrl       ' update digit control
  Segs = display(digPntr)          ' output new segments

ISR_Exit:
  RETURNINT

' =========================================================================
PROGRAM Start
' =========================================================================

' -------------------------------------------------------------------------
' Subroutine Declarations
' -------------------------------------------------------------------------

CLOCK_SSTH    SUB    0          ' show secs, tenths & hnds

' -------------------------------------------------------------------------
' Program Code
' -------------------------------------------------------------------------

Start:
  DigCtrl = %1111             ' disable all digits
  TRIS_A = %0000             ' make dig pins outputs
  Segs = %00000000             ' clear seg drivers
  TRIS_B = %00000000             ' make seg pins outputs
  PLP_C = %11000000             ' pull-up unused pins

Main:
  DO
    PAUSE 50
      CLOCK_SSTH
  LOOP

' -------------------------------------------------------------------------
' Subroutine Code
' -------------------------------------------------------------------------

' Display timer in SS.TH (00.00 .. 10.99) format with solid DP

SUB CLOCK_SSTH                ' display mins & secs
  tmpB1 = mins / 10             ' get 10's digit
  tmpB2 = __REMAINDER             ' save 1's digit
  READ SegMap + tmpB1, display(3)
  READ SegMap + tmpB2, display(2)
  display(2) = display(2) | DecPnt       ' add DP to hr01 digit
  tmpB1 = secs / 10
  tmpB2 = __REMAINDER
  READ SegMap + tmpB1, display(1)
  READ SegMap + tmpB2, display(0)
ENDSUB

' -------------------------------------------------------------------------


' =========================================================================
' User Data
' =========================================================================

chuck

You beat me to it  ::) How come my paste segments are never neat  :-[

JonnyMac

If you're serious about SX coding, and you seem to be, let me encourage you to buy a Parallax Professional Development Board (PDB).  It is the best money you'll ever spend on microcontroller development (supports SX28 [what we use in the Prop-SX] and BASIC Stamps [what we use in the Prop-1 and Prop-2]).  It will make all the difference in the world when you can actually test your code changes; this, in fact, is the best way to learn.
Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Here's what I do to paste code with neat formatting (so you can read it):

1 -- copy program into an editor (EditPlus) that will convert tabs to spaces
2 -- strip off any dangling spaces (also a feature in my editor
3 -- in the forums I click on the font button and change the name to Courier New
4 -- paste the code between the tags
Jon McPhalen
EFX-TEK Hollywood Office

chuck

Gotta agree, as the saying goes 'you'll never learn to play the piano by reading a book'  ;D I'll see if I can get PDB over here. I can't get a Prop-SX yet as the Dutch are on holiday and, typically European, they have about 6 weeks off! I'll also plow my way through your posting and see if I can make sense of it. Cheers Jon

JonnyMac

Parallax has a disti in the UK, or our friends at Antratek might be able to help you out. 
Jon McPhalen
EFX-TEK Hollywood Office