Shop OBEX P1 Docs P2 Docs Learn Events
BS2 counter divider — Parallax Forums

BS2 counter divider

New to forum.
Using BS2, because I have them, from many years ago.
Need to refresh my skills to use pics.

Looking for ideas on using BS2 to divide by 4 and divide by "N" up to 500 simultaneously.
I input and two outputs.
Needs to work from 10 to 1,000hz input from hall tach sensor on motor.

I have a program working with about 15 lines of code.
2 "pulsout,1"

Works to 1khz with either divider output, but only to a few 100hz with both outputs.
Misses counts.

Is there a better (faster) way than pulsout?

Intention is to migrate to pic when it's debugged.
Will a faster pic take care of problem?

Comments

  • 1. I believe PULSOUT is the fastest possible way to generate an output pulse on BS-2.

    2. BS-2x or p or whatever would be faster by up to a factor of maybe four or so.

    3. This sounds to me like a job for PROPELLORMAN. You could get an Activity board for $50 direct from the factory.
  • I'm surprised you can get it up to 1kHz even with just one of the divisors. On the vanilla BS2, this simple code,
    Main:
      PULSOUT 2,1
      GOTO Main
    
    Take 468 microseconds, 218 of that for the PULSOUT and 250 for the GOTO. Code to detect input edges and to execute something like x // N will stretch it out to around 2ms for the loop with no hope of catching edges at 0.5ms for 1kHz input. If you can use a divide by 4 logic chip as a prescaler ahead of the BS2, that just might give it enough time with edges at manageable 2ms intervals instead of .5ms.

    Are you using a vanilla BS2, or do you already have a BS2p? I agree with Tom, the Propeller can do this task easily. Also a Pic, if that is the way you want to go, as it is easily done in assembly language. The BASIC Stamp is relatively slow, because its PIC processor is executing an interpreter.
  • Thank you,

    Yes, I'm using plain BS2 from many years ago.

    Have other issues now getting my old epic pic equipment working.

    Also can't get my old win98 computer to find BS2 activity board.
    "no hrdw found"
    Everything works on dos computer, but hard to see. Even in monochrome.

    Serial port works with other dos programs.

    Have the hardware coming (from parallax) to start using my win7 desktop. A belkin usb to serial didn't work.

    All the same sw and hrdw from 15 years ago. Only my brain is different. :)
  • Have the project working in 555 and cmos logic.

    Changes are difficult in hrdw.
    Hope to migrate to a pic only, with sw changes as needed.

    Don't know asm. :(

    Epic will compile from BS2 if I figure it out again.
  • This works at 200hz.[img][/img][img][/img]DIVIDE2.BS2
  • InwoInwo Posts: 12
    edited 2015-12-31 21:25
    Looking for better way to post file..............
    Paste text???

    Did not have it commented, so I'll add a couple.


    Total var word


    wfp: 'waiting for pulse
    if in10 = 0 then plsout
    if in10 = 1 then wfp


    plsout:
    total = total + 1
    'debug dec total,cr 'slows program
    if total // 10 = 0 then plsout9 'divide by 10
    'if total // 4 = 0 then plsout8 'remark

    wfnp: 'waiting for next pulse
    if in10 = 1 then wfp
    goto wfnp

    plsout9:
    pulsout 9,1
    total = 0 ' zero total after divide by "N"
    goto wfnp

    plsout8:
    pulsout 8,1
    goto wfnp

  • Tracy AllenTracy Allen Posts: 6,664
    edited 2015-12-31 22:02
    Nicely done! Although as written if the total is a multiple of 20, it will give the pulse on p9 but not the /4 pulse on p8.

    I put together a non-modal snippet as follows.
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    
    N VAR WORD
    X VAR WORD
    y VAR BIT
    z VAR BIT
    
    DIR1=1
    DIR2=1
    DO
      y = IN0
      X = y ^ z + x     ' detect edges and add to X
      z =  y
      OUT1 = x.BIT1       ' square wave output at 1/4 the input frequency
      OUT2 = x // N MAX 1    ' low pulses at 1/N the input frequency
    LOOP
    
    This uses XOR logic to detect the edges, also logic that doesn't use pulsout to generate the outputs. Avoids a mix of GOTOs. It may work at 200Hz too, but certainly not at 1kHz.

    Are you using the most recent PBASIC 2.5 editor from Parallax?
  • tomcrawfordtomcrawford Posts: 1,129
    edited 2015-12-31 23:35
    Flippant comment deleted.
  • I have the new sw on this computer. Waiting for hrdw.
    My usb won't work.

    That was just my first attempt. I have no idea about speed and such.
    First I've attempted in 15 years.

    Not coming back easily.

    All my pic stuff is outdated. Can't get it to run on anything so far.
    Found an XP with a parallel port.

    Better I start over with something windows if I have to re-learn anyway.
  • This is a really non-critical application.

    All it does is send pulses to a tachometer and speedometer from electric vehicle.

    Motor hall effect gives 4PPR hence the divide by 4.
    Speedometer changes with gear ratio and tire size. Divide by "N".

    There are a few other things I may want it to do.
  • Here is a snippet for Propellor. It runs just fine at 4 kHz and uses 19 longs and one cog. The output waveform is a pretty close approximation of the input waveform (lags a few microseconds).
    
    CON
       _clkmode = xtal1 + pll16x    'Standard clock mode 
       _xinfreq = 5_000_000         '* crystal frequency = 80 MHz
    
       PulsIn = 1                   'input signal
       Out4 = 2                     'divide by four 
       OutN = 3                     'divide by n
       DivideN = 23                 'divisor      
            
    VAR
      word Count4, CountN
      
    PUB main
        dira[Out4]~~
        dira[OutN]~~
    
        repeat
          waitpeq(|<PulsIn, |<PulsIn, 0)    'input signal rises
          if (++Count4 == 4)                'count to four      
            outa[Out4]~~                    'output goes high if needful
            Count4 := 0                     'and counter is reset
    
          if (++CountN == DivideN)          'counts to n
            outa[OutN]~~
            CountN := 0  
            
          waitpeq(0, |<PulsIn, 0)            'input signal falls
          outa[Out4..OutN]~                  'assumes they are adjacent
           
    

    This would leave room for lots of "few other things I may want to do". -_-
  • Thank you,

    Couldn't get the xor to work BS2.
    Nor do I understand it.
    This divides by 4 and 10 when tested slow input.

    n var word
    x var word
    y var bit
    z var bit

    dir8=1
    dir9 =1

    loop:
    y = in10

    x = y ^ z + x

    z = y

    out8 = x // 8 max 1
    out9 = x // 20 max 1

    goto loop
  • Here is a snippet for Propellor. It runs just fine at 4 kHz and uses 19 longs and one cog. The output waveform is a pretty close approximation of the input waveform (lags a few microseconds).

    -_-

    Thank you.

    I'm looking for something that I can move to a pic.

    I've done that from stamp.
    How about if I get "into" propellor?

    Or should I jump right into pic?

    Either way, I'll have to learn a new language. :(

  • jmgjmg Posts: 15,175
    Inwo wrote: »
    I'm looking for something that I can move to a pic.

    I've done that from stamp.
    How about if I get "into" propellor?

    Or should I jump right into pic?
    Either way, I'll have to learn a new language. :(
    You will need to learn a new Microcontroller in all cases - the language is not so hard.

    If your PIC stuff is so old it no longer works, but you want a small MCU, (ie smaller than a Prop), I'd suggest moving to a more capable family like the SiLabs EFM8 series.

    Cheapest starting hardware there, is either TOOLSTICK850-B-SK (sub$10 for Debug+Device) or SLSTK2020A (sub $30, with LCD)
    and because this is a good teaching example, I took your specs, and here is the EFM8 code....
    Note the coded steps are very similar to the Spin above, but somewhat faster again as this is Assembler.
    At default /8 clock Sim says this can cope with 58.892kHz Tacho in, and with /1 it can do 471.142kHz
    (These parts have a 24.5MHz 2% on chip calibrated oscillator)
    ; EFM8BB1_Spartan_PollDiv.asm  - Smallest working file for Pin Poll and Divide EFM8BB1  TSim51 Example.
    ;
    ; Web Example: Someone wanted Tacho divider, of /4 and /N=500, Fin of 1kHz (500us edges)
    ; The venerable Basic Stamp manages just ~200Hz so too slow to be usable.
    ;
    ; With just 3+4 ASM lines of INIT, and 5+9 ASM lines of 3 Loop code, this tiny example works in 42 bytes.
    
    ; TSim51 Scope and Breadboard are used, Generator drives TachoIN, and Scope shows DivA.DivB results. 
    ;
    
    $DATE
    $TITLE ( EFM8BB1_Spartan_PollDiv )
    $NOPAGING
    $NOMOD51
    $INCLUDE (SI_EFM8BB1_Defs.inc)    ; Eval: SLSTK2020A   Smallest & cheapest device 31c/1k (!) for 2k model
    ; or
    ;$INCLUDE (SI_C8051F850_Defs.INC) ; Eval: TOOLSTICK850-B-SK 
    
    ; ~~~~~~~~~~~~~~ SLSTK2020A Eval Board mapping LED and Buttons ~~~~~~~~~~~~~~~~~
    
    UIF_LED2_Red_P16        BIT     P1.6 ; L=On
    UIF_LED1_Blue_P15       BIT     P1.5 ; L=On
    UIF_LED0_Green_P14      BIT     P1.4 ; L=On
    
    UIF_PB1                 BIT     P0.3 ; L=On
    UIF_PB0                 BIT     P0.2 ; L=On
    
    EFM_DISP_ENABLE         bit     P2.3 ; L=EFM8 off, BC on
    
            DSEG    at      20H
    BitAdrB0:        ds      1
    UserBit6        BIT     BitAdrB0.6
            DSEG    at      30H
    PrevP0:        ds      1
    
    ;CLK_24p5MHz     EQU     1  ;comment out for /8 SysCLK 3.0625MHz
    
    PinMask         EQU     0000_0100b  ; Choose a pin to poll  P0.2 Connect to 1kHz Gen in Breadboard.
    DivA_Val        EQU     04
    DivB_Val        EQU     500
    DivA_OutPin_P16 BIT     UIF_LED2_Red_P16
    DivB_OutPin_P15 BIT     UIF_LED1_Blue_P15
    
    
    ; ~~~~~~~~~~~~~~~~~~ CODE START ~~~~~~~~~~~~~~~~~~~~~~~~~~
            CSEG    at 0000h       ;Reset vector
    ;        AJMP    Init
    ; No interrupts in this Spartan101 example
    ;        ORG     7BH            ; may not be needed
    Init:
            MOV     WDTCN,#0DEh       ; Disable WDT !IMPORTANT! as defaults ON in this variant.
            MOV     WDTCN,#0ADh
    ; If remove this, WDTO occurs @ (1/80k)*4^(0x7+3) = 13.1072s  ~ 2 scope sweeps. Try it and see.
    ;
    ;       MOV     XBR0,#00000000b   ; XBR0: Port I/O Crossbar [SYSCKE CP1AE CP1E CP0AE CP0E SMB0E SPI0E URT0E] SFR Page = 0x0, 0x20; SFR Address: 0xE1
    ; No peripherals used
    IFDEF CLK_24p5MHz
            MOV     CLKSEL,#0 ;CLKSEL: Clock Select [DIVRDY CLKDIV2..0 - CLKSL2..0] Reset 10110000  SFR Page = ALL; SFR Address: 0xA9
    ENDIF
    ; Keep Default 24.5MHz /8 SysCLK , uncomment to speed x8
    
            MOV     XBR2,#01000000b    ; XBR2: Port I/O Crossbar [WEAKPUD XBARE - - - URT1CTSE URT1RTSE URT1E] SFR Page = 0x0, 0x20; SFR Address: 0xE3
    ;XBARE = Enable Port Connection, other bits low, No peripherals used, Weak Pullups enabled
    
    InitVARs:
    TestPath  EQU 01 
    
    IF TestPath
            MOV     A,#01           ; first path is all counters overflow, use for timing test, longest path.
            MOV     R7,A
            MOV     R6,A
            MOV     R5,A
    Else
            MOV     R7,#DivA_Val    ; Same as overflow init.
            MOV     R6,#LOW(DivB_Val)
            MOV     R5,#HIGH(DivB_Val)+1
    ENDIF
    PinPollLoop:
            MOV     A,P0            ; <<break here = Time Start Poll loop (eg 14 SysCLK)
            XCH     A,PrevP0        ; Save this sample, get last copy 
            XRL     A,PrevP0        ; Hi on any BITs <>
            ANL     A,#PinMask      ; get just the wanted bit
            JZ      PinPollLoop     ; Test for Change ?  Inner loop 11 SysCLKs
    ; Have a Pin Change
    ; Check Divider A  eg /4
            DJNZ    R7,ChkDivB      ; Divider A
    ;
            MOV     R7,#DivA_Val
            CPL     DivA_OutPin_P16 ; Toggles at /DivA_Val of IP toggle rate
    ChkDivB:  ; Check Divider B eg /500
            DJNZ    R6,ChkDivC
            DJNZ    R5,ChkDivC     ; 16b counter 
    ;
            MOV     R6,#LOW(DivB_Val)
            MOV     R5,#HIGH(DivB_Val)+1
            CPL     DivB_OutPin_P15   ; Toggles at /DivB_Val of IP toggle rate
    ChkDivC:  ;No more Div checks ? then reloop
            AJMP     PinPollLoop     ; << Break here end both Counters, eg 26 Clks 8.49us @ 3.0625MHz default low speed.
    
    Size_EFM8BB1_Spartan_PollDiv EQU  $-Init ; 0x2a = 42 bytes
    
    ; Tests fine at 1kHz, can push to 0.5/8.49u = 58892.81508 at default slow /8 clk )
    ; Test at 58.892kHz ? OK
    ; 471.142kHz count tracking capable at 24.5MHz full speed.
    
            END
    

  • Inwo wrote: »

    Thank you.

    I'm looking for something that I can move to a pic.

    If you plan to end up with pic, any detour (say, into propellorLand) seems unneedful.

  • Now that this thread has been highjacked, here is the same program in PASM. Attached is a logic analyzer capture showing operation at 1 MHz. The loop is 10 instructions; it always takes exactly 500 nsec plus wait time in the waitpeq instructions.

    I used the propellor itself as a pulse generator; had been using a 555 but it (the 555) wouldn't run much above 100 kHz.

    This exercise got me to understand just how cool waitpeq actually is. Without it, syncing up to an edge would take at least two instructions (three if you had to mask something off). With it, you just start executing instructions again at exactly the right time and with very little uncertainty.
    
    CON
       _clkmode = xtal1 + pll16x    'Standard clock mode 
       _xinfreq = 5_000_000         '* crystal frequency = 80 MHz
    
       PulsIn = 1                   'input signal
       Out4 = 2                     'divide by four 
       OutN = 3                     'divide by n
       DivideN = 23                 'divisor
    
    OBJ
      Freq : "Synth"
               
    VAR
      long MyPar[4]               'used to pass parameters
      byte cog                    'in case we need to stop the ccog
      
    PUB main
    
        Freq.Synth("A",5, 1_000_000)          'start up a sythesizer in this cog
                                              ' FrequencySynth v1.1    
                                              'page 4 of signals in OBEX
        MyPar[0] := DivideN                       'divisor
        MyPar[1] := 1 << PulsIn                   'mask corresponding to input
        MyPar[2] := 1 << Out4
        MyPar[3] := 1 << OutN 
        cog := cognew(@Mach, @MyPar)              'start the PASM cog
    
        repeat                 'forever
          waitcnt(clkfreq+cnt)
    
    dat                              'this is the machine cog
        org  0                       'begin at the beginning
    Mach mov  AdPar, Par             'get the parameter address
         rdlong divis, AdPar          'get the divisor
         add AdPar, #4                'to next parameter
         rdlong PulsInMsk, AdPar      'mask corresponding to input
         add AdPar, #4
         rdlong Out4Msk, AdPar
         add AdPar, #4
         rdlong OutNMsk, AdPar    
         mov  OutBMsk, OutNMsk
         or   outbMsk, Out4Msk       'and a mask for both outputs
         or   dira, OutBMsk          'make them outputs
         mov  Count4, #4             'initialize the counters 
         mov  CountN, divis
    
    Loop waitpeq PulsInMsk, PulsInMsk  'wait for positive edge
         sub Count4, #1 wz             'decrement and saee if done
         if_z or outa, Out4Msk         'generate the pulse
         if_z mov Count4, #4           'and re-initialize the counter
         sub CountN, #1 wz             'now the same for count by N
         if_z or outa, OutNMsk         'generate that pulse
         if_z mov CountN, divis
         waitpeq Zero, PulsInMsk     'wait for negative edge
         andn outa, OutBMsk          'terminate either or both
         jmp #Loop                   'forever
    
    Zero       long 0
    AdPar      res  1                 'address of parameter
    divis      res  1                 'divisor for outN
    PulsInMsk  res 1                  'mask for input pin
    Out4Msk    res 1                  'mask for output
    OutNMsk    res 1
    OutBMsk    res 1                  'mask for both outputs
    Count4     res 1                  'counts to four
    CountN     res 1                  'counts to N       
    
    
    1219 x 632 - 71K
  • Last time, migrating to pic from stamp was pretty easy, as I recall.

    Think I'll get some new equipment and give it a try.

    Thanks for all the suggestions.

  • Learned a lot studying this.
    I think I understand the XOR now. Detects both edges as I understand it?

    Also googled -do, still haven't found it in my BS2 book???

    I'll try again using a different bit "OUT1 = x.BIT1" for divide by 4.

    Slowly coming back to me.
    Got the new stamp hrdw, so I can run in windows now. :)



    Nicely done! Although as written if the total is a multiple of 20, it will give the pulse on p9 but not the /4 pulse on p8.

    I put together a non-modal snippet as follows.
    ' {$STAMP BS2}
    ' {$PBASIC 2.5}
    
    N VAR WORD
    X VAR WORD
    y VAR BIT
    z VAR BIT
    
    DIR1=1
    DIR2=1
    DO
      y = IN0
      X = y ^ z + x     ' detect edges and add to X
      z =  y
      OUT1 = x.BIT1       ' square wave output at 1/4 the input frequency
      OUT2 = x // N MAX 1    ' low pulses at 1/N the input frequency
    LOOP
    
    This uses XOR logic to detect the edges, also logic that doesn't use pulsout to generate the outputs. Avoids a mix of GOTOs. It may work at 200Hz too, but certainly not at 1kHz.

    Are you using the most recent PBASIC 2.5 editor from Parallax?

  • PublisonPublison Posts: 12,366
    edited 2016-01-03 16:57
    Inwo wrote: »

    Also googled -do, still haven't found it in my BS2 book???


    Look for DO...LOOP in the most recent manual:

    https://www.parallax.com/downloads/basic-stamp-manual
  • Thanks, my 15 yo stamp accepted it, but I didn't know what it was.

    Would have never thought of using logic and word bits, even though I've done a lot with ttl logic gates.
Sign In or Register to comment.