I just realized that the US digital encoder outputs 0.4 - 2.4V. I need to interface that with a pin of a PIC, and thus convert it to 0 -5V. I believe I need a comparator at 1.4V to do that.
Are there some “1.4V comparators”, or do I need to use a generic comparator and provide 1.4V on one of its pins? In that case, what’s the best way to generate 1.4V (or close to that, it doesn’t need to be precisely 1.4V) given that I have a 5V source?
Is it common to use a voltage divider in that case? If so, I computed that I need two resistors R1 and R2 such that R1 = 2.6*R2. What value should I give to R1 and R2? I could go 1kOhm and 2.4 or 2.7kOhm to get something like 7mA current, or 1MOhm and 2.4 or 2.7MOhm and get a 7µA current… Which will work?
If the encoder outputs .4V for low, that is less than the Vin low max for the PIC at 0.8V. If it outputs 2.4V for a high, that is higher than the Vin high min for the PIC at 2V. (assuming a 5V supply to PIC)
What’s the problem with a few inches of copper between ?
The USD encoders are typically TTL; this sounds like what you are describing. Their output should be compatible with a PIC input directly.
Yes, a simple voltage divider is often used to feed a comparator input. Can be done off of the 5v supply, or use a zener diode, or a special reference chip. I believe some PICs (or is that ARM?) have a reference voltage output that you can use. But If you have a TTL encoder, you don’t need any of this.
1 to 10K is a good range of values for simple dividers. Use a little current, keep the noise out of the comparator. Sometimes pull-up resistors are needed on inputs for open-collector driving devices.
Yes I went to the USDigital site and looked at the spec. It says 2.4vdc is the minimum on voltage, but it does not list the max. It does say TTL compatible outputs, and it never mentions it as a 3v part. Doesn’t TTL consider greater than like 1.8vdc as a high. I don’t think you need any level shifting…
I’m planning to plug the signal of the encoder as a timer 0 or 1 of my pic18F6627, so that the ticks are automatically counted. Those pins are not TTL but Schmitt triggered with a max low voltage of 0.2 or 0.3V (which is unfortunately under the 0.4V of the low output of the encoder).
I was considering adding a XOR gate to use both signals of the encoder, but if not needed I think using only one signal will be enough… Maybe I can find a XOR gate that has TTL input pins? I searched a little but all the gates I find have wether a bad output for the PIC or a too high limit for high inputs…
Are you certain it is not 0.2 VDD, which would be 1V for a 5V part? Looking at data sheet ww1.microchip.com/downloads/en/D … 39646b.pdf page 393, parameter D031 indicates a maximum input low voltage for schmitt trigger inputs to be 0.2 VDD, and parameter D041 indicates a minimum input high voltage threshold of 0.8 VDD. Operating at VDD=5V it appears more like your problem will be meeting the CMOS level Vih threshold of 4V however you can possibly/probably use a pull-up to +5V on the output of the encoder to guarantee it meets that level. Alternatively any 74HCT series logic gate should be able to do the level translation for you if powered from 5V. I would still recommend the pull-up resistors since if you don’t have the encoder connected then you leave the CMOS inputs floating which is a no-no.
You might have a point there… I’m not sure I’m reading the data sheet correctly.
The pins I’ll use are T0CKI for timer 0 (let’s say for the left wheel) and T13CKI for timer 1 (let’s say for the right wheel). The parameters D034 and D044 indicate that the low value for T13CKI has to be lower than 0.3V (not 0.3VDD unless it’s a typo) and the high ones higher than 1.6V. I can’t find any information for T0CKI.
I’m unclear how you would use a pull up resistor on the output of the encoder to bring the 2.4V to at least 4V. Could you explain more in depth (I’m new to a lot of things in electronic, for example the fact that I shouldn’t leave floating input pins around…)
I am pretty sure that D044 specification is if you are using T1 in its oscillator mode with a 32KHz crystal, or that is how I would have interpreted it. Using it as a clock input it should be using the schmitt trigger input threshold value, but you are correct in questioning it because it isn’t very clear one way or the other. Perhaps an e-mail to their tech support or a post on the pic forum might find someone with direct hands on or an official answer.
I’ll hit the second part first, CMOS inputs are capacitive in nature and left unconnected will float to one rail or the other. The problem is the float is determined by parasitic leakage currents, usualy through the ESD protection diodes, and as an IC warms up the balance can gradually change. When this happens the input drifts through the undefined region between 0.8V and 2.0V which can cause the output to ocsillate and really drive up power consumption, which considering CMOS circuits are frequently used specifically for their low power consumption really defeats the point. Old 4000 series CMOS could actually be destroyed by transient electric fields as the input was literally the gate of a FET, however most modern CMOS has ESD protection diodes so you just get the temperature drift and oscillation issues. Typically you tie unused CMOS inputs to a supply rail either directly or using a resistor. Most microcontroller port pins however have a residual pull-up of a few hundred Kohms that makes this unneccessary.
Whether a pull-up resistor is able to solve the Vih level problem depends on a couple of factors, the foremost is going to be the previous question about Vil being 0.3V or 0.2VDD. If it turns out to be 0.2VDD then the next question is if the IC in the encoder is running at 3V or 5V. If it is 3V then you might need the buffer since you are trying to pull the output above its rail, but if it is 5V you should be able to use a pull-up resistor. Benerally speaking a high-side TTL output does not drive a high sourcing current, partly due to the output structure driving the top side transistor but also the transistor is also not saturated so it switches faster. So by adding a pull-up resistor you can “help” the transistor get closer to the rail. Be careful not to use so small a value as to exceed the sink capabilities of the output though or you will have problems pulling he output below the Vil threshold.
If it turns out that 0.3V IS the real Vil threshold for the T1 clock input then probably your best (simplest and smallest) bet will be a logic-level n-channel MOSFET such as a 2N7002 wired with pull-up resistors on the gate and drain. The MOSFET will switch below your 0.3V threshold if the drain pull-up resistor is not too small, and the gate pull-up serves the same purpose we are discussing of guaranteeing you will meet its turn on threshold of the transistor. You might be able to use an NPN such as a 2N3904 but you need to be real careful about currents if you are going to try and guarantee hitting 0.3V at the T1 clock input. Either way, as you are just counting pulses the logic inversion should not matter.
Not sure why you are using the count inputs, you can simply generate interrupts on the edges on the A & B signals, which gives you the information to count up/down yourself in the ISR.
Actually this quite a valid point/suggestion. Using the pin change interrupt you can even grab both phases and get not only counts but direction as well. This also feeds into your earlier thread where you were asking about the resolution of the encoders and why you would buy one with less resolution for the same price. I believe Jim’s answer was that the encoders supplied by Lynxmotion provided more than adequate resolution to do the job. If you need only 120cps to get 0.001" resolution then going to 240 or 480cps increases the hardware and software required to deal with the higher clock rates and count totals while your end result does not show any perceptible increase in performance for the effort involved. Just something to ponder as you work through your design details.
That is what I did on an Atmega32 chip interfacing to a couple of Nubotics WW-02 encoders. However I found my code was more reliable when I only generated interrupts on one of the signals and in the interrupt handler I would check the state of the other signal.
This is because if I have two encoders to read, I’ll have 4 channels and interrupts happening at 30kHz. The PIC works at 10 MIPS, so the interruption will fire every 333 instructions. Saving and restoring the context when entering/exiting the interruption function takes already more than 333 instructions…
Using the timers as counters, I can handle a theoretical 40MHz for each encoder without missing a single tick. The draw back is that the timers are incrementing only on a rising edge (or only on a falling edge, but not both), which means that I discard half of the information… But hey, we start with such a high precision that it’s an acceptable loss.
It’s also true that I can’t see the direction of the encoders. I could add a small memory component that takes the value of line B on every raising edge of line A (I know this kind of component exists, what are there name by the way?), but for now I’ll just considere that we know in the code the direction in which the wheels turn…
About the earlier thread about the precision of the encoders, I was assuming that interruptions aren’t used and that most counters could deal with frequencies way higher than the 15kHz the encoders are outputing. In that case, the solutions I could imagine (counters, or using the clocks as counters as I’m intending to do) could all handle frequency way higher than what the encoder outputs, so there is no real effort in hardware or software to handle a precision 3 times higher.
I was also considering discarding a forth of the information (just read one of the two channels and just count the rising edges). That was still enough for my application, but I was just wondering why not get the “better” encoders…
As I said in my previous post, I also tried using interrupts for both A and B signals and had problems making it work, especially since both wheels had encoders on them. I then had some luck with 1 interrupt, but relooking at my earlier code I ended up polling both and was able to get a reasonably accurate count as well as direction. I was not so concerned about seeing the edges as simply knowing the state of the lines had transitioned.
I am not proud of this code, but I believe it was working the last time I played with my SRS workshop robot. Here is the method I had that checked the state of a single encoder.
void ENCODER::CheckStates()
{
// We will do this as a psuedo state machine.
char bNewState;
// First the Left One...
RecheckState:
bNewState = 0;
switch (_bState)
{
case ENS_00_PBIAS: // Neither Channel High Positive bias.
if (_pinA->IsHigh())
{
// Channel A went high
_sTicks++;
_sDist += _sIncr;
bNewState = ENS_A;
}
else if (_pinB->IsHigh())
{
// Channel A went high
_sTicks++;
_sDist -= _sIncr;
bNewState = ENS_B;
}
break;
case ENS_00_NBIAS: // Neither Channel High Positive bias.
if (_pinB->IsHigh())
{
// Channel A went high
_sTicks++;
_sDist -= _sIncr;
bNewState = ENS_B;
}
else if (_pinA->IsHigh())
{
// Channel A went high
_sTicks++;
_sDist += _sIncr;
bNewState = ENS_A;
}
break;
case ENS_A: // A went high first wait for both to go to zero
if (!_pinA->IsHigh() && !_pinB->IsHigh())
bNewState = ENS_00_PBIAS;
break;
case ENS_B: // B went high first wait for both to go to zero
if (!_pinA->IsHigh() && !_pinB->IsHigh())
bNewState = ENS_00_NBIAS;
}
if (bNewState)
{
_bState = bNewState;
goto RecheckState;
}
}
This type of checking could easily be done on a timer. Not sure if this helps or not, but good Luck
Thank for your code Kurte… I think I’m still going to use the timers as counters to achieve what I want, just because it simplifies things on the PIC (I think your code has to be executed very frequently in order to make sure that we don’t miss a tick on the encoders and I’m not sure I can do that since I want to run other code on the PIC).
Anyways, the design I came up with is:
Use a comparator (I chose the TS374CN) to compare the 4 channels to 1.35V. I get this tension thanks to a tension divider (I divide 5V with a 2.7kOhm and a 1kOhm resistors). I know this might not be entirely necessary but it supposedly allows to have a clean signal after for the rest of the design…
Use a XOR gate (I chose the HCF4070B) to compute the xor value of the two channels for each encoder
Use a flip/flop (I chose the HCF4013B) to capture the value of channel B every time channel A turns high.
The outputs of the XOR gates go to the inputs of the timers of the PIC
The outputs of the flip flop go to 2 random free pins of the PIC
The code can read the value on the timers to know by how much the wheel turned and read the value on the pins of the PIC to know in which direction. With that and a little trigonometry, the position of the robot can be calculated.
Now for the questions
Does that sound a reasonnable thing to do? Am I missing something? (will I have problems using the different components I mentionned together…)
Where should I put some pull up resistors? Should I use them only on input pins? I’m using all the pins of the comparator, so that shouldn’t be an issue, but for the XOR gate, I’m using only 2 of the 4 gates (so there are 4 inputs and 2 outputs that aren’t used), and for the flip flop, I’m not reading two of the outputs (it outputs both the saved value and its opposite). Can I just put all the inputs to the ground and leave the unused outputs unconnected?
Have you tried using the two capture inputs? Most 16F PICs even have two capture inputs available and I believe all the 18F PICs have at least two. These are meant for exactly what you are doing, since PICs don’t have any quadrature encoder modules. Some dsPICs, like the 30F4011 and 30F4012, have quadrature encoder modules, which I am going to implement to read the QME-01 quadrature encoders I have for WALTER’s GHM-04 motors.
You are welcome. I am not sure of the power of the pic you are using to say how difficult it is… I was running the code on an atmel atmega32 for my SRS (Seattle Robotics Society) workshop robot. I put calls in at the beginning of each loop. In addition I had my own timer functions including things like WaitMS (Wait for a number of milliseconds), which wrapped the ATMEGA timer. In the wait functions I would also call out to the encoder code (which I registered with the timer class)…
Sounds like you have a plan. It has been a long time since I had to work with random flip flops and the like. I am no hardware designer and it has been a long long time since I had a hardware design class. But I wonder if your design would be the easiest to implement, or you could possibly use a second processor (pic or atmel), which does all of this work for you and communicates back to your chip by some standard protocol such as SPI, I2C, … Just a random though…
All the 4 capture inputs of my PIC are already used to read PWM from some Pings and some other sensors. Plus, I’m not convinced this is the best way to do it. The capture inputs don’t act as counter, their use is more to be able to know precisely the time when the signal became high, aren’t they? I don’t think it will require less computing power than having an interrupt on some pins.
A good part of the computing power of the PIC is used to generate by software some PWM to command some servos, so I don’t think I’ll be able to afford that
Let me know which PIC are you using, and I will check the datasheet. I think I have datasheets on all the commonly used PICs. I have not paid much attention to the capture inputs, so am not sure until I look at it more closely.
You could help your PIC out by using a dedicated servo controller, such as the SSC-32, for controlling your servos. You send standard ASCII text commands to the SSC-32 to tell it what to do, and can also use nifty features like time and speed to control group servo moves. You get a lot of very nice features with the SSC-32, and I would not want to do without those.
So if I don’t read the values fast enough, I’m still going to loose some data, which can’t happen if I’m using the timers to count the number of ticks.
Maybe you’re right that I should use an SSC32 (heck, I even already have one). But I find satisfying to understand the code that control the servos, and also to fully use the PIC. Plus I think the communication between two components always introduces problems. I’ll use an embedded PC for the “brain” of the robot and the PIC for the low level communication with the peripherals (like a reptilian brain that controls your heart and your breathing ), the communication between the two is one of the complex and not exciting to write parts