CT515 Counter-debouncher from Emesystems
Moskog
Posts: 556
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
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.
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!
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.
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!
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.
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.
Dave