Image of eBits Academy display illustration

Joystick och display

  • June 23, 2023
  • |
  • Jonas Rothausen

Hej och välkommen tillbaka till vår elektronikserie! Det här är blogg 5 och vi utforskar ett praktiskt projekt: att skriva och redigera text på en LCD med en joystick. Det är ett interaktivt sätt att lära sig grunderna i elektronik och programmering.

Vi använder en vanlig I2C-LCD-skärm (samma LCD som i bloggen Ultraljud & display ) och en joystick för en interaktiv skrivmiljö. Med Arduino och lite programmering kan vi navigera på skärmen och skriva, redigera och radera text med joysticken.

 

Projektet utforskar in- och utenheter, analoga och digitala signaler samt Arduinobibliotek och funktioner. Följ med in i elektronikens värld – nu börjar vi!
Komponenter i projektet

Arduino UNO
KY-023 Joystick
20x4 LCD
Anslutningskablar som passar kontakterna
Anslutningskablar
Kopplingsdäck

 

Här är en kort förklaring av komponenterna:

  1. 20x4 LCD-skärm: En alfanumerisk skärm med 4 rader och 20 tecken per rad. I2C-adaptern låter den kommunicera med Arduino och visa text och symboler med färre anslutningar. 
  2. Arduino Uno: Arduino Uno är mikrokontrollerkortet som återigen fungerar som projektets hjärna. Det styr LCD-skärmen och behandlar joystickens indata med programmerad logik.
  3. Kablar till LCD-skärmen: Välj kablar efter hårdvaran. En skärm med hanstift behöver normalt hona-hane-kablar direkt till UNO:s honkontakter; hona-hona-kablar passar bara när båda ändarna har hanstift.
  4. Övriga anslutningskablar: De kopplar ihop Arduino Uno, joysticken och övriga punkter i kretsen. De är flexibla och lätta att ansluta och koppla loss.
  5. KY-023-joystick: Huvudingången använder analoga signaler för x/y-rörelse och en digital tryckknapp. Det är en joystickmodul av PS2-typ som är enkel att ansluta och använda.
  6. Kopplingsdäck: Ett kopplingsdäck ger tillfälliga förbindelser mellan elektroniska komponenter och gör dem lätta att organisera och ansluta under utvecklingen.

Komponenterna räcker för skrivverktyget och för att utforska skrivning och redigering med joystick och LCD.

KY-023

Låt oss titta närmare på joysticken i projektet, en KY-023-joystick. Det är en kompakt och mångsidig inmatningsenhet med två axlar och en tryckknapp.

 

Den har två analoga axlar, VRx och VRy, som registrerar vågrät och lodrät rörelse. Spänningarna varierar med joystickens läge. Genom att läsa dem bestämmer vi riktningen.

Den har också en tryckknapp, kallad SW, som används som en digital ingång. Den visar om knappen är nedtryckt och möjliggör programmerade åtgärder.

 

  1. 5V: Matningsstiftet ansluts till en +5V-källa på Arduino-kortet eller en annan lämplig matningsmodul för att driva joysticken.
  2. VRx: Den analoga x-utgången ger en spänning som beror på det vågräta läget. Anslut den till en analog ingång på Arduino-kortet.
  3. VRy: Den analoga y-utgången varierar med det lodräta läget. Anslut den till en annan analog ingång på Arduino-kortet.
  4. SW: SW är knappkontakten. Med pull-up aktiverad läser Arduino HIGH när knappen är släppt och LOW när den trycks. Anslut SW till en digital ingång på Arduino-kortet.


Nu när vi förstår joysticken går vi igenom kretsens anslutningar.

 

Projektets krets

Kretsen är ganska enkel. Anslut 20x4 LCD-skärmen och Arduino Uno som i bloggen om ultraljudsmätning: GND till GND, VCC till 5V, SDA till A4 och SCL till A5 på klassiska UNO. Anslutningen till Arduino Uno låter oss skriva och visa text i realtid.

För joysticken ansluter vi först SW till stift 2Arduino Uno. Det registrerar knapptryckningar. Anslut också joystickens GND till Arduino GND.

För att försörja joysticken ansluter vi VCC på joysticken till 5VArduino Uno. Det ger matningsspänningen.

Till sist ansluts joystickens VRx till A0Arduino Uno och VRy till A1Arduino Uno. Anslutningarna läser de analoga rörelsevärdena. Figuren nedan visar kretsen.

 


Koden

Även om kretsen är enkel är koden seriens mest avancerade hittills. Den hanterar joystickens indata och styr LCD-skärmen i realtid med analoga ingångar, villkor, loopar och LCD-styrning

Här är koden. Vi går igenom den rad för rad.

#include <Wire.h>               // Inkluderer Wire biblioteket, der bruges til I2C kommunikation
#include <LiquidCrystal_I2C.h>  // Inkluderer LiquidCrystal_I2C biblioteket til styring af I2C LCD

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7);  // Initialiserer et LiquidCrystal_I2C objekt til at styre LCD

const int VRx = 0;        // Definerer VRx pinnummeret til joystickens x-retning
const int VRy = 1;        // Definerer VRy pinnummeret til joystickens y-retning
const int switchPin = 2;  // Definerer switchPin pinnummeret til joystickens knap
int LCDpos80 = 0;         // Initialiserer variablen LCDpos80 til at holde styr på LCD positionen
bool flip = true;         // En variabel til at skifte mellem at vise og skjule markøren


char line[4][21] = {
  // En todimensional array til at opbevare teksten til hver række på LCD
  "|Hello!             ",  // Første række
  "|You can            ",  // Anden række
  "|write anything     ",  // Tredje række
  "|on this display    "   // Fjerde række
};


void setup() {
  lcd.begin(20, 4);                  // Initialiserer LCD-displayet med 20 tegn pr. linje og 4 linjer
  lcd.setBacklightPin(3, POSITIVE);  // Sætter bagbelysningspin til ben 3 og polaritet som positiv
  lcd.setBacklight(HIGH);            // Tænder for bagbelysningen
  pinMode(switchPin, INPUT);         // Sætter switchPin til input-tilstand
  digitalWrite(switchPin, HIGH);     // Aktiverer den interne pull-up modstand på switchPin

  line[0][19] = '|';  // Indsætter et lodret linjetegn i slutningen af første række
  line[1][19] = '|';  // Indsætter et lodret linjetegn i slutningen af anden række
  line[2][19] = '|';  // Indsætter et lodret linjetegn i slutningen af tredje række
  line[3][19] = '|';  // Indsætter et lodret linjetegn i slutningen af fjerde række
}


void checkJoy() {
  static unsigned long buttonPressStartTime = 0;
  bool buttonPressed = (digitalRead(switchPin) == LOW);

  // Justér positionen til venstre eller højre baseret på VRx-værdien
  if (analogRead(VRx) < 175 && LCDpos80 > 0) {
    LCDpos80--;
  } else if (analogRead(VRx) > 530 && LCDpos80 < 79) {
    LCDpos80++;
  }

  // Justér værdien i den aktuelle placeholder op eller ned baseret på VRy-værdien
  if (LCDpos80 >= 0 && LCDpos80 <= 79) {
    if (analogRead(VRy) < 175 && line[LCDpos80 / 20][LCDpos80 % 20] < 127) {
      line[LCDpos80 / 20][LCDpos80 % 20]++;
    } else if (analogRead(VRy) > 530 && line[LCDpos80 / 20][LCDpos80 % 20] > 32) {
      line[LCDpos80 / 20][LCDpos80 % 20]--;
    }
  }

  // Hvis knappen er trykket ned, gemmes starttiden for knaptrykket
  if (buttonPressed && buttonPressStartTime == 0) {
    buttonPressStartTime = millis();  // Gem starttiden for knaptrykket
  }

  // Hvis knappen er sluppet og der er registreret en starttid for knaptrykket
  if (!buttonPressed && buttonPressStartTime != 0) {
    unsigned long buttonPressDuration = millis() - buttonPressStartTime;
    buttonPressStartTime = 0;  // Nulstil starttiden for knaptrykket


    // Hvis knappen er holdt nede i mindst 1 sekund
    if (buttonPressDuration >= 1000) {
      // Ryd hele displayet
      for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 20; j++) {
          line[i][j] = ' ';
        }
      }
    }
    // Hvis knappen slippes inden for 1 sekund og positionen er inden for gyldigt område
    else if (buttonPressDuration < 1000 && LCDpos80 >= 0 && LCDpos80 <= 79) {
      // Ryd den aktuelle placeholder
      line[LCDpos80 / 20][LCDpos80 % 20] = ' ';
    }
  }
}


void LCD() {                // Funktion til at opdatere LCD-displayet
  int row = LCDpos80 / 20;  // Beregn rækken baseret på værdien af LCDpos80
  int col = LCDpos80 % 20;  // Beregn kolonnen baseret på værdien af LCDpos80

  lcd.setCursor(0, 0);  // Sæt markøren til (0, 0) (øverste venstre hjørne)
  lcd.print(line[0]);   // Udskriv indholdet af line[0] i LCD-displayet

  lcd.setCursor(0, 1);  // Sæt markøren til (0, 1) (anden række)
  lcd.print(line[1]);   // Udskriv indholdet af line[1] i LCD-displayet

  lcd.setCursor(0, 2);  // Sæt markøren til (0, 2) (tredje række)
  lcd.print(line[2]);   // Udskriv indholdet af line[2] i LCD-displayet

  lcd.setCursor(0, 3);  // Sæt markøren til (0, 3) (fjerde række)
  lcd.print(line[3]);   // Udskriv indholdet af line[3] i LCD-displayet

  if (flip) {
    lcd.setCursor(col, row);  // Sæt markøren til den aktuelle position (col, row)
    lcd.print('_');           // Udskriv et understregningstegn i LCD-displayet på den aktuelle position
  }

  flip = !flip;  // Skift værdien af flip-variablen
  delay(100);    // Vent i 100 millisekunder
}


void switchCategory() {
  static unsigned long pressStartTime = 0;
  unsigned long currentTime = millis();  // Deklarér variablen currentTime

  // Tjek om knappen er trykket ned og om den aktuelle placeholder er tom
  bool buttonPressed = (analogRead(VRy) > 530 && line[LCDpos80 / 20][LCDpos80 % 20] == ' ');

  // Hvis knappen er trykket ned og det er første gang, gemmes starttiden for trykket
  if (buttonPressed && pressStartTime == 0) {
    pressStartTime = currentTime;  // Gem starttiden for trykket
  }

  // Hvis knappen slippes og der er registreret en starttid for trykket
  if (!buttonPressed && pressStartTime != 0) {
    unsigned long pressDuration = currentTime - pressStartTime;  // Beregn varigheden af trykket
    pressStartTime = 0;                                          // Nulstil starttiden for trykket

    // Bestem kategorien baseret på trykkets varighed
    if (pressDuration >= 0 && pressDuration < 1000) {
      line[LCDpos80 / 20][LCDpos80 % 20] = 'A';  // Kategori A
    } else if (pressDuration >= 1000 && pressDuration < 2000) {
      line[LCDpos80 / 20][LCDpos80 % 20] = 'a';  // Kategori a
    } else if (pressDuration >= 2000 && pressDuration < 3000) {
      line[LCDpos80 / 20][LCDpos80 % 20] = '1';  // Kategori 1
    } else if (pressDuration >= 3000 && pressDuration < 4000) {
      line[LCDpos80 / 20][LCDpos80 % 20] = '.';  // Kategori .

      // Tilføj flere betingelser for yderligere kategorier efter behov
    }
  }
}


void loop() {        // Hovedløkken for programmet
  checkJoy();        // Kald checkJoy-funktionen for at håndtere joystick-input
  LCD();             // Kald LCD-funktionen for at opdatere LCD-displayet
  switchCategory();  // Kald switchCategory-funktionen for at skrive hurtigere
}

 

Låt oss titta närmare på koden...

#include <Wire.h>           	// Vi inkluderer Wire-biblioteket, som giver os mulighed for at kommunikere via I2C-protokollen.
#include <LiquidCrystal_I2C.h>  // Vi inkluderer LiquidCrystal_I2C-biblioteket, der giver os funktioner til at styre vores I2C-LCD.

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7);  // Vi initialiserer et LiquidCrystal_I2C-objekt med den specifikke I2C-adresse (0x27) og tilsluttede pins på Arduinoen (2, 1, 0, 4, 5, 6, 7). Dette objekt vil blive brugt til at styre vores LCD-display

Avsnittet inkluderar biblioteken för I2C-skärmen och skapar ett objekt, lcd, av typen LiquidCrystal_I2C . Det anger även anslutna stift. Med biblioteken och objektet kan vi styra skärmen och visa text.

 

 

const int VRx = 0;    	// Vi definerer VRx som variabel og tildeler den pinnummeret (0) til joystickens x-retning.
const int VRy = 1;    	// Vi definerer VRy som variabel og tildeler den pinnummeret (1) til joystickens y-retning.
const int switchPin = 2;  // Vi definerer switchPin som variabel og tildeler den pinnummeret (2) til joystickens knap.
int LCDpos80 = 0;     	// Vi initialiserer variablen LCDpos80 til 0 for at holde styr på LCD'ens position.
bool flip = true;     	// Vi opretter en boolsk variabel ved navn "flip" og tildeler den værdien "true". Denne variabel bruges til at skifte mellem at vise og skjule markøren.

Raderna definierar och initierar variabler för joystick och LCD. VRx är stiftnumret för joystickens x-axel, VRy är stiftnumret för joystickens y-axel, och switchPin är stiftnumret för joystickknappen.

 

Variabeln LCDpos80 håller reda på LCD-positionen och används senare för markörplacering.

flip är en boolesk variabel som börjar med true. Den ska växla mellan att visa och dölja LCD-markören senare i koden.

 

char line[4][21] = {
  // En todimensional array til at opbevare teksten til hver række på LCD
  "|Hello!         	",  // Første række
  "|You can        	",  // Anden række
  "|write anything 	",  // Tredje række
  "|on this display	"   // Fjerde række
};
Här deklareras en tvådimensionell array som heter line. Den lagrar texten för varje LCD-rad.

Arrayen line[4][21] har fyra rader med 21 byte: 20 tecken plus nollterminering per rad, totalt 84 byte. Den tidigare deklarationen med 80 rader använde 1680 byte utan att använda de extra raderna. Alla radåtkomster är begränsade till 0–3, så huvudexemplet och utdragen har rättats till fyra rader.

De första fyra raderna innehåller text. Varje sträng omges av citattecken (") och poster skiljs med kommatecken (,). Varje post representerar en LCD-rad.

Redigera arrayen för egen text. Varje synlig rad har högst 20 tecken plus en avslutande nollbyte.

Det initierar LCD-texten så att den kan redigeras senare.


 

void setup() {
  lcd.begin(20, 4);              	// Initialiserer LCD-displayet med 20 tegn pr. linje og 4 linjer
  lcd.setBacklightPin(3, POSITIVE);  // Sætter bagbelysningspin til ben 3 og polaritet som positiv
  lcd.setBacklight(HIGH);        	// Tænder for bagbelysningen
  pinMode(switchPin, INPUT);     	// Sætter switchPin til input-tilstand
  digitalWrite(switchPin, HIGH); 	// Aktiverer den interne pull-up modstand på switchPin

  line[0][19] = '|';  // Indsætter et lodret linjetegn i slutningen af første række
  line[1][19] = '|';  // Indsætter et lodret linjetegn i slutningen af anden række
  line[2][19] = '|';  // Indsætter et lodret linjetegn i slutningen af tredje række
  line[3][19] = '|';  // Indsætter et lodret linjetegn i slutningen af fjerde række
}
2 / 2
I setup()-funktionen udføres den indledende konfiguration og initialisering af vores projekt. Lad os gennemgå koden linje for linje:
cpp
void setup() {
  lcd.begin(20, 4);                  // Initialiserer LCD-displayet med 20 tegn pr. linje og 4 linjer
  lcd.setBacklightPin(3, POSITIVE);  // Sætter bagbelysningspin til ben 3 og polaritet som positiv
  lcd.setBacklight(HIGH);            // Tænder for bagbelysningen
  pinMode(switchPin, INPUT);         // Sætter switchPin til input-tilstand
  digitalWrite(switchPin, HIGH);     // Aktiverer den interne pull-up modstand på switchPin

  line[0][19] = '|';  // Indsætter et lodret linjetegn i slutningen af første række
  line[1][19] = '|';  // Indsætter et lodret linjetegn i slutningen af anden række
  line[2][19] = '|';  // Indsætter et lodret linjetegn i slutningen af tredje række
  line[3][19] = '|';  // Indsætter et lodret linjetegn i slutningen af fjerde række
}

I setup()-funktionen gör vi följande:

  1. lcd.begin(20, 4);: Initiera LCD:n genom att anropa begin()lcd-objektet med 20 tecken per rad och 4 rader.
  2. lcd.setBacklightPin(3, POSITIVE);: I bibliotekets mappning syftar 3 på I2C-expanderns bit för bakgrundsbelysning, inte Arduino-stift 3. POSITIVE anger aktiv polaritet; kontrollera adapterkortets koppling.
  3. lcd.setBacklight(HIGH);: Slå på bakgrundsbelysningen genom att anropa setBacklight() med argumentet HIGH.
  4. pinMode(switchPin, INPUT);: Ställ in switchPin som ingång med pinMode() med stiftnummer och läge.
  5. digitalWrite(switchPin, HIGH);: Aktivera intern pull-up på switchPin med digitalWrite() med stiftnummer och värdet HIGH. Ingången är HIGH när knappen är släppt.

De fyra sista raderna i setup() visar hur starttexten ändras. Ett lodrätt streck (|) i slutet av var och en av de fyra första raderna i line ändrar startvisningen. Det skapar en visuell avdelare och anpassar presentationen. Prova olika texter och layouter.

 

 

void checkJoy() {
  static unsigned long buttonPressStartTime = 0;
  bool buttonPressed = (digitalRead(switchPin) == LOW);

  // Justér positionen til venstre eller højre baseret på VRx-værdien
  if (analogRead(VRx) < 175 && LCDpos80 > 0) {
	LCDpos80--;
  } else if (analogRead(VRx) > 530 && LCDpos80 < 79) {
	LCDpos80++;
  }

checkJoy()-funktionen övervakar rörelse och knapptryck. Först skapas en statisk variabel, buttonPressStartTime, för att lagra när ett tryck börjar.

Sedan skapas en boolesk variabel, buttonPressed, som anger om switchPin läses som LOW.

Ett villkor kontrollerar sedan om joystickens VRx (x-axel) är under 175 och LCDpos80 (LCD-position) är större än 0, flytta LCDpos80 åt vänster genom att minska värdet med 1. Markören flyttas åt vänster.

På samma sätt, om VRx är över 530 och LCDpos80 är mindre än 79, flytta LCDpos80 åt höger genom att öka värdet med 1. Det flyttar markören åt höger.

Det låter användaren flytta markören åt vänster eller höger med x-axeln.

Trösklarna 175 og 530 kan anpassas till joystickens uppmätta mittläge/dödzon. Markörens upprepningshastighet beror också på looptiden, inte bara trösklarna.

 

 

// Justér værdien i den aktuelle placeholder op eller ned baseret på VRy-værdien 
if (LCDpos80 >= 0 && LCDpos80 <= 79) 
 { if (analogRead(VRy) < 175 && line[LCDpos80 / 20][LCDpos80 % 20] < 127) { line[LCDpos80 / 20][LCDpos80 % 20]++; } 
 else if (analogRead(VRy) > 530 && line[LCDpos80 / 20][LCDpos80 % 20] > 32) { line[LCDpos80 / 20][LCDpos80 % 20]--;
 } 
}

Det här avsnittet av checkJoy()-funktionen behandlar joystickens VRy (y-axel) för att ändra tecknet vid aktuell LCD-position.

Kontrollera först att LCDpos80 är inom det tillåtna positionsområdet (0-79). Det begränsar ändringarna till den synliga skärmen.

Nästa villkor beror på joystickens VRy-värde. Om VRy är under 175 och aktuellt teckenvärde (line[LCDpos80 / 20][LCDpos80 % 20]) är under 127 (kodens övre gräns; ASCII 127 är DEL, inget skrivbart tecken),öka det med 1. Det ökar teckenkoden. LCD:ns faktiska symboler beror på dess tecken-ROM.

På samma sätt, om VRy är över 530 och teckenvärdet är större än 32 (ASCII-koden för blanksteg som används som nedre gräns),minska det med 1. Det går till föregående teckenkod.

Ändringarna låter användaren ändra aktuellt tecken med y-axeln.


tegn på LCD-displayet opad eller nedad ved at bevæge joystickens y-retning.
// Hvis knappen er trykket ned, gemmes starttiden for knaptrykket
  if (buttonPressed && buttonPressStartTime == 0) {
	buttonPressStartTime = millis();  // Gem starttiden for knaptrykket
  }

  // Hvis knappen er sluppet og der er registreret en starttid for knaptrykket
  if (!buttonPressed && buttonPressStartTime != 0) {
	unsigned long buttonPressDuration = millis() - buttonPressStartTime;
	buttonPressStartTime = 0;  // Nulstil starttiden for knaptrykket
	// Hvis knappen er holdt nede i mindst 1 sekund
	if (buttonPressDuration >= 1000) {
  	// Ryd hele displayet
  	for (int i = 0; i < 4; i++) {
    	for (int j = 0; j < 20; j++) {
      	line[i][j] = ' ';
    	}
  	}
	}
	// Hvis knappen slippes inden for 1 sekund og positionen er inden for gyldigt område
	else if (buttonPressDuration < 1000 && LCDpos80 >= 0 && LCDpos80 <= 79) {
  	// Ryd den aktuelle placeholder
  	line[LCDpos80 / 20][LCDpos80 % 20] = ' ';
	}
  }
}

Den sista delen av checkJoy()-funktionen hanterar knapptryck och deras längd:

Kontrollera först om knappen är nedtryckt (buttonPressed) och ingen starttid är sparad (kontroll av starttid: buttonPressStartTime == 0). Spara då aktuell tid med millis().

Kontrollera sedan om knappen har släppts (!buttonPressed) och en starttid finns (buttonPressStartTime != 0). Då beräknas tryckets längd genom att dra starttiden från aktuell tid (millis() - buttonPressStartTime). Nollställ sedan starttiden (buttonPressStartTime = 0).

Om knappen hölls nere i minst 1 sekund (buttonPressDuration >= 1000), raderas all visad text genom att sätta varje position i varje rad till blanksteg (' ').

Om knappen i stället släpptes inom 1 sekund (buttonPressDuration < 1000) och markörpositionen är giltig (LCDpos80 >= 0 && LCDpos80 <= 79), raderas bara aktuellt tecken genom att sätta det till blanksteg (' ').

Det hanterar knapptryck olika beroende på längd och aktuell markörposition.

 

 

void LCD() {            	// Funktion til at opdatere LCD-displayet
  int row = LCDpos80 / 20;  // Beregn rækken baseret på værdien af LCDpos80
  int col = LCDpos80 % 20;  // Beregn kolonnen baseret på værdien af LCDpos80
  lcd.setCursor(0, 0);  // Sæt markøren til (0, 0) (øverste venstre hjørne)
  lcd.print(line[0]);   // Udskriv indholdet af line[0] i LCD-displayet
  lcd.setCursor(0, 1);  // Sæt markøren til (0, 1) (anden række)
  lcd.print(line[1]);   // Udskriv indholdet af line[1] i LCD-displayet
  lcd.setCursor(0, 2);  // Sæt markøren til (0, 2) (tredje række)
  lcd.print(line[2]);   // Udskriv indholdet af line[2] i LCD-displayet

  lcd.setCursor(0, 3);  // Sæt markøren til (0, 3) (fjerde række)
  lcd.print(line[3]);   // Udskriv indholdet af line[3] i LCD-displayet
  if (flip) {
	lcd.setCursor(col, row);  // Sæt markøren til den aktuelle position (col, row)
	lcd.print('_');       	// Udskriv et understregningstegn i LCD-displayet på den aktuelle position
  }
  flip = !flip;  // Skift værdien af flip-variablen
  delay(100);	// Vent i 100 millisekunder
}
LCD() uppdaterar LCD:n med text från line[]. Så fungerar det:

Beräkna först aktuell rad och kolumn från LCDpos80. Raden är LCDpos80 / 20, och kolumnen är LCDpos80 % 20.

Använd sedan lcd.setCursor()-funktionen för att placera markören. För varje rad 0–3 sätts markören i början och motsvarande rad i line[] skrivs med lcd.print().

Efter utskrift kontrolleras flip. Om värdet är true flyttas markören till (col, row) med lcd.setCursor() och ett understreck ('_') skrivs där med lcd.print().

Till sist växlas flip genom negation (flip = !flip), så att markören växlar mellan synlig och dold på samma position. Vänta 100 millisekunder med delay(100) för den visuella effekten.

Det visar texten från line[] och blinkar en understrecksmarkör vid redigeringspositionen.

 

void switchCategory() {
  static unsigned long pressStartTime = 0;
  unsigned long currentTime = millis();  // Deklarér variablen currentTime

  // Tjek om knappen er trykket ned og om den aktuelle placeholder er tom
  bool buttonPressed = (analogRead(VRy) > 530 && line[LCDpos80 / 20][LCDpos80 % 20] == ' ');

  // Hvis knappen er trykket ned og det er første gang, gemmes starttiden for trykket
  if (buttonPressed && pressStartTime == 0) {
	pressStartTime = currentTime;  // Gem starttiden for trykket
  }

  // Hvis knappen slippes og der er registreret en starttid for trykket
  if (!buttonPressed && pressStartTime != 0) {
	unsigned long pressDuration = currentTime - pressStartTime;  // Beregn varigheden af trykket
	pressStartTime = 0;                                      	// Nulstil starttiden for trykket

	// Bestem kategorien baseret på trykkets varighed
	if (pressDuration >= 0 && pressDuration < 1000) {
  	line[LCDpos80 / 20][LCDpos80 % 20] = 'A';  // Kategori A
	} else if (pressDuration >= 1000 && pressDuration < 2000) {
  	line[LCDpos80 / 20][LCDpos80 % 20] = 'a';  // Kategori a
	} else if (pressDuration >= 2000 && pressDuration < 3000) {
  	line[LCDpos80 / 20][LCDpos80 % 20] = '1';  // Kategori 1
	} else if (pressDuration >= 3000 && pressDuration < 4000) {
  	line[LCDpos80 / 20][LCDpos80 % 20] = '.';  // Kategori .

  	// Tilføj flere betingelser for yderligere kategorier efter behov
	}
  }
}

switchCategory()-funktionen ändrar aktuell teckenkategori. Trots variabelnamnet buttonPressed använder funktionen VRy > 530 medan aktuellt tecken är ett blanksteg; den läser inte SW-knappen.

Initiera först pressStartTime för att lagra när axelvillkoret blir aktivt, och currentTime uppdateras med aktuell tid genom millis().

Kontrollera sedan om axelvillkoret är aktivt (buttonPressed) och aktuellt tecken är ett blanksteg (line[LCDpos80 / 20][LCDpos80 % 20] == ' ').

När villkoret blir aktivt första gången (pressStartTime == 0), sparas starttiden (pressStartTime = currentTime).

När villkoret inte längre är aktivt (!buttonPressed) och en starttid finns (pressStartTime != 0), beräknas längden genom att dra starttiden från aktuell tid (currentTime - pressStartTime). Nollställ sedan starttiden (pressStartTime = 0).

Välj kategori från längden. Om varaktigheten är mellan 0 og 1000 millisekunder sätts tecknet till 'A' (kategori A). Om varaktigheten är mellan 1000 og 2000 millisekunder sätts det till 'a' (kategori a), och så vidare för fler kategorier. Lägg till villkor om fler behövs.

Det väljer en startkategori efter hur länge y-axelvillkoret hålls och hjälper till att skriva teckengrupper snabbare. Det är inte kategoribyte med SW-knappen.

void loop() {    	// Hovedløkken for programmet
  checkJoy();    	// Kald checkJoy-funktionen for at håndtere joystick-input
  LCD();         	// Kald LCD-funktionen for at opdatere LCD-displayet
  switchCategory();  // Kald switchCategory-funktionen for at skrive hurtigere
}

 

loop()-funktionen är programmets återkommande huvudloop:

I loop() anropar tre funktioner:

  1. checkJoy()-funktionen hanterar indata: x-rörelse ändrar markörposition, y-rörelse ändrar tecken och SW-knappen raderar ett tecken eller all text enligt beskrivningen ovan.
  2. LCD()-funktionen uppdaterar LCD:n, placerar markören och skriver varje rad från line[] på rätt plats. Den blinkar också markören på aktuell position.
  3. switchCategory()-funktionen ger snabbare inmatning genom att välja en startkategori. Den mäter VRy-villkorets längd enligt ovan och skriver motsvarande tecken på aktuell position.

Loopen behandlar joystickindata, uppdaterar LCD:n och hanterar kategorival upprepade gånger. Testa samspelet och tidsförhållandena på den faktiska hårdvaran.


Guiden använde KY-023 och Arduino för att styra en LCD. Den enkla kretsen ledde till den mest utmanande koden hittills. Vi utforskade markörrörelse, teckenredigering och kategorival med joystick.

Vi hoppas att guiden var rolig och användbar. Joystickar erbjuder många möjligheter, så fortsätt utforska och experimentera. Lycka till med kodningen – vi ses i nästa projekt!

Lämna en kommentar

Observera att kommentarer måste godkännas innan de publiceras.