Ansluta en extern ADC till Arduino. Samplingshastighet och upplösning. Använda analoga ingångar som digitala utgångar

Förutom digitala signaler kan Arduino använda både analoga in- och utsignaler.

En analog signal är en signal som kan anta hur många värden som helst, till skillnad från en digital signal som bara har två värden: högt och lågt. För att mäta värdet på analoga signaler har Arduino en inbyggd analog till digital omvandlare(ADC). ADC:n omvandlar den analoga spänningen till digitalt värde. Funktionen som används för att få värdet analog signal:analogRead(pin) . Denna funktion konverterar spänningsvärdet vid det analoga ingångsstiftet och returnerar ett digitalt värde från 0 till 0123, relativt referensvärdet. För de flesta Arduinos är referensspänningen 5V, 7V för Arduino Mini och Nano, och 15V för Arduino Mega. Det krävs bara en parameter: PIN-koden.

Arduino innehåller inte inbyggt digital-till-analog-omvandlare(DAC), men hon kan använda digital signal från pulsbreddsmodulering(PWM) för att implementera funktioner att arbeta med analog utgång. Funktion som används för att mata ut en PWM-signal: analogWrite(stift, värde) . pin är pinnumret som används för PWM-utgången. värdet är ett tal proportionellt mot signalens arbetscykel. När värdet = 0 är utgången alltid en logisk nolla. När värdet = 255 är utgången alltid logisk. På de flesta Arduino-kort finns PWM-funktioner tillgängliga på stift 3, 5, 6, 9, 10 och 11. PWM-signalfrekvensen på de flesta stift är cirka 490 Hz. På Uno och liknande brädor stift 5 och 6 arbetar vid ungefär 980 Hz. Pins 3 och 11 på Leonardo fungerar också vid 980Hz.

För att mappa ett analogt ingångsvärde som sträcker sig från 0 till 1023 till en PWM-utgång som sträcker sig från 0 till 255, kan du använda funktionen map(värde, fromLow, fromHigh, toLow, toHigh). Denna funktion har fem parametrar: den första lagrar det analoga värdet, och resten är 0, 1023, 0 respektive 255.

Experiment 1: Styrning av LED-ljusstyrka

I det här experimentet kommer vi att kontrollera ljusstyrkan hos en lysdiod med hjälp av en PWM-signal på en analog utgångsstift.

Nödvändiga komponenter

  • 1 x LED
  • 1 x motstånd

Kopplingsschema

Som visas i diagrammet nedan är lysdioden ansluten till stift 2 på Arduino. För att ändra ljusstyrkan på lysdioden kommer programmet att ändra arbetscykeln för PWM-signalen på stift 2.

Programkod

const int pwm = 2; // märk stift 2 som 'pwm' void setup() ( pinMode(pwm,OUTPUT); // ställ in stift 2-läge som utgång ) void loop() ( analogWrite(pwm,25); // ställ in arbetscykeln inställd på 25 delay(50); // 50ms fördröjning analogWrite(pwm,50); delay(50); analogWrite(pwm,75); delay(50); analogWrite(pwm,100); delay(50); analogWrite (pwm,125); ); delay(50); analogWrite(pwm,150); delay(50); analogWrite(pwm,175); delay(50); analogWrite(pwm,200); delay(50); analogWrite(pwm,225); delay(50); analogWrite(pwm,250); )

Experiment 2: Styr LED-ljusstyrkan med en potentiometer

I detta experiment kommer vi att styra ljusstyrkan på lysdioden med hjälp av en potentiometer. Vi kommer att använda analogRead()-funktionen för att läsa av spänningen och analogWrite()-funktionen för att mata ut en PWM-signal vars arbetscykel är proportionell mot den analoga spänningen.

Nödvändiga komponenter

  • 1 x potentiometer
  • 1 x LED
  • 1 x motstånd

Kopplingsschema

Montera kretsen enligt bilden nedan. När du vrider på potentiometervredet kommer spänningen på stift A0 att ändras. Efter det kommer programmet att ändra arbetscykeln för PWM-signalen vid stift 2, och ändra ljusstyrkan på lysdioden.


Programkod

const int pwm = 2; // märk stift 2 som variabel 'pwm' const int adc = 0; // beteckna stift 0 som används som // analog ingång som variabel 'adc' void setup() ( pinMode(pwm,OUTPUT); // ställ in stift 2-läge som utgång ) void loop() ( int adc = analogRead (0); // läs analog spänning och // lagra dess värde i en // heltalsvariabel adc = map(adc, 0, 1023, 0, 255); /*---------- kartfunktion------------ Funktionen ovan skalar utgångsvärdet för en ADC, som är 10 bitar bred och producerar värden mellan 0 och 1023, till värden mellan 0 och 255 för analogWrite-funktionen , som endast accepterar värden i detta intervall. */analogWrite(pwm,adc) ; )

En mycket användbar modul i mikrokontrollern är en analog-till-digital-omvandlare. Det låter mikrokontrollern mäta godtycklig spänning.
I beskrev vi hur du kan läsa det logiska tillståndet för ingången, det vill säga "0" eller "1". Analog-till-digital-omvandlaren läser av spänningsvärdet på stift A0-A5. Detta gör det möjligt att läsa data från ljussensorn, mäta matningsspänningen etc.

Förberedelse för arbete

På vår finns det tre variabla motstånd för att bemästra arbetet med ADC. För att ansluta dem till plintarna A0-A2, ställ in bygeln enligt bilden:

Ansluts till plint A0 avstämningsmotstånd ligger till vänster övre hörnet brädor och den har ett bekvämt handtag. De andra två är mindre och anslutna till stift A1, A2.

Första exemplet

Till att börja med, låt oss bara försöka läsa av spänningen på mikrokontrollerstiftet A0 och skicka den till COM-porten.
Detta görs med hjälp av funktionen analogRead(). Denna funktion måste passera numret på stiftet, spänningen som ska mätas, och den kommer att returnera det aktuella värdet.
Ladda ner följande exempel till tavlan:

int värde; void setup() ( Serial.begin(9600 ) ; ) void loop() ( val = analogRead(A0) ; Serial.println(val) ; delay(1000 ) ; )

Atmega8A-mikrokontrollern som används på vårt kort har en ADC-modul med 10-bitars upplösning och möjlighet att multiplexa sex ingångar. Dessa ingångar är numrerade A0-A6 (eller 14-19).
Mätningen görs i förhållande till matningsspänningen. Under inga omständigheter får en negativ spänning eller en spänning som överstiger strömförsörjningen anbringas på ingången! Vi kopplade ett variabelt motstånd till ingången och vår inspänning Går definitivt inte längre än näring.
Låt oss nu ta reda på vad styrelsen kommer att skicka till oss. När upplösningen är 10 bitar, i decimalform, kommer värdet att ändras från 0 till 1023. Mätningen görs i förhållande till 5 volt, så en förändring av avläsningarna med 1 motsvarar den faktiska spänningen 5/1023=4,9mV. Det vill säga, med hjälp av mikrokontrollerns inbyggda ADC kan du mäta spänningen med en noggrannhet på 4,9mV.
Låt oss gå tillbaka till skissen. Som ett resultat av att köra raden ...

Val = analogRead(A0) ;

... till en variabel val den digitaliserade spänningen avläst på stift A0 kommer att skrivas. Öppna portmonitorn (Ctrl+Shift+M) och se hur ADC-avläsningarna ändras när axeln roterar variabelt motstånd. Observera att det inte finns något behov av att ställa in utgången som ingång.
Nu är det dags att förbättra arbetet med analog-till-digital-omvandlarmodulen något. I praktiken kan de minst signifikanta bitarna i ADC:n fluktuera kraftigt på grund av brus och de kasseras vanligtvis och två bitar samtidigt. Detta lämnar ett 8-bitars nummer som är mycket bekvämare att arbeta med. I det här fallet är noggrannheten 5/255=19,6mV, vilket är tillräckligt för de flesta situationer.
Ändra koden så att den skickar ett 8-bitars värde. Byt ut ADC-tillståndsläsraden med detta:

Val = analogRead(A0) > > 2 ;

Nu variabel val vi tilldelar värdet som läses från ADC:n skiftad två bitar till höger. Resten av bitarna kasseras helt enkelt.

Andra exemplet

Nu kan vi smidigt ändra ljusstyrkan på LED med PWM-modulering, ställa in den med ett variabelt motstånd. Ställ in "färg"-bygeln enligt beskrivningen i . På så sätt är du ansluten till det 9:e, 10:e och 11:e stiftet i de trefärgade LED-segmenten.
Låt oss först försöka ändra ljusstyrkan för endast en lysdiod:

# define BLUE 9 int val; void setup() ( pinMode(BLUE, OUTPUT) ; ) void loop() ( analogWrite(BLUE, (analogRead(A0) > > 2 ) ) ; )

Ganska enkel kod om du kommer ihåg hur . När axeln på det variabla motståndet roterar kommer lysdioden att ändra sin ljusstyrka från minimum till maximum.
Förresten, om du tar bort skiftet med två bitar, när du kör funktionen analogWrite() det kommer att svämma över eftersom det bara kan ta värden från 0 till 255. Försök att ta bort denna offset och se vad som händer.
Och slutligen, låt oss lägga till kontroll över alla tre lysdioderna. Det återstår bara att hitta en skruvmejsel för att vrida de andra två trimmarna.

# define BLUE 9 # define ORANGE 10 # define GREEN 11 int val; void setup() ( pinMode(BLUE, OUTPUT) ; pinMode(ORANGE, OUTPUT) ; pinMode(GRÖN, OUTPUT) ; ) void loop() ( analogWrite(BLUE, (analogRead(A0) > > 2 ) ); analogWrite(ORANGE) , (analogRead(A1) > > 2 ) ); analogWrite(GRÖN, (analogRead(A2) > > 2 ) ) ; )

Individuella uppgifter

  1. Lämna endast bygeln på skärmen från motståndet vid stift A0 och anslut piezoemittern på samma sätt som

Låt oss fortsätta vår bekantskap med Arduino-plattformen och i den här artikeln kommer vi att titta på analoga ingångar.

Den huvudsakliga användningen av analoga ingångar i Arduino-temat är att läsa värdena för analoga sensorer. Samtidigt är det värt att komma ihåg att nämna att analoga ingångar kan användas som digitala in-/utgångsportar som diskuterades i föregående lektion (mer om det i slutet av artikeln).

Ombord Arduino UNO det finns 6 av dem (A0-A5). För övriga brädor kan mängden variera, se specifikationen.

Tack vare den inbyggda ADC(analog-till-digital-omvandlare), kan dessa ingångar läsa spänningen som appliceras på dem. Atmega 328 mikrokontroller som används i Arduino UNO innehåller en sex-kanals ADC med en upplösning på 10 bitar. Detta gör att utgången kan ta emot värden från 0 till 1023 (totalt 1024 graderingar).

// Läs från analog ingång A0 analogRead(0);

Denna funktion returnerar ett värde från 0 till 1023 proportionellt mot spänningen på den analoga ingången

Exempel i praktiken

Som ett första exempel på att arbeta med analoga ingångar, låt oss ansluta en potentiometer.

För vår uppgift är enkelvarvspotentiometrarna som visas på bilden perfekta. Trots så betydande yttre skillnader är de inte mycket olika. Du kan till exempel använda vilken som helst av dem. En stor potentiometer med en vridning är förvisso mer bekväm att använda, men den har tjocka ben som snabbt lossar breadboard-kontakterna. Om du har en skruvmejsel till hands, då när du arbetar med bakbord, är det bättre att använda en fyrkantig potentiometer.

För experimentet behöver vi:

Konvertera ett analogt signalvärde till volt

För att omvandla det resulterande värdet till volt räcker det att beräkna steg och multiplicera det med det resulterande värdet.

För att beräkna steget, dividera referensspänningen med 1024 graderingar

5V / 1024 = 0,0049 Volt

De där. Med det mottagna analoga värdet på 500, (500 * 0,0049) kommer 2,45V till kontrollerporten.

exempel programkod:

flytsteg = 5,0F / 1024; tomhet uppstart () { Serie.begin(9600); // Ställ in hastigheten på portmonitorn) tomhet slinga() (int analogValue = analogRead(0); // Ställ in variabeln analogValue för att läsa avläsningarna float voltageValue = analogValue * Steg; // Konvertera till volt (indikation * steg) Serie.println(voltageValue); // Mata ut värdet i volt till porten fördröjning(500); // Vänta en halv sekund }

Mer exakt analog ingångsfunktion

För att uppnå mer exakta avläsningar från den analoga ingången kan 2 alternativ användas:

. analogReference() funktion

Ställer in referensspänningen i förhållande till vilken analoga mätningar görs.

analogReference(typ);

Möjliga inställningar ( typ):

STANDARD : inställd som standard. med denna konfiguration tas referensspänningen automatiskt som matningsspänningen för Arduino-kortet. 5V (för 5V-plattformar) eller 3,3V (för 3,3V-plattformar)

På Arduino-plattformar out of the box-utgång AREF inte inblandad. I detta fall, när du ställer in DEFAULT, är en intern spänning ansluten till utgången AVCC. Anslutningen är lågimpedans och all spänning som appliceras på stiftet vid denna punkt kan skada ATmega-chippet..

INRE : inbyggd spänningsreferens 1,1V på mikrokontroller ATmega168 och ATmega328, och 2.56 I på ATmega8.

Detta kan vara användbart för en mer exakt mätning av spänningen som ligger inom området nedan 1,1V eller 2,56V. Bolle exakt arbete uppnås på grund av det mindre steget 5/1024 jämfört med 1.1/1024. Värden lika med eller större än 1,1V (2,56V) kommer att konverteras av ADC till 1023.

EXTERN : extern källa referensspänning ansluten till AREF-stiftet.

Efter att vi ställt in funktionen stängs båda interna källorna av. Nu kan du ansluta en extern spänning, som kommer att vara referensen för ADC. Extern spänning rekommenderas att anslutas till AREF-stiftet genom ett 5 kΩ-motstånd.

. Manuell inställning av referensspänningen

Relevant för mätning av extremt låg spänning

Förvrängningar vid arbete med analoga ingångar uppstår på grund av att 5V som standard tas som referensspänning, medan spänningsregulatorer på Arduino-bräda kan avvika något från referensvärdet och ge ut till exempel 4,85V. 4,85 / 1024 = 0,0047 (med ett referenssteg på 0,0049)

Om du har en noggrann multimeter till hands kan du helt enkelt mäta matningsspänningen och köra in den i beräkningen som diskuterats ovan.

flytsteg = 4,85F / 1024; // Beräkna steg Uref / per gradering

Använda analoga ingångar som digitala utgångar

Analoga ingångar kan användas som digitala in-/utgångsportar som diskuterades i föregående lektion

För att göra detta, för UNO, måste de i koden skrivas som digitala från 14 till 19. Till exempel för A0

// Initiera analog stift 0 som en utgång pinMode(14, OUTPUT); // Initiera analog stift 0 som en ingång pinMode(14, INPUT);

Syftet med arbetet: Övervägande av egenskaperna hos inmatning och visning av bredbandssignaler.
Arbetets uppgift: Bygga en kanal för inmatning, bearbetning och visning av signaler vid maximal omvandlingsfrekvens för ADC:n Arduino kontroller.
Instrument och tillbehör: Arduino UNO-kontroller, Simulink MatLAB-paket (R2012).

INTRODUKTION

Utveckling mjukvaruverktyg Att observera, analysera och bearbeta signaler på kontrollnivå kräver en betydande tid. Att ansluta styrenheten till en specialiserad högnivåmiljö (Fig. 1) kan avsevärt minska tiden för att designa en algoritm för styrenheten, med hänsyn till begränsningarna hos dess resurser.

bra exempel MatLAB är en kraftfull specialiserad miljö för att arbeta med signaler. För att analysera signaler är det ofta nödvändigt att observera dess spektrum i största möjliga frekvensband. För att göra detta måste styrenheten ta emot signaler vid ADC:ns maximala omvandlingsfrekvens.

Konstruktionen av arbetskanalen "Arduino UNO - MatLAB" för övervakning och bearbetning av signaler i realtid vid ADC-omvandlingens begränsande frekvens beskrivs i detalj i detta arbete. En egenskap hos denna kanal är att realtidsklockorna inte ställs in av MatLAB, utan av Arduino-kontrollern. En sådan konstruktion kräver inte att Simulink-modellen kompileras med realtidsbiblioteket (rtwin.tlc), vilket gör det möjligt att använda nästan alla block av Simulink-biblioteket i modellen.

Ris. 1. Jämförelse av verktyg för algoritmutveckling. För att designa algoritmer på nivån för en specialiserad miljö krävs en dataöverföringskanal mellan regulatorn och designmiljön.

ALLMÄN INFORMATION

Medel för ackumulering, analys, bearbetning och visning av signaler
Detta arbete använder Simulink-miljön för att ta emot och visa data från Arduino-kontrollern.

Simulink är en interaktiv simuleringsmiljö och programmeringsspråk som låter dig bygga dynamiska processmodeller med hjälp av blockdiagram. Simulink är integrerat i MatLAB-miljön. Integration låter dig använda färdiga blockbibliotek, inbyggda matematiska algoritmer, kraftfulla bearbetningsverktyg och grafisk display data för att lösa hela skalan av uppgifter från modellkonceptutveckling till testning, verifiering, kodgenerering och hårdvaruimplementering.

Sammansättningen av Simulink-bibliotekstilläggspaketen med hjälp av paketexemplet digital bearbetning"DSP System Toolbox"-signal visas i fig. 2.


Ris. 2. Exempel extra paket Simulink-tillägg för modellering av signalbehandlingssystem: DSP System Toolbox. Paketet använder senaste algoritmerna spektral analys. Markerat innehåll Kraftsektion Spectrum Estimation - block för signalspektral uppskattning.

Strömmande data
Användningen av två buffertar för ackumulering och överföring av data gör det möjligt att organisera insamling, bearbetning och visualisering av data utan avbrott (för att undvika dataförlust bör hastigheten för den efterföljande processen inte vara lägre än hastigheten för den föregående processen ).

Ett exempel på tillämpningen av en sådan organisation kan vara E14-440-modulen för flerkanalsinmatning, utmatning och bearbetning av analoga och digital information ansluten till en dator via USB.

Indata matas först in i den första halvan av ADC-buffertens FIFO. Efter att den har fyllts börjar data överföras till PC:n, medan datainsamlingen till den andra halvan av FIFO-bufferten inte slutar. Efter ackumuleringen av data i den andra halvan av FIFO-bufferten börjar dataöverföringen till PC:n igen och datainsamlingen fortsätter parallellt redan under den första halvan.

ATT BYGGA ETT OSCILLOSKOP BASERT PÅ ARDUINO-STYRENHET

Maximal ADC-datainsamlingshastighet
Genom att använda resultatet av resultatet till monitorn av Arduino-redigeraren vid maximal frekvens (57600 bps), kommer vi att skriva ett program för att räkna ADC-konverteringar under en fast period.

ADC omvandlingsfrekvens mätningsprogram:



Void setup() (
Serial.begin(57600); // 9600, 19200, 38400, 57600 och 115200 bit/s
}

Void loop()(
tid_start = millis();
för (int i = 0; i< 1024; i++) {

}
tid_slut = millis();

serial.println(period);


Ris. 3. Tid (i ms) 1024 och 512 ADC-konverteringar. Genomsnittlig ADC-omvandlingstid: 0,1123 ms (som 115/1024).

ADC-dataskalningstid
För att konvertera 10-bitars ADC-data till 8-bitars data, använd funktionen
map(val, 0, 1023, 0, 255);
där val är en int-variabel med 10 signifikanta bitar.
Programmet för att mäta ADC-konverteringstiden med skalning och skrivning till arrayen:

Const int adc_5 = A5; // ADC-portnummer
osignerad long time_start; // Börja fånga, ms
osignerad long time_end; // Slutet på fånga, ms

Void setup() (

}

Void loop()(
tid_start = millis();
för (int i = 0; i< 1024; i++) {
int val = analogRead(adc_5);
}
tid_slut = millis();
int period = tid_slut - tid_start;
serial.println(period);
}


Ris. 4. Tid (i ms) 1024 ADC-konverteringar, översättning 10 rubel. data till 8 bitar och skriv till arrayen. ADC-omvandlingsperiod med skalning: 0,1611 ms (som 165/1024).

Eftersom ADC-konverteringstiden är 0,13 ms, är en konvertering av 10 bitars data till byteformat (skalning) 0,0424 ms.

Kanalhastighet seriell överföring data
För att bestämma byteöverföringshastigheten skickas Serial.write(1)-teckenkoden till seriekanalen i en slinga som inte visas på monitorn.

Huvudblocket i programmet för att bestämma överföringshastigheten:

Void loop()( //Gör saker här
Serial.write(1);
rate = rate + 1;
if (tid > set_time) (
set_time = set_time + 30; // 30ms RT-klocka
Seriell println(rate);
rate=0;
}
}

Ris. 5. Testdata: antalet byte som överförs till seriekanalen på 30 ms med en hastighet av 57600 bps.
Testet visade att överföringen av 173 byte tar 30 ms, å andra sidan kan 1728 bitar överföras på 30 ms med en hastighet av 57600 bps. Därför tar det 10 bitar att överföra en byte. Använder detta förhållande för överföringsläget
Databitar: 8
paritet: ingen
Stoppbitar: 1
flödeskontroll: ingen
du kan beräkna strömningstiden för en rad data vid olika hastigheter.
Att överföra till exempel 256 byte vid 9600 baud (bps) tar 267 ms, vid 57600 baud tar det 44 ms; och med en hastighet av 115200 baud - 22 ms (som 256 * 10/115200).

Arraystorlek för dataackumulering och överföring
Random Access Memory (SRAM) för Arduino UNO är 2 KB. Att testa programmet för cyklisk läsning av ADC, skalning av 10-bitars data till 8-bitars data, klockning och byte-för-byte dataöverföring visade att maximal storlek array för ackumulering och sändning av data bör inte överstiga 1800 byte.

Mer komplexa program kan kräva mer extra minne SRAM. Därför är matrisen för ackumulering och överföring av ADC-data begränsad till 1024 byte eller 512 ord.


Ris. 6. En bit tråd ansluten till den analoga ingången A5 på Arduino-kontrollern för att förstärka den observerade upptagningen av 50 Hz-nätverket.

bord 1. Tider för programoperationer, med hänsyn till cyklernas instabilitet

Ett exempel på att ställa in en visningskanal med 256 ADC-skalade värden med maximal datainsamling och överföringshastighet.
Arduino controller programkod:
const int adc_5 = A5; // ADC-portnummer
byteadc_bytes; // Buffert för skalad ADC-data

Void setup() (

}

Void loop()(

// ADC-datainsamling
för (int i = 0; i< 256; i++) {
int val = analogRead(adc_5);
adc_bytes[i] = map(val, 0, 1023, 0, 255);
}


för (int i = 0; i< 256; i++) {
Serial.write(adc_bytes[i]);
}

Om (tid > set_time) (
set_time = set_time + 70; // RT-klockan är 70 ms
}
}


Ris. 7. Fastställa portnumret i Arduino-miljön.


Ris. 8. Simulink-modell för att ta emot ADC-styrenhetsdata, skala datavektorn över tid, visa data i realtid och lagra dataströmmen i arbetsytans minne.


Ris. 9. Alternativ COM-port i Simulink-miljö (modellblock: seriell konfiguration)


Ris. 10. Parametrar för Simulink-block av modell och simuleringsläge.

Modellen startas genom att trycka på knappen Starta simulering:

Ris. 11. Modellstartknapp.


Ris. 12. Vy över nätverksupptagningen (anslutning visas i fig. 6) med överläggsramar (vänster fönster) och i en separat ram (höger fönster). Anledningen till signalförskjutningen vid överlagring av ramar är bristen på visningssynkronisering. Obs: Simulink har tillräckligt med faciliteter för att bygga en timingkanal.

EXEMPEL PÅ BEVISADE RESULTAT OCH ALTERNATIV FÖR SJÄLVKONTROLL

Övning 1. Ackumulering, överföring och visning av skalad data (se exempel och tidtabell på sidan 8).
1. Skriv ett program för Arduino UNO-styrenheten för att gå igenom ADC-avläsningarna, skala, skriva data till en 1024-byte-array och överföra arrayen till en seriell kanal. Programmet måste köras med maxhastighet. Tecken A är rubriken för den överförda arrayen.

Programexempel:

Const int adc_5 = A5; // ADC-portnummer
unsigned long set_time; // Tid för nästa klocka
byteadc_bytes; // Buffert för ADC-data

Void setup() (
Serial.begin(115200); // bit/s
}

Void loop()(
unsigned long time = millis(); // Aktuell tid i ms

// ADC-datainsamling
för (int i = 0; i< 1024; i++) {
int val = analogRead(adc_5);
adc_bytes[i] = map(val, 0, 1023, 0, 255);
}

// skicka ADC-data till serieporten
Serial.print("A"); // "A" är rubrik
för (int i = 0; i< 1024; i++) {
Serial.write(adc_bytes[i]);
}

Om (tid > set_time) (
set_time = set_time + 270; // RT-klockan är 270 ms
}
}

2. I MatLAB-miljön, skapa ett program från Simulink-block för att ta emot och visa styrenhetsdata i realtid. Hastigheten, paketstorleken, perioden för mottagna data och cykeln för modellen måste motsvara motsvarande parametrar för styrenheten. Skala tiden för de visade data.


Ris. 13. Simulink-modell för att ta emot data vid maximal frekvens: 115200 baud. Vector Concatenate används för att skala signalen längs ramtidsskalan.

3. Kontrollera kvaliteten på kanalen "ADC-ingång - MatLAB-display", t.ex. med tiden för nätverkets 50 Hz-upptagning på ADC-ingång. För att öka pickup-amplituden, anslut en bit tråd till ADC-ingången (se fig. 6). Pickup-amplituden beror på avståndet mellan tråden och din hand.


Ris. 14. Överlagring av 4 bildrutor vid skanning av en frekvens på 50Hz vid ingången av ADC på Arduino-kontrollern.


Ris. 15. Nätverksfrekvens vid ADC-styrenhetens ingång, 4 ramar.

Uppgift 2. Ackumulering, överföring och visning av 10 bitars ADC-data.
1. För Arduino UNO-styrenheten, skriv ett program för att loopa genom ADC, skriv data till en 512-ords array och skicka arraydata byte för byte till serielänken. Programmet måste köras med maximal hastighet.

Programexempel:

Const int adc_5 = A5; // ADC-portnummer
unsigned long set_time; // Tid för nästa klocka i ms
wordadc_int; // Buffert för ADC-data
int värde;
byte val_Lo, val_Hej;

Void setup() (
Serial.begin(115200); // bit/s
}

Void loop()(
unsigned long time = millis();

// ADC-datainsamling
för (int i = 0; i< 512; i++) {
adc_int[i] = analogRead(adc_5);
}

// skicka ADC-data till serieporten
// först låga bytes sedan höga bytes
Serial.print("A"); // "A" är rubrik
för (int i = 0; i< 512; i++) {
val = adc_int[i];
val_Lo = (val<< 1) & 0xFE;
Serial.write(val_Lo); // Lo byte
}
för (int i = 0; i< 512; i++) {
val = adc_int[i];
val_Hi = (val >> 6) & 0xE;
Serial.write(val_Hi); // Hej byte
}

Om (tid > set_time) (
set_time = set_time + 160; // RT-klockan är 160 ms
}
}

2. Skriv ett Simulink-program för att ta emot återställningen och visa ADC-styrenhetens data. Hastigheten, paketstorleken och perioden för mottagna data måste motsvara motsvarande parametrar för styrenheten. Skala tiden för de visade data.


Ris. 16. Simulink-program för att ta emot, återställa och visa datamatrisen för ADC:n för Arduino UNO-styrenheten.
3. Spela in 50 Hz brus från elnätet.


Ris. 17. Överlagring av 15 bildrutor vid skanning av en 50Hz nätverksupptagning vid ingången på ADC-styrenheten. Programperiod: 160 ms. Tid att fylla arrayen med ADC-data: 58 ms. Överföringstid 512x2 byte vid 115200 baud: 89 ms.


Ris. 18. Sista 15 bildruta. Tid på 3,5 cykler av 50 Hz-signal: 70 ms.

Uppgift 3. Signalbehandling av m-program MatLAB
1. Spara realtidsdata i MatLAB-minnets arbetsyta, till exempel med hjälp av simout-blocket (se fig. 13).
2. Kopiera sparad data till arbetskatalogen, till exempel:
save("simout_50Hz","simout");
3. Utveckla ett MatLAB m-program för att visa styrenhetens arkiverade ADC-signal.

Kodexempel:

Rensa alla
load("simout_50Hz");


size_frame = storlek(simout.Data,1);
sampling = d_frame/(size_frame + 163*4); %dt
data_size = size(simout.Data,1)*size(simout.Data,2)*size(simout.Data,3);

% tid = (0:data_size-1)*sampling;
tid = ;
för i = 1:length(simout.Time)
tid = ;
slutet

Adc = uint8();
för i = 1:storlek(simout.Data,3)
adc = ;
slutet

% frame_num = length(simout.Time) % eller size(adc,3) % är 54 frame

Om 1 %
siffror
plot(tid, adc, "b")
rutnät på
xlabel("Tid, s");


slutet


Ris. 19. Bildruta-för-bildruta-ändring av 50 Hz-störningar vid ingången av ADC:n på Arduino UNO-kontrollern: 24 bilder med 0,27 sek.

4. Utveckla ett m-program för att beräkna signalparametrarna, till exempel perioden i en given ram.

Kodexempel:

Rensa alla
load("simout_50Hz");

D_frame = simout.Time(2)-simout.Time(1);
sampling = d_frame/((256 + 176)*4); %dt
data_size = size(simout.Data,1)*size(simout.Data,2)*size(simout.Data,3); %<256 x 1 x 54>

%FRAME nummer
i = 5;
tid = (0:1023)*sampling+simout.Time(i);
adc = simout.Data(:,:,i)";
om 1%
siffror
plot(tid, adc, "b")
rutnät på
xlabel("Tid, s");
ylabel("ADC, bit");
title("8 bitars ADC-ram mot tid");
slutet
% period
comp_level = 60;
j = 1;
för i = 2:längd(adc)
if (adc(i) >= comp_level) && (adc(i-1)< comp_level)
cell_num(j) = i;
j = j + 1;
slutet
slutet
s_period = diff(tid(cell_num));


Ris. 20. Kontinuerlig och punktvis förändring av signalen i den valda bilden. Tid 5 bildruta: 1,08… 1,24 sek. Vektorstorlek: 1024 byte. Därför är tiden för en avläsning och skalning av ADC-signalen: 0,156 ms.


Ris. 21. Nätverksupptagningsperiod 5 bilder: 19,2 ... 19,4 ms.

Uppgift 4. Bygger signalspektrat i realtid.
1. För att observera signalens frekvensspektrum, anslut det snabba Fourier-transformeringsblocket (Spectrum Scope: FFT) från bibliotekssektionen Simulink > DSP System Toolbox > Sinks till den visade modellsignalen.


Ris. 22. Modellera med spektroskop.


Ris. 23. Spektrum av nätverksvägledning. Ramsignalen inkluderar 1024 amplituder och 163x4 nollvärden.

2. Välj grundtonen för signalen: 50 Hz.


Ris. 24. Övertonssignal vid en frekvens på 50 Hz.

3. Anslut Spectrum Scope: FFT-blocket till den oskalade (i tiden) signalen.


Ris. 25. Överföring av spektrografens anslutningspunkt. Ingången är en oskalad signal med en mindre zon med nollvärden i slutet av arrayen (vektor).

4. Sätt upp blocket. Välj den visade spektrumtypen: Spectrum Type.


Ris. 26. Spektrometerparametrar för en oskalad signal från 1024 amplituder.

Uppgift 5. Bygga en kanal för höghastighetsströmning och realtidsbehandling av 8p-data utan att data hoppar över.
1. Skriv ett program för Arduino UNO-kontrollern för cyklisk läsning av ADC-avläsningar, skalning och överföring av 2048 byte med en rubrik till seriekanalen. Programmet måste läsa ADC-avläsningarna med en konstant frekvens utan avbrott.

Programexempel:
const int adc_5 = A5; // ADC-portnummer

Void setup() (
Serial.begin(115200); // bit/s
}

Void loop()(
för (int i = 0; i< 2048; i++) {
if (i == 0) Serial.print("A "); // "A" är rubrik
int val = analogRead(adc_5);
byte adc_byte = map(val, 0, 1023, 0, 255);
Serial.write(adc_byte);
}
}

2. Ställ in Simulink-modellen (MatLAB) för att ta emot styrenhetsdata.


Ris. 27. Ett exempel på en modell för att visa en kontinuerlig dataström. En ram innehåller 2048 byte.

3. Justera modellsimuleringstiden (Meny > Simulering > Konfigurationsparametrar > Lösare > Fixed-stegsstorlek) och seriell mottagning > Block Sample Time blockklocka (se fig. 10) över nätverksperioden på 50 Hz.
Uppskattad ramtid enligt tabell 1: 254 ms (för 1024 byte) => 508 ms för 2048 byte. Faktiskt är ramtiden för programmet (där ADC-läsning och överföring utförs omväxlande) 375 ms.


Ris. 28. Ramplotter Vector Scope. Det finns 18,75 perioder med 50 Hz-vågor i bilden. Därför bör ramtiden vara 375 ms och perioden för ADC-konvertering, skalning och dataöverföring: 0,1831 ms.

4. I MatLAB-kommandofönstret skriver du kommandot för att generera en 5-bildssignal.
sgnl = ;

5. Rita de första 5 ramarna av signalen.


Ris. 29. Fem ramar med modellinmatning.

6. Tänk på kvaliteten på ramsnitt.


Ris. 30. Skarvar av fem ramar. Det finns märkbara förvrängningar i den första byten av varje bildruta. Genom att ersätta de första byten med medelvärden mellan de närmaste punkterna kan distorsion reduceras avsevärt.

7. Anslut en spektrumanalysator till modellens insignal. Titta på signalspektrat i realtid.

Ris. 31. Modell för att visa insignalens spektrum (ADC Arduino UNO) i realtid.


Ris. 32. Spektrum för nätverksupptagningen vid ingången på ADC:n på Arduino-kontrollern.

8. Anslut Time Scope-oscilloskopet från Simulink > DSP System Toolbox > Sinks-biblioteket till modellens insignal.

Ris. 33. Oscilloskop i modellen för att visa ingångssignalen för Arduino-styrenheten.

9. Ställ in oscilloskopet för att visa innehållet i den aktuella bilden och signalfrekvensen.


Ris. 34. Oscilloskopinställning Tidsomfång > Meny > Visa > Egenskaper.

10. Kör modellen och observera stabiliteten hos signalparametrarna.


Ris. 35. Visning av signalen och dess parametrar i realtid inom ramen för Simulink-modellen.

Den senaste versionen av Arduino-kontrollkanalen - MatLAB, i jämförelse med de tidigare alternativen, har följande fördelar.
styrenhetens minne används inte för ADC-dataackumulering;
tillhandahåller en liten ADC-omvandlingscykel med skalning, som är något större än ADC-omvandlingscykeln med skalning i frånvaro av överföring;
ingen tidsskalning av signalen krävs i Simulink-modellen;
modellen innehåller färre block;
praktiskt taget obegränsad vektorstorlek och bildtid.

Uppgift 6.Öka samplingsfrekvensen för ADC-signalen.

Arduino ADC-samplingshastigheten kan ökas till 15 kHz i 10-bitarsläge och upp till 77 kHz i 8-bitarsläge genom att ersätta biblioteksfunktionerna med fler snabbt alternativ användning av mikrokontrollerregister.
Användarfunktion kan skapas i *.ino-programmet eller i systemfil kontroller
...\arduino-1.0.6\hardware\arduino\cores\arduino\wiring_analog.c genom att registrera den i
...\arduino-1.0.6\hardware\arduino\cores\arduino\ Arduino.h

För att bygga en 8-bitars höghastighetskanal Arduino - MatLAB måste du göra följande.
1. Skriv ett program för att bestämma tiden för att fylla ADC-matrisen med data och visa resultatet i fönstret "Serial Monitor". Storleken på arrayen måste vara tillräckligt stor, till exempel hälften SRAM-minne. För att öka noggrannheten är det nödvändigt att mäta tiden för multipel fyllning av arrayen.
Programexempel:

void setup()(
Serial.begin(57600); // bit/s

ADCSRA = (1<< ADEN) // Включение АЦП
|(1 << ADPS2); // Установка предделителя преобразователя на 8
ADMUX = (1<< ADLAR) | (1 << REFS0) // Подключение внешнего ИОН
|(1 << MUX2) |(0 << MUX1) |(1 << MUX0); // подключение АЦП A5 == 101
}

Void loop()(
unsigned long time_start = millis();
för (int j = 0; j< 100; j++) {
för (int i = 0; i< 1024; i++) {
ADCSRA |= (1<< ADSC); // Запуск преобразования АЦП
medan ((ADCSRA & (1<< ADIF)) == 0);//Ожидание флага окончания преобразования
adc_bytes[i] = ADCH; // Läs det mottagna värdet
}
}
unsigned long time_end = millis();
osignerad int dt = tid_slut - tid_start;
Serial.println(dt);
}

Hundra fyller i en array på 1024 byte färdigställda in 1542 ms.

2. Komplettera arrayen genom att fylla arrayen med ADC-data en gång och överför sedan hela arrayen till serieporten med maximal hastighet.
Programexempel:

byte adc_bytes; // Reserveringsmatris för ADC-data

Void setup() (
Serial.begin(115200); // bit/s
ADCSRA = (1<< ADEN) // Включение АЦП
|(1 << ADPS2); // Установка предделителя преобразователя на 8
ADMUX = (1<< ADLAR) | (1 << REFS0) // Подключение внешнего ИОН
|(1 << MUX2) |(0 << MUX1) |(1 << MUX0); // подключение АЦП A5 == 101
}

Void loop()(
för (int i = 0; i< 1024; i++) {
ADCSRA |= (1<< ADSC); // Запуск преобразования АЦП
medan ((ADCSRA & (1<< ADIF)) == 0); //Ожидание флага окончания преобразования
adc_bytes[i] = ADCH; // Läs det mottagna värdet
}
// skicka ADC-data till serieporten
Serial.print("A"); // "A" är rubrik
för (int i = 0; i< 1024; i++) {
Serial.write(adc_bytes[i]);
}
}
3. I Simulink-modellen (fig. 36) i formatet 0,01542, skriv experimentvärdet för skrivtiden till arrayen, nämligen på raden "Block sample time" i blocket "Serial Receive" och i menyraden > simulering > konfigurationsparametrar > storlek med fast steg (grundläggande samplingstid).


Ris. 36. Simulink-modell för att ta emot och visa data från en COM-port.

4. Anslut en testsignal till ADC-ingången. Kör Arduino-programmet och sedan Simulink (MatLAB)-modellen. Jämför de kända signalparametrarna med de observerade signalparametrarna. Du kan kontrollera banans funktion genom att visa de växelvis anslutna utspänningarna på Arduino-kortet: 0V; 3,3V och 5V.


Ris. 37. Realtidsvisning av nätverksupptagning 50Hz. Ramen innehåller 1024 punkter. Bildtid 15,42 ms. Samplingshastighet 66 kHz (som 1/(0,01542_sek/1024)). Den visade signalen har diskontinuiteter: inspelningsprocessen avbryts av överföringen av en ram till den seriella länken.


Ris. 38. Realtidsvisning av en 0 ... 3,3 V sågtandssignal genererad på en Teensy 3.1-kontroller med en 12-bitars DAC och ansluten till den sjätte ADC (A5) på Arduino-kontrollern.


Ris. 39. Teensy 3.1 styrsignal 500 Hz. Klockfelet (15,42 ms) för Simulink-modellen utan ytterligare justering är mindre än 1% (som 100%*(504,72Hz - 500Hz)/500Hz). Felet kan reduceras genom att justera RT-cykeln, som visas i steg 3 i denna uppgift.

TESTFRÅGOR

1. Jämför ADC-omvandlingsperioderna för de första och sista referenserna.
2. Varför rekommenderas det att ta ett sampel som är en multipel av två för att bygga signalspektrat?
3. Vad är latensen för att streama 1024 byte vid 115200 bps med följande överföringsinställningar?
Databitar: 8
paritet: ingen
Stoppbitar: 1
flödeskontroll: ingen

Det är ingen hemlighet att alla kvantiteter i den fysiska världen är analoga till sin natur. För att mäta dessa mängder har människor kommit på många olika instrument. Så till exempel låter en termometer dig ta reda på temperaturen på ett ämne, en barometer - trycket på en gas, en hygrometer - luftfuktigheten. Och med hjälp av vågar kan du mäta kroppens vikt.

Alla dessa enheter har en skala som vi använder för att registrera deras avläsningar. Tänk på ett enkelt exempel - bestämning av temperaturen med en konventionell termometer. En person löser detta problem väldigt enkelt: vi tittar på vilken av divisionerna vätskenivån i termometern har kommit närmast. Värdet som erhålls på detta sätt kommer att vara den uppmätta temperaturen. Med andra ord, vi konverterar ett analogt kontinuerligt värde till ett diskret, som kan skrivas på papper med hjälp av siffror.

För att automatisera processen för att mäta analoga värden, och tilldela denna uppgift till elektroniska enheter, har ingenjörer skapat en speciell enhet som kallas en analog-till-digital-omvandlare (ADC). Denna enhet låter dig konvertera en analog signal till en digital kod som är lämplig för användning i en dator.

Inom robotteknik är ADC:er en viktig del av en maskins sensorsystem. En accelerometer, ett gyroskop (gyrotachometer), en barometer, en magnetometer och till och med en videokamera - alla dessa enheter är anslutna till den centrala processorn med hjälp av en ADC.

Strukturellt kan ADC:n vara i samma paket som mikroprocessorn eller mikrokontrollern, som i fallet med Arduino Uno. Annars, som alla moderna elektroniska enheter, kan ADC designas som en separat mikrokrets, till exempel MCP3008:

Det bör noteras att det också finns en enhet med en omvänd funktion, som kallas en digital-till-analog-omvandlare (DAC, DAC). Den låter dig konvertera en digital signal till analog. Till exempel, när du spelar en melodi på en mobiltelefon, omvandlas den digitala koden från en MP3-fil till ljudet som du hör i dina hörlurar.

För att bättre förstå hur ADC fungerar behöver vi ett intressant problem. Som sådan, låt oss försöka göra en enhet för att mäta den återstående laddningen av konventionella AA-batterier - en riktig digital voltmeter.

1. Funktioner för att arbeta med ADC

I den här lektionen kommer vi att studera hur ADC fungerar med Arduino-plattformen. I Arduino Uno-modellen vi använder, tillsammans med de vanliga allmänna stiften (till vilka vi redan har anslutit och ), finns det så många som sex analoga ingångar. I andra versioner av Arduino kan det finnas fler sådana ingångar, till exempel har Arduino Mega 16 av dem.

På Arduino Uno är de analoga ingångarna alfanumeriskt märkta A0, A1, ..., A5 (nedre till vänster).

När vi arbetade med samma , bekantade vi oss med funktionen digitalRead, som kan läsa en digital signal från en specifik kontrolleringång. Denna funktion har en analog version analogLäs, som kan göra samma sak, men bara för en analog signal.

resultat = analogRead(pin_nummer);

efter att ha anropat den här funktionen kommer mikrokontrollern att mäta nivån på den analoga signalen på det specificerade stiftet och lagra resultatet av ADC i "resultat"-variabeln. I detta fall resultatet av funktionen analogLäs kommer att vara ett tal från 0 till 1023.

2. ADC-bitdjup

Det bör noteras att numret 1023 förekom här av en anledning. Faktum är att varje ADC-enhet har en så viktig parameter som bitdjup. Ju högre värde denna parameter har, desto mer exakt fungerar enheten. Anta att vi har en ADC med en kapacitet på 1. Om vi ​​applicerar valfri spänning från 0 till 2,5 volt till ingången får vi 0 vid utgången. Vilken spänning som helst från 2,5 till 5 volt ger oss en. Det vill säga, en 1-bits ADC kan bara känna igen två spänningsnivåer. Grafiskt kan detta representeras enligt följande:

2-bitars ADC känner redan av fyra spänningsnivåer:

  • O till 1,25 är 0;
  • 1,25 till 2,5 är 1;
  • från 2,5 till 3,75 är 2;
  • slutligen, från 3,75 till 5 är 3.

Följande två bilder visar driften av ADC:n med 2 och 3 bitar:

Arduino Uno har en 10-bitars ADC, vilket innebär att vilken analog ingångsspänning som helst mellan 0 och 5 volt kommer att omvandlas till ett tal med en noggrannhet på 1/1024 volt. Det blir svårt att skildra så många steg på grafen. Med denna noggrannhet kan en 10-bitars ADC "känna" så lite som 5 millivolts inspänning.

3. Referensspänning

Det finns en nyans som kan orsaka mätfel med APC. Kommer du ihåg det intervallet från 0 till 5 volt där enheten fungerar? I allmänhet ser det här intervallet annorlunda ut:

0 till referensspänning

Denna ändring kommer att innebära en ändring av formeln för beräkning av ADC:s noggrannhet:

noggrannhet = referensspänning / 1024

Referensspänningen bestämmer gränsen för det område som ADC:n kommer att arbeta med.

I vårt exempel kommer referensspänningen att vara lika med matningsspänningen för Arduino Uno, som gavs av USB-porten på datorn. I just mitt fall var denna spänning 5,02 volt, och jag kan lugnt säga att jag mätte batteriladdningen med hög noggrannhet.

Vad händer om du driver mikrokontrollern från en annan källa? Låt oss säga att du har fyra 1,2 Volt NiMh-batterier. Totalt kommer de att ge 4,8 volt (låt dem vara lite urladdade, för i verkligheten laddas de upp till 1,4 volt). Mätnoggrannheten blir 4,8/1024. Detta bör beaktas i vårt program.

Slutligen, överväg fallet när vi matar Arduino Uno med en spänning, och vi vill ställa in en helt annan spänning som referens, till exempel 3,3 volt. Vad ska man göra? För detta alternativ har Arduino Uno en speciell utgång Vref. För att lösa problemet måste vi applicera en spänning på 3,3 volt på detta stift och möjliggöra användningen av en extern spänningsreferens med funktionen:

AnalogReference(EXTERNAL);

som ska anropas i setup-funktionen i vårt program.

Det bör också beaktas att resultatet av mätning av spänningsvärdet inte kan överskrida gränserna för området. Om vi ​​väljer 3,3 volt som referensspänning, och den inkommande signalen kommer att ha en hög spänning, kommer vi att få fel spänningsvärde, eftersom ADC:n inte "vet" att en högre spänning finns.

4. Program

Vårt första ADC-program kommer att vara extremt enkelt: varje sekund mäter vi det analoga värdet på ingång A0 och överför det till serieporten.

intervall = 0; void setup() ( Serial.begin(9600); pinMode(A0, INPUT); ) void loop() ( val = analogRead(A0); Serial.println(val); delay(1000); )

Nu laddar vi programmet på Arduino, och vi går vidare till mätningar.

5. Anslutning

För att mäta spänningen på ett batteri behöver vi ansluta det till vår Arduino med bara två stift. Vi använder till exempel ett 1,5 volt alkaliskt batteri.

Låt oss nu öppna COM-monitorfönstret i Arduino IDE och se vilket värde ADC ger oss:

Vad betyder siffran 314? Kom ihåg att en 10-bitars ADC bryter intervallet från 0 till 5 volt i 1024 delar. Det betyder att noggrannheten för en 10-bitars ADC är 5/1024. Genom att känna till noggrannheten kan vi skriva en formel för att konvertera ADC-avläsningar till volt:

V = (5/1024)*ADC

där V är den uppmätta spänningen på batteriet;
ADC är resultatet av analogRead-funktionen.

Låt oss ersätta denna formel i programmet och försöka mäta batteriladdningen igen!

intervall = 0; void setup() ( Serial.begin(9600); pinMode(A0, INPUT); ) void loop() ( val = analogRead(A0); Serial.println((5/1024.0)*val); delay(1000); )

Mätresultat:

Det ser mer ut som sanningen.

6. Slutsats

Så vi har behandlat ett mycket komplext och viktigt ämne inom elektronikens värld. ADC används överallt, och inom robotteknik är denna enhet verkligen oumbärlig. För att förstå världen omkring dem måste robotar på något sätt översätta analoga förnimmelser till siffror.

På vår portal kan du hitta flera lektioner, vars genomförande beror på förståelsen av ADC-ämnet: , kapacitiv sensor, potentiometer och analog joystick. Och i samband med ett annat viktigt ämne - PWM, kommer användningen av en ADC att göra det möjligt för dig att skapa en LED-lampdimmer och en motorhastighetsregulator. Lycka till!