Arduino ja LCD

Moi,

Arduinon ohjelmointia nyt kovasti opettelen ja napin painallus laskuri projekti on meneillään. Siinä lisätään tai vähennetään painallusten määrää. Mutta 2x16 lcd-näytöllä on tämmöinen ongelma.
Esim, painettu + nappia 10 kertaa, lcd:llä tämä:
Nappilaskuri
Kpl: 10
Sitten vähennetään yksi ja lcd:llä tämä:
Nappilaskuri
Kpl: 90

Eli nuo viimeset numerot ei poistu näytöltä ja ois hauska saada ne pois. Tuossa koodi:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int switchPin = 6;              // switch is connected to pin 2
int switchPin2 = 7;              // switch is connected to pin 2
int val;                        // variable for reading the pin status
int val2;                        // variable for reading the pin status
int buttonState;                // variable to hold the button state
int buttonState2;                // variable to hold the button state
int buttonPresses = 0;          // how many times the button has been pressed

void setup() {
  pinMode(switchPin, INPUT);    // Set the switch pin as input
  pinMode(switchPin2, INPUT);    // Set the switch pin as input

  buttonState = digitalRead(switchPin);   // read the initial state
  buttonState2 = digitalRead(switchPin2);   // read the initial state

  lcd.begin(16, 2);
  lcd.print("Nappilaskuri");

}


void loop(){
  val = digitalRead(switchPin);      // read input value and store it in val
  val2 = digitalRead(switchPin2);      // read input value and store it in val


  if (val != buttonState) {          // the button state has changed!
    if (val == HIGH) {                // check if the button is pressed
      buttonPresses++;               // increment the buttonPresses variable
            
       }
  }
    
    if (val2 != buttonState2) {          // the button state has changed!
    if (val2 == HIGH) {                // check if the button is pressed
    buttonPresses--;               // increment the buttonPresses variable
      
    }
  }
  lcd.setCursor(0, 1); // bottom left
  lcd.print("Kpl:");
  lcd.print(buttonPresses);
  
  buttonState2 = val2;   
  buttonState = val;                 // save the 8tate in our variable
}

Tulosta vaikka numeroiden tilalle välilyöntejä ennen kuin tulostat uuden numeron.

Tulipa opittua, että homma hoituu “takakautta”. Elikkäs lcd.clear() komentoa käyttäen ja sitä ennen pieni delay(), jotta teksti ehtii silmälle näkyä. :slight_smile:

[code]
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int switchPin = 6; // switch is connected to pin 2
int switchPin2 = 7; // switch is connected to pin 2
int val; // variable for reading the pin status
int val2; // variable for reading the pin status
int buttonState; // variable to hold the button state
int buttonState2; // variable to hold the button state
int buttonPresses = 0; // how many times the button has been pressed

void setup() {
pinMode(switchPin, INPUT); // Set the switch pin as input
pinMode(switchPin2, INPUT); // Set the switch pin as input

buttonState = digitalRead(switchPin); // read the initial state
buttonState2 = digitalRead(switchPin2); // read the initial state

lcd.begin(16, 2);

}

void loop(){
val = digitalRead(switchPin); // read input value and store it in val
val2 = digitalRead(switchPin2); // read input value and store it in val

if (val != buttonState) { // the button state has changed!
if (val == HIGH) { // check if the button is pressed
buttonPresses++; // increment the buttonPresses variable

   }

}

if (val2 != buttonState2) {          // the button state has changed!
if (val2 == HIGH) {                // check if the button is pressed
buttonPresses--;               // increment the buttonPresses variable
  
}

}

//LCD-printing

lcd.setCursor(0, 0); // bottom left
lcd.print(“Nappilaskuri”);
lcd.setCursor(0, 1); // bottom left
lcd.print(“Kpl:”);

lcd.setCursor(4, 1); // bottom left
lcd.print(buttonPresses);
delay(50);
lcd.clear();

buttonState2 = val2;
buttonState = val; // save the 8tate in our variable
}[/code]

Iltaa,

Täähän homma on hauskaa, nyt on opittu float:n käyttöä ja samalla array hommia. Nyt alkaa olla jo vähän itsevarmuuttakin tähän ohjelmointiin. :slight_smile: Oisko sitä kohta viikonpäivät jo koodaillu enemmän tai vähemmän tosissaan.

Tarkoitus ois tehdä kouluprojektina pieni penkkiporakone, jolla pystyis poraamaan reikiä ja tekemään kierteitä kierretapilla. Ideana on asettaa kierteen nousu ja tarvittava syvyys, jolloin tietty määrä steppejä askelmoottorille ja sit sama takaisin. Porausmoodissa ei varmaan kauheita nopeuksia saavuteta, mutta jotain kuitenkin. Ehkä tuhat rpm?

Katselin tuossa jo stepperi kirjastoa ja tuli mieleen miten asettaa ääretön määrä steppejä(tai no ihan mikä tahansa päättymätön luku)? Toinen kysymys, riittääkö Unon tehot tähän hommaan? Pitäisikö jonnekkin muualle uusiketju pistää vai otsikkoa muuttaa?

No tuossa tän päivän kikkailuja. Luulen että tuossa on minulla liika kiertoteitä asioiden ratkaisuun. Saa mielellään neuvoa miten voisi paremmin tehdä.

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int switchPin = 6;              // switch is connected to pin 6
int switchPin2 = 7;              // switch is connected to pin 7
int val;                        // variable for reading the pin1 status
int val2;                        // variable for reading the pin2 status
int buttonState;                // variable to hold the button1 state
int buttonState2;                // variable to hold the button2 state
int buttonPresses = 0;          // how many times the button has been pressed

int buttonArray[] = {0, 30, 45, 50, 60, 70, 75, 80, 100, 125};    //Tuossa M-kierteen nousuja kerrottuna sadalla
float valArray;                  //Apuhässäkkä ylemmänkäyttämiseen
float valSteps;                  //Steppien laskuun
float valRevs;                   //Kierrosten laskuun


void setup() {
  pinMode(switchPin, INPUT);    // Set the switch pin1 as input
  pinMode(switchPin2, INPUT);    // Set the switch pin2 as input

  buttonState = digitalRead(switchPin);   // read the initial state
  buttonState2 = digitalRead(switchPin2);   // read the initial state

  lcd.begin(16, 2);


}


void loop(){
  
  //Tuolla kikkaillaan ettei valArray arvo mene yli tai ali
  if (buttonPresses < 0)
    { buttonPresses = 0;
  }
  if (buttonPresses > 9) 
    { buttonPresses = 9;
  }
  //Nappien logiikka
  val = digitalRead(switchPin);      
  val2 = digitalRead(switchPin2);      

  if (val != buttonState) {          
    if (val == HIGH) {              
      buttonPresses++;               
         }
  }
    
    if (val2 != buttonState2) {          
    if (val2 == HIGH) {                
    buttonPresses--;               
         }
  }
  
  //Math section - Lasketaan stepit ja kierrokset
  valArray =  (float)20000 / buttonArray[buttonPresses] ;  // 
  valSteps =  (float)valArray * 22; //22 edustaa 22mm syvää tapin reikää
  valRevs = (float)valSteps / 200;  //Montako kierrosta 22mm syvään reikään
  
  //LCD-printing
  lcd.setCursor(0, 0);
  lcd.print("Revs:");
  lcd.setCursor(0, 1);
  lcd.print("Steps:");
  
  lcd.setCursor(6, 0); 
  lcd.print(valRevs);
  lcd.setCursor(5, 1);
  lcd.print(valSteps);
     
  delay(50);
  lcd.clear();
  
 
  //Näillä tallennetaan napin tila...    
  buttonState2 = val2;   
  buttonState = val;                
}

Jos haluat projektista tarinoida enemmän, niin suosittelen luomaan uuden threadin vaikka Ideat ja projektit tai Lukija-artikkelit alueelle.

Pieni huomio noista floateista AVR:llä: AVR on 8-bittinen mikrokontrolleri, jossa ei ole floating point unittia. Ts. se veivaa floatit ja doublet (ja kaikki yli 8-bittiset integeritkin) softalla. Floattien ja doublejen tapauksessa kyseinen homma on todella hidasta ja bloattia. Ts. jokainen laskuoperaatio jonka teet floateilla vie luokkaa satoja tai tuhansia käskyjä, eli ohjelmastasi tulee todella hidas, samalla kun koodin koko paisuu. Myös yli 8-bittisten integerien käsittely muuntuu useiksi käskyiksi, mutta se on luokkaa muutamasta ehkä max. pariinkymmeneen (hattuvakio) muuttujan tyypistä riippuen (16/32/64-bittinen).

Elikkä kannattaa aina miettiä minkälaista dataa ollaan käsittelemässä, mikä on pienin muuttujatyyppi (mieluiten integer AVR:illä), joka kykenee tallentamaan tarvittavan datan.

Lisäksi pikaisella koodisi vilkaisulla semmoinen vinkki, että jos sulla on kiinteitä arvoja kuten jonkin toiminnon pinni, joka ei muutu käytön aikana, niin käytä ennemmin defineä kuin muuttujia. Säästät muistia sekä prosun ei tarvii hakea muuttujan arvoa muistista ajon aikana (ellei kääntäjä jo osaa optimoida tota pois), vaan arvo määrittyy suoraan ohjelmakoodiin.

Elikkä esimerkkiä:

#include <avr/io.h>
#include <inttypes.h>
...
#define PINNI 3

uint8_t jokumuuttuja; // Etumerkitön 8-bittinen integer (0..255)
int8_t toinenmuuttuja; // Etumerkillinen 8-bittinen integer (-128..127)
uint16_t kolmasmuuttuja; // Etumerkitön 16-bittinen integer (0..65535)
...

int main(void)
{
...
    vilkutapinnia(PINNI);
...
}

Elikkä #define siis toimii niin, että kääntäjä (tai tarkemmin preprosesori) korvaa koodista kaikki definejä vastaavat merkkijonot sillä toisella merkkijonolla joksi se on määritelty. Esimerkin tapauksessa muuttuu koodi siis muotoon vilkutapinnia(3); Tällöin saat siis helposti koodin alussa tehtyä määrittelyt eikä niitä tarvii hard-koodata niitä jokapuolelle, ja et silti käytä muuttujaa ja tuhlaa muistia tehdessäsi niin. Definellä saat samoin tehtyä myös ns. makroja.

esim.
#define TEE_JOTAIN() JOKUREKISTERI |= (1 << JOKUBITTINIMI)

Suurin piirtein noin.

Vielä sellainen pikku juttu, että floatilla toisinaan ampuu vain jalkaan. Jossain vaiheessa ne virheet voivat kerrannaistua tai sitten käy niin ikävästi, että vertailu ei osukkaan.

Aikoinaan näin demon joka oli tehty PC:llä mutta kaunis if lause:

if( testitulos != TESTIVAKIO && // testituloksessa enempi bittejä, kuin TESTIVAKIOSSA funktio() != MAHDOTON_PALUUARVO && // pudotti FPU:n bitit ja testitulosta verrattiin muistissa olevaan kopioon ! (testitulos < TESTIVAKIO) && ! (testitulos > TESTIVAKIO) ) Loogisesti tuo on aina väärin mutta, ATK:lla onnistui.

AVR laskee sujuvasti vielä isoja inttejä. Nehän ovat vain muistissa olevia taulukoita, tai rekisterissä möllötteleviä versioita niistä.

Ja sitäpaitsi esimerkkikoodissasi pystyit jakamaan nollalla, jos nappia ei ollutkaan painettu.
Itse tuota ongelmaa lähtisin miettimään murtolukujen kanssa. kerro, jaa ja kun tuon tempun tekee aina uint8_t muuttuja = uint8_t( uint16_t(muuttuja * kerroin)/jakaja) tyylisesti, niin ei satu omaan nilkkaan. Pitää vain huolen, että muuttujan * kertoja / jakaja pysyy 8-bittisen luvun sisällä.16 laajennetaan sitten 32-bittisiksi jne… CERTin sivuilla on jossain miten kerrotaan, vähennetään ja jaetaan turvallisesti. Jos operaatio ei onnistu turvallisesti niin sitten pitää vain jakaa operaatio osiin ja tehdä pienemmällä osalla.

Mitä makroihin tulee niin esitän jyrkän mielipiteen: Vasta sitten kun osaat käyttää gotoa oikein, opettele käyttämään makroja. Siihen saakka makrot ovat murheensiementen kasvualusta. #define vakio on ihan oikein. Niin ja B_set on myös jotenkin ilkeä. Jos on sen tehnyt itse niin sattuu hama sulkeisten kanssa ihan varmasti. Paljon selkeämpi on edelleen |= (1 << bitti);
Mutta ehkäturvallinen #deifne BYTE_BIT_SET(x) ( ( x < 8 && x >= 0? 1 : 0 ) << ( x )) Ja tuota käytetään sitten vain yhdessä PORTX |= kanssa.
Mitä jännää tuolle tapahtuisikaan, jos sille syöttäisi ‘a’ arvoksi… Ja tuo tapahtuu uskomattoman helposti.

Eli vedetään vielä yhteen, että opettele ensin käsin tekemällä ja tutustu vasta sitten kielen hienouksiin ja väärinkäyttömahdollisuuksiin. Bittien nypläämisestä olen kirjoittanut lukija-artikkelinkin. Jos se tuntuu vieraalta niin tutustu siihen.

Tässähän on tullut jo paljon asiaa ja sitä myötä muutoksia tehty. Kiitokset siitä. Tarvettahan ei ollut jakaa nollalla ollenkaan, joten kiersin ongelman if lausekkeella. Koitin tuossa jotain muita taikoja saada askellusmäärän laskettua tarpeeksi lähelle, mutta niillä nuo virheet kertaantuivat. Tuolla saanut oikeita tuloksia:

if ( buttonArray[buttonPresses] && valDepth > 0){ valArray = (float)20000 / buttonArray[buttonPresses] ; //buttonArray[buttonPresses] = kierteen nousu valSteps = (float)valArray * valDepth; }
Pitää aloittaa projekti puolelle oma topikki, kunhan jossain vaiheessa saa Solidworksillä tehtyä piirrustukset ja Eaglella piirilevyt. Luulenpa että projekti on valmis jouluntienoilla, joten rennosti edetään.