- Thuis
- Arduino-codering
- Arduino-kaart
Arduino-kaart
- Kaarten éénbereik van waardennaar een ander.
- Hetzou moeten werkenzoals je denkt...maar hetdoet niet!
- Mogelijk vindt u uwuitgangsbereik verpletterdaan het ene uiteinde!
- Er achter komenWaaromdat is zo.
- Ontdek het ookwat moeten we doenover het!
Waarom het misschien niet precies zo werkt als je denkt! De kaartfunctie is bedoeld om het ene bereik van waarden te veranderen in een ander bereik van waarden en een algemeen gebruik is het lezen van eenanaloge ingang(10 bits lang, dus waarden variëren van 0 tot 1023) en verander de uitvoer in een byte zodat de uitvoer van 0 tot 255 zou zijn.
TIP:De Arduino map()-functie kan van positieve naar negatieve bereiken converteren.
Je zou dan de volgende code schrijven
val = kaart(adc_val, 0, 1023, 0, 255);
Alles is in orde, 0 is gekoppeld aan 0 en 1023 is gekoppeld aan 255...
...met een gelijkmatige verdeling (echt?????).
De functie map() is handig, maar er zit een geheim in verborgen. Het is gemakkelijk genoeg om te gebruiken (althans dat denk je) totdat je er wat dieper naar binnen kijkt. Een gelijkmatige verdeling is wat je wilt, maar is dat ook echt zo?
Arduino-kaart testen
Laten we een schets schrijven om uit te testen wat het precies doet
leegte opgericht() { Serieel.beginnen(9600); voor (int bijvoeglijk naamwoord = 0; bijvoeglijk naamwoord < 1024; bijvoeglijk naamwoord++) { int in kaart gebracht = kaart(bijvoeglijk naamwoord, 0, 1023, 0, 255); Serieel.afdrukken(bijvoeglijk naamwoord); Serieel.afdrukken(','); Serieel.println(in kaart gebracht); }}leegte lus() {}
Eerste deel van de seriële uitvoer (i/p-waarde, o/p-waarde) | Laatste deel van de seriële uitvoer (i/p-waarde, o/p-waarde) |
0,0 1,0 2,0 3,0 | 1007.251 1008.251 1009.251 1010.251 |
4,0 5,1 6,1 7,1 | 1011.252 1012.252 1013.252 1014.252 |
8,1 9,2 10,2 11,2 | 1015.253 1016.253 1017.253 1018.253 |
12,2 13,3 14,3 15,3 | 1019.254 1020.254 1021.254 1022.254 |
1023,255 |
* Roze waarden geven aan dat de uitvoer 5 bakken beslaat in plaats van de vereiste 4.
* De waarde rood geeft de uiteindelijke fout aan, d.w.z. de laatste waarde wordt slechts één keer uitgevoerd.
In de tabel hierboven is de waarde links van de komma de adc-waarde, terwijl rechts de toegewezen uitvoerwaarde is.
Uit de bovenstaande tabel kunt u zien dat invoer wordt toegewezen aan uitvoerbereiken in blokken van 4 (1 uitvoerwaarde voor een bereik van 4 invoerwaarden). Dit wordt verwacht aangezien 1024/4 = 256.
Waarschuwing:De laatste uitvoer heeft slechts één uitvoerbak die overeenkomt met één invoer.
Het probleem is dat de uiteindelijke uitvoerwaarde (rood gemarkeerd) slechts 1 uitvoerbak heeft voor één invoerwaarde, d.w.z. 1023 resulteert in 255, terwijl 1019~1022 resulteert in 254 als uitvoer (4 invoerbakken). Wat je echt wilt is een gelijkmatige spreiding van waarden over het hele bereik.
Om dit punt te bereiken moeten sommige van de andere uitgangen 5 waarden als invoer hebben gehad (je kunt zien dat voor adc-waarden 0~4 - alle 5 ingangen resulteren in een invoer van een nul.
Schets: Arduino-kaartdistributie testen
Deze schets verhoogt de waarde in de bins-array elke keer dat de kaart een waarde retourneert - dus elke bins[] bevat het aantal keren dat een uitvoer is gemaakt.
#define MONSTERS 1024#define UITGANGEN 256int bakken[UITGANGEN];const int bakformaat = (MONSTERS-1)/(UITGANGEN-1);leegte opgericht() { Serieel.beginnen(9600); Serieel.println("Arduino-kaartuitvoerdistributie"); Serieel.afdrukken("Afmeting bak: "); Serieel.println(bakformaat); // Initialiseer bakken voor (int i = 0; i < UITGANGEN; i++) bakken[i]=0; voor (int bijvoeglijk naamwoord = 0; bijvoeglijk naamwoord < MONSTERS; bijvoeglijk naamwoord++) { int in kaart gebracht = kaart(bijvoeglijk naamwoord, 0, MONSTERS-1, 0, UITGANGEN-1); bakken[in kaart gebracht] +=1; } voor(int i=0;i<UITGANGEN;i++) { Serieel.afdrukken("Bin:"); Serieel.afdrukken(i); Serieel.afdrukken(" graaf "); Serieel.afdrukken(bakken[i]); // Toon bin-distributiefout als ((bakken[i] != bakformaat)) { Serieel.println(" ***") ; } anders Serieel.println(); } // Vind het verkeerde aantal bakken voor(int i=0;i<UITGANGEN;i++) { als (bakken[i]!=bakformaat) { Serieel.afdrukken("Bin-fout:"); Serieel.println(i); } }}leegte lus() {}
Het laatste deel van de uitvoer toont vier bakken met verkeerde waarden:
Bin: 253 aantal 4Bin: 254 aantal 4Bin: 255 aantal 1 ***Bin-fout: 0Bin-fout: 85Bin-fout: 170Bin-fout: 255
Dus waarom de fout voor de Arduino-kaart?
Dearduino map() referentieheeft dit te zeggen:
"Zoals eerder vermeld, gebruikt de functie map() wiskunde met gehele getallen. Sofracties kunnen hierdoor onderdrukt worden. Breuken zoals 3/2, 4/3, 5/4 worden bijvoorbeeld allemaal geretourneerd als 1 van de functie map() ondanks hun verschillende werkelijke waarden. Dus als uw project nauwkeurige berekeningen vereist (bijvoorbeeld een spanning die nauwkeurig is tot op 3 decimalen), overweeg dan om map() te vermijden en de berekeningen zelf handmatig in uw code te implementeren."
Het probleem is dat de bovenste waarde van 1023 niet precies deelbaar is door 255, dus je krijgt een kleine fout. Het is dus een fractie die onderdrukt wordt.
De code voor de functie is:
lange kaart(lange x, lang in_min, lang in_max, lang uit_min, lang uit_max) {
retour (x - in_min) * (uit_max - uit_min) / (in_max - in_min) + uit_min;
}
De berekeningen zijn
0 *255/1023 = 01 *255/1023 = 02 *255/1023 = 03 *255/1023 = 04 *255/1023 = 05 *255/1023 = 11022 * 255/1023 = 2541023 * 255/1023 = 255
Deze komen overeen met de Arduino-uitgangen.
Kijkend naar een eenvoudiger uitvoer
Het probleem wordt nog duidelijker.
als je 1023 toewijst aan het uitvoerbereik 0 tot 7, wordt het probleem nog duidelijker.
Wijzig de code in de vorige schets en definieer 'OUTPUTS' opnieuw als 8.
De uitvoer wordt dan:
Arduino-kaartuitvoerverdelingBin-grootte: 146Bin: 0 telling 147 ***Bin: 1 telling 146Bin: 2 telling 146Bin: 3 telling 146Bin: 4 telling 146Bin: 5 telling 146Bin: 6 telling 146Bin: 7 telling 1 ***Bin fout: 0Bin fout: 7
Als je probeert een ADC-ingang in kaart te brengen met behulp van een potentiometer om een 8LED-staafdiagram te besturen, is de enige keer dat de laatste LED oplicht, wanneer de ingang 1023 is!
Hoe het op te lossen
Om dit probleem op te lossen, maakt u de waarden een veelvoud van een macht van 2, zodat de breuk niet wordt onderdrukt.
Oplossing:Stel de maximale invoerwaarde in als een veelvoud van een macht van 2.
Let op: Voor verschillende bereiken moet het verschil tussen max en min een macht van 2 zijn.
Het volgende programma gebruikt de macht van 2 waarden als invoer en toont de gecorrigeerde uitvoer.
//#define NUM_SAMPLES 1024 // Moet een macht van 2 zijn (bereik 0-1023)//#define NUM_OUTPUTS 256 // Moet een macht van 2 zijn (bereik 0-255)#define NUM_SAMPLES 1024// Moet een macht van 2 zijn (bereik 0-1023)#define NUM_OUTPUTS 8// Moet een macht van 2 zijn (bereik 0-7)#define NUM_BINS (NUM_OUTPUTS)int bakken[NUM_BINS];const int bakformaat = (NUM_MONSTERS)/(NUM_OUTPUTS);leegte opgericht() { Serieel.beginnen(9600); Serieel.println("Arduino-kaartuitvoerdistributie"); Serieel.afdrukken("Afmeting bak: "); Serieel.println(bakformaat); // Initialiseer bakken voor (int i = 0; i < NUM_BINS; i++) bakken[i]=0; voor (int bijvoeglijk naamwoord = 0; bijvoeglijk naamwoord < NUM_MONSTERS; bijvoeglijk naamwoord++) { int in kaart gebracht = kaart(bijvoeglijk naamwoord, 0, NUM_MONSTERS, 0, NUM_OUTPUTS); bakken[in kaart gebracht] +=1; } voor(int i=0;i< NUM_BINS;i++) { Serieel.afdrukken("Bin:"); Serieel.afdrukken(i); Serieel.afdrukken(" graaf "); Serieel.afdrukken(bakken[i]); // Toon bin-distributiefout als ((bakken[i] != bakformaat)) { Serieel.println(" ***") ; } anders Serieel.println(); } // Vind het verkeerde aantal bakken voor(int i=0;i< NUM_BINS;i++) { als (bakken[i]!=bakformaat) { Serieel.afdrukken("Bin-fout:"); Serieel.println(i); } }}leegte lus() {}
Uitvoerresultaten: voor NUM_SAMPLES = 1024, NUM_OUTPUTS = 8
Arduino-kaartuitvoerverdelingBin-grootte: 128Bin: 0 tellen 128Bin: 1 tellen 128Bin: 2 tellen 128Bin: 3 tellen 128Bin: 4 tellen 128Bin: 5 tellen 128Bin: 6 tellen 128Bin: 7 tellen 128
Let op: Het eerste voorbeeld is ook gecorrigeerd met een gelijkmatige spreiding van 4 invoerwaarden per uitvoer.
Een ander voorbeeld
Hier is nog een voorbeeld met willekeurige steekproeven en uitvoer, dat wil zeggen niet-macht van 2 waarden.
#define MONSTERS 1976
#define UITGANGEN 153
Hier is 1976/153 = 12,91 en elke bak bevat 13 waarden, behalve de laatste die er één heeft. Het algoritme heeft het dus ongeveer bij het juiste eind.
Eerste deel van de seriële uitvoer | Laatste deel van de seriële uitvoer |
Bak: 0 telling 13 ***Bak: 1 telling 13 ***Bak: 2 telling 13 ***Bak: 3 telling 13 ***Bak: 4 telling 13 ***Bak: 5 telling 13 ***Bak: 6 tellen 13 ***Bak: 7 tellen 13 *** | Bak: 145 tellen 13 ***Bak: 146 tellen 13 ***Bak: 147 tellen 13 ***Bak: 148 tellen 13 ***Bak: 149 tellen 13 ***Bak: 150 tellen 13 ***Bak: 151 tellen 12Bin: 152 tellen 1 *** |
Omdat het zo lastig is om precies goed te werken, is het waarschijnlijk beter om een van de volgende dingen te doen.
- Maak je geen zorgen over de fout- het is alleen klein als de in kaart gebrachte waarde redelijk groot is in vergelijking met de invoer - maar onthoud dat de laatste uitvoerwaarde slechts één keer wordt gegenereerd.
- Gebruik een drijvende-kommaberekening- maar zal langzamer zijn en meer geheugen gebruiken.
- Vermijd het gebruik van map()- Gebruik bijvoorbeeld voor een ADC-conversie naar 0 naar 255 gewoon de bovenste 8 bits van het resultaat - gebruik hiervoor de functieanalogReadResolution().
×
Bovenaan de pagina
Arduino-kaart
Arduino-kaart testen
Schets: Arduino-kaartdistributie testen
Dus waarom de fout voor de Arduino-kaart?
Kijkend naar een eenvoudiger uitvoer
Hoe het op te lossen
Conclusie van de Arduino-kaart
Opmerkingen
Geef uw mening over wat u zojuist heeft gelezen! Laat een reactie achter in het onderstaande vak.
Zie je het opmerkingenveld niet? Log in op uw Facebook-account, geef Facebook toestemming, keer terug naar deze pagina en vernieuw deze.
Sitemap|Gebruiksvoorwaarden