NXT Frequency counter

Sometimes it’s nice to know the frequency of something. You can use an oscilloscope or digital frequency meter (or many other pieces of test equipment), but I don’t have any such equipment that works for the ranges I want.

I decided to try to make an NXT based counter. The NXT ADCs are only read at about 330Hz, and that is far too slow for what I want. I considered trying something with IO’s 5 and or 6, but then realized there was already a solution implemented in the NXT.

I thought, why not use the encoder inputs? When the NXT motors are running at 160 RPM the encoder states are changing at a rate of RPM / seconds per minute * Counts per rotation * two (it counts once per 2 changes of states), or 160 / 60 * 360 * 2 which equals 1920 Hz of change. 1920Hz isn’t really all that impressive, but I figured that the NXT must be able to handle at least a little more than what I know works fine with the motors. I also remembered having heard about someone using a higher resolution encoder without issues. I came to the conclusion, that even if I can only measure 2k Hz, it would be worth a try. Besides, I can make a factor of ten divider very easily with a 4017 (for much higher frequencies).

Okay, so enough thought, lets get this thing into reality! I needed to convert pulses into quadrature type signals. A full quadrature cycle consists of 4 states as follows:
00
10
11
01

So obviously I needed to divide the input by 4, to have 4 states. A 4017 is an awesome IC for dividing and counting. By default it counts from 0 – 9 (or divides by up to 10). What’s really cool though, is that it has a reset pin that you can tie to one of the outputs so that it doesn’t count as far before restarting. If I tie the reset pin (15) to output 4 (of 0-9), it divides the input by 4 (as soon as it reaches out 4, it resets to output 0). At this point I have it output on one of 4 pins, changing with every pulse. Now, I just need to convert that into a quadrature style output. With just 4 diodes (plus 2 pulldown resistors), I get the quadrature signals I need.

See the schematic for details.

Here is a picture of the circuit with LEDs to indicate the logic states of the signal wires:

The red wire is the input, and the NXT socket connects to an NXT motor port.

It changes quadrature states every pulse on the input line. The NXT adds to the encoder count every two quadrature state changes. This is really no big deal, I just need to multiply the result by two.

Here is the core of the NXC program.

LastTick=CurrentTick();
ResetTachoCount(OUT_A);
until(CurrentTick()>=LastTick+TimeFrame);
Frequency=MotorTachoCount(OUT_A);
Frequency*=2;

That code resets the “TachoCount” and then waits until “TimeFrame” number of ms have gone by. It then sets “Frequency” to the TachoCount. To get the result in Hz, TimeFrame should be 1000. However, the “Frequency” variable will take a whole second to get updated. What I prefer to do is set TimeFrame to 100 (1/10th of a second), and then multiply by 10 to get Hz (though with lower resolution).

Here is the complete program I currently use.

char LoopClip(char in, char min, char max){
  return in<min? max : in>max? min : in;
}

unsigned long LastTick;

long Frequency;
long TimeFrame=100;
char TimeFramePos=2;

string SRawFrequency;

string FrequencySuffix[]={
"   /ms",
"  /cs",
" /ds",
"/Sec"
};

string SFrequency;

task main(){
  SetLongAbort(true);
  while(true){
    LastTick=CurrentTick();
    ResetTachoCount(OUT_A);
    until(CurrentTick()>=LastTick+TimeFrame){
      if(ButtonPressed(BTNCENTER, false)||ButtonPressed(BTNEXIT, false))goto Buttons;
    }
    Frequency=MotorTachoCount(OUT_A);

    Frequency*=2;

    SRawFrequency = NumToStr(Frequency) + FrequencySuffix[TimeFramePos];

    repeat(TimeFramePos*(-1)+3){Frequency*=10;}
    repeat(TimeFramePos-3){Frequency/=10;}
    
    SFrequency = NumToStr(Frequency) + " Hz";
    
    ClearScreen();
    TextOut(0, LCD_LINE1, SFrequency);
    TextOut(0, LCD_LINE2, SRawFrequency);
    
    Buttons:
    if(ButtonPressed(BTNCENTER, false)||ButtonPressed(BTNEXIT, false)){
      if(ButtonPressed(BTNCENTER, false))TimeFramePos--;
      if(ButtonPressed(BTNEXIT, false))TimeFramePos++;
      until(!ButtonPressed(BTNCENTER, false)&&!ButtonPressed(BTNEXIT, false));
      TimeFramePos=LoopClip(TimeFramePos, 0, 3);
      TimeFrame=1;
      repeat(TimeFramePos){
        TimeFrame*=10;
      }
    }
  }
}

Ideas for future additions that will improve functionality:
– Make the program start at the beginning of the current CurrentTick for the until statement to be more stable.
– Add a round function to round the last several frequency measurements.
– Add a Schmitt trigger on the input for noisy signals.
– Add one or more 4017s to divide by 10 for much higher frequencies. Maybe also add a 8574 or 20X2 so the NXT can select the range.

Here is something interesting I found that I was actually very surprised by. The NXT registers up to a max of about 44kHz! I would say it’s fine up to at least 40kHz. After that it seems sorta unstable, and at ~44kHz it goes crazy. That is good to know for the frequency counter.

This limit should also be really nice to know for using other encoders on the motor ports. With an actual encoder, I don’t know if it would loose counts badly once it gets up into the 40,000s, but I would think that at least 15 – 30kHz encoders should be fine. This is really good to know, because that means you should be able to use a PF motor with a 4096 position encoder (even a PF M-motor). You could get incredible resolution (even at high speeds).

Advertisements
This entry was posted in Electronics, Mindstorms, NXT and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s