Projektinani ollut vuoden verran GPS:llä toimiva venemittaristo.
Käytössä perus kaksirivinen LCD-näyttö ja Arduino Uno.
Olen "leikkaa + liimaa" menetelmällä saanut jonkinlaista tulosta, mutta vieläkään ei tahdo kunnolla toimia.
Unolle olen syöttämässä:
-NMEA dataa GPS:ltä
-Moottorin kierroslukutietoa (pulssia)
Muuttuvia lukuja on:
-Potkurin nousu (kaksinumeroinen lukuarvo)
-Vaihteiston perävälitys ( lukuarvo kahdella desimaalilla)
GPS:ltä lasketaan näyttöön reaaliaikaista nopeutta
Moottorin kierrosnopeus myös näytöllä
Kierrosluvun, potkurinousun ja vaihteistovälityksen avulla lasketaan teoreettinen nopeus.
Näytölle lasketaan GPS-nopeuden ja teoreettisen nopeuden ero => potkurin luisto %
Näytöstä poiketen ei vedenpainetta enää mitata. => Mutta sen tilalle olisi tarkoitus saada maksimi nopeus pysymään näytössä.
Projekti jäi jäihin keväällä, kun piti mitata moottorista kierroslukutiedon amplitudi... Ei viitsisi polttaa piiriä sen takia.
Lisään jo olevan raakilekoodin naurettavaksenne, kun vanhalta koneelta sen löydän.
Sitten pitäisi taas jatkaa projektia.
se lcd-settinksi valikko- tallennus juttu josta oli puhetta toisessa topikissa, meillä on tulossa/menossa(mikäli projektin rautapuolta ei todeta sudeksi) eräs projekti johon näillä näkymin tulee vastaava asetusten muutos mahdollisuus, voin lainata valikko systeemiä käyttöösi jos/kun projektimme etenee siihen pisteeseen...
Tuossa ollut koodi kaverilla katseltavana... Toimii, mutta ei tajua kuin se on tehty.
Pitää hieman opiskella alkeita, jotta tietää edes vähän mitä nuo käskyt tarkoittaa
Nyt olisi jonkinmoista koodia tarjolla.
GPS toimii ja vuorossa olisi luiston laskeminen.
En saa Arduinoa laskemaan millään oikein?
Nyt koodin tarkistamiseksi olen laittanut nopeuden ja kierrokset kiinteiksi numeroiksi (nopeus & kierros)
Tuo "SLIP" olisi se lopullinen tuotos.
alla olevin arvoin tulokseksi pitäisi tulla 13%
SPEED X RATIO X C
SLIP = 100 X [ 1 - (-------------------) ]
RPM X PITCH
const int nousu = 30;
const int gear = 2;
const int kerroin = 1215.2;
const int nopeus = 60;
const int kierros = 5600;
const int yla = (nopeusgearkerroin); // Luistolaskelman jakoviivan yläpuoli = 145824
const int ala = (kierros*nousu);
const int lasku = (yla/ala);
Laskenta ja näyttö toimii odotetulla tavalla
Ainoastaan kierroslukusignaalin puuttuessa, laitoin sille kiinteän arvon. 6100 RPM
Muuten potkurinousuksi 23" ja vaihteiston välitykseksi 2.4:1, jotka on mökkipikkuveneeni arvot.
Näin ollen ~80km/h autolla ajaessa näyttää aikalailla sitä mitä venekkin menee.
Luistoksikin laskee vielä aivan oikeat arvot
En ole LCD-näytöillä vielä pelannut, mutta näyttäisi että tuon kitin napin painallus luetaan analogisesti ja mapataan esimerkkikoodin mukaan seuraavasti.
int adc_key_val[5] ={30, 150, 360, 535, 760 };
Eli:
<29: oikea
30-149: ylös
150-359: alas
360-534: vasen
535-759: valinta
Tuon linkin takaa löytyy ihan hyvännäköinen koodinpätkä, mikä ei jää turhia blokkaamaan luupin sisälle. Turhat delayt luupin sisällä aiheuttavat sen, että näyttö ei vastaisi painalluksiin luotettavasti.
Tuo msgs[5][15] merkkijonotaulu on tässä turha. Sen sijaan pitäisi vain ohjata muuttujan key arvo vaikuttamaan siihen mitä näytöllä näytetään. Tai tarkemmin, jos key on jotain muuta kuin -1, niin päivitetään joku muuttuja kyseiseen arvoon. Sitten vaikka joku switch-case, tai if-else hässäkkä ajamaan tuon muuttujan perusteella se oikea funktio tai lcd.print tms. Minä rakentaisin ohjelman niin, että jokaista näytettävää moodia varten olisi oma funktionsa, mutta se vähän riippuu miten tätä piti ohjata. Käyttöliittymän voisi suunnitella vaikka tilakaaviona ja kirjoittaa sitten auki koodiksi.
Tai sitten jos on tosiaan vain kaksi moodia, niin siihen riittää tilamuuttuja, jolla on arvot 0 ja 1. Napin painallus vaihtaa tilan nollasta ykkökseksi ja päin vastoin. Kannattaa säilyttää koodista tuo key != oldkey ja key>=0 kohta, koska muuten se vetäisi villissä luupissa tilasta toiseen.
Minä en tunne tuota LCD:tä, mutta hyvä että jotenkin saat luettua arvot.
Menuvalinnoissa nappien pitäisi toimia johdonmukaisesti vasen-oikea, ylös-alas, valinta tyyliin, mutta se riippuu siitä että saa jotenkin noin pienen näytön alueella ilmaistua tilan.
Ehkä kuitenkin jotenkin niin, että select nappi vaihtaisi aina tilaa info-näytön ja muokkaus-näytön välillä. Jos info-näytössä, niin näytetään ne asiat mitä haluatkin näyttää, ja muokkaus-näytössä voit vasen-oikea napeilla vaihtaa potkurin nousu-, ja vaihteiston välitys -alitilaa. Ylös-alas lisäisi tai vähentäisi sitä arvoa mikä näkyy näytössä. Kun tässä tilassa painaa select-nappia, niin arvot sijoitetaan muuttujiin, tai voihan ne sijoittaa jo suoraan napin painalluksesta.
Joka tapauksessa select-nappi palauttaisi tilaan info-näyttöön muutosten jälkeen. Tarvitaan muuttuja ainakin sille, onko muokkausnäyttö päällä vai ei. Jos muokkausnäyttö on päällä, toinen muuttuja kertoo kumpaan muuttujaan ylös-alas painallukset vaikuttavat. Melko yksinkertainen tilakone siitä muodostuisi.
Maksiminopeus on vain muuttuja, jonka arvo näytetään info-tilassa. Nopeuden varmasti jo mittaat. Kunhan vain tila riittää näytöllä.
if (nopeus > maxnopeus) maxnopeus = nopeus;
Tarvinnee jonkin tavan resetoida maxnopeus takaisin nollaksi. Ellei tässä riitä Arduinon oma reset-nappi, ja sitten setup- tai alustusfunktioon maxnopeuden nollaus. Reset-nappi tosin tarkoittaa myös sitä, että muut muistiasetukset alustettaisiin myös.
Nappien sijaintia minä vaan ajattelin, kun kirjoitin ylös-alas. Kyllä kai ne jotenkin neliön sisälle on aseteltu näytön alle.
http://playground.arduino.cc/Main/InterfacingWithHardware#tui
Täältä löytyy muutama kirjasto, joilla voi rakentaa menujakin 16x2 tms näytöille, mutta saattaa olla hieman overkill tähän tarkoitukseen. Esimerkiksi se viimeinen LCD Menu, tai jokin sitä ylempänä, mistä vaan löytyy parhaat esimerkit - en ehtinyt tarkistaa.
Jotain tähän suuntaan sitten. Käänsin, mutta en ole ajanut kertaakaan läpi, kun ei ole mitään millä testata. Jos sinulla onkin digitaaliset napit, niin pitäisi korvata analogRead useammalla digitalRead-kutsulla ja toimia sen mukaan mikä nappi oli pohjassa. Funktiota get_key ei silloin välttämättä tarvita ainakaan tuossa muodossa. Tämäkin koodi lukee napin tilan kahteen kertaan ja ilmeisesti tarkoitus on välttää reagoimasta kohinaan tms (debounce).
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int NUM_KEYS = 5;
int adc_key_val[NUM_KEYS] ={30, 150, 360, 535, 760 };
int adc_key_in;
int key=-1;
int oldKey=-1;
enum tila_t { INFO, NOUSU, GEAR } tila;
const double MIN_NOUSU = 10;
const double MAX_NOUSU = 32;
const double MIN_GEAR = 1.32;
const double MAX_GEAR = 2.60;
double nousu;
double gear;
double maxnopeus;
void setup()
{
pinMode(13, OUTPUT);
lcd.begin(16,2);
lcd.print("Initializing...");
nousu = 17.00;
gear = 2.60;
maxnopeus = 0.00;
tila = INFO;
}
void loop()
{
adc_key_in = analogRead(0); // read the value from the sensor
digitalWrite(13, HIGH);
key = get_key(adc_key_in);
if (key != oldKey)
{
delay(50); // wait for debounce time
adc_key_in = analogRead(0); // read the value from the sensor
key = get_key(adc_key_in);
if (key != oldKey)
{
oldKey = key;
if (key >= 0)
paivitaTila(key);
}
}
switch(tila)
{
case INFO:
menuInfo();
break;
case NOUSU:
menuNousu();
break;
case GEAR:
menuGear();
break;
}
digitalWrite(13, LOW);
}
// näytä infotila
// lue nopeus, jos nopeus suurempi kuin max, päivitä.
// lue kierrosluku, laske, päivitä näyttö uusilla arvoilla.
void menuInfo()
{
lcd.print("info");
}
// näytä potkurin asetustila
// lue nousu
void menuNousu()
{
lcd.print("nousu");
}
// näytä vaihteiston asetustila
// lue gear
void menuGear()
{
lcd.print("gear");
}
//tilakone
// muokkaa muuttujien arvoja
void paivitaTila(int input)
{
switch(input)
{
case 0: // oikea
case 3: // vasen
if (tila == NOUSU)
tila = GEAR;
else if (tila == GEAR)
tila = NOUSU;
break;
case 1: // ylos
if (tila == NOUSU && nousu < MAX_NOUSU)
nousu++;
else if (tila == GEAR && gear < MAX_GEAR)
gear += 0.01;
break;
case 2: // alas
if (tila == NOUSU && nousu > MIN_NOUSU)
nousu--;
else if (tila == GEAR && gear > MAX_GEAR)
gear -= 0.01;
break;
case 4: // select
if (tila == INFO)
tila = NOUSU;
else
tila = INFO;
break;
}
}
// Convert ADC value to key number
int get_key(unsigned int input)
{
int k;
for (k = 0; k < NUM_KEYS; k++)
{
if (input < adc_key_val[k])
return k;
}
if (k >= NUM_KEYS)
k = -1; // No valid key pressed
return k;
}