Lektion 5: Läsa Analoga In

Nu skall vi lära oss att läsa av analoga ingångar. En analog ingång mäter spänning och som standard på ATMega328P (som är den microkontroller vi använder på vårt utvecklingskort) är den 0 till +5VDC, men kan vara annan beroende på matningsspänning eller om man satt ett annat referensvärde (AREF). Men här kör vi med 5VDC. Utvecklingskortet har 6 analoga ingångar (A0 till A5) och finns nere i vänstra hörnet på utvecklingskortet (om du har USB kontakten ifrån dig). Dessa analoga ingångar har en upplösning på 10bit vilket kan ge ett värde från 0 till 1023 (1024 steg). Låt oss utgå från förra kopplingen utan att ändra något på dessa 8 lysdioder, vi skall göra en enkel digital VU mätare, dvs. en stapel av lysdioder som tänds beroende på hur mycket värde som vi läser på en analog ingång. Är där ingen spänning (0V) så skall ingen vara tänd och är där full spänning (+5V) så skall alla lysa upp. Vi använder oss av en potentiometer (blå 10Kohm som finns med i starterkitet) och den kopplas in som bilden nedan visar. En potentiometer är som ett variabelt motstånd eller spänningsdelare.

VU Mätare

Tryck fast potentiometern i de 3 raderna längst ner till vänster, ha den svarta texten på potentiometern till vänster (på detta viset ökar spänningen när vi vrider medurs). Anslut sedan ytterbenen till +5V (överst på potentiometern, röd kopplingstråd) och till 0V (nederst på potentiometern, svart kopplingstråd). Mittersta pinnen på potentiometern ansluter du till ANALOG IN och A0 som finns på utvecklingskortet längst nere till vänster (blå kopplingstråd). Nedan är ett enkelt kopplingsschema på symbol för potentiometer samt hur den kopplas in (obs lysdioderna syns inte här).

Hämta hem programmet här, kompilera, ladda upp och testa att vrida potentiometern. Nedan visas programmet i sin helhet.

/*
  Read Analog Input and display on 8 LEDs

  Turns on LEDs depending on how high Analog Value is on channel 0
  Like a simple VU meter

  Created FEB-24, 2012 by Lars Wictorsson
  LAWICEL AB, http://www.lawicel-shop.se

  This example code is in the public domain.
*/
// LED Pin Variables in an Array, First LED is attached to I/O 2 etc.
int LED_Pins[] = {2, 3, 4, 5, 6, 7, 8, 9};
// Temporary variable to use in e.g. for next loops etc.
int tmp;
// Variable to hold which LED was turned on last time
int Old_LED = 0;
// Variable to hold the read from the Analog input
int PotValue = 0;
void setup() {
// Make sure all I/O for external LEDs are outputs. 
  for (tmp = 0; tmp < 8; tmp++) {
    pinMode(LED_Pins[tmp], OUTPUT);
  }
}
void loop() {
// Read value from Analog input 0, add 2 and divide with 128, then save to variable
  PotValue = (analogRead(0) + 2) / 128;
  for (tmp = 0; tmp < 8; tmp++) {
    digitalWrite(LED_Pins[tmp], LOW);     // Turn of all LEDs
  }
  for (tmp = 0; tmp < PotValue; tmp++) {
    digitalWrite(LED_Pins[tmp], HIGH);    // Turn on all LEDs as high as the analog value is
  }
}

Programmet är enkelt uppbyggt och vi förklarar här bara vad som är nytt jämfört med förra programmet. Vi har lagt till en variabel av typen i int (heltal) strax ovanför setup() funktionen.

// Variable to hold the read from the Analog input
int PotValue = 0;

Nedan är själva huvudloopen som snurrar runt hela tiden. Den första raden läser av det analoga värdet från I/O pinne A0 (detta värde kan vara från 0 till 1023) sedan lägger vi till 2 och anledningen till att vi gör detta är för att vi vill tända upp den sista lysdioden när vi har ett maxvärde på analoga ingången. Vi vill representera 0-1023 på endast 8 lysdioder. Vid 0 skall inga lysdioder lysa, så det ger oss 1024 värde som skall delas upp på 8 lysdioder. 1024/8=128 och det är det vi delar värdet med för att få ett heltal mellan 0-8. Dock är nu max 1023 och delar man det med 128, så får man 7.99 och när man har heltal rundar den inte av som vi gör i matte utan det blir endast 7. Det är därför vi lägger till 2 på det analog värdet, så i teorin kan vi få 1025 som max innan vi delar med 128, dvs. resultatet blir 8.0078. 2 kan vara för lite, så det kan hända att ni får öka detta värde (det kan i princip vara allt från 1 till 127, ju högre värde desto lägre spänning behövs för att första gula lysdioden skall tändas).

När vi läst det analoga värdet och räknat ut hur många lysdioder som skall tändas, ser vi till att släcka alla först (utifall nästa gång vi läser och värdet är mindre skulle lysdioder vara kvar tända i toppen). Vi släcker dem enkelt med en for sats.

Nästa for sats tänder upp så många lysdioder som värdet anger.

void loop() {
// Read value from Analog input 0, add 2 and divide with 128, then save to variable
  PotValue = (analogRead(0) + 2) / 128;
  for (tmp = 0; tmp < 8; tmp++) {
    digitalWrite(LED_Pins[tmp], LOW);     // Turn of all LEDs
  }
  for (tmp = 0; tmp < PotValue; tmp++) {
    digitalWrite(LED_Pins[tmp], HIGH);    // Turn on all LEDs as high as the analog value is
  }
}

Nu har vi lärt oss lite om analoga ingångar. Vi kan fortsätta lite till med att ändra programmet och lära oss att skriva ut det råa analoga värdet via USB så vi kan få upp det i ett s.k. terminalfönster på datorn. Ny version av programmet finns här. Skillnaden i programmet är dels i setup() funktionen där vi lagt till 2 rader för att initiera upp serieporten (UART:en eller USART:en som den även kallas i AVR:en). Vi initierar upp den med 9600baud. Serieporten finns på I/O 0 (TX) och I/O 1 (RX) så skall du använda serieporten så kan du inte använda dessa I/O till annat.

// Opens serial port, sets data rate to 9600 bps.
  Serial.begin(9600);

I loop() har vi fått ändra lite när vi läser det analoga värdet och räknar ut det för lysdioderna. Istället för att göra allt på en rad har vi delat upp det så att vi först läser det analoga värdet och sparar det i variabeln PotValue (detta värde kallas ofra “raw value”, dvs. obehandlat). Sedan kommer 2 rader där vi skriver ut dels “A0=” utan radmatning som en ledtext och sedan skriver vi ut det obehandlade värdet med radmatning, så nästa varv får vi en ny rad att skriva på. Efter detta räknar vi ut värdet som skall vara för lysdioderna.

// Read value from Analog input 0
  PotValue = analogRead(0);
// Print raw value on UART (USB)
  Serial.print("A0=");
  Serial.println(PotValue);
// Calculate value for LED's by adding 2 and divide with 128, then save back to variable
  PotValue = (PotValue + 2) / 128;

När du kompilerat och laddat ner programmet, så gå upp i menyn under “Tools” och välj “Serial Monitor”, ett litet fönster kommer upp och värden skall vara som de visar på bilden nedan. Vrid på potentiometern och du kommer att se att värdet ändrar sig från 0 till 1023.

Vi har nu lärt oss hur analoga ingångar fungerar och lite hur man kan få över information till PC via UART/USB. Att göra på detta kallas ofta för “fattigmans debug”, man kan skicka över debugvärden (variabler, uträkningar, ingångar m.m.) via UARTen och upp via USB till värddatorn (PC, Mac, Linux).

Föregående Sida    –    Nästa sida