opengauge development: gunio technical considerations
The stand alone opengauge (aka MPGGuino, or guino for short), has a number of issues to consider:
Display: 1. [deleted my 8 bit ramblings, suggest using the 4 bit library that is being worked on:] http://www.arduino.cc/playground/Code/LCD4BitLibrary 2. Display Size. Displays in general, the more the better. 20x4 would be my vote (or 1024x768), but I am only starting to understand the technical limitations facing a bigger display. But it should be at least as big as the arduino so we can hide the arduino behind it. 3. Display Interface. [deleted interface stuff, 4 bit libraries look sufficient, moved flow to organization] Development Environment I like the ease of the arduino ide, and how it can drop down to AVR with relative of ease. I also like that there are a lot of people using it and posting solutions to real world problem. I also like the fact that it is free, and open source (so you can look and see how millis() is implemented) and the free version is not deliberately crippled. Persistence: The atmega specs list the 512 byte EEPROM memoy (where we will keep the trip data that persists when the atmega is turned off) as only allowing 1000000 writes, then apparently it turns to dust. This means we do NOT want to save the persistent trips once a second!!! One logical solution would be to save them when the key is turned off, but we will need a digital pin tied to ignition power to do that. Trip Organization: With only 512 bytes of persistent data storage, we need to think somewhat carefully about what we save from run to run. If we have a persistent tank trip and a handful of other trips, they should each take about 20 bytes, assuming a similiar structure as below, which means about 26 persistent trips maximum, that get updated when the ignition is switched off. //things will start rolling over @ about 1900 hours class Trip{ unsigned long seconds; unsigned long injHi; unsigned long injHiOverflow;//need more precision on the injectorHI time unsigned long injCount; unsigned long vssCount; } in the one second loop()... make a copy of the instant trip and reset it clear lcd if(english) print("MPG<TAB/>MPH<TAB/>MLS<TAB/>HRS"); else print(something besides english); go to next lcd line for(int trip = 0; trip < NumLines; trip ++){ trips[trip].printData(); go to next lcd line } in Trip.printData(){ //functions handle conversions to english/metric printConsumption(); printVelocity(); printDistance(); printTime(); } add setup options to hide the header row, and to keep the instant trip row always viewable. |
[deleted my 8 bit ramblings]
re: LCD hardware. A bigger display would be nice, but the source we have for the freeduino only has a 16x2 offering for $10. http://www.nkcelectronics.com/16x2-l...backli162.html Simplified ordering is nice too. Ok, I bought one of those 16x2 to play with. AND an $18 20x4 from http://www.sparkfun.com/commerce/pro...roducts_id=256 (100 or more= $14.36!!) |
simple buttons?
Also want to look into simple to make touch sensitive switches: http://www.bytecraft.com/Touch_Sensitive_Switch
http://www.bytecraft.com/graphics/touchsw3.gif Code:
char touch_switch (void) { |
Last thing for now, thought this was kind of cool :)
the dCoreDuino http://www.modxhost.com/dual168-pcb-fin.jpg |
Ok, it looks like all the action is on the 4 bit arduino library. Lots of people are working on that and the library compiled out of the box for me, and apparently it is supporting multiple lines and 20x4 displays. And it uses less pins than the 8 bit one:
http://www.arduino.cc/playground/Code/LCD4BitLibrary :thumbup: It looks like the most promising solution at this point in time, better than the 8 bit solution. |
Ladyada.net - Hooking up an LCD to Arduino
This is a howto from Ladyada.net for LCD's and *duino's. This should be helpful for us to learn the best methods.
http://www.ladyada.net/rant/2008/04/...to-an-arduino/ |
So, are you still thinking the 16x2 LCD mentioned in post #2 is the one to get? If so, I'll order one too. I'm a bit out of my depth, but I can at least be beta testing along side you guys.
Also, the Guino is boring with only a blinking LED to program. :) |
I don't know 2 or 4. Ease of ordering vs more data display area. how about keeping gunio 1.0 simple and get the 2?
it isn't much to work with though, but it's cute :) some examples, (the *'s are buttons outside the LCD area) Code:
INS 045mpg mnu* |
Agreed: cheap & simple are good goals for 1.0.
I just ordered the 2x16 - came to $13.29 US including shipping to Canuckistan. Your sample display interface looks good & makes sense. I like it. |
Ok, I've got a couple of thought's, for consideration.
In thinking about it, if we are only looking to update the display or send out the serial data, once per second, then the code and hardware don't really need to sample either the speed, injector on time or frequency any more quickly. Consequently, the code could reasonably sample the speed for 10 cycles, average that and store it. The same thing is true for the injector on time and frequency. Statistically this would give us some pretty highly reliable intervals for calculation and display. It should also make the code pretty straight forward. One request was for RPM to be displayed. In thinking about the above, the RPM can be inferred, largely, from the frequency of the injector pulse. The exception to this would be if the injector is not turned on, as it is not when my rpm is above about 1200 and I have my foot off of the throttle. Third, one of the things I would like to have is the ability to see if my speed is going up or down and whether my fuel mileage is going up, or down. On the display, it may turn out that we have to not update the screen, to frequently, as at some rate of change it may become jibberish. Although I ordered my freeduino a week ago, I still haven't received it. |
Mine took over a week to arrive. The donkey train across the border into Canuckistan is facing swollen rivers & streams from the spring runoff, dontcha know.
EDIT: Whoops, whoops. I read your post and thought it was from fellow hoser Who. Thus you can ignore this post entirely. |
Whoops, the occasional sampling of the injectors would be reasonably accurate, but then you need to add tight timing control around the code that would enable the timer interrupts and disable them. And then make an exception for the vss signal, because on my vehicle, it is more than a second between pulses at low speed and you wouldn't want to miss one of those.
I don't think it would make it more straightforward though, since it adds code, but it would be a good optimization, a strategy to consider if reacting to the button presses and displaying prove to be too time consuming. But I think we are ok and might even be able to shorten the 1 second display rate and keep microsecond accuracy. if you wanted to plug into the serial processor as it stands today: http://ecomodder.com/forum/showthrea...7979#post17979 Basically in the middle of loop, get rid of the serial calls and replace it with updateTrips(tmpInjHiMS, tmpInjCount, tmpvssCount );//quick addition in the trip objects updateDisplay() updateTrips might look like: void updateTrips(long injHiMS, injCount, vssCount ){ instant.reset(); instant.update(injHiMS,injCount,vssCount); current.update(injHiMS,injCount,vssCount); tank.update(injHiMS,injCount,vssCount); trip1.update(injHiMS,injCount,vssCount); trip2.update(injHiMS,injCount,vssCount); } and the trips themselves would provide functions like: current.mpg(), instant.kph(), instant.mph(), tank.dte(), trip1.lper100km() now updateDisplay() is tricky, as well as keeping track of the button interrupts and deciding the next screen. Might want to look at how coyote did his for starters. |
Quote:
http://www.arduino.cc/playground/Mai...ralCodeLibrary This should help to understand a lot of the nuances in coding the *duino. As a project to learn coding I'm trying to figure out how to wire up a Battlestar Galactica Cylon scanning eye. I know its a cheesy LED thing but it should be a good first step to learn about *duino's. |
Whoops, one more note, there was a caution about the lcd and interrupts at: http://www.arduino.cc/cgi-bin/yabb2/...m=1173553276/3
it is summarized as follows: 1.) Never use a delay or any library which introduces a delay while in an interrupt (like the Wire library or LCD libraries). Serial communication, or any communication requiring a clock will also fail. 2.) Use an external pull-up on the interrupt line. re: 1. not a problem if updateDisplay is called directly in loop() as I'm suggesting. re: 2. This is an external hookup issue. Also I did some scratching and I think worst case scenario (i.e. a v8 with tbi doing 150mph at 8000RPM), there should be about 10 milliseconds of overhead for all the interrupts, which leaves .99 seconds to figure out what to display and display it. P.S the 2x16 showed up today, I still can't tell if it is the one with less built in characters but more user definable characters or not. |
Sorry, I couldn't resist playing with the lcd. The library didn't work for me, wound up poking at it in arduino ide till I got somewhere. All those somewhat arbitrary hokey delays need to be replaced with a status check on the lcd (i.e. LCD? are you ready for another command or piece of data?) I also moved the pins all around to keep the timer1 and 2 pwm pins open (and the serial ports open).
http://opengauge.org/diympggauge/mpguino1.JPG I call this configuration the boreduino :) http://opengauge.org/diympggauge/boreduino.JPG |
Awesome! I love it! Can't wait for mine to come too.
I also love that you're not not blowing the project budget on mounting hardware/shields. :) (Correct me if I'm wrong, but a "shield" is Arduino-speak for separate circuit boards that you mount additional electronics on and then connect to the 'duino, right?) |
Quote:
FYI, radio shack had a bag of 4 little buttons for $2. I'll probably mount them flush with the LCD face on the sides with some long leads for now. Or maby along the top right where it would be easier. Yah, I like easy, that looks like a plan. Edit: easiest mounting turns out to be to jam them in under the LCD. Now how many? 2, 3 ,4? Each button takes a pin 4 buttons should be easier to navigate. I.e. a select, 2 scrolls and a back. 3 buttons isn't too bad either, I e a scroll in either direction (so you don't have to cycle through all the options if you pass it) plus a select button, but "go back" becomes a thing you have to select. 2 buttons is the easiest to hook up and simplifies the design choices. Harder on the users as there's lots more clicking, but not a big deal. Ok Pin check: We don't have any sensors plugged in yet or buttons (or a piezo speaker), but after the LCD we have: 4 pwm pins 2 "serial" pins 0,1, I think we can give up 0, but TX might be useful for debugging. 6 analog/digital read pins (yep, sorry blinky fans, I took pin 13 for the LCD) So that leaves us 11 pins without buttons or car signals. we need 3 digital read pins to talk to the car. vss,inj,ign power. and each button will need a pin, so maybe 4 there. piezo speaker for another 1, would be good for the "your mpg is dropping" alert. |
Can we combine 2 buttons simultaneously pressed for some fuction, such as "home"? That could let us get away with 3 buttons with 4 button functionality (assuming just one "combo" button). Might not be the best usability though. Just a thought.
|
I think the answer to the number of buttons happens to be 3 :) And they will be in the upper right corner.
I sat it in the car, it is the same height as a scangauge but about two inches narrower, and fits. I pretended to use the buttons, and am of the conclusion that a small cluster of them is better than spreading them around. upper right corner was the easiest place I could get to them and still see the screen. 3 because that is what fits in the upper right with sufficient space between the buttons, with sitting flush with the lcd and not increasing the profile. So just need to glue down a block there of the right thickness, solder up the switch leads, with a common ground and three signals, and glue them to the block. edit: re chording buttons. I was actually looking at those earlier today, that is weird. I think the only chord that people might intuitively know is the soft reset, where you mash everything down. |
Agreed about combining buttons. Probably not the best (intuitive) idea.
I also agree that a cluster is best - as Trebuchet pointed out earlier, you'll learn which ones you need to press and eventually will be able to do it without looking. Cluster = useful tactile feedback for selecting the right one. |
Buttons
Here is a simple approach, can be had from the 'shack
needed: 1 bag of 4 surface mount push button switches . Mine were $2 though the site says $4 1 general purpose dual pc board ~$2 Some hookup wore (cut open an old network cable or something). Hot Glue gun that really thin solder helps, especially inbetween the buttons. And sharpen up your iron first. Tin the iron with solder as soon as it can melt it, before it gets too hot and oxidizes. Assembly: Find a 12x3 group of copper circles on the board, by the edge but not on the edge. Score through the next row out in all 4 directions and snap off the extra. Tin the circles lightly that you will be using. X=tinned XOOXXOOXXOOX OOOOOOOOOOOO XOOXXOOXXOOX Starting with the middle switch (leads touching one X each), surface mount the switches to the tinned copper spots, don't let the switch leads touch the other switches on the bottom, but do solder bridge them on the top. That That will be the ground. Hold your breath, and (CAREFULLY) grind the top and bottom flush on the grinding wheel, bring in the sides to just outside the rings where the switches are connected. Add the wires (and leave yourself plenty of wire for now). Pull them through the plain side and bend them over an appropriate switch leg and solder. Attach three signal wires and one for the ground. grind the extra solder and wire off the top/bottom/ Straighten out the wires and run them to one end Feed the wires through the top right hole in the lcd and position the buttons so the metal part is flush with the front of the lcd and they are straight, and the right side is flush with the right of the lcd board. Pull the buttons back out just enough to put a thin layer of hot glue on the bottom of the buttons, and quickly but accurately put them in their final position. If your happy with their position and protrusion from the lcd, squirt in (caulk style) some hotglue to fill in behind the button boar. coding: In your code, you can use the internal pullup resistors via: pinMode(pin, INPUT); // set pin to input digitalWrite(pin, HIGH); // turn on pullup resistors then attachInterrpupt (pin, function, FALLING) and or with the "button has been pressed" flag. Hookup, the ground goes to ground and the signals go to the pin they control. http://opengauge.org/diympggauge/buttons.JPG http://opengauge.org/diympggauge/buttons2.JPG http://opengauge.org/diympggauge/buttons3.JPG http://opengauge.org/diympggauge/buttons4.JPG |
(EDIT, this is not current information)
Oh, and here is the LCD connection setup I used to preserve the multipurpose ports Code:
NC=Not Connected |
Nice placement for those 3 buttons.
|
FYI, dont take the pin assignments to seriously yet. The arduino has blocked external interrupts on most of the ports and it *might* require some rewiring.
I'm reading some things that say arduino only allows two external interrupts, and obviously we need those for the injector and the vss. the atmega can support lots more external interrupts, so it probably just needs a little digging, and dipping into AVR. |
interrupt vectors
2 0x0002 INT0 External Interrupt Request 0 3 0x0004 INT1 External Interrupt Request 1 4 0x0006 PCINT0 Pin Change Interrupt Request 0 5 0x0008 PCINT1 Pin Change Interrupt Request 1 6 0x000A PCINT2 Pin Change Interrupt Request 2 arduino board mappings: INT0 = digital pin 2 INT1 = digital pin 3 PCINT0= digital pin 8 PCINT1= digital pin 9 PCINT2= digital pin 10 PCINT3= digital pin 11 PCINT4= digital pin 12 PCINT5= digital pin 13 attachInterrupt only works with INT0 and INT1, so need to (INT0 example, translate for PCINT): <chickenscratch> #include <avr/interrupt.h> ... int sensePin = 2; ... ISR(INT0_vect) { value = digitalRead(sensePin); } ... setup() // Global Enable INT0 interrupt GICR |= ( 1 < < INT0); // Signal change triggers interrupt MCUCR |= ( 1 << ISC00); MCUCR |= ( 0 << ISC01); } </chickenscratch> Don't know why there are not interrupt vectors for all the PCInts yet. Note: in an ideal place we would use 6 external interrupts, 3 buttons, 1 injector signal, 1 vss signal, and one ignition power. But I recon we can poll the buttons and the ignition power if absolutely necessary. |
Note: I Updated the pin assignments on the freeduino serial processor draft to just use pins 2 and 3 (INTR0 and INTR1), and those do seem to respond to the buttons anyway. I'm going to move LCD wire connected to Pin 2 to pin 0 and we can assure ourselves of VSS and Injector signals that way by reserving pins 2 and 3 respectively.
I think the guino should try and dip into AVR and get more interrupts going for the buttons though, it *should* be easier than polling, and less flakey. But if someone wants to come up with a "wait" that can guarantee one second accuracy on the main loop but still do things like poll buttons while it is "idle", then that is cool. |
I'm still lurking,
waiting for a day when I would have something intelligent to add, You guys are over my head, but I am patiently waiting the day you post schematics and parts list. Thanx, S. |
Well I've made miniscule progress, but heh, progress. I've been waiting and watching every day for the board I ordered to come in. I finally went to the Post Office, multiple times and they told me the package had already been delivered, like a week earlier. I checked here in the office and nobody knows what I'm talking about.
Someone finally found the package mixed in with some magazines. I presumed it was in a box and it came in a plain white plastic padded bag, so it was just presumed to be a bag. On the inputs, if we can run the injector and the speed inputs to interupt pins on the PC, that would be better than not. The problem on the injector is that we need to measure two things, relative to the signal. First, we need to measure how long the injector is on, each cycle and second, we need to measure how long it is before the next cycle, which will give us the frequency or period of time the cycles occur, each second. This is effectively, also the same number as the rpm, unless the car is coasting, in gear, injectors off. The problem on the injector timing is that effectively we need to measure a falling edge signal, have timing to a leading edge and then have timing to the next falling edge. Generally on edge triggered inputs, you can set it up to do one, or the other, but not both, but I haven't gotten far enough to look into that, yet. |
Quote:
|
Quote:
1) I didn't know what a pull up/down resistor was until recently. 2) This simple tutorial shows an external pull up resistor in a test button circuit. http://www.arduino.cc/en/Tutorial/Button So ... the external resistor isn't strictly needed for that tutorial? |
Quote:
|
OK - thanks.
|
Quote:
Can you point me in the right direction (links?) to play around with it? It sounds from your experience like it's not straightforward. |
Well, I didn't get anywhere with the 4 bit library, and it was getting annoying recompiling the library for a bunch of trial and error, so I tried this:
http://www.arduino.cc/cgi-bin/yabb2/...m=1160586800/0 I didn't get results at first and don't recall everything that was involved (predefined timings was one of the gotchas). But here are my current pin assignments and the mpguino display code. It does a good job of highlighting the sequence of events but the delays do need to be redone as status checks and pushed back into the lcd library. Note, with this code I had to hit the reset button after downloading the script or powering up sometimes. Code:
LCD arduino Code:
int DI = 4; // register select RS |
Here is a data sheet on the LCD controller. The LCD itself has a 5x10 character format.
http://www.electronic-engineering.ch...cd/hd44780.pdf One of the possible tweaks might be to create custom characters that use the whole 5x8 character box. They could be larger numbers perhaps for easier reading or maybe custom characters to conserve display real estate , i.e. MPG might have this in front of it instead of three characters: (Note, just realized the lcd is 5x8, not 5x10!!!) http://planetchampions.org/diympggauge/mgfont.GIF (just using paintbrush at 800% zoom) I don't know how many user defined characters are on this display yet, however. |
I've gotten my LCD to work. It actually is a pretty nice display. Can't wait to see it posting some real data. dcb, i like the little fading feature you setup in the code.
|
Very Cool :)
The only thing to add to it is LCD pin 15 (Backlight power) should probably be controlled by an arduino pin and a transistor, so you can controll the brightness from a menu option, and turn off the LED when the ignition is off. |
Do you mean turn off the LCD when the ignition is off? I assume you mean that you would want a pin to turn off the LCD when you want to release the keys from the igninition. Otherwise you want the LCD to stay on when you cut the engine during P&G'ing. Is this correct?
Otherwise why not use a power source from the car that cuts off when the keys are in the OFF position. |
You have a point about the key, I had kill switch in my head so it didn't occur to me that folks might be turning off the ignition.
I need to list out my assumptions I think. 1. The arduino is powered by battery power. Because: A. there are a limited number of eeprom writes, the trips should be saved when the key is turned off, but the arduino can't do that if you are turning off it's power also. B. there are some sleep modes for the arduino that it could utilize when the ignition is off, but I don't think the drain will be terribly noticable. 2. The arduino should sense the ignition power, Because: A. it needs to write out the current state of the trips to the eeprom on the ignition off event. B. If the arduino has control of the LED Backlight (i.e. fancy schmancy menu brightness option) it can turn it off on the ignition off event and save ~200 milliamps. This adds one component (transistor) to the design. Switching it with the ignition directly will add one component in the form of a resistor to limit the current, and not give user control. So I was thinking have the arduino turn off the LED, since the arduino was already connected to ignition power (in my head) and it was a simple task to have a menu driven brightness. The LCD only takes about ~4ma so I'm not worried about it yet. But, maybe, it just has to be a (hokey) delay thing. Like if the car hasnt shown any rpm or travelled any distance in, say, 10 minutes, then it saves the trips in their 10 minutes ago state, and turns off the backlight? Saves us a ignition power pin. |
button interrupts have been sorted out.
Phew, finally got the buttons to be read reliably with interrupts in arduino IDE. No polling required, though we might want to elaborate on the debouncing at some point. This also means there are a lot more pins for doing external interrupts with than arduino allows "out of the box", though only pins 2&3 do RISING/FALLING, the rest are state change, not a big deal.
Code:
#include <avr/interrupt.h> |
All times are GMT -4. The time now is 03:36 AM. |
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Content Relevant URLs by vBSEO 3.5.2
All content copyright EcoModder.com