Arduino-kaart - wijs een waarde toe van het ene bereik naar het andere (2023)

  1. Thuis
  2. Arduino-codering
  3. 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.

Privacybeleid|Contact|Over mij

Sitemap|Gebruiksvoorwaarden

References

Top Articles
Latest Posts
Article information

Author: Greg Kuvalis

Last Updated: 02/07/2023

Views: 6400

Rating: 4.4 / 5 (75 voted)

Reviews: 82% of readers found this page helpful

Author information

Name: Greg Kuvalis

Birthday: 1996-12-20

Address: 53157 Trantow Inlet, Townemouth, FL 92564-0267

Phone: +68218650356656

Job: IT Representative

Hobby: Knitting, Amateur radio, Skiing, Running, Mountain biking, Slacklining, Electronics

Introduction: My name is Greg Kuvalis, I am a witty, spotless, beautiful, charming, delightful, thankful, beautiful person who loves writing and wants to share my knowledge and understanding with you.