tone() werkt niet zoals gewenst.

Arduino specifieke Software
Gebruikers-avatar
Berichten: 48
Geregistreerd: 22 Jun 2013, 00:04

tone() werkt niet zoals gewenst.

Berichtdoor Duiker » 18 Mei 2024, 19:47

Hallo allemaal.

In onderstaande code roep ik Call_Buzzer aan. Maar ik hoor slechts een toon, terwijl ik er meerdere verwacht.
Het aanroepen gebeurd in Call_TekenCompas(int Angle).

Call_Buzzer op zich werkt prima als ik deze los test. Vandaar ook mijn vraag. Wie zou me op weg kunnen helpen?


Code:Alles selecteren
/*##############################################################################
This programm shows a Compass
The angle is set with a rotary encoder
This program is made for fun


##############################################################################*/

//Used library's
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

//Define connections
//Display
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST 8
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_CLK 13
//AngelEncoder
#define AngleEncoder_CLK 2 //Dit is een Interupt pin
#define AngleEncoder_DT 6
#define AngleEncoder_SW 7
#define SDA A4
#define SCL A5
//Buzzer
#define Buzzer A0

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

//Define colors B G R
#define Black tft.color565( 0, 0, 0) //BGR
#define Blue tft.color565(255, 0, 0) //BGR
#define Red tft.color565( 0, 0, 255) //BGR
#define Green tft.color565( 0, 255, 0) //BGR
#define Cyan tft.color565(255, 255, 0) //BGR
#define Magenta tft.color565(255, 0, 255) //BGR
#define Yellow tft.color565( 0, 255, 255) //BGR
#define DarkYellow tft.color565( 0, 128, 128) //BGR
#define White tft.color565(255, 255, 255) //BGR
#define Silver tft.color565(192, 192, 192) //BGR
#define DarkSilver tft.color565( 96, 96, 96) //BGR

//Define variabelen
int ScreenWidth;
int ScreenHeight;
int BackGroundColor = Black;
float SinVal;
float CosVal;
int X1;
int Y1;
int X2;
int Y2;
int X3;
int Y3;
int Angle = 0;
int OldAngle;
int Radius;
int StreepLengte;
int GradenKleur = Green;
int BinnenCirkelKleur = DarkSilver;
int BuitenCirkelKleur = DarkSilver;
int CompassOriginX;
int CompassOriginY;
bool AngleLastClk;

void setup() {
//Init SerialPrinter
Serial.begin(9600);

//Init TFT Screen
tft.begin();
tft.setRotation(0); //Connector down
Call_ClearScreen();

//Init AngleEncoder
pinMode(AngleEncoder_CLK, INPUT);
pinMode(AngleEncoder_DT, INPUT);
pinMode(AngleEncoder_SW, INPUT);
AngleLastClk = HIGH;
attachInterrupt(digitalPinToInterrupt(AngleEncoder_CLK), ReadAngleEncoder, FALLING);

//Init Buzzer
pinMode(Buzzer, OUTPUT);

//Define screen dimensions
CompassOriginX = (tft.width() / 2);
//CompassOriginY = tft.height() / 2;
CompassOriginY = (tft.width() / 2); //Square compass

ScreenWidth = tft.width();
ScreenHeight = tft.height();

Radius = ScreenWidth / 2;
StreepLengte = 15;

//Draw cirkels
tft.drawCircle(CompassOriginX, CompassOriginY, Radius - 1, BuitenCirkelKleur); //Buitenste cirkel
tft.drawCircle(CompassOriginX, CompassOriginY, Radius - 1 - StreepLengte - 1, BinnenCirkelKleur); //Binnenste cirkel

//Print Noord
tft.setCursor( CompassOriginX - 2, CompassOriginY - Radius + 1 + StreepLengte + 0 + 5); //5 = afstand tot cirkel
tft.print("N");

//Print Zuid
tft.setCursor( CompassOriginX - 2, CompassOriginY + Radius - 1 - StreepLengte - 7 - 5); //7 = karakterHoogte
tft.print("Z");

//Print Oost cirkel | afstand | | char / 2
tft.setCursor( CompassOriginX - Radius + 1 + StreepLengte + 0 + 5, CompassOriginY - 3); //5 = afstand tot cirkel
tft.print("O");

//Print West cirkel | afstand | | (charW / 2) | (CharH / 2)
tft.setCursor( CompassOriginX + Radius - 1 - StreepLengte - 5 - 5, CompassOriginY - 3 ); //5 = karakterBreedte
tft.print("W");

//Sin Hoek omzetten naar Sin in graden

//Print NoordOost
Angle = 45;
SinVal = (sin(Angle * (3.1415 / 180)));
CosVal = (cos(Angle * (3.1415 / 180)));
X1 = CompassOriginX + ( CosVal * Radius * 0.8 ) - 6; // 6=midchar
Y1 = CompassOriginY - ( SinVal * Radius * 0.8 ) - 1; //
tft.setCursor( X1, Y1 );
tft.print("NO");

//Print ZuidOost
Angle = 315;
SinVal = (sin(Angle * (3.1415 / 180)));
CosVal = (cos(Angle * (3.1415 / 180)));
X1 = CompassOriginX + ( CosVal * Radius * 0.8 ) - 6; // 6=midchar
Y1 = CompassOriginY - ( SinVal * Radius * 0.8 ) - 4; //
tft.setCursor( X1, Y1 );
tft.print("ZO");

//Print NoordWest
Angle = 135;
SinVal = (sin(Angle * (3.1415 / 180)));
CosVal = (cos(Angle * (3.1415 / 180)));
X1 = CompassOriginX + ( CosVal * Radius * 0.8 ) - 3; // -4 6=midchar
Y1 = CompassOriginY - ( SinVal * Radius * 0.8 ) - 1; // -2
tft.setCursor( X1, Y1 );
tft.print("NW");

//Print ZuidWest
Angle = 225;
SinVal = (sin(Angle * (3.1415 / 180)));
CosVal = (cos(Angle * (3.1415 / 180)));
X1 = CompassOriginX + ( CosVal * Radius * 0.8 ) - 2; // -2 6=midchar
Y1 = CompassOriginY - ( SinVal * Radius * 0.8 ) - 4; // -0
tft.setCursor( X1, Y1 );
tft.print("ZW");

Angle = 0;
OldAngle = 0;
Call_TekenCompas(Angle);

}

void loop(void) {
//There is no loop because the compass is interupt driven

}

void Call_ClearScreen() {
tft.fillScreen(BackGroundColor);
} //Call_ClearScreen()

void Call_TekenCompas(int Angle) {
Call_Buzzer(3);
//Tijdelijk
//tft.drawFastHLine(0, tft.height() / 2, tft.width(), CYAN);
//tft.drawFastVLine(tft.width() / 2, 0, tft.height(), CYAN);
//tft.drawLine( CompassOriginX, CompassOriginY, (tft.width() / 2) - (tft.height() / 2), (tft.height() / 2) - (tft.height() / 2), Yellow);
//tft.drawLine( CompassOriginX, CompassOriginY, (tft.width() / 2) + (tft.height() / 2), (tft.height() / 2) - (tft.height() / 2), Yellow);
//tft.drawLine( CompassOriginX, CompassOriginY, (tft.width() / 2) - (tft.height() / 2), (tft.height() / 2) + (tft.height() / 2), Yellow);
//tft.drawLine( CompassOriginX, CompassOriginY, (tft.width() / 2) + (tft.height() / 2), (tft.height() / 2) + (tft.height() / 2), Yellow);

//Delete old angle
//Sin OldAngle omzetten naar Sin in graden
SinVal = (sin(OldAngle * (3.1415 / 180)));
CosVal = (cos(OldAngle * (3.1415 / 180)));

//X1, Y1 = binnencirkel X2, Y2 = buitencirkel
X1 = CosVal * (Radius - 1 - StreepLengte + 2); // - 1, anders wordt op de cirkel getekend
Y1 = SinVal * (Radius - 1 - StreepLengte + 2);

X2 = CosVal * (Radius - 2); //- 2, anders wordt op de cirkel getekend
Y2 = SinVal * (Radius - 2);

X3 = CompassOriginX;
Y3 = CompassOriginY;

//Correctie voor het aantal digits, 1, 2 of 3
if (OldAngle < 10) { X3 = X3 - 5; }
if (OldAngle < 10) { Y3 = Y3 - 7; }

if (OldAngle >= 10) { X3 = X3 - 10; }
if (OldAngle >= 10) { Y3 = Y3 - 7; }

if (OldAngle >= 100) { X3 = X3 - 7; }

//Cirkel streepjes wissen
tft.drawLine( CompassOriginX + X1, //Binnencirkel
CompassOriginY - Y1, //Binnencirkel
CompassOriginX + X2, //Buitencirkel
CompassOriginY - Y2, //Buitencirkel
BackGroundColor);

//Aantal graden wissen
tft.setTextColor(BackGroundColor);
tft.setCursor(X3, Y3);
tft.print(OldAngle);
tft.print((char)247); //Graden symbool
tft.setTextSize(2); //Herstellen TextSize

//Nieuwe hoek tekenen
//Sin Angle omzetten naar Sin in graden
SinVal = (sin(Angle * (3.1415 / 180)));
CosVal = (cos(Angle * (3.1415 / 180)));

//X1, Y1 = binnencirkel X2, Y2 = buitencirkel
X1 = CosVal * (Radius - 1 - StreepLengte + 2); // - 1, anders wordt op de cirkel getekend
Y1 = SinVal * (Radius - 1 - StreepLengte + 2);

X2 = CosVal * (Radius - 2); //- 2, anders wordt op de cirkel getekend
Y2 = SinVal * (Radius - 2);

X3 = CompassOriginX;
Y3 = CompassOriginY;

//Correctie voor het aantal digits, 1, 2 of 3
if (Angle < 10) { X3 = X3 - 5; }
if (Angle < 10) { Y3 = Y3 - 7; }

if (Angle >= 10) { X3 = X3 - 10; }
if (Angle >= 10) { Y3 = Y3 - 7; }

if (Angle >= 100) { X3 = X3 - 7; }

//Cirkel streepjes tekenen
tft.drawLine( CompassOriginX + X1, //Binnencirkel
CompassOriginY - Y1, //Binnencirkel
CompassOriginX + X2, //Buitencirkel
CompassOriginY - Y2, //Buitencirkel
GradenKleur);

//Aantal graden
tft.setTextColor(GradenKleur);
tft.setCursor(X3, Y3);
tft.setTextSize(2); //Instellen TextSize
tft.print(Angle);
tft.print((char)247); //Graden symbool

OldAngle = Angle;
} //Call_TekenCompas()

void ReadAngleEncoder() {
int dtValue = digitalRead(AngleEncoder_DT);
if (dtValue == HIGH) {
Angle--;
}
if (dtValue == LOW) {
Angle++;
}

//Hoek correctie rondom 0 graden
if (Angle < 0) { Angle = 359; }
if (Angle >= 360) { Angle = 0; }

Call_TekenCompas(Angle);

} //ReadAngleEncoder

void Call_Buzzer(int AantalKeer) {
for(int Teller = 1; Teller<=AantalKeer; Teller+=1) {
tone(Buzzer, 800, 50); //Tone, time
delay(100);
}
} //Call_Buzzer
We leven in het midden van de ruimte, maar aan de rand van de tijd.

Advertisement

Gebruikers-avatar
Berichten: 48
Geregistreerd: 22 Jun 2013, 00:04

Re: tone() werkt niet zoals gewenst.

Berichtdoor Duiker » 18 Mei 2024, 23:34

Bericht verwijderd.
Laatst gewijzigd door Duiker op 19 Mei 2024, 00:00, in totaal 1 keer gewijzigd.
We leven in het midden van de ruimte, maar aan de rand van de tijd.

Gebruikers-avatar
Berichten: 48
Geregistreerd: 22 Jun 2013, 00:04

Re: tone() werkt niet zoals gewenst.

Berichtdoor Duiker » 18 Mei 2024, 23:57

Het project heb ik verkleind to alleen het noodzakelijke om tone te onderzoeken.

Als de interupt geactiveerd wordt, dan gaat het met tone nog steeds mis. Slechts een piepje is te horen.

Hier is het project te vinden: https://wokwi.com/projects/398258883324485633

Code: Alles selecteren
/*##############################################################################
This programm shows a Compass
The angle is set with a rotary encoder
This program is made for fun


##############################################################################*/

//Define connections
//AngelEncoder
#define AngleEncoder_CLK 2 //Dit is een Interupt pin
#define AngleEncoder_DT  6
#define AngleEncoder_SW  7
#define SDA A4
#define SCL A5
//Buzzer
#define Buzzer A0

bool AngleLastClk;

void setup() {
  //Init SerialPrinter
  Serial.begin(9600);
 
  //Init AngleEncoder
  pinMode(AngleEncoder_CLK, INPUT);
  pinMode(AngleEncoder_DT,  INPUT);
  pinMode(AngleEncoder_SW,  INPUT);
  AngleLastClk = HIGH;
  attachInterrupt(digitalPinToInterrupt(AngleEncoder_CLK), ReadAngleEncoder, FALLING);

  //Init Buzzer
  pinMode(Buzzer, OUTPUT);

  int Angle = 0;
  int OldAngle = 0;
 
  Call_Buzzer(3);
}

void loop(void) {
  //There is no loop because the compass is interupt driven
}

void ReadAngleEncoder() {
  //Deze procedure wordt gecativeerd omdat de CLK van de encoder een
  //puls op de Interupt_0 ingang (D2) genereerd. Alleen daarom.
  Call_Buzzer(3);
  delay(2000);
} //ReadAngleEncoder

void Call_Buzzer(int AantalKeer) {
  Serial.println(AantalKeer);
  for(int Teller = 1; Teller<=AantalKeer; Teller+=1) {
    tone(Buzzer, 1000, 50); //Tone, time
    delay(100);             //Delay moet groter zijn dan tone time
  }
}
We leven in het midden van de ruimte, maar aan de rand van de tijd.

Berichten: 186
Geregistreerd: 26 Aug 2015, 11:57

Re: tone() werkt niet zoals gewenst.

Berichtdoor Frits1956 » 19 Mei 2024, 23:57

Wat mij opvalt is de tijd dat de toon duurt. 50 ms.
Lijkt mij super kort. wat ik zou proberen is een toon van 500 ms en luisteren wat het resultaat dan is.

Gebruikers-avatar
Berichten: 48
Geregistreerd: 22 Jun 2013, 00:04

Re: tone() werkt niet zoals gewenst.

Berichtdoor Duiker » 20 Mei 2024, 08:29

Hallo Frits1956,
Dat heb ik ook geprobeerd. 50 ms is om alleen een klik te laten horen. Inmiddels heb ik e.e.a. opgelost.

De oplossing bestaat er uit om een bool te plaatsen in ReadAngleEncoder().
In de hoofdloop wordt die bool getest op TRUE. Pas dan wordt er naar Call_Buzzer gesprongen. Op deze manuer is het geluid prima te horen.

Kanttekening:
tone(Buzzer, 1000, 50); //Tone, time
delay(100); //Delay moet groter zijn dan tone time

Als die delay te kort is, dan is er slechts een tone to horen.
Ik DENK dat het programma gewoon doorloopt terwijl deze met tone bezig is. Anders was een kortere delay ook goed.

Maar waarom dit nou binnen de interupt niet werkt is me een raadsel.
Bij een interupt stopt het lopende programma, en gaat naar de interupt procedure.
Daar wordt een tone gegenereerd, ondertussen loopt het programma verder met de delay. Ik heb altijd begrepen dat tijdens de delay geen programma code uitgevoerd kan worden.
We leven in het midden van de ruimte, maar aan de rand van de tijd.

Berichten: 186
Geregistreerd: 26 Aug 2015, 11:57

Re: tone() werkt niet zoals gewenst.

Berichtdoor Frits1956 » 20 Mei 2024, 09:06

Ik keek nog eens naar de code en met name naar de interrupt procedure ReadAngleEncoder().
daar zag ik een delay staan maar.......
dit is een quote uit de Reference. https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
Notes and Warnings

Note

Inside the attached function, delay() won't work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.

Gebruikers-avatar
Berichten: 636
Geregistreerd: 15 Nov 2015, 11:54

Re: tone() werkt niet zoals gewenst.

Berichtdoor Gij Kieken » 20 Mei 2024, 09:34

Hey Duiker,
In een Isr werkt millis niet (de millis functie is zelf interrupt gestuurd), mocht je kiezen voor delay microSeconds dan gaat het ook al vlug fout na een paar milli seconden.
Dus geen vertragingen gebruiken in een ISR, dus ook geen Serial.prints liefst.
De variabelen die je gebruikt met een ISR maak je best ook volatile.
Maak ook je input Pullup anders zweeft die (ofwel ingebouwd danwel extern).
Bijgevoegd een stukje code voor wat te proberen.
Code: Alles selecteren
//Define connections
//AngelEncoder
volatile int AngleEncoder_CLK = 2; //Dit is een Interupt pin
int count = 0;
#define AngleEncoder_DT  6
#define AngleEncoder_SW  7
#define SDA A4
#define SCL A5
//Buzzer
#define Buzzer A0

bool AngleLastClk;

void setup() {
  //Init SerialPrinter
  Serial.begin(9600);
 
  //Init AngleEncoder
  pinMode(AngleEncoder_CLK, INPUT_PULLUP);
  pinMode(AngleEncoder_DT,  INPUT);
  pinMode(AngleEncoder_SW,  INPUT);
  AngleLastClk = HIGH;
  attachInterrupt(digitalPinToInterrupt(AngleEncoder_CLK), ReadAngleEncoder, FALLING);

  //Init Buzzer
  pinMode(Buzzer, OUTPUT);

  int Angle = 0;
  int OldAngle = 0;
 
  Call_Buzzer(3);
}

void loop(void) {
  if (count){
   for(int Teller = 1; Teller<=count; Teller+=1) {
   tone(Buzzer, 1000, 50);
   delay(200);
    }
   }
 count=0;
}

void ReadAngleEncoder() {
  //Deze procedure wordt gecativeerd omdat de CLK van de encoder een
  //puls op de Interupt_0 ingang (D2) genereerd. Alleen daarom.
  Call_Buzzer(3);
}

void Call_Buzzer(int AantalKeer) {
  count = AantalKeer;
    return count;
  }


Gebruikers-avatar
Berichten: 48
Geregistreerd: 22 Jun 2013, 00:04

Re: tone() werkt niet zoals gewenst.

Berichtdoor Duiker » 24 Mei 2024, 09:20

Frits1956, en Gij Kieken bedankt voor de reacties. E.e.a. is me nu een stuk duidelijker.
We leven in het midden van de ruimte, maar aan de rand van de tijd.

Terug naar Arduino software

Wie is er online?

Gebruikers in dit forum: ebuvoxoivemi en 24 gasten