NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » Digital Engine Tach
January 19, 2011 by huzbum |
as a baby step to my CDI project I'm making an ignition tachometer. I haven't wired up the hardware yet, but the input is a pulse from a wire coiled around one of the spark plug wires into a 2n3055 transistor then into a mosfet. Tests with a volt meter showed 20-50 volts. It is necessary for my intentions to calculate RPM each revolution on the fly rather than count revolutions over a timed interval. After hours reading and re-reading timer and capture tutorials and the Atmega168 datasheet I put this code together:
Then it occurred to me... will this interfere with the USB download interface? Is there any way around this? I want to keep as much done in hardware as possible, because I intend to add more demanding functions, so if I can use the timer1 capture function I would certainly prefer to, but not if it means I can't program the chip again. Also, do you see any other problems? |
---|---|
January 20, 2011 by Ralphxyz |
What is your concern with interference with USB download. I was having problems with using PB0 (ICP1) munging the bootloader but now I am able to use the bootloader fine overwriting the loaded program as expected. I sure cannot wait to digest your code, I have been on a similar quest for the past three or four weeks scouring the web for examples of RPM counting. I have just yesterday finally found a tutorial that I could understand and could modify to meet my needs and now you post your code. Thank you so much. Ralph |
January 20, 2011 by huzbum |
The above code compiles successfully, but I have not yet downloaded it to my MCU for fear of it disabling the bootloader. If I program pin14 to do something else, will it still work for enabling the programming mode? I do not have another way to program the chip if it will not work with the usb programming cable. So it's not that I have experienced problems with it, but that I wish to prevent that... rather safe than sorry... I seem to recall reading somewhere that using ICP1 caused problems with the USB cable, but maybe that was just an issue with live communication, which would not bother me. I am glad to see that my code will be of use to more than just me. It's untested and I'm still just learning micro-controllers, so be careful what you take from it. If you are looking for a more reliable source, I put my code together based on what I learned from the temp sensor project, these tutorials: http://www.protostack.com/blog/2010/09/external-interrupts-on-an-atmega168/ http://www.protostack.com/blog/2010/09/timer-interrupts-on-an-atmega168/ and the atmega 168 datasheet. As I mentioned my future applications for this code require an on the fly estimation of current engine speed. As soon as I have this code tested and working I will modify it to accept a timing pulse and then produce the ignition pulse, so I can't wait for more than one revolution to make my estimate. If your applications do not share that requirement, then it would be much simpler to read average RPM data over a given time. You could simply have a pin change interrupt add to a counter and read, reset, and output to LCD at timed intervals with a timer interrupt. |
January 20, 2011 by Ralphxyz |
I compiled your code, and get the stuck two black programming bars in run mode! This is either OK or a conflict with the bootloader. I had assumed it was a conflict with the bootloader so had switched to using a programmer (ATmel Dragon) and flashing the .hex directly without using the bootloader. Now I realize that this also could be because of lack of output going to the LCD with the code compiling and loading correctly. The two black bars are also possible because I am not generating a pulse, I have modified tempsensor code that outputs a pulse with the width dependent on position of a potentiometer taking the place of the LM34. I will put your code and my rpm simulator code together to see if we can get this to work! re: "You could simply have a pin change interrupt add to a counter and read, reset, and output to LCD at timed intervals with a timer interrupt." Simple in principle but I have been struggling with that for three to four weeks :-) Your code compiles fine! Here are the changes I made to the tempsensor code to generate a variable length pulse using a pot on PIN23 in place of the LM34.
This produces a variable ADC: reading! Using the tempsensor project code. Jump a wire from PB4(PIN18) to PB0(PIN14). Adjust the pot to vary the time of the pulse. Ralph |
January 20, 2011 by huzbum |
hmm... after reviewing my code I see that if the counter has started before a pulse is detected it will not produce output for the LCD. I also noticed that I hadn't changed the print code for line2 to accept an integer instead of a double. I believe I fixed these problems... probably a better way of doing it, but this should work.
Ralph, have you tried to re-program the MCU after having flashed this program to it? If so, I would be comfortable trying it, otherwise I'll have to wait till I get a programmer. |
January 20, 2011 by Ralphxyz |
Yes I reprogramed but as I could not get any output I do not know if it was effective. The compiler did not complain. I will try your new code. Ralph |
January 20, 2011 by Ralphxyz |
Well this is progress! I combined your latest code with my RPMsimulator code (modified temp sensor code). I compiled on the Nerdkit using the command line then copied the .hex over to my pc with the Dragon and flashed the .hex to the mcu deleting the bootloader. I see
I have a flashing led on PB4 which is jumped to PB0 (ICP1). Your code is not registering any flashes. Also I am not able to vary the led flash rate so I missed something in porting my code (and probable also yours) so I will look further into this tomorrow. Also I will compare with my code that uses PB0 that I am able to load using the bootloader, it has to be doable. So at least now I am able to get output to the LCD. My code is uploaded to my web site (work in progress). You can load the .hex but chances are you will only see the two black bars. I have to load the .hex using the Dragon. Possible you can see something in simulator.c I have not gone over it yet. Ralph |
January 21, 2011 by huzbum |
I don't know if the problem is in your pulse generator, my pulse detector code, or the display update code. You can try removing the if statement in the display update code.
Maybe add some debug data to the output to see what's happening...
The other thing to note is that when an interrupt hits, anything in the main code is interrupted and put on hold while the interrupt code is executed. Not sure what affect that would have on delay_ms() |
January 21, 2011 by Ralphxyz |
Well this was not easy and took a lot of hair pulling and beard stroking. You cannot use ICP1(PB0) as signal capture pin IF you are using the BootLoader!! This is opposite with what I would think but if you put a pulse onto PB0(PIN14) the bootloader grabs it as a signal to switch to programming mode, hence you (I) get the two black bars!! Or possible PB4 is pulled to ground at startup if it is wired to PB0. Now this is only at bootup!! If I remove the signal wire (jumper from PB4) start the program and after the program starts insert the jumper once the program is running the program continues running. So there might be a way to do this if you can keep PB0 floating at the start. Now "normally" once deployed there will not be wire between PB4 and PB0 so possible we will not face this situation. It is a very intriguing situation (at least for me it is). If I load the hex using my Dragon (flash with no bootloader) the signal jumper can stay inserted and the program runs. So the boot loader seeing a non floating PB0 thinks programming mode is desired. The programming switch goes to ground for programming and "floats" for run mode. But also if PB0 is pulled high it goes to programming mode. I do not know if it just the pulse or if you connected PB0 to constant Vcc it would goto programming mode at startup. All of my processors stopped "running" and it was driving me crazy trying to figure out why, until I realized it was the jumper wire. Now I can start to look to see why your program is not recognizing a pulse. The pulse last 50ms might that be to fast? I can easily slow the pulse down. The frequency of the pulse which also stopped working last night is variable from real slow to pretty fast. Either fast or slow the duration of the pulse is 50ms. So with this caveat you can use the NerdKit bootloader to program and re-program your mcu during development but for deployment you will need to come up with a way to float PB0 during start up. Again here is my current project I was composing this while huzbum replied to my previous post so I'll post a reply that next. Whew, Ralph |
January 21, 2011 by Ralphxyz |
Here is a problem (I think) PB0 is at Vcc all of the time. This is with the boot loader installed I'll try with out the boot loader. Ralph |
January 21, 2011 by huzbum |
Too much trouble... I'll make a software work-around for a different pin... A few clocks aren't going to make a big difference with the clock/256 pre-scaler. If I need the clock cycles later I'll have to get a programmer and run without the bootloader. Should have new code soon. |
January 21, 2011 by Ralphxyz |
Without the bootloader I see approx. 205 mv which I guess is the float value. So I guess I will have to work with the Dragon programmer. Even with 205mv I still get no RPM. Speaking of programmers, I really like the ATmel Dragon programmer it cost $49.00. The only other programmers I have been exposed to were a ISP (Inline Serial Programmer) which the developers considered beta and never released (which by the way worked great once I got the AVRDUDE syntax figured out). I also have a ATmel STK600. I like using ATmel devices instead of the cheaper knockoffs from ebay as when ATmel makes changes or adds devices the Dragon is updated so any future device "should" be supported. Of course the Dragon has it's issues. There is no Dragon lair, it is literally a bare PCB board with a 40 pin zif socket. You have to solder the access pins on yourself and makeup your own cabling. Because of no box the earlier version crapped out if you touched them while energized in certain places. So if you have a soldering iron I recommend the Dragon. Ralph |
January 21, 2011 by Ralphxyz |
I have been wanting to use ICP1(PB0) because of the Input Capturing feature: 15.2.1
The digital filtering means you should not have to use additional debounce code. Of course noise depends on what you use to generate your pulse so the filtering might not be needed. Keep me posted with your new code. Ralph |
January 21, 2011 by huzbum |
heh... silly thing... I never ENABLED interrupts! LoL We're missing an "sei()" in the main code!
LoL I removed it from the source I was working with because I was going to put it somewhere specific (who knows what I was thinking?) and I forgot all about it... Hope this fixes it... |
January 21, 2011 by Ralphxyz |
Darn, I was hoping that would be it but no. That was certainly necessary but I am still getting zero rpm. I am going to connect a momentary contact switch to PB0 to by pass my code (which isn't working any longer). Ralph |
January 21, 2011 by Ralphxyz |
Nope, same results using a switch. Ralph |
January 23, 2011 by huzbum |
OK. Fixed innumerable errors in my code. There was no way that code would have worked. Had bits wrong, writing to wrong registers, etc. I have much more confidence in this code, though I'm too tired to double check it. I eliminated a lot of opportunities for mistakes. I think I'm going to have to order a programmer... until then, I may rewrite my code to use pin change interrupts in place of the ICP1, but input capture seems to me the best way to do this.
|
January 24, 2011 by Ralphxyz |
Nope, your code compiles fine but I am not getting anything for RPM: or Ticks/REV:. I am not even getting a flicker so it looks like RPM and revTick are not being incremented. Maybe you could ask in the Support thread (What is wrong with this code) and get opinion. I am working on my own code so I have not looked at your code at all beyond loading it. Maybe I'll take a look. I am using my pulse code and also just fliping a switch (Vcc) to get a pulse. Ralph |
January 24, 2011 by Ralphxyz |
huzbum, I added a count variable to your code but it is not getting incremented!
...
Nothing is being touched. Ralph |
January 24, 2011 by hevans (NerdKits Staff) |
Hi Huzbum and Rick, I think the reason your interrupts are not firing is due to an error in the setup routine. Up on line 28 of Huzbums code you meant to set the ICIE1 bit of the TIMSK1 register. This means you want to set bit 5, and your current code is setting bit 4 (remember the bit numbers are zero indexed). I would suggest changing that line to set the registers the way we usually do:
This is more readable, and slightly better from a code design standpoint. Another point I would like to make here is that using a pin change interrupt would probably work just fine in this case. You would have to think about the denouncing yourself, but you would trade away the added complexity of using the same pin as the programming switch. Let me know if that does the trick. Humberto |
January 24, 2011 by Ralphxyz |
Thanks Humberto, I made your change but still getting the same results. Ralph |
January 24, 2011 by Ralphxyz |
I have made further changes and I get the "count" variable I added to increment with button push and from the pulse from my code pulsing PB4!! I have a button on PB0 to Vcc (+). When I push the button I increment count. But not RPM or revTick!! Here is the change to the latest program:
This with my prior code change for the LCD. Here that code is again:
So I have the TIMER1_CAPT_vect interrupt capturing the count!! Here is that code again:
Now I am looking at RPM and revTick but at least we know the interupt is working! Ralph |
January 25, 2011 by hevans (NerdKits Staff) |
Hi Ralph, It looks like you are no longer setting any of the clock bits on the TCCR1B register. huzbum's code was setting the clock prescaler to 256, you don't necessarily have to do the same thing, but you need to set one of the bits to something to turn the Timer/Counter module on. See the chart on page 134 of the datasheet. Humberto |
January 25, 2011 by Ralphxyz |
I was primarily just trying to get some acknowledgement that the ISR was being called. Thanks, now that I know the pulse is being detected I'll re-implement huzbum's code. Ralph |
January 27, 2011 by huzbum |
Sorry for my slow update, but I finally have working code. ICP1 works fine without interfering with the boot-loader or programming function. I have PC4 delivering a 120RPM (2hz) test pulse jumpered directly to ICP1. I'm still working on my high voltage signal pickup. I attempted to hook in to the tach signal on the distributor of my 89 f-150 and it was bad news... DO NOT rustle around in 20 year old wiring unless you intend to replace it. Spent all day getting fuel and spark back. So, here's my working code for all to use:
|
January 28, 2011 by Ralphxyz |
huzbum, thanks so much for your code, it's funny how so many people will ask questions and post code they are having problems with but never publish there working code. Your code is working!! I have a jumper between PC4 and PB0. I let your code run for a couple of hours and now I cannot get to program mode! Your program can not be modified and recompiled! I have not looked at your code yet so I do not know what to expect. I am seeing RPM: 10 Ticks/REV: -31351(2) switches between 1 and 2 revolution: increments 1 per second (apprx) Ralph |
January 29, 2011 by huzbum |
That is odd... I've never experience any of those problems, but I've also never left it run longer than like 5 or 10 minutes or so... Sounds like you're having signal problems. Maybe you should try a resistor or diode in place of the jumper wire. also, maybe your battery is going dead, so a fresh battery may help. The test pulse is based on the time it takes to do all of the operations plus the delay_ms() time. Also, do you have the boot-loader installed, or just the program? |
January 29, 2011 by huzbum |
There does seem to be some degree of error for the first second or two... possibly as it is booting up? But after about a second and a half mine holds steady at 120 RPM and 28768 ticks/revolution. incrementing one revolution at a time. If you're getting more than one revolution then your pulse is being counted twice! I would certainly try a new battery and if that doesn't do it, a resistor and/or diode. |
January 29, 2011 by Ralphxyz |
I use a pda power supply not a battery (i'd go broke). I am using the bootloader to do the initial load. But I cannot reload (program) the mcu first I have to re-install the bootloader. Are you able to re-load the program? This is much more convenient to use the bootloader, what did you add to the code (I know I could look, which I will) to get it to work?. I do not believe you need line 79 "delay_ms(425);" I can read the display results fine without the delay. I'll put the delay back in just so we are looking at the same code. Possible the behavior is different without the delay. Ralph |
January 30, 2011 by huzbum |
the time it takes to run through the program is what sets the frequency of PC4. Without the delay you'll be running a much higher and more random frequency. The test frequency is just a quick addition of turning pc4 on for 10ms each time it goes through the loop. |
May 26, 2011 by huzbum |
Now that it's not 20 below I finally got around to testing this on a vehicle. I soldered a hall effect switch to about 5ft of twisted pair wire and set it next to a spark plug. It works great! There are only 2 issues. 1) if you run the wire parallel to the spark plug wire, it will induce voltage in your wire and make funky things happen... so try to keep your wires away from the plug wires. 2) depending on your engine, you may need to multiply your RPM x 2. The 4 stroke engine only needs spark once every other revolution. Engines with a distributor will need to multiply the RPM x 2. Engines with a waste spark ignition (coil pack, etc) will not need to double the RPM count. Also, not sure if I mentioned this earlier, but the hall effect switch does not interfere with the boot loader or programmer. I have my kit set up in a cigar box and I just leave everything connected and coiled up in the box. If I want to program I just flip the program switch and reload it. |
Please log in to post a reply.
Did you know that a square wave sounds different than a sine wave? Learn more...
|