Measuring RPM´s and displaying in analog tachometer?

Hello community members!

I have one project that requires to measure RPM´s using a Hall sensor and displaying it in an analog tachometer.

RPM´s will be measured using interruptions, and the tachometer will be driven using the "tone" library, which is very easy to use.

These are the two parts of the code but......As I´ll be using interruptions, I can see a conflict with the PWM required output for the "tone" function. It´s always said that if you use interruptions, timers are fully dedicated to that and that no PWM pin will work correctly.

I am correct? I there any possiblity to make it work?

Best regards

Which MCU will you be using?

For instance, if you used a ESP32 measuring RPM's can be done as a background task and PWM, another background task.

Other MCU's will use different techniques to do the thing. So how the thing will be done is dependent upon the MCU that will be used.

I think you are misinterpreting something you have read. There is no such restriction on most common types of Arduino because interrupt circuits and timer circuits are independent parts of the MCU chip.

On most Arduino it is possible to use one of the timers as a counter to count interrupts so that the CPU is not occupied with that task. But for measuring the RPM of most internal combustion engines that is not necessary because the RPM is likely to be less than 10,000. For other types of machines with RPM higher than 50,000, using a timer as a counter can be useful to keep the CPU free for other tasks.

Hi,
This is my code for reading a hall sensor and showing the output.

/*
*
*	Author : Zedric
*
*/
// Timer Counter 1 Prescaler is set to F_CPU 16 / 8 = 2 ticks per microsecond
uint16_t TIME {39999}; // ticks / 2 * TIME = 20 milliseconds
uint16_t MIN {};
uint16_t MAX {1023};
uint16_t MIN_2 {1805}; // Minimum On Time in microseconds = ticks / 2 = 0.903 milliseconds
uint16_t MAX_2 {4193}; // Maximum On Time in microseconds = ticks / 2 = 2.096 milliseconds
uint16_t rpm {};
const uint32_t tu {60000000}; // 1 Minute in microseconds
// Volatiles for use in Interupt Routine
volatile bool x {false};
volatile uint32_t t1 {};
volatile uint32_t t2 {};

uint16_t remap(long x, long in_min, long in_max, long out_min, long out_max);

ISR (INT0_vect)
{
    t2 = t1;
    t1 = micros();
    x = true;
}

void setup()
{
    DDRB |= (1 << PORTB5) | (1 << PORTB2);
    //AVcc Ref
    ADMUX = (1 << REFS0);
    // ADC Enabeld, ADC Start Conversion, ADC Auto Trigger, ADC Prescaler / 128
    ADCSRA = (1 << ADEN) | (1 << ADSC) | (1 << ADATE) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
    // Digital Input Disabled 
    DIDR0 = (1 << ADC0D);
    // Clear all Timer Counter 1 registers
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1 = 0;
    // OCR1A is TOP in Mode (15)
    OCR1A = TIME;
    // Initialise OCR1B at lowest running value
    OCR1B = MIN_2;
    // Clear OCR1B on Compare Match, set OCR1B at BOTTOM
    TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10);
    // Mode (15) Fast PWM & Clk/8
    TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
    // Rising edge generates Interupt
    EICRA = (1 << ISC01) | (1 << ISC00);
    // External Interrupt Request 0 Enable
    EIMSK = (1 << INT0);
    sei();
    Serial.begin(115200);
}

void loop()
{
    OCR1B = remap(ADC, MIN, MAX, MIN_2, MAX_2);
    // x will only be TRUE if there has been an Interrupt
    if (x)
    {
        x = false;
        rpm = tu / (t1 - t2);
        PINB |=  (1 << 5);
        Serial.println(rpm);
    }
}
// Remap is the same as Arduino Map function except returns uint16_t
uint16_t remap(long x, long in_min, long in_max, long out_min, long out_max)
{
    return out_min + (x - in_min) * (out_max - out_min) / (in_max - in_min);
}

Using interrupts not "interruptions" is essential to critical timing events and should be favoured above all other options. Using "delay" should be avoided at all cost.
If you need any clarification, please let me know.

Same thing dude?

@diegusvv
I have only just joined this forum so forgive me if I stuff up!
All I can tell you from my own experience is that Arduino teaches laziness when it comes to C++,
you will notice that I used a function "Prototype" as well as the function "Header and Body",
In Arduino the "Prototype" is not needed as the IDE will generate it for you.
Don't get me wrong, I love the Arduino platform and it is fantastic for beginners but my advice is to study the Atmel 328p data sheet and learn what this little chip has to offer.
Manipulating the registers manually will give you a lot more options with less memory usage.
The inbuilt Arduino functions are a bit of a hit and miss when it comes to memory usage, they tend to favour all usage scenarios and that sometimes leads to excessive memory loading.
I like to make my own libraries for the most common peripherals, ie, TWI ,UART and so on.

@diegusvv , Sorry mate, I forgot to say that my code in post #4 mostly outputs a servo pulse to drive a brushless ESC from a HDD and I have 2 magnets on the disk to activate the Hall sensor.
The timer 1 is set up for that purpose and the ADC registers are set up for a potentiometer to control the RPM's, the actual reading of the hall sensor is the least amount of code.
Any way, you can look at my code and study the data sheet and I'm sure you'll work it out.

Cheers,
Chris.

Unless I'm missing something, I don't believe the use of interrupts is necessary for this application. Since the smoothed? RPM value is being displayed on an analog tachometer and an error of less than 1% would quite difficult to notice, I suggest using millis() or micros() for timing of the RPM pulse period to get your raw data. This should be more than accurate enough and also non-blocking to the rest of your code.

You can easily do it that way, I think what the OP asked should be easily doable.
As PaulRB stated in post #3, interrupts and timers are independent.
So, reading a pin and using the Tone library shouldn't be a problem.
The Tone library uses Timer 2 if outputting a single tone.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.