Shop OBEX P1 Docs P2 Docs Learn Events
CT515 Counter-debouncher from Emesystems — Parallax Forums

CT515 Counter-debouncher from Emesystems

MoskogMoskog Posts: 554
edited 2014-01-29 18:43 in General Discussion
Hi, while reading through Tracy Allen's environment-pages I found this chip for counting/debounching. This chip sounds very interesting for me who is frequently dealing with counters, anemometers, switches and other related devices. I understand it an handle up to five counters while occupying only one microcontroller pin. So, my question now is where can I get this chip, does emesystems still make and sell them and how much will I need to pay for a handfull of them? Does it exist a "getting started-code" i Spin for this chip?

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2013-07-06 12:05
    I suggest you contact Tracy directly. This looks like some kind of low power microcontroller with a custom program to do the counting/debouncing.
  • MoskogMoskog Posts: 554
    edited 2013-07-06 12:15
    I was thinking of doing that but thought this could be interesting for others too, maybe we'll be seeing him here soon!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2013-07-08 09:43
    Thanks for the mention and the heads'up!

    I developed that originally for a customer who needed to monitor flow meters with a BASIC Stamp, for irrigation. At the time the flow meters often had big reed relays with lots of bounce. We also wanted to throw in a rain gage and anemometer, both with reed relays too. Keeping track of multiple asynchronous bouncy inputs along with ADC and other tasks tasks along with micro-power is not a task well suited to the Stamp. The debounce circuits I saw commercially available did not quite fit the bill. Enter the CT515. As Mike surmised, it is an 8-pin PIC chip running my proprietary firmware, which is a state machine keyed to the wake-on-change interrupt. The interface is simple 9600 baud serial, TTL level. The Stamp (or Prop) brings the data pin low for 10 milliseconds, and when it releases that pin (open drain), the CT515 responds with a string of 12 bytes that includes the current state of each pin as well as the accumulated 16-bit count for each of the 5 channels, and then the counts are reset to zero. I've incorporated the CT515 in breakout boards for my OWL2pe data loggers ever since. Not on the Propeller boards though, because it can devote a cog to the same purpose. Even so, there would be good reasons to offload the task, to save pins or code space, or to provide a level of isolation.

    Originally the maximum input frequency was limited to 100Hz, but now that those big slow reed relays are a thing of the past, I field requests for flow meters that have higher resolution, clean hall effect or optical switches, and output up to 400 or 500 Hz.

    I do have the chip available as a separate item. Sorry, I don't have an shopping cart on line, but can take orders via email, and payment by paypal and by the usual means. The price page is here.
  • MoskogMoskog Posts: 554
    edited 2014-01-12 07:34
    I tried to make a spin file for the debouncher because the propeller project is running out of available pins. The project here is a davis anemometer and the spin file is suppose to wait for the $80 startbyte. The anemometer is hooked up between ct515-c4 and Vss and the whole thing build on a Propeller BOE using 3V and according to Tracy's ct515 datasheet.
    Program so far is as follows:
    CON
      _clkmode = xtal1 + pll16x        'Standard clock mode * crystal frequency = 80 MHz
      _xinfreq = 5_000_000                  
      RXp              = 0             
      BaudM         = 9600            
     
    VAR
      byte Startbyte, PinState, cwvL, cwvH, cwwL, cwwH, cwxL, cwxH, cwyL, cwyH, cwzL, cwzH 
      byte  Buffer [12], rxByte
      long  sin,  inverted, bitTime, bitTime2, rxOkay
      
    OBJ
      Timing        : "Timing.spin"
      VGA           : "VGA_Text"
    PUB   Initialize
      VGA.start(16)                                         ' Start the Debug on VGA screen
      VGA.out($01)
      init (RXp,BaudM)                                  ' Start serial driver
      Timing.Pause (200)
      Main
    PUB Main
      repeat
        outa[RXp]~ 
        Timing.Pause (10)                         '10ms
        Recieve
        Timing.Pause (3000)                       '3 s interval
        
    PUB Recieve | Index
      repeat until rxbyte == $80
        rx
        Buffer [0] := rxByte
      repeat Index from 1 to 11                  
        rx
        Buffer [index] := rxByte
      calculate
      Display_Values
       
    PUB init(rxPin, Baud): Okay
      'finalize                                              ' clean-up if restart
      rxOkay := rxPin > -1                                  ' receiving?
      sin := rxPin & $1F                                    ' set rx pin
      inverted := baud > 0                                  ' set inverted flag
      bitTime := clkfreq / ((||baud))
      return rxOkay 
    PUB finalize
                                          '   float tx pin
      rxOkay :=  false
         
    PUB rx |  t
    {{ Receive a byte; blocks caller until byte received. }}
     if rxOkay
       dira[sin]~                                           ' make rx pin an input
       waitpeq(inverted & |< sin, |< sin, 0)                ' wait for start bit
       t := cnt + bitTime >> 1                              ' sync + 1/2 bit  
       repeat 8
         waitcnt(t += bitTime)                              ' wait for middle of bit
         rxByte := ina[sin] << 7 | rxByte >> 1              ' sample bit      
       waitcnt(t+bitTime)                                   ' allow for stop bit  
       rxByte := (rxByte ^ inverted) & $FF                  ' adjust for mode and strip off high bits
     
    PUB calculate
       Startbyte := Buffer [0]                            
       PinState  := Buffer [1]                            
       cwvL      := Buffer [2]                             
       cwvH      := Buffer [3]                             
       cwwL      := Buffer [4]
       cwwH      := Buffer [5]
       cwxL      := Buffer [6]
       cwxH      := Buffer [7]
       cwyL      := Buffer [8]
       cwyH      := Buffer [9]
       cwyL      := Buffer [10]
       cwyH      := Buffer [11]
               
    PUB Display_values   | CWV, CWW, CWX, CWY, CWZ
        VGA.out($00)
        VGA.str(string("Result of ct515:",$0D))
        VGA.str(string($0D,"Startbyte : "))
        VGA.hex(Startbyte,2)
        VGA.str(string($0D,"Pinstate  : "))
        VGA.bin(Pinstate,6 )
        VGA.str(string($0D,"CWV       : ")) 
        CWV := cwvL + (cwvH * 256)
        VGA.dec(CWV)
        VGA.str(string($0D,"CWW       : ")) 
        CWV := cwwL + (cwwH * 256)
        VGA.dec(CWW)
        VGA.str(string($0D,"CWX       : ")) 
        CWV := cwxL + (cwxH * 256)
        VGA.dec(CWX)
        VGA.str(string($0D,"CWY       : ")) 
        CWV := cwyL + (cwyH * 256)
        VGA.dec(CWY)
        VGA.str(string($0D,"CWZ       : ")) 
        CWV := cwzL + (cwzH * 256)
        VGA.dec(CWZ)
    

    The program is supposed to be based on the BS2pe example in the datasheet, using the SPSTR formatter and wait for the $80 startbyte. But there is something wrong here,it doesn't seem to work like I wanted. And I'm too blind to be able to see the problem!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-01-12 13:10
    Hi Kjell,

    I like the resonance of the new word debounche/debaunche. That has panache, to wit, to eradicate a more serious rodent than a dull debounce!

    The thing that strikes me about the code is that the serial output of the CT515 is non-inverted, but in your Spin implementation of the serial input, I think you have it as inverted. I'm not sure, I'll have to take a closer look.

    The start edge should be a high to low transition.
    [SIZE=1][FONT=courier new]dira[sin]~                                           ' make rx pin an input
    baud := 9600
    inverted := baud > 0   ' this will be true, $ffffffff
      ' ...
    waitpeq(inverted & |< sin, |< sin, 0)  ' this will be waiting for start=1[/FONT][/SIZE]
    
  • MoskogMoskog Posts: 554
    edited 2014-01-14 04:47
    OK, Tracy, sorry about the bounching here, I didn't see that, hehe.
    Yes, the inverted was set to true, I corrected that and also found some errors in the calculate-pub, and then did a few changes to the receive-pub. Now it seems to work. I get the same output as in one of the debug-screens of your original basic stamp code. I still see things could have been done more smoothly but will correct that when integrating with the main project. Most important is that it works the way I want.

    Here is a scrennshot of the updated code:
    CON
      _clkmode = xtal1 + pll16x        'Standard clock mode * crystal frequency = 80 MHz
      _xinfreq = 5_000_000                  
      RXp              = 0             'Input pin from ct515
      BaudM         = 9600            
     
    VAR
      byte Startbyte, PinState, cwvL, cwvH, cwwL, cwwH, cwxL, cwxH, cwyL, cwyH, cwzL, cwzH 
      byte  Buffer [12], rxByte 
      long  sin,  inverted, bitTime, rxOkay
      
    OBJ
      Timing        : "Timing.spin"
      VGA           : "VGA_Text"
    PUB   Initialize
      VGA.start(16)                                ' Start the Debug on VGA screen
      VGA.out($01)
      init (RXp,BaudM)                             ' Start serial driver
      Timing.Pause (200)
      Main
    PUB Main
      repeat                                      'Main loop
        Recieve
        calculate
        Display_Values
        Timing.Pause (3000)                       '3 s interval
        
    PUB Recieve | Index
      repeat until rxByte == $80                  'Wait for ascii char 80 
        dira[sin]~~                               'Set input pin to Output
        outa[sin]~                                'Then to Low
        Timing.Pause (10)                         '10ms
        dira[sin]~                                'Set input pin to input
        rx                                        'Receive first byte
        Buffer [0] := rxByte                      'Put first byte into rxByte array
      repeat Index from 1 to 11                   'Continue with the other bytes and put them into the array
        rx
        Buffer [index] := rxByte  
       
    PUB init(rxPin, Baud): Okay
      rxOkay := rxPin > -1                                  ' receiving?
      sin := rxPin & $1F                                    ' set rx pin
      inverted := baud < 0                                  ' set inverted flag to be false
      bitTime := clkfreq / ((||baud))
      return rxOkay 
         
    PUB rx |  t
    {{ Receive a byte; blocks caller until byte received. }}
     if rxOkay
       dira[sin]~                                           ' make rx pin an input
       waitpeq(inverted & |< sin, |< sin, 0)                ' wait for start bit
       t := cnt + bitTime >> 1                              ' sync + 1/2 bit  
       repeat 8
         waitcnt(t += bitTime)                              ' wait for middle of bit
         rxByte := ina[sin] << 7 | rxByte >> 1              ' sample bit      
       waitcnt(t+bitTime)                                   ' allow for stop bit  
       rxByte := (rxByte ^ inverted) & $FF                  ' adjust for mode and strip off high bits
     
    PUB calculate                                           ' Load values into variables
       Startbyte := Buffer [0]                            
       PinState  := Buffer [1]                            
       cwvL      := Buffer [2]                             
       cwvH      := Buffer [3]                             
       cwwL      := Buffer [4]
       cwwH      := Buffer [5]
       cwxL      := Buffer [6]
       cwxH      := Buffer [7]
       cwyL      := Buffer [8]
       cwyH      := Buffer [9]
       cwzL      := Buffer [10]
       cwzH      := Buffer [11]
               
    PUB Display_values   | CWV, CWW, CWX, CWY, CWZ           'Display result on VGA screen
        VGA.out($00)
        VGA.str(string("Result of ct515:",$0D))
        VGA.str(string($0D,"Startbyte : "))
        VGA.hex(Startbyte,2)
        VGA.str(string($0D,"Pinstate  : "))
        VGA.bin(Pinstate,6 )
        VGA.str(string($0D,"CWV       : ")) 
        CWV := cwvL + (cwvH * 256)
        VGA.dec(CWV)
        VGA.str(string($0D,"CWW       : ")) 
        CWW := cwwL + (cwwH * 256)
        VGA.dec(CWW)
        VGA.str(string($0D,"CWX       : ")) 
        CWX := cwxL + (cwxH * 256)
        VGA.dec(CWX)
        VGA.str(string($0D,"CWY       : ")) 
        CWY := cwyL + (cwyH * 256)
        VGA.dec(CWY)
        VGA.str(string($0D,"CWZ       : ")) 
        CWZ := cwzL + (cwzH * 256)
        VGA.dec(CWZ)
    

    Thanks again!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-01-27 09:52
    I like that you wrote the RS232 routine written in Spin for this. I'm uncomfortable with the lack of timeouts though. The waitpxx commands will never time out in case the CT515 is disconnected. (chewed off by a reindeer perhaps?) Attached is a CT515 program that adds timeouts to the waitpxx commands, based on an auxiliary Prop pin, X_PIN, coupled to cog ctra.

    The first character in the response from the CT515 is an ascii $80. The program measures the width of that pulse (8 bit-times low) and uses it to autobaud the rest of the communication. (That way of implementing autobaud was expedient with the BASIC Stamp.) The PIC675 is set for a nominal baud rate of 9600. However, it is running on its RC clock. While temperature compensated, the TickTimer method tracks it for applications that might be out in extremes of temperature.
  • MoskogMoskog Posts: 554
    edited 2014-01-29 00:29
    Thanks for sharing this, I knew things could be done much better then my version, especially the timeout function will be very useful even though we have to spend another propeller-pin. Also a good lesson in using programming technics that can easily be transferred to other serial communication projects, I suppose.
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-01-29 07:39
    "The Art of Electronics, 2ed" mentions a commercial counter/debouncer chip. Not sure it is still available, but it seems to have targeted devices similar to what Tracy has. The idea is to adjust the count to what works.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-01-29 12:07
    Here is a nice article about debouncing by Jack Ganssle.

    I implemented the debounce algorithm on the PIC as a vertical counter. It operates in parallel on all 6 input pins, and the debounced signals are followed by the event counters for each channel. I think when I first started with this, I was looking at commercial hex debouncers like the MC14490. Or maybe it was a Maxim chip. But they didn't include the event counters, so doing it on a PIC with a unified serial interface to the Stamp made sense.

    I also have a version of the CT515 program that uses fullDuplexSerial4port. It measures the CT515 baud rate, which may come out slightly more or less than 9600, and uses that when it starts the ports. The RxTime(port, timeout) method subsequently takes care of the timeouts.
  • xanatosxanatos Posts: 1,120
    edited 2014-01-29 18:35
    Just chiming in here to say that the CT515 chips I got from you are all still running flawlessly in the field after all this time! Thanks again!

    Dave
  • LoopyBytelooseLoopyByteloose Posts: 12,537
    edited 2014-01-29 18:43
    Well the CT515 looks pretty good. Having multiple switch capability in one package in the only way to go as most instances require several switches to the uProcessor. ... five switch inputs is a good supply.
Sign In or Register to comment.