Arduino - Passive buzzer

From SPAD-it Wiki
Revision as of 08:36, 12 September 2017 by WikiAdmin (talk | contribs) (Navigatie)

Jump to: navigation, search

In een vorig projectje hebben we active buzzer al gezien. Dat elementje piept vanzelf als er spanning op wordt gezet. De pasive buzzer maakt alleen geluid als je de invoer spanning snel laat wisselen. Het voordeel daarvan is dat je de toonhoogte kunt aanpassen, maar de Arduino moet dan het werk doen.

De schakeling

Extra benodigdheden:

  • 1 (passive) buzzer
  • 1 potmeter

Onderstaande schakeling is erg eenvoudig en snel in elkaar te zetten.

Passive buzzer.png
Verbindingen in het breadboard met een bijbehorende schema tekening

Het programma

Om geluid uit de passive buzzer te krijgen moet het programma de buzzer continu aan en uit zetten met de gewenste frequentie. Dat gebeurt door de betreffende pin (pin 6) aan en uit te zetten. In principe kun je ook een PWM signaal gebruiken met voldoende breedte (pin 6 heeft ook PWM). Als je bijvoorbeeld 128/255 zou gebruiken is de spanning de helft van de tijd hoog en de andere helft laag. Met een PWM signaal kunnen we de buzzer alleen aan- en uitzetten; de frequentie wordt dan bepaald door de ingebakken frequentie van de PWM elektronica. In plaats van die ingebouwde frequentie willen we de frequentie laten bepalen door de stand van de potmeter.

int buzzerpin = 6; // aansluitpin van de buzzer
int pot_pin = 0;   // A0 is the analog input pin for the potmeter

void setup()
{
  pinMode(buzzerpin, OUTPUT);
}

void loop()
{
  int freq = 5 * digitalRead(pot_pin);  
  // de frequentie is nu 5x de uitgelezen waarde
  // de potmeter geeft een waarde tussen 0 en 1023, dus de frequentie loopt zo van 0 tot 5 kHz
  // elke seconde freq pulsen => elke puls duurt dan 1/freq seconden
  // de spanning moet dan steeds een halve puls aan en een halve puls uit
  int wait = 1000000/freq/2;    // wait is de helft van een puls - in micro-seonden!!
  
  digitalWrite(buzzerpin,HIGH); // signaal hoog
  delayMicroseconds(wait);      // wacht halve periode  - delayMicroseconds() wacht microseconden (1-miljoenste seconde)
  digitalWrite(buzzerpin,LOW);  // signaal laag
  delayMicroseconds(wait-100);  // wacht andere helft periode - minus 100 microseconde ter compensatie van analogRead()
}

Uitleg van het programma

De setup() functie hoeft niet te worden uitgelegd. De loop() functie leest als eerste de waarde uit van de potmeter. Dat is een getal tussen 0 en 1023. Door dit met 5 te vermenigvuldigen krijgen we een getal tussen de 0 en 5115. Dit is freq: de gewenste frequentie of toonhoogte die dus tussen de 0 en 5 kHz ligt (kHz is kilo Herz, ofwel duizend Herz, waarbij Herz het aantal trillingen per seconde is). Om die frequentie te realiseren moet het signaal elke seconde freq keer aan- en uitgezet worden. Elke keer aan- en uitzetten moet dus 1/freq seconde duren. Bij een frequentie van 5 kHz duurt zo'n periode dus maar 1/5000 seconde. Dat is maar 1/5de van een microseconde! De delay() functie wacht steeds een aantal microseconden en dat is nu veel te lang. Daarom gebruiken we hier een andere delay functie: delayMicroseconds() die het opgegeven aantal microseconden wacht. Een microseconde is 1/1000ste van een milliseconde, ofwel, een miljoenste van een seconde. 1/freq seconde is 1000000/freq microseconde. De helft van die periode moet het signaal hoog zijn en de andere helft laag. Dat is wat we zien:

int wait = 1000000/freq/2;

De processor in de Arduino UNO werkt op 16 MHz en kan dus 16 miljoen keer per seconde een micro-taakje uitvoeren. Dat is snel genoeg om microseconden te kunnen wachten en tussendoor ongemerkt simpele sommetjes te maken. Maar toch zit er nog een verborgen probleem in het programma. De analogRead() functie heeft namelijk heel veel micro-taakjes uit te voeren voor hij met resultaat komt. In de praktijk duurt een analogRead() ongeveer 100 microseconde!! Dat is zoveel tijd dat we er in het programma rekening mee moeten houden, omdat gedurende de analogRead() pin 6 steeds LOW is. Daarom staat er in de tweede delayMicroseconds(wait-100).

Elke keer als tijdsduur echt belangrijk is moet je even naar je programma kijken of er dit soort problemen in kunnen zitten. Vooral analogRead() is wat dat betreft een "dure" functie, maar ook het zwaardere rekenwerk kan natuurlijk veel tijd vergen. Je kunt desnoods ook meten hoe lang een bepaald stuk van je programma duurt door via de serial monitor tijdsinformatie terug te sturen. De micros() functie is dan heel behulpzaam omdat die het aantal microseconde na de laatste reset van de Arduino teruggeeft. Het resultaat is een unsigned long: een type variabele dat veel grotere getallen aankan dan de door ons veel gebruikte int.

Beetje spelen

  • Eerder gaven we aan dat je ook met een PWM signaal van bijv 128/255 een geluid moet kunnen produceren met de buzzer. De toonhoogte is dan een afspiegeling van de ingebakken frequentie van de PWM. Door dit nu te doen kun je een idee krijgen van die ingebouwde PWM frequentie van de Arduino. Kun jij erachter komen wat die frequentie ongeveer is?
  • Eerlijk gezegd hebben we wel wat moeilijk zitten doen in dit project. De toonhoogte hebben we afgesteld met loops en wachttijden, terwijl het Arduino platform hiervoor een heel handige functie biedt: tone(). deze functie heeft twee parameters, pin en frequentie, waarmee heel gemakkelijk een toon kan worden weergegeven. Dit werkt op alle digitale pins en dus niet alleen op PWM pins. Probeer het volgende programmaatje maar eens en kijk dan of je begrijpt hoe het werkt:
int buzzerpin = 6;

void setup()
{
  pinMode(buzzerpin, OUTPUT);
}

void loop()
{
  for (int i=10; i<4000; i++)
    tone(buzzerpin,i);
}

Navigatie