Monitoring a button and a tachometer at the same time

What I'm trying to do is automatically feed a metal rod into a bench grinder at maximum burn rate without stalling the grinder. I've been experimenting using a linear actuator controlled by a manual potentiometer, and I want to switch to controlling it with a button on an Arduino.

I want to use an optical tachometer to determine the speed of the grinder to tell if it's slowing down excessively/about to stall. I was going to use an IR reflectivity sensor to do so, with some black tape on the grinding wheel to change the reflectivity. It outputs high if black and low if not black or vice versa, I'm not sure.

Then I want to use a button to control a linear actuator. The linear actuator in question can be controlled with a voltage, with 5 volts being full extension and 0 volts being full contraction. I can use an analog out to do this. I'll reduce the voltage if the tachometer reports a stall coming on, and increase it if it's going too quickly.

individually, these seem simple enough, with tutorials for the former and the latter being straightforward. What I'm worried about is whether an Arduino can monitor a button and an optical tachometer at the same time; the button tutorial constantly loops to monitor a button. But then it seems I need to use attachInterrupt() to monitor the RPM which seems like it will prevent reading the button outputs. Is there any way to make this work?

These two programs will actually integrate splendidly. Ideally the button and the tach would each have their own interrupts, but its not necessary here.

You can poll the button continuously in the main loop, and whenever the tach changes it will cause an interrupt that will deal with the tach and then get back to the button. The interrupt handling happens very quickly, so the button's functionality will be almost entirely unaffected by the addition of the tach.

Another thing to remember is that analog outs are actually a pulsed signal and not a true analog value. If you need a real analog voltage you can use a capacitor and resistor to filter the PWM down to near DC or use an external DAC.

Good to know about the analog outputs. I can use PWM instead, the actuators support it. The coding is near-identical, I believe. Thanks

You should be able to easily do both. The interrupt just adds one to a counter.

I have some frequency counter sketches here:

For a fast response just measure the time between two consecutive pulses (using micros() ). The difference is the period, and the inverse of that is the frequency (which you convert to RPM).

Even without conversion you could measure that it takes (say) 50 mS to measure one pulse. Then if it takes 60 mS clearly the wheel is slowing down.

Meanwhile you can be testing the switch status.

Yes, okay, that helps a lot. Thanks.

It occurs to me that the linear actuator feeds too quickly by default, so increasing from 4 to 5 volts moves it 5 mm/s which is way too much. What I'll have to do is increase the voltage by 1 step every X microseconds so the actuator is on some of the time and off some of the time, and modify X depending on the speed of the grinder. I guess I just do another micros() check for that as well, so I'll be using the same timer for the interrupts and the actuator feed. As long as X is fairly large it too shouldn't interfere with the operation of the other two timers. Right?

Is there any way to control the duty cycle of PWM more finely than in 255 steps?

Yes, timer 1 is a 16-bit timer and thus you potentially have 65535 steps. However there is a trade-off between resolution and frequency.

As an example, if you count up to 65535 (per cycle) then you can have PWM on/off duty cycles anywhere between 0 and 65535. However 16 MHz / 65535 gives a frequency of 244 Hz. The lower the number you count up to the higher the frequency, but then you have lower PWM resolution.

If I'm reading this correctly, it's not possible to get a 1 kHz PWM on timer 1. Is this correct? The linear actuator I'm using requires a 1 kHz signal and then uses the duty cycle to determine location.

Sure you can.

Count up to 2000 with a prescaler of 8.

Then your duty cycle can be anywhere between 0 and 1999.

Awesome, thank you very much.

Looking at I've run into a bit of trouble trying to get this PWM working.

TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20); TCCR2B = _BV(WGM22) | _BV(CS22); OCR2A = 180; OCR2B = 50;

The writing doesn't match the code. It looks like CS is set to 22, not 100, and COM2A and COM2B are set to 1, not 10, and WGM is set to 1 and 0 separately. Also I'm unclear on what _BV means.

I need help adapting it. I'm trying to set up timer 1 to count to 2000 with a prescaler of 8 in fast PWM mode, as posted above.

I appreciate your help.

None of that is for Timer 1. That would be TCCR1A etc.

I figured out that part, the rest is the problematic part.

This is close:

_BV(x) means "bit x" where x is going to be 0, 1, 2, 3, 4, 5, 6, 7 in the byte.



Sets bit COM2A0 in the byte TCCR2A.

Oh, does _BV make that bit a 1 with 0’s placed elsewhere?

If you assign like that, yes. Usually people "or" in extra bits, eg.

TCCR2A = _BV(COM2A0) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);

I think I'm almost there with

    TCCR1A = _BV(COM1A1) | _BV(WGM13) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10) | _BV(CS11);
   TCCR1B = _BV(COM1A1) | _BV(WGM13) | _BV(WGM12) | _BV(WGM11) | _BV(WGM10) | _BV(CS11);
    OCR1A = 0;
   OCR1B = 0;

But should OCR1A/B be 2000 or 0? I want the compare to be initially 0 (0 duty cycle) while counting up to 2000. If those should be 0, how do I get the 2000 count thing going?

Don't make TCCR1A and TCCR1B identical. They do different things, refer to the datasheet.

OCR1A is the number it counts up to (eg. 2000). OCR1B is the duty cycle. (eg. 1000 would be a 50% duty cycle).

I see what you're saying about TCCR1A/B now. Oh... I can only use output B for PWM then. I would need to switch to using a Mega to run 2+ outputs.