PCM Diagnostics & Tuning HP Tuners | Holley | Diablo

Adruino RPM

Thread Tools
 
Search this Thread
 
Old Dec 31, 2018 | 10:40 AM
  #1  
MaroonMonsterLS1's Avatar
Thread Starter
TECH Junkie
10 Year Member
Liked
Loved
Community Favorite
 
Joined: Dec 2012
Posts: 3,618
Likes: 1,328
From: Iowa
Default Adruino RPM

Hi Everybody,

I've been following along with this thread https://ls1tech.com/forums/automatic...ontroller.html
and It's pretty cool and figured it might get some attention here. it's not my thread, i just really like the project. Seeing that project do SO much...I'm hoping I can handle something a little more simple.

I'm looking for some help with getting a steady RPM input from the LS (411 pcm if it makes a difference) to the arduino. I've considered using the coil 1 trigger wire with a "PulseIn()" function, and some smoothing, but I was hoping someone here has already done a project like this and they have a working schematic and code that they would be willing to share!

This is my first big venture with arduino so I'll take all the help and advice I can get!!

Thanks
Reply
Old Dec 31, 2018 | 12:47 PM
  #2  
JoeNova's Avatar
Restricted User
 
Joined: Mar 2014
Posts: 7,192
Likes: 109
From: Ohio
Default

You can use the ground from the coil to the PCM, it works OK.
Can also use the wire from the PCM to the tach.

I don't use pulseIn to often. Too many weird issues. I typically use an interrupt that's triggered by a ground (like the coil wire).
This is a rough code I just borrowed from the arduino website and modified it to work in your case, but it won't be exact since I'm at work (Do the CODE tags work here)?
I use a VERY similar code to measure RPM on my small go-kart engine dyno.

Code:
 unsigned long timeold;

 void setup()
 {
   Serial.begin(115200);
   pinMode(2,INPUT_PULLUP);
   attachInterrupt(0, rpm_fun, FALLING);
   revolutions = 0;
   rpm = 0;
   timeold = 0;
 }

 void loop()
 {
   if (revolutions >= 5) {
     rpm = 60*1000000/((micros() - timeold)*revolutions);
     timeold = micros();
     revolutions = 0;
     Serial.println(rpm,DEC);
   }
 }

 void rpm_fun()
 {
  revolutions++;
 }
In a nutshell:

Code is setup for an arduino nano. Interrupt 0 is pin 2 on the Nano.
Basically, the pullup on pin 2 sets it to 5v, so its always high.
You attach an interrupt to that pin that triggers when its FALLING (when it gets grounded).
The interrupt add 1 to the revolutions variable. (The point of the interrupt is that it will function outside main loop, completely independent).
When the revolutions variable gets up to 5 revolutions, it tallies up the total amount of microseconds it took for those 5 revolutions, and divides 60,000,000 microseconds (1 minute) by that number to get RPM.
Then it resets the micro counter and the revolutions variable and waits for the next 5 counts.

I use CHEAP Nanos. I get the cheapest 10-pack I can from ebay or amazon probably once a month.
Reply
Old Dec 31, 2018 | 12:59 PM
  #3  
JoeNova's Avatar
Restricted User
 
Joined: Mar 2014
Posts: 7,192
Likes: 109
From: Ohio
Default

Sorry, I screwed up the rpm code there with the parenthesis.
Try this instead:
Code:
rpm = revolutions * 60000000/(micros() - timeold);
You can increase or decrease the number in the "if (revolutions >= 5)" to fine tune it.
A higher number will give a better RPM resolution, a lower number will output the RPM variable more often.
Reply
Old Dec 31, 2018 | 01:12 PM
  #4  
JoeNova's Avatar
Restricted User
 
Joined: Mar 2014
Posts: 7,192
Likes: 109
From: Ohio
Default

DAMNIT I WISH I COULD EDIT POSTS. ITS BEEN OVER 2 YEARS LS1TECH.

That little tidbit there about increasing RPM resolution doesn't really apply to this code. Using micros() instead of the typical millis() allows you to get single RPM resolution, which wouldn't happen with millis().
Here, you will want to use the lowest revolution count that will still allow your code to function properly.
Once you add a ton of stuff inside of the loop(), the amount of time it takes for the loop to run might scew your RPM readings, so you'll need to raise the number of revolutions before RPM is calculated.
If I use this exact code on my small engine dyno with the FULL coding that calculated SAE correction, load cell readings, wideband readings, and outputs a graph through serial data, "if (revolutions >= 2)" only allows me to read RPM up to 1800 before it begins to throw off the readings. "if (revolutions >= 5)" lets me have 4500 or so RPM.

But with this code alone, you can change it to "if (revolutions >= 1)", forcing an output every revolution and it will be fine.
Reply
Old Dec 31, 2018 | 02:19 PM
  #5  
MaroonMonsterLS1's Avatar
Thread Starter
TECH Junkie
10 Year Member
Liked
Loved
Community Favorite
 
Joined: Dec 2012
Posts: 3,618
Likes: 1,328
From: Iowa
Default

Thanks very much Joe!!
I had actually found some old posts of yours and tried to send you a PM but couldn't. I'm glad you commented!

Will this interrupt method be able to constantly run outside of the main loop? So I can always know what's going on with RPM regardless of where the loop is?
I'm trying to do some very basic nitrous control and I have most of my loop setup to use the RPM/TPS etc as allowable windows...but I would like the rpm to be able to be constantly calculated and used in the main loop. So that at any time if the RPM goes outside of the pre-set window, it can interject and kill the output.
Reply
Old Dec 31, 2018 | 02:48 PM
  #6  
JoeNova's Avatar
Restricted User
 
Joined: Mar 2014
Posts: 7,192
Likes: 109
From: Ohio
Default

Yes, it'll always run in the background. Its called an interrupt because it will still trigger right in the middle of a loop, so do your RPM calculations FIRST in the loop before anything else that way they'll always be calculated without error.
Reply
Old Jan 1, 2019 | 12:55 PM
  #7  
NSFW's Avatar
TECH Fanatic
5 Year Member
Liked
Loved
Community Favorite
 
Joined: Jan 2018
Posts: 1,060
Likes: 198
Default

I used a little bit different approach in a VVT controller for my Subaru, where code in the interrupt handler calculates the elapsed time between interrupts, and calculates RPM from that:

newRpmValue = TicksPerMinute / elapsedTimeInTicks;

I'm not currently using any smoothing, but I was going to use this approach:

UpdateRollingAverage(&Rpm, newRpmValue, 0.5f);

https://github.com/LegacyNsfw/AvcsCo...llingAverage.h

The basic idea is to use a global variable to hold the smoothed RPM value, and call UpdateRollingAverage with the new raw (unsmoothed) value, and UpdateRollingAverage basically moves the smoothed value closer to the raw value. The "weight" value determines how much weight is given to the new value. With a weight of 1.0, there is no smoothing, with a weight of 0.1, the smoothed value moves 10% of the way toward the new value. For now it's actually working just fine without any smoothing (weights are all 1.0) but I that might only work because VVT is disabled at idle (which is where RPM is the most erratic). I'm going to try to keep it active at idle some day, but I haven't actually tested that yet.

Some of my interrupts were being triggered by noise (which I assume came from the actual sparks), so I ended up using short loops in the interrupt handlers to make sure the pin state change interrupt was caused by an actual sensor signal rather than just spark noise. That's in the getPinState function here:

https://github.com/LegacyNsfw/AvcsCo...ptHandlers.cpp

In the beginning I tried the keep the code in the interrupt handlers as trivial as possible, but then someone reminded me that interrupt time isn't nearly as precious on an Arduino as it is in, say, Windows. The CPU in my project spends the vast majority of its time spinning in the main loop evaluating variables that haven't even changed since the last iteration, so there's really no harm done by using interrupt time to do useful work. The only important thing is that the interrupt handlers don't run long enough to compete with each other.
Reply
Old Jan 1, 2019 | 07:27 PM
  #8  
JoeNova's Avatar
Restricted User
 
Joined: Mar 2014
Posts: 7,192
Likes: 109
From: Ohio
Default

I had noise from the magneto ignition on the dyno triggering the interrupts, which is why I used the pullup resistor to keep the pin high and triggering the interrupt when grounding.

I then put a double check in the interrupt loop to make sure that the pin was still low before increasing the counter.

Zero interference now.
Reply
LS1 Tech Stories

The Best V8 Stories One Small Block at Time

story-0

Topdon ONE vs. Artidiag 800 BT2: Which is the Diagnostic Tablet For You?

 Pouria Savadkouei
story-1

Gas Monkey Built a 6-Wheel Ferrari Testarossa With a Corvette LT4 Engine

 Verdad Gallardo
story-2

7 Most Reliable High-Performance Engines GM Has Ever Built

 Verdad Gallardo
story-3

Amazing '71 Camaro Restomod Is Modern Muscle Car Under the Skin

 Verdad Gallardo
story-4

6 Common C5 Corvette Failures and What's Involved In Repairing Them

 Pouria Savadkouei
story-5

Retro Modern Bandit Pontiac Trans AM Comes With Burt Reynolds' Autograph

 Verdad Gallardo
story-6

Top 10 Greatest Cadillac V Series Performance Models Ever, Ranked

 Pouria Savadkouei
story-7

Top 10 Most Powerful Chevy Trucks Ever Made!

 
story-8

Hennessey's New Supercharged Silverado ZR2 Has 700 HP

 Verdad Gallardo
story-9

Coachbuilt N2A Anteros Is an LS2-Powered C6 Corvette In Italian Clothes

 Verdad Gallardo




All times are GMT -5. The time now is 01:07 PM.

story-0
Topdon ONE vs. Artidiag 800 BT2: Which is the Diagnostic Tablet For You?

Slideshow: We take a close look at the ONE and Artidiag 800BT2 diagnostic tools from Topdon and the reasons to buy one over the other.

By Pouria Savadkouei | 2026-05-28 11:05:11


VIEW MORE
story-1
Gas Monkey Built a 6-Wheel Ferrari Testarossa With a Corvette LT4 Engine

Slideshow: The controversial Ferrari F6 swaps its original flat-12 for a Corvette Z06-derived LT4 V8 and sends power to four rear wheels through a custom-built drivetrain.

By Verdad Gallardo | 2026-05-26 18:23:54


VIEW MORE
story-2
7 Most Reliable High-Performance Engines GM Has Ever Built

Slideshow:These GM engines didn't just make huge power, they survived abuse, boost, track days, and six-digit mileage with a reputation for refusing to quit.

By Verdad Gallardo | 2026-05-21 16:45:27


VIEW MORE
story-3
Amazing '71 Camaro Restomod Is Modern Muscle Car Under the Skin

Slideshow: This heavily modified 1971 Camaro mixes classic muscle car styling with a fifth-generation Camaro interior and modern LS3 power.

By Verdad Gallardo | 2026-05-12 18:06:42


VIEW MORE
story-4
6 Common C5 Corvette Failures and What's Involved In Repairing Them

Slideshow: From wobbling harmonic balancers to failed EBCMs, these are the issues that define long-term C5 ownership and what repairs typically involve.

By Pouria Savadkouei | 2026-05-07 18:44:57


VIEW MORE
story-5
Retro Modern Bandit Pontiac Trans AM Comes With Burt Reynolds' Autograph

Slideshow: A modern Camaro transformed into a retro icon, this limited-run "Bandit" build blends nostalgia with brute force in a way few revivals manage.

By Verdad Gallardo | 2026-04-21 13:57:02


VIEW MORE
story-6
Top 10 Greatest Cadillac V Series Performance Models Ever, Ranked

Slideshow: Cadillac didn't just crash the high-performance luxury vehicle party, it showed up loud, supercharged, and occasionally a little unhinged...

By Pouria Savadkouei | 2026-04-16 10:05:15


VIEW MORE
story-7
Top 10 Most Powerful Chevy Trucks Ever Made!

Slideshow: Top ten most powerful Chevy trucks ever made

By | 2026-03-25 09:22:26


VIEW MORE
story-8
Hennessey's New Supercharged Silverado ZR2 Has 700 HP

Slideshow: Hennessey has turned the Silverado ZR2 into a 700-hp off-road monster with supercharged V8 power and a limited production run.

By Verdad Gallardo | 2026-03-24 18:57:52


VIEW MORE
story-9
Coachbuilt N2A Anteros Is an LS2-Powered C6 Corvette In Italian Clothes

Slideshow: A one-off sports car that looks like a vintage Italian exotic-but hides a C6 Corvette underneath-just sold for the price of a new mid-engine Corvette.

By Verdad Gallardo | 2026-03-23 18:53:41


VIEW MORE