Inhoudsopgave:

BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie - Ajarnpa
BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie - Ajarnpa

Video: BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie - Ajarnpa

Video: BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie - Ajarnpa
Video: TFT Blueberry Breeze 2024, Juli-
Anonim
BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie
BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie
BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie
BluBerriSix - een TFT TouchScreen / Arduino-zelfstudie

2019 is het 20-jarig jubileum van de RIM Blackberry 850! Deze kleine Canadese uitvinding veranderde de manier waarop de wereld communiceert. Het is al lang voorbij, maar zijn erfenis gaat door!

In deze instructable leer je hoe je het MCUfriend.com 2,4-inch TFT-scherm voor de Uno/Mega gebruikt. Je leert hoe je grafische objecten en tekst kunt weergeven en hoe je aanrakingen kunt ontvangen en op de aanrakingsgebeurtenissen kunt reageren. scherm lijkt erg op Adafruit en andere TFT-schermen/schermen Dus als je hier bent, blijf dan in de buurt voor de show.

We zullen een vereenvoudigde 2-app-versie van mijn bluBerriSIX-schets bouwen.

Laten we beginnen!

Stap 1: BluBerriSIX - Overzicht

Image
Image
BluBerriSIX - Overzicht
BluBerriSIX - Overzicht
BluBerriSIX - Overzicht
BluBerriSIX - Overzicht

De bluBerriSIX-app is een TFT-project met zes functies.

Het bevat:

Een zaklamp

Een Saucy '7'-app (zoals een Magic '8' Ball)

Een rekenmachine

Een app voor afstandsmeting met behulp van de SR-04 ultrasone afstandssensor

Een app voor temperatuur en luchtvochtigheid die ook realtime gegevens registreert tot 1,5 km met de HC-12-transceiver

Een sms-app die HC-12 gebruikt.

Dit project kostte 1100 regels code. We zullen een aanzienlijk eenvoudigere versie bouwen die nog steeds TFT-display en aanraakgevoelige concepten demonstreert.

Stap 2: Wat is nodig?

Wat is er nodig?
Wat is er nodig?
Wat is er nodig?
Wat is er nodig?

- Een Arduino Uno of Mega 2560

- Een MCUfriend 2,4 TFT-schild

De volgende bibliotheken:

- Adafruit_GFX-bibliotheek

- Adafruit Touchscreen-bibliotheek

- MCUFRIEND_kbv bibliotheek

Deze bibliotheken kunnen worden geïnstalleerd met de Library Manager in de Arduino IDE.

Om een bibliotheek te laden, gaat u naar de menuoptie Schets -> Bibliotheek opnemen -> Bibliotheken beheren….

Voer in het veld 'filter uw zoekopdracht…' de eerste paar tekens van de naam van de bibliotheek in en selecteer en installeer vervolgens de juiste bibliotheek. Als u klaar bent, verlaat u dit scherm gewoon weer.

Wanneer u het TFT-scherm op de Uno/Mega monteert, WEES ZEER VOORZICHTIG om ervoor te zorgen dat u de pinnen correct uitlijnt. Ik heb mijn eerste schild verkeerd uitgelijnd en gebakken. Ik bracht twee weken van groeiende frustratie door met het zoeken naar de juiste bibliotheken voordat ik me realiseerde dat het scherm dood was. DOE VOORZICHTIG

Stap 3: Ons project

Ons project
Ons project
Ons project
Ons project
Ons project
Ons project
Ons project
Ons project

We zullen een eenvoudigere versie van de bluBerriSIX-schets bouwen.

Het zal hebben, - een opstartscherm

- een hoofdmenuscherm met twee knoppen

- een Saucy 7-app

- een vereenvoudigde tekstinvoer-app

U kunt ook terugkeren naar het hoofdmenu door op het 'Home'-pictogram in de linkerbenedenhoek van dit specifieke scherm te drukken. Als je zo'n pictogram niet hebt, hoef je alleen maar een 'thuis'-gebied van je scherm te definiëren. In deze zelfstudie leert u hoe u de aanraakgebieden op het scherm kunt bepalen.

Hoewel dit een vereenvoudigd project is, duurt het nog vrij lang. Ik zal in elke belangrijke fase versies van de Arduino-schetsen leveren, zodat je ze kunt uploaden als je dat wilt.

Stap 4: Headercode, globale variabelen, scherminstelling

Kopcode, globale variabelen, scherminstelling
Kopcode, globale variabelen, scherminstelling
Kopcode, globale variabelen, scherminstelling
Kopcode, globale variabelen, scherminstelling

Het hele project is goed gedocumenteerd. Maar de details volgen.

Start een nieuw Arduino-project en noem het 'tft-demo' of een andere naam die je maar wilt.

Het eerste codepaneel hierboven laat ons zien hoe we globale variabelen definiëren. We voegen ook de bibliotheken toe die we moeten gebruiken voor zowel de weergavefunctie van het scherm als de aanraakdetectie van het scherm.

We definiëren de analoge pinnen ook met verwijzing naar hun schermspecifieke doeleinden.

We definiëren het tft-object (display) en het ts-object (touch) als referenties voor hun respectievelijke functies.

We definiëren enkele 16-bits kleurconstanten om het gemakkelijk te maken om de kleuren voor het scherm en voor tekst- en grafische objecten weer te geven. U zult zien dat er een URL is naar een website met een kleurkiezer en converter om zichtbare kleuren om te zetten naar hun 16-bits hexadecimale waarden. Het is een erg handig hulpmiddel.

In het tweede codepaneel definiëren we de globale variabelen voor onze app-specifieke doeleinden.

De strings en arrays cString, letter en letterX en letterY worden gebruikt om a) de letters op de knoppen voor de app voor tekstinvoer weer te geven en b) de x- en y-coördinaten van een aanraking te matchen met de x- en y-coördinaten van elke respectieve letter op het toetsenbord. Meer hierover wanneer we bij dat gedeelte van de schets komen.

funcX, funcY en func zijn arrays die bepalen welke app-knop is ingedrukt in het hoofdmenuscherm en die informatie vervolgens gebruiken om de respectievelijke app te starten.

lastTouch en tThresh worden gebruikt in de aanraakmethoden om ervoor te zorgen dat we niet meerdere aanrakingen krijgen door te lang op het scherm te drukken. Daarover later meer.

De mode-variabele bepaalt welk scherm wordt weergegeven en de tMode-variabele bepaalt welke aanraakmethoden op een bepaald moment worden gebruikt.

In het setup()-blok openen we een serieel kanaal als we Serial.println()-opdrachten willen gebruiken voor foutopsporing. U hebt deze regel niet nodig als u Serial Monitor-foutopsporing niet wilt uitvoeren.

De volgende vier regels zijn slechts setup-code voor het tft-object.

Vervolgens stellen we de oriëntatie van het scherm in op de portretmodus.

De opdracht randomSeed() start gewoon de generator voor willekeurige getallen voor later gebruik door de Saucy 7-app.

Ten slotte noemen we de splashscreen-methode.

Stap 5: Het Spash-scherm bouwen en weergave versus Touch Mapping begrijpen

Het Spash-scherm bouwen en weergave versus Touch Mapping begrijpen
Het Spash-scherm bouwen en weergave versus Touch Mapping begrijpen
Het Spash-scherm bouwen en weergave versus Touch Mapping begrijpen
Het Spash-scherm bouwen en weergave versus Touch Mapping begrijpen

We beginnen nu met het bouwen van het spash-scherm.

Maar kijk eerst naar de afbeelding voor scherm- en aanraaktoewijzing. Merk op dat de oorsprong op verschillende locaties ligt. Voor weergave bevindt de oorsprong (0, 0) zich linksboven in het scherm (wanneer de RESET-knop bovenaan staat) en groeit van links naar rechts en van boven naar beneden.

Voor aanraakdetectie bevindt de oorsprong zich in de linkerbenedenhoek van het scherm en groeit van links naar rechts en van onder naar boven.

DISPLAY- EN TOUCH-KAARTEN ZIJN dus APART GEDEFINIEERD en hebben verschillende resoluties. Het scherm heeft een resolutie van 240 bij 320 en de touch heeft een veel hogere resolutie zoals je snel zult zien.

Ga naar een gebied van je schets onder de loop(){}-methode en we zullen de splash()-methodecode invoeren.

We beginnen met een opdracht fillScreen() om het scherm te vullen met de WITTE kleur die we in de kopcode hebben gedefinieerd.

Vervolgens zetten we de tekstgrootte op '5'. Dit is een relatief grote basistekstgrootte. We stellen de x- en y-positie voor de tekstcursor in en we stellen de tekstkleur in. Ten slotte tekent de opdracht print("TFT") de blauwe tekst ter grootte van '5' op de opgegeven positie.

Naarmate u de tekstgrootte vergroot, zult u zien dat de tekens steeds dikker worden. Dus boven de 5 gaan is waarschijnlijk niet nuttig. Aan het einde van deze tutorial laat ik je zien hoe je bitmaplettertypen gebruikt om mooiere tekst in je apps te krijgen. Het nadeel is dat het gebruik van bitmaplettertypensets veel geheugen in beslag neemt in je Arduino, wat je schetsgroottes beperkt

We herhalen vergelijkbare opdrachten voor de andere twee tekstitems op het opstartscherm.

Ten slotte vertragen we 2,5 seconden om de gebruiker de kans te geven de inhoud van het scherm te lezen voordat de app naar het hoofdmenuscherm gaat.

Ga je gang en upload deze schets naar je Arduino. Het zou het opstartscherm moeten weergeven.

Stap 6: een diagnostisch hulpmiddel voor aanraakkaarten maken

Een diagnostisch hulpmiddel voor aanraakkaarten maken
Een diagnostisch hulpmiddel voor aanraakkaarten maken
Een diagnostisch hulpmiddel voor aanraakkaarten maken
Een diagnostisch hulpmiddel voor aanraakkaarten maken

De methode showTouch() is erg handig om u te helpen de aanraakcoördinaten van verschillende delen van het scherm te krijgen. U moet dit doen om de aanraakgebieden voor uw knoppen te definiëren.

Ga je gang en voer deze methode in onder je splash()-methode die je eerder hebt gedaan.

Dit is hoe het werkt.

De if-instructie bepaalt of er voldoende tijd is verstreken sinds de laatste aanraking. Het neemt de huidige systeemtijd millis() en trekt de lastTouch-tijd af. Als het groter is dan de tThresh-waarde (200 milliseconden), accepteert het de aanraking. Anders worden onbedoelde multi-touch-gebeurtenissen genegeerd.

Vervolgens krijgt de opdracht getpoint() de x-, y- en z-coördinaten van de aanraking. De z-coördinaat is een maat voor de aanraakdruk.

Als de druk binnen de max- en min-constanten ligt die we in de schetskop hebben gedefinieerd, zal de methode eerst de YP- en XM-pinnen terugzetten naar OUTPUT, waardoor het scherm in de DISPLAY-modus wordt gezet.

Vervolgens zal het een witte rechthoek tekenen om eventuele coördinaten die eerder zijn weergegeven te wissen.

De schets stelt vervolgens het lettertype in op maat 2, zwarte kleur en geeft de x (p.x) en y (p.y) coördinaten weer op het scherm. U kunt deze locaties dan noteren om u te helpen bij het programmeren van uw aanraakzones voor uw eigen schetsen.

Het if-statement onderaan de methode controleert of de 'Home'-knop op het scherm is ingedrukt. de operators '<=' zorgen voor de breedte en hoogte van de Home-knop. De opgegeven coördinaten zijn de coördinaten van het x-centrum en het y-centrum van de Home-knop. Als deze wordt ingedrukt, wordt de modus ingesteld op 0, wat uiteindelijk 'Ga naar het hoofdmenuscherm' betekent. Daarover later meer.

Ten slotte werken we lastTouch bij naar de huidige systeemtijd millis() om ons voor te bereiden op een latere touch-gebeurtenis.

Ga nu naar het blok loop() en voeg de regel showTouch();

Upload nu je schets en probeer het. Het zal het opstartscherm tekenen en als u het scherm begint aan te raken, worden de TOUCH x- en y-coördinaten op het scherm weergegeven.

Laten we, voordat we verder gaan, nog eens kijken naar twee belangrijke coderegels:

pinMode (YP, UITGANG); // herstel de TFT-bedieningspinnen

pinMode (XM, OUTPUT);// voor weergave na detectie van een aanraking

Elke keer dat u iets op het scherm wilt weergeven, MOET u deze twee commando's uitvoeren om het scherm van TOUCH-modus naar DISPLAY-modus te veranderen. Anders werken uw weergaveopdrachten niet.

Goed gedaan tot nu toe! Neem een pauze!

Stap 7: Bouw het hoofdmenuscherm

Bouw het hoofdmenuscherm
Bouw het hoofdmenuscherm
Bouw het hoofdmenuscherm
Bouw het hoofdmenuscherm
Bouw het hoofdmenuscherm
Bouw het hoofdmenuscherm

We bouwen nu ons hoofdmenuscherm met twee knoppen die je kunt indrukken om elke app te activeren. De methode heet menuScreen().

We beginnen met het scherm in de DISPLAY-modus te zetten.

Vervolgens stellen we de lettergrootte, kleur en positie in en printen we de tekst 'Hoofdmenu'.

We tekenen nu twee rechthoeken die de knoppen zijn.

Alle grafische opdrachten hebben een vergelijkbare structuur:

graphicShape(x-coördinaat, y-coördinaat, breedte, hoogte, KLEUR)

- x-coördinaat - linksboven voor rechthoekige objecten, middelpunt voor cirkels

- y-coördinaat - linksboven voor rechthoekige objecten, middelpunt voor cirkels

- breedte - breedte van het object in pixels

- KLEUR - een kleurconstante die we in de kop hebben gedefinieerd

Ten slotte noemen we twee methoden om het Saucy 7-pictogram en het QWERTY-tekstinvoerpictogram te tekenen. Dat zijn aparte methoden.

De methode draw7icon(0) neemt een integer-parameter die de y-offset is voor het tekenen van de bal. We doen dit zodat we dezelfde methode kunnen gebruiken voor het tekenen van de bal op het menuscherm EN op het Saucy 7 app-scherm. De offset stelt ons alleen in staat om de y-coördinaat van de bal programmatisch naar boven of naar beneden aan te passen.

De methode draw7Ball(0) wordt aangeroepen vanuit draw7Icon(0). Er is ook een parameter voor nodig waarmee we de verticale positie van de bal kunnen aanpassen, afhankelijk van of we hem op het menuscherm of op het app-scherm tekenen.

De opdracht fillCircle() heeft 4 argumenten nodig.

- x-coördinaat van het middelpunt van de cirkel

- y-coördinaat van het middelpunt van de cirkel

- straal van de cirkel (in pixels)

- KLEUR - een kleurconstante die we in de kop hebben gedefinieerd

Ten slotte wordt de methode drawTextIcon() aangeroepen om het pictogram voor de app Tekstinvoer te tekenen.

U kunt proberen de methode uit te voeren door commentaar te geven op de methode splash() in setup() en menuScreen() toe te voegen.

Upload de schets naar je Arduino en probeer het uit!

Stap 8: De Saucy 7-app en de hoofdmenumethoden

De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden
De Saucy 7-app en de hoofdmenumethoden

De methode sevenScreen() tekent het scherm voor de app, inclusief het tekenen van de bal en het weergeven van de instructies.

De methode sevenInstr() geeft de instructies weer en wist het scherm van eerdere reacties. Het tekent ook de knop 'Reactie'.

De methode show7Response() zorgt ervoor dat de vorige antwoordmethode van het scherm wordt gewist, een geanimeerd 'denken…'-bericht wordt weergegeven en vervolgens het willekeurig gekozen antwoordbericht wordt weergegeven.

read7Touch() is de methode die wacht op een touch-gebeurtenis om het willekeurig gegenereerde bericht te produceren. De aanraakcode lijkt erg op de showTouch() diagnostische methode die eerder is beschreven. Voor de eenvoud accepteert de methode een aanraking overal op het scherm als de 'Reageren'-knop.

Bovenaan de methode definiëren we een array response van strings die de berichten zijn die kunnen worden gegenereerd op basis van een touch-gebeurtenis.

Als de Home-knop wordt ingedrukt, wordt de app beëindigd en wordt teruggekeerd naar het hoofdmenuscherm. Anders genereert de methode een willekeurig getal tussen 0 en 7 (exclusief) en geeft het bijbehorende tekstbericht van de array response door aan de methode show7Response().

Ten slotte let de backToMenu()-methode op een druk op de Home-knop en keert de controle terug naar het hoofdmenuscherm.

De methode readMenuTouch() let op een aanraakgebeurtenis wanneer u zich in het hoofdmenuscherm bevindt. Wanneer een aanraking wordt gedetecteerd, geeft het de x- en y-coördinaten door aan de getFunc(x, y)-methode die in de funcX- en funcY-arrays zoekt om overeen te komen met de x- en y-coördinaten van de aanraking. Het retourneert vervolgens het nummer uit de func-array voor de app die is geselecteerd. '1' is Saucy 7 en '2' is de app voor tekstinvoer. Vervolgens wordt de modus ingesteld op de waarde van die app, zodat de app wordt uitgevoerd.

Stap 9: Het Loop()-blok

Het Loop()-blok
Het Loop()-blok

We beginnen nu met het bouwen van de loop()-blokcode om het juiste scherm weer te geven en vervolgens de juiste aanraakmethoden aan te roepen op basis van de momenteel geselecteerde optie.

De methode loop() bestaat uit twee switch()-structuren.

De structuur van de bovenste schakelaar zorgt voor het weergeven van het juiste scherm, afhankelijk van welke optie is geselecteerd. Het stelt ook de tMode-waarde in voor de juiste aanraakmethode die moet worden uitgevoerd voor de huidige geselecteerde optie. Ten slotte stelt het de moduswaarde in op 9 zodat het scherm niet eindeloos opnieuw wordt getekend.

De structuur van de onderste schakelaar bepaalt welke aanraakmethoden worden uitgevoerd op basis van de door de gebruiker geselecteerde app-optie zoals weergegeven door de waarde van tMode.

Laad de schets in je Arduino en je zou de Saucy 7-app moeten kunnen selecteren en gebruiken.

Je hebt veel werk verzet! Even pauze:-)

Stap 10: de app voor tekstinvoer - we zijn in de thuissituatie

De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!
De app voor tekstinvoer - we zijn in de thuissituatie!

We zullen nu de methoden van de app voor tekstinvoer opnemen.

makeKbd() tekent het toetsenbord op het scherm.

Het tekent zes gevulde afgeronde rechthoeken en legt vervolgens de juiste letter op elke 'toets' door de letter uit de cString-reeks te halen die het op het scherm over de toets drukt. Merk op dat de voorlaatste parameter in een opdracht fillRoundedRect() de straal van elke hoek in pixels is. Hoe hoger deze waarde, hoe meer afgerond de hoeken.

De methode readKbdTouch() werkt vergelijkbaar met de andere aanraakdetectiemethoden.

Als een aanraking wordt gedetecteerd die NIET op de Home-knop staat, geeft het de x- en y-coördinaten door aan de curChar(x, y)-methode die het teken retourneert dat overeenkomt met die x- en y-locatie op het scherm. Het bericht dat is 'getypt' wordt vervolgens op het scherm weergegeven met behulp van de 'displayMsg(theChar)-methode.

De curChar(x, y)-methode doorzoekt de letterX- en letterY-arrays om een overeenkomst te vinden die dicht bij de x- en y-coördinaten ligt die zijn doorgegeven door readKbdTouch(). Als het een overeenkomst vindt, retourneert het de corresponderende letter naar de readKbdTouch-methode. Merk op dat we de variabele theChar initialiseren op 32, wat de ASCII-code is voor een spatie, ' '. We doen dit zodat als de gebruiker een gebied buiten het toetsenbord aanraakt, er geen niet-beschikbare tekens worden weergegeven.

De methode displayMsg(theChar) neemt het teken dat wordt geretourneerd uit curChar(x, y) en voegt het toe aan de msg-tekenreeks. Vervolgens wordt het bericht op het scherm weergegeven.

Ten slotte zullen we het loop()-blok bijwerken om de app-selectie voor tekstinvoer te accepteren.

Upload de tftDemo-schets naar je Arduino en je zou de voltooide app moeten kunnen gebruiken.

Gefeliciteerd! je hebt een TFT-touchscreen-app gebouwd! Neem de rest van de dag vrij!

Stap 11: Slick worden! - Adafruit Bitmap-lettertypen gebruiken in uw schets

De standaard tft-lettertypeset is in orde. Maar het is fijner als we de juiste bitmap-lettertypen kunnen gebruiken in onze TFT-schetsen.

Het nadeel is dat het laden van lettertypesets in het Arduino-geheugen veel ruimte in beslag neemt. Het is zelfs heel gemakkelijk om je schets te vullen met zoveel lettertypen dat hij niet in de Arduino wordt geladen.

De lettertypen zijn beschikbaar in de Adafruit_GFX-bibliotheekmap die u al voor dit project hebt geïnstalleerd. Een uitstekende tutorial over het gebruik van lettertypen staat op deze site.

Voeg in het koptekstgebied van uw schets de lettertypeverwijzing toe voor het lettertype dat u wilt gebruiken. Voor dit voorbeeld gebruiken we het lettertype FreeSerifBoldItalic18p7b.

#erbij betrekken

In uw splash()-methode, becommentarieert u de tft.setTextSize(); opdracht.

Voeg de volgende opdracht toe,

tft.setFont(&FreeSerifBoldItalic18pt7b);

Nu zullen alle print()-opdrachten het momenteel gespecificeerde lettertype gebruiken. Om naar een ander lettertype te gaan, gebruikt u een ander tft.setFont()-commando met het volgende lettertype dat u wilt gebruiken.

Om het lettertype terug te zetten naar het standaard tft-lettertype, gebruikt u gewoon een tft.setFont(); commando zonder parameter.

Upload de schets naar je Arduino en je zou moeten zien dat het opstartscherm nu het bitmap-lettertype gebruikt om de tekst op het scherm weer te geven. Je zult merken dat de schets aanzienlijk groter is nu je een lettertype hebt toegevoegd.

Stap 12: Laatste gedachten

Er zijn veel andere grafische objectopdrachten voor u beschikbaar. Ze bevatten:

tft.drawRect(x, y, breedte, hoogte, KLEUR);

tft.drawLine(x1, y1, x2, y2, KLEUR);

In de volgende voorbeelden wordt de methode tft.color565 gebruikt om u de kleur te laten specificeren op basis van rode, groene en blauwe waarden. Dit is een alternatieve manier voor het gebruik van de constant gedefinieerde HEX-kleurwaarden die we in onze schets hebben gebruikt.

tft.drawRoundRect(x, y, breedte, hoogte, straal, tft.color565(255, 0, 0)); // dit zou rood zijn

tft.drawCircle(x, y, straal, tft.color565(0, 255, 0)); // dit zou groen zijn

tft.drawTriangle(vertex1x, vertex1y, vertex2x, vertex2y, vertex3x, vertex3y, tft.color565(0, 0, 255)); // blauw

tft.fillTriangle(vertex1x, vertex1y, vertex2x, vertex2y, vertex3x, vertex3y, tft.color565(255, 0, 0);

Speel met deze opdrachten en ontdek hoe ze kunnen worden toegevoegd aan uw TFT-projecten.

Het leren gebruiken van een TFT-scherm is een uitdaging en je mag trots op jezelf zijn dat je de tijd hebt genomen om deze eerste stappen te leren.

TFT-schermen kunnen een aantrekkelijk en nuttig aspect van de grafische gebruikersinterface toevoegen aan uw Arduino-projecten.

Bedankt voor het doornemen van deze tutorial.

GA NU UIT EN MAAK IETS PRACHTIG!

Aanbevolen: