Start Elkretssimulator


Koppla knappar till analog ingång

Problemet: digitala pinnar slut

Det finns bara ett begränsat antal digitala in/ut -gångar på de flesta mikrokontrollers. Säg att de digitala in/ut -gångarna är slut men du behöver ansluta några knappar. En variant är att använda en analog ingång på mikrokontrollern. Studera nedan schema.



Beroende på vilken knapp vi klickar på så skapas en spänningsdelare som ger olika typer av spänningar. Denna spänning läser vi sedan av med den analoga ingångens A/D -omvandlare och kan på så vis avgöra vilken knapp vi klickat på. Spänningen i ovan schema är 5 volt.

Prova kretsen i simulatorn. Klicka på någon av knapparna och studera hur det fungerar.

Klickar på S1

Om vi klickar på S1 så skapas en sluten krets med strömmen

I = U / (R1+R4) = 5 volt / ( 22 Ω + 220 Ω) = 5 volt / 244 Ω = ca 20 mA

Det betyder att spänning över voltmetern, som också är vår inkoppling till den analoga ingången på vår arduino senare, i schemat är

U1 = 20mA x 220 Ω = 4.5 volt

Klickar på S2

På motsvarande sätt om vi klickar på knapp S2 så får vi en sluten krets med strömmen

I = U / (R2+R4) = 5 volt / ( 100 Ω + 220 Ω) = 5 volt / 330 Ω = ca 15.6 mA.

Detta ger spänningen

U1 = 15.6 mA x 220 Ω = 3.4 volt

Klickar på S3

Klickar vi på S3 så får vi en sluten krets med strömmen

I = U / (R3+R4) = 5 volt / ( 220 Ω + 220 Ω) = 5 volt / 440 Ω = ca 11 mA

Detta ger spänningen

U1 = 11mA x 220 Ω = 2.5 volt

I vår kod måste sedan läsa av ett intervall eftersom spänningarna inte kommer bli exakt ovan värden. Men de är tillräckligt distinkta (åtskilda) för att vi säkert skall kunna avgöra i koden vilken knapp som är nertryckt.

Vad händer om vi klickar på flera knappar samtidigt, t.ex. alla 3 samtidigt? Om vi parallellkopplar R1, R2 och R3 får vi följande resistans

R = 1 / (1/R1 + 1/R2 + 1/R3) = 1 / (1/22 + 1/100 + 1/220) Ω = 1 / 0.06 Ω = 16.7 Ω

Dvs, vi får en ström på

5 volt / (16.7 &ohm + 220 Ω) = 5 volt / 236 Ω = 21 mA

Dvs spänningen U1 blir

U1 = 21mA x 220 Ω = ca 4.7 volt

Koppla ihop

Efter att ha grottat lite i motstånds -lådan hittade jag inte exakt ovanstående resistanser men däremot värden 24 Ω, 110 Ω samt 2 st 200 Ω så ovanstående spänningar kommer inte stämma för mig. Strunt i det! Den ihoplödda knappgrejen ser ut som nedan. Svart och Röd spänning in och organge signal ut till lämplig A/D -ingång.



Test

Mäter jag spänningen med multimeter får jag nu 2.48 volt, 3.19 volt eller 4.39 volt beroende på vilken knapp jag trycker.

Om jag trycker in signalen från knapparna i analog in pinne 3 och kör över följande program ...

int val = 0;

void setup() 
{
  Serial.begin(115200); 
}

void loop() 
{
  val = analogRead(3);
  Serial.println(val);  
}


Så får jag nu detta resultat beroende på vilken knapp jag trycker:

Trycker på knapp 1.



Trycker på knapp 2.



Trycker på knapp 3.



Är ovan värden vettiga? Vi kan göra en liten kontrollräkning. Den analoga insignalen ger ett värde 0-1024 mellan 0-5 volt. Vår kontrollmätning gav 2.48 volt, 3.19 volt eller 4.39 volt beroende på vilken knapp vi tryckte på. Det betyder att vi borde fått värdena:

2.48 * (1024 / 5) = 508
3.19 * (1024 / 5) = 653
4.39 * (1024 / 5) = 899

Detta stämmer inte riktigt med de värden vi fick men det är ganska bra ändå. Min voltmeter är troligtvis felkällan då batterierna är dåliga och den är inte heller kalibrerad. Det är inte så noga!

Okej, så vi kan skriva om programmet så att det ser ut såhär.

int val = 0;

void setup() 
{
  Serial.begin(115200); 
}

int knapp(int v)
{
  if(v>450&&v<550) return 1;
  if(v>600&&v<700) return 2;
  if(v>850&&v<950) return 3;
  return 0;
}

void loop() 
{
  val = knapp(analogRead(3));
  if(val)
  {
      Serial.println(val); 
  }
}


Fixa knappstuds

Ovan kod ger oss med säkerhet den knapp vi klickar på. Men det återstår fortfarande ett problem och det är knappstudset. Ett sätt att komma runt är t.ex. på följande sätt. Dvs vi fångar knapptrycket och behåller detta värde tills ingen knapp har varit tryckt på en liten stund. Interruptet anropar ISR ca 16 ggr per sekund.

int pval = 0;
int val = 0;
int keyPressed = 0;
int countNopress = 0;

void setup() 
{
  Serial.begin(115200); 

  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A =  1000; 
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10); // 1024 prescaler
  TIMSK1 |= (1 << OCIE1A);
  sei();  
}

int knapp(int v)
{
  if(v>450&&v<550) return 1;
  if(v>600&&v<700) return 2;
  if(v>850&&v<950) return 3;
  return 0;
}

ISR(TIMER1_COMPA_vect)  // 16 ggr/sekund cirka
{
  pval = knapp(analogRead(3));
    
  if(pval == 0)
  {
    countNopress++;
    if(countNopress > 1)
      val = 0;    
  }
  else
  {
    if(val != pval)
    {
      val = pval;
      countNopress = 0;      
      doSomething(val);
    }
  }
}

int doSomething(int k)
{
  Serial.println(k); 
}

void loop() 
{
  
}



Nu anropas doSometing() bara 1 gång varje gång vi trycker på en knapp, precis som vi önskar. Programmet accepterar nu bara ett knapptryck om knapparna varit uppsläpta en liten stund (0.1 sek någonting).