antidender op Arduinopoort?

blackdog

Golden Member

Hi Fantomaz,

Bijna alle meetinstrumenten die hier een netwerk aansluiting hebben hangen hier in het netwerk.
Als het meetinstrument een Web interface heeft, zoals de Hameg scoop of b.v. mijn KeySight 3446xA multimeters,
dan krijgen ze een snelkoppeling in de browser zodat het werken hiermee weinig tijd kost.
Dit samen met Irfanview maak het voor mij efficient goede plaatjes hier te tonen op CO zonder dat dit al te veel tijd kost.
Doordat ik zelf de plaatjes host op mijn webserver, gaat het oploaden daarvan ook soepel.

Wat deKees zegt gebruik ik ook nog af en toe, dus via een USB stick, voor al als b.v. mijn OWON digitale scoop "zwevend" wordt gebruikt.
Ondanks dat een netwerk interface via CAT5 zwevend is, plug ik er dan toch geen netwerkabel in, dit omdat ik dit niet veilig genoeg vind.

Maar ik heb een paar jaar geleden ook nette plaatjes laten zien, gemaakt van mijn Philips Scoop.
Ik doe dan mijn best de camera of telefoon zo goed mogelijk voor het beeld te houden en pas de verlichting een beetje aan.
Kost wat meer moeite maar het kan nog steeds heel netjes.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Lambiek plaatste in een ander topic deze link:
http://www.talkingelectronics.com/projects/50%20-%20555%20Circuits/50%…

Laat daar nu ook een mooie debounce schakeling staan met een NE555:
http://www.talkingelectronics.com/projects/50%20-%20555%20Circuits/images/SwitchDebounce.gif

reading can seriously damage your ignorance

Mag ik een voorstel doen: Doe alles in software.

code:


void loop (void)
{
  unsigned char k; 
  static int kk;
  unsigned char key_debounced; 

  k = getkey ();

  kk = (kk << 1) | k;

  if (kk == -1) key_debounced = 1;
  if (kk ==  0) key_debounced = 0;

  // verwerk key_debounced... 


  delay_ms (1);
}

Je reageert nu na 16ms, je kan nog steeds nauwkeurig (op de ms!) de key lengte meten. Als je sneller wil reageren, doe je iets als

code:


  if ((k & 0x1ff) == 0x1ff) key_debounced = 1;

als je na 9 keer dezelfde waarde al wil reageren. Geen gedoe met extra hardware, maar een paar regels code.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Interessant REW,
Ik probeer je code te doorgronden, maar dat gaat me nog niet zo goed af.

Kun je hem stap voor stap beschrijven?
Mijn kennis is nog erg beperkt qua Arduino programmeren.

Waar ik mijn hoofd over breek wat Hardwarematig betreft, is het volgende:
Als mijn key dendert, doet hij dat tussen 5v en 0v...
Een Schmitt trigger, zal bij de eerste aangelegde spanning meteen de ingang hoog maken (al dan niet met de overbrugging van R2 met een diode), en daarmee dus de inverted uitgang laag.
https://www.circuitsonline.net/forum/file/29783
Als ik de key aansla, trek ik de C1 naar massa via R2 en de RC combinatie bepaalt hoe snel C1 weer is ontladen.
De eerste RC tijd zakt de spanning op de schmitt trigger voldoende om hem te laten "afvallen".
Maar Denderen is een snelle opeenvolging van (in mijn situatie) 5v en 0v.
Dan zal binnen de ontlaadtijd mogelijk het contact weer een fractie in tijd verbreken, waardoor C1 weer geladen wordt.
Dus zal die (geinverteerde) uitgang weer kort laag zijn, wat ik even niet wil.

Als ik de RC tijd wat langer maak, zal C1 nog niet voldoende zijn ontladen en zelfs weer laden, waardoor de ingang hoog blijft en de uitgang laag, wat ik niet wil want ik heb die Key aangeslagen.

Of zit de truc erin dat ik de ST ingang pas kan laten omslaan als C1 voldoende is ontladen?
Ik probeer dit te doorgronden.

Ik zal ook nog eens die scoop beelden van Blackdog proberen te begrijpen.

Fascinerend! maar nog te onduidelijk.

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)

Op 18 juni 2020 14:59:13 schreef hennep:
Lambiek plaatste in een ander topic deze link:
http://www.talkingelectronics.com/projects/50%20-%20555%20Circuits/50%…

Laat daar nu ook een mooie debounce schakeling staan met een NE555:
[afbeelding]

Wat een ontzettend informatieve site!
Daar valt ook goed mee te spelen, volgens mij!

Als ik het vluchtig doorgrond triggert de key bij de eerste aanslag meteen de 555 om naar null te gaan en daar een voorgeprogrammeerde tijd te blijven hangen.

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)

Op 18 juni 2020 21:51:08 schreef Fantomaz:
Waar ik mijn hoofd over breek wat Hardwarematig betreft, is het volgende:
Als mijn key dendert, doet hij dat tussen 5v en 0v...
Een Schmitt trigger, zal bij de eerste aangelegde spanning meteen de ingang hoog maken (al dan niet met de overbrugging van R2 met een diode), en daarmee dus de inverted uitgang laag.

Dat is niet zo. Zodra je de 5V spanning aanlegt is de condensator C1 nog ontladen. De uitgang is hoog (inverter). Na xRC seconde is C1 zover opgeladen dat de schmitt-trigger omklapt. De uitgang wordt laag. Nu druk ik de seinsleutel in. De condensator C1 ontlaadt zich nu over R2. Na yRC seconde wordt de uitgang hoog. Nu laat ik de seinsleutel heel even los en druk hem weer in. Zodra ik hem loslaat wordt condensator C1 opgeladen via R1, maar nog voordat C1 voldoende opgeladen is wordt C1 weer ontladen door R2. De spanning stijgt dan tekort om de schmitt-trigger te laten omklappen. Soortgelijk verhaal geldt ook als de seinsleutel langer niet ingedrukt is.

@rew

Geinig wel. Erg compact ook.
Je moet wel zorgen dat getkey() alleen een 0 of een 1 terug kan geven.

Op 18 juni 2020 23:11:25 schreef deKees:
Geinig wel. Erg compact ook.

En dat terwijl ik om de code duidelijker te maken de boel wat "luchtig" heb opgeschreven. Als het niet "demo-code" is, wordt het drie regels korter (2 code regels en 1 lege). :-)

De "naive" implmentatie van "get_key()" is gewoon "digitalRead()" en die returned gewoon een 1 of een 0.

@Fantomaz

Er wordt een variabele "kk" gedeclareerd die de historie van de toetswaardes bewaart. 16 bits voor de laatste 16 waardes.

Dan worden de 16 bits er 1 opgeschoven en de laatste toetswaarde toegevoegd. Verder is het simpel: Als de historie alleen maar 1-en bevat, (0xffff = -1) dan is de gefilderde waarde "hoog" en als de historie alleen maar nullen bevat (0x0000 = 0) dan is de gefilterde waarde laag.

Je kan op de randen triggeren met:

code:

if (kk == 0x7fff) toets_is_zojuist_ingedrukt ();
if (kk == 0x8000) toets_is_zojuist_losgelaten ();

Nu reageer je na 15 keer dezelfde waarde, maar je roept de functie aan bij de verandering en hoeft dan niet op te letten voor wanneer key_debounced verandert.

Ik zal vast een paar typefoutjes gemaakt hebben die de compiler kan vinden. Zo heet de delay_ms functie in arduino geloof ik gewoon "delay".

Als je wilt gaan morse-seinen en zeker als je dan een "kwaliteitscontrole" wil gaan doen, dan zou ik echt graag een hoge resolutie hebben en niet iets wat maar iedere 10ms sampled.

Oh... Met op de flanken reageren.... Je kan ook 15ms eerder reageren:

code:

if (kk == 0x0001) toets_is_zojuist_ingedrukt ();
if (kk == 0xfffe) toets_is_zojuist_losgelaten ();

Officieel is onder de 100ms "niet waarneembaar kort". Ik heb met een collega in de jaren negentig wat zitten experimenteren maar rond de 40ms konden we met wat oefenen gewoon waarnemen. Als je met een seinsleutel morse gaat trainen kan je vast beter worden dan wij toen.

Met de hardware oplossing, zoals jij hem tekent: Met de twee weerstanden gelijk is de RC tijd vrijwel gelijk zowel naar hoog als naar laag. Kies de RC tijd iets van 5-10 ms en ik denk dat het heel aardig zal werken.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Op 19 juni 2020 09:02:08 schreef rew:
Er wordt een variabele "kk" gedeclareerd die de historie van de toetswaardes bewaart. 16 bits voor de laatste 16 waardes.

Hoe regel je dat het een 16 bits variabele is?
(dit zal ongetwijfeld iets te maken hebben met "static int kk" (static als een standaard waarde in aanvang?) (Int als "Integer" Heb ik ooit eens gelezen)?))

Dan worden de 16 bits er 1 opgeschoven en de laatste toetswaarde toegevoegd.

En dat gebeurt hier:
kk = (kk << 1) | k; ?
Ofwel de nieuwe waarde KK is de oude waarde Bitshift Left 1 position, aangevuld met waarde (char, dus 1 bit) "k"?

Verder is het simpel: Als de historie alleen maar 1-en bevat, (0xffff = -1) dan is de gefilderde waarde "hoog" en als de historie alleen maar nullen bevat (0x0000 = 0) dan is de gefilterde waarde laag.

Dit begrijp ik niet...
Ik begrijp dat je met ffff en 0000 2 uiterste waarden bedoelt, maar ik begrijp niet wat dat inhoudt.

Ik vermoed dat je eigenlijk 1111111111111111 versus 0000000000000000 bedoeld, hexadecimaal weergegeven...
Wel overzichtelijk als ik er zo over nadenk.

Je kan op de randen triggeren met:

code:

if (kk == 0x7fff) toets_is_zojuist_ingedrukt ();
if (kk == 0x8000) toets_is_zojuist_losgelaten ();

Nu reageer je na 15 keer dezelfde waarde, maar je roept de functie aan bij de verandering en hoeft dan niet op te letten voor wanneer key_debounced verandert.

Ook dit ontgaat me even...

Als je wilt gaan morse-seinen en zeker als je dan een "kwaliteitscontrole" wil gaan doen, dan zou ik echt graag een hoge resolutie hebben en niet iets wat maar iedere 10ms sampled.

DAar heb je een punt.
Het wordt wel héél grof genomen inderdaad.
Daar is wat mee te doen.

Oh... Met op de flanken reageren.... Je kan ook 15ms eerder reageren:

code:

if (kk == 0x0001) toets_is_zojuist_ingedrukt ();
if (kk == 0xfffe) toets_is_zojuist_losgelaten ();

Maak me gek! eerst even dat eerste verwerken. :-)

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)

Op 18 juni 2020 22:14:06 schreef ohm pi:
[...]Dat is niet zo. Zodra je de 5V spanning aanlegt is de condensator C1 nog ontladen. De uitgang is hoog (inverter). Na xRC seconde is C1 zover opgeladen dat de schmitt-trigger omklapt. De uitgang wordt laag. Nu druk ik de seinsleutel in. De condensator C1 ontlaadt zich nu over R2. Na yRC seconde wordt de uitgang hoog. Nu laat ik de seinsleutel heel even los en druk hem weer in. Zodra ik hem loslaat wordt condensator C1 opgeladen via R1, maar nog voordat C1 voldoende opgeladen is wordt C1 weer ontladen door R2. De spanning stijgt dan tekort om de schmitt-trigger te laten omklappen. Soortgelijk verhaal geldt ook als de seinsleutel langer niet ingedrukt is.

Een goed punt!
Ik "zag" de aangelegde spanning meteen als een "hoogmaker" maar de Condensator moet eerst laden tot een zekere waarde.
Dat was me even ontgaan.

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)

Hoe regel je dat het een 16 bits variabele is?

De lengte van int is per compiler verschillend, dus niet echt gedefinieerd. Maar voor de AVR compiler is die 16 bit. Een char is 8 bits.

Als je het echt wilt regelen (meestal wel een goed idee) dan gebruik je :

code:


  uint8_t  x;   //  8 bit unsigned
  int8_t   x;   //  8 bit signed

  uint16_t x;   // 16 bit unsigned
  int16_t  x;   // 16 bit signed

  uint32_t x;   // 32 bit unsigned
  int32_t  x;   // 32 bit signed

Maar dat kan alleen met een extra header file want deze types zijn niet officieel erkend in de compiler standaard.

code:


   #include <inttypes.h>
benleentje

Golden Member

k = getkey ();

Ik snap deze regel niet. Getkey() begrijp ik op zich wel maar hoe weet de functie welke pin of ingang het moet ophalen?

Mensen zijn soms net als een gelijkrichter, ze willen graag hun gelijk hebben.

Die funktie moet je zelf maken, en dan kun je ook een pin kiezen.
En als je wilt kun je ook parameters toevoegen. Dan wordt het

code:


  k = getkey(ButtonPin);
blackdog

Golden Member

Hi,

Ik lees lekker mee, want ik wil ook graag de beste manier voor het ontdenderen in software leren, maar het lukt mij niet het totaal plaatje te zien.

Kunnen jullie hier nu de totale code laten zien, waarmee je een schakelaar ontdendert en
dit samen en het schema van de componenten die eventueel nodig zijn aan de ingang van een Arduino of een gelijke controler.

Dank en groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Op 20 juni 2020 19:12:41 schreef blackdog:
Hi,

Ik lees lekker mee, want ik wil ook graag de beste manier voor het ontdenderen in software leren, maar het lukt mij niet het totaal plaatje te zien.

Kunnen jullie hier nu de totale code laten zien, waarmee je een schakelaar ontdendert en
dit samen en het schema van de componenten die eventueel nodig zijn aan de ingang van een Arduino of een gelijke controler.

Dank en groet,
Bram

En met stap voor stap de code ontleed.
Het is erg leerzaam! Ik kan een beetje overweg met Arduino in C, maar dan ook alleen door een beetje PIC basic achtergrond.

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)

Zo een debounce wordt (bij mij toch) altijd aangepast aan de omstandigheden. Meestal worden de toetsen gelezen in een timer interupt, zodat je weet hoeveel tijd er tussen de samples zit.

En als je een toetsenbord gebruikt dan heb je een enkele debouncer voor alle toetsen. Heb je losse buttons die onafhankelijk van elkaar werken dan heb je voor elke button een eigen debouncer nodig.

En bij een toets wil je weten wanneer die wordt ingedrukt. Bij een seinsleutel wil je ook weten wanneer die weer losgelaten wordt.

Hierbij voor de liefhebbers een kompleet voorbeeld in Arduino. Extra uitgebreid om mee te spelen.

De 4 toeten worden aangesloten op pin 2 t/m 5, en de debounce status wordt teruggegeven op pinnen 8 t/m 11, zodat je kunt zien wat er gebeurt.

Toetsen schakelen naar massa, met pullup weerstand naar +5.

Hierbij de complete sketch:

code:


//=================================================================================================
// Debouncing a button
// Using a DEBOUNCE_HANDLER class
class DEBOUNCE_HANDLER
{
public:

   int           m_State;
   int           m_Counter;
   int           m_Value;

   int           m_ButtonPin;
   int           m_StatusPin;

   unsigned long m_Time;

   // Constructor
   DEBOUNCE_HANDLER(int ButtonPin, int StatusPin)
   {  m_State   = LOW;
      m_Value   = LOW;
      m_Counter = 0;

      m_ButtonPin = ButtonPin;
      m_StatusPin = StatusPin;
      pinMode(m_ButtonPin, INPUT_PULLUP); 
      pinMode(m_StatusPin, OUTPUT); 
      digitalWrite(m_StatusPin, LOW);
   }

   // TestPin(). 
   // At most once per millisecond
   // -- digitalRead(Pin)
   // -- Update m_State if Pin is stable for a minimum number of reads
   // -- Using limit as thresshold 
   void TestPin()
   {  
      unsigned long Now = millis();
      if( (Now - m_Time) >= 1 )
      {  m_Time = Now;
           
         int Threshold = 500;   // Rediculously large, just to show the effect

         if(m_State != digitalRead(m_ButtonPin) )
         {  // Pin changed. Count.
            if(m_Counter < Threshold)
            {  m_Counter += 1;
            }
            if(m_Counter == Threshold)
            {  m_State   = m_State ? LOW : HIGH;
               m_Counter = 0;
               digitalWrite(m_StatusPin, m_State);
            }
         }
         else
         {  // Pin Same as State : Restart counter.
            m_Counter = 0;
         }
      }
      else
      {  // Too soon. Try again next time
      }
   }

   // Button : Only true when m_State changes from 1 to 0
   bool Button()
   {  
      TestPin();

      if( (m_Value == 0) && (m_State == 1) )
      {  m_Value = 1;
         return false;
      }
      else if( (m_Value == 1) && (m_State == 0) )
      {  m_Value = 0;
         return true;
      }
      else
      {  // No change
         return false;
      }
   }
   
   // MorseKey : Return true when key is down, false when key is up
   bool MorseKey()
   {  
      TestPin();
      return m_State ? false : true;
   }
};

//=================================================================================================

// This application has 4 buttons. Each has its own handler
// - Using pins 2, 3, 4 and 5
// - Pin Status is available on Pins 8, 9, 10 and 11
DEBOUNCE_HANDLER Button1( 2,  8);
DEBOUNCE_HANDLER Button2( 3,  9);
DEBOUNCE_HANDLER Button3( 4, 10);
DEBOUNCE_HANDLER Button4( 5, 11);


void setup() 
{
   Serial.begin(38400);
   pinMode(LED_BUILTIN, OUTPUT);
}

void loop() 
{
   // Button() returns true as long as the button s pressed.
   if( Button1.Button() )
   {  Serial.println( F("Button 1 pressed") );
   }
   if( Button2.Button() )
   {  Serial.println( F("Button 2 pressed") );
   }
   if( Button3.Button() )
   {  Serial.println( F("Button 3 pressed") );
   }

   // MorseKey() returns true as long as the button is pressed.
   // - Use it to switch a light
   digitalWrite( LED_BUILTIN, Button4.MorseKey() );
}

Om te debouncen heb je een aantal variabelen nodig om de history te bewaren. Als je elke pin een eigen set variabelen wilt geven moet je die samen kunnen voegen. Dat is hier gedaan door een class DEBOUNCE_HANDLER te definieren.

code:


class DEBOUNCE_HANDLER
{
public:

   int           m_State;
   int           m_Counter;
   int           m_Value;

   int           m_ButtonPin;
   int           m_StatusPin;

   unsigned long m_Time;

Die variabelen kun je initialiseren als je een button object aanmaakt zoals we verderop zien. Daarvoor heb je een constructor functie nodig. Een constructor funktie heeft dezelfde naam als de class, en geen return value. De funcktie wordt automatisch uitgevoerd als je een nieuw object aanmaakt.

code:


   DEBOUNCE_HANDLER(int ButtonPin, int StatusPin)
   {  m_State   = LOW;
      m_Value   = LOW;
      m_Counter = 0;

      m_ButtonPin = ButtonPin;
      m_StatusPin = StatusPin;
      pinMode(m_ButtonPin, INPUT_PULLUP); 
      pinMode(m_StatusPin, OUTPUT); 
      digitalWrite(m_StatusPin, LOW);
   }

De feitelijke debounce gebeurt in de TestPin() funktie. Dit is een member funktie binnen de DEBOUNCE_HANDLER dus die werkt voor elke pin met een eigen set variabelen.

code:


   void TestPin()
   {  
      unsigned long Now = millis();
      if( (Now - m_Time) >= 1 )
      {  m_Time = Now;
           
         int Threshold = 500;   // Rediculously large, just to show the effect

         if(m_State != digitalRead(m_ButtonPin) )
         {  // Pin changed. Count.
            if(m_Counter < Threshold)
            {  m_Counter += 1;
            }
            if(m_Counter == Threshold)
            {  m_State   = m_State ? LOW : HIGH;
               m_Counter = 0;
               digitalWrite(m_StatusPin, m_State);
            }
         }
         else
         {  // Pin Same as State : Restart counter.
            m_Counter = 0;
         }
      }
      else
      {  // Too soon. Try again next time
      }
   }

Allereerst test de funktie of er al genoeg tijd verstreken is sinds de vorige keer. Zoniet dan gebeurt er niks.

Vervolgens wordt m_State vergeleken met de digitalRead(). m_State is de pin status na debounce en digitalRead() geeft de aktuele pinstatus. Als die verschillend zijn, dan wordt m_Counter opgehoogd, zijn ze hetzelfde dan wordt m_Counter terug op nul gezet.

Als m_Counter de Thresshold waarde bereikt, dan heeft digitalRead() dus meerdere keren dezelfde waarde opgeleverd, en kunnen we m_State aanpassen. Als bonus wordt de m_State na debounce ook weggeschreven naar de m_StatusPin.

De thresshold staat hier op 500. Speciaal om het effect te laten zien. Het systeem wordt daarmee wel erg traag natuurlijk ( een halve seconde reaktie - tijd). Normaal zal een waarde tussen 10 en 50 wel volstaan.

Dan krijgen we de Button() funktie. De applikatie moet die funktie regelmatig uitvoeren. Elke keer dat die funktie wordt gebruikt wordt de Pin Status gelezen en gedebounced in TestPin(). De funktie zelf bevat een edge detector die alleen true geeft als de pin status na debounce (m_State) verandert van 1 naar 0. De extra variabele m_Value hebben we nodig om te zien of m_State anders is dan de vorige keer.

code:


   bool Button()
   {  
      TestPin();

      if( (m_Value == 0) && (m_State == 1) )
      {  m_Value = 1;
         return false;
      }
      else if( (m_Value == 1) && (m_State == 0) )
      {  m_Value = 0;
         return true;
      }
      else
      {  // No change
         return false;
      }
   }

Speciaal voor seinsleutels is er een aparte funktie MorseKey()
Die gebruikt ook de TestPin() funktie om te debouncen, en daarna geeft die m_State terug, zodat je weet of de sleutel na debonce aan is of uit.

code:


   bool MorseKey()
   {  
      TestPin();
      return m_State ? false : true;
   }

En dan zijn we aan het einde van de class definitie.

Nu kunnen we die gebruiken om een 4-tal button objecten aan te maken. Elke button variabele krijgt een eigen set data en eigen pin nummers.

code:


DEBOUNCE_HANDLER Button1( 2,  8);
DEBOUNCE_HANDLER Button2( 3,  9);
DEBOUNCE_HANDLER Button3( 4, 10);
DEBOUNCE_HANDLER Button4( 5, 11);

En dan kunnen we die button objecten gaan gebruiken in onze applikatie.

code:


void loop() 
{
   // Button() returns true as long as the button s pressed.
   if( Button1.Button() )
   {  Serial.println( F("Button 1 pressed") );
   }
   if( Button2.Button() )
   {  Serial.println( F("Button 2 pressed") );
   }
   if( Button3.Button() )
   {  Serial.println( F("Button 3 pressed") );
   }

   // MorseKey() returns true as long as the button is pressed.
   // - Use it to switch a light
   digitalWrite( LED_BUILTIN, Button4.MorseKey() );
}

code:


   if( Button1.Button() )
   {  Serial.println( F("Button 1 pressed") );
   }

Hier gebruiken we de Button() funktie van het Button1 object.
Die funktie test de status van de button op Pin 2. Je moet die funktie meerdere keren aanroepen want de toets wordt pas geaccepteerd als die meerdere keren ziet dat de toets is ingedrukt. Dus meestal geeft de funktie false. Maar uiteindelijk toch true. Dat kun je dan zien op de serial port monitor, en op pin 8.

Hetzelfde gebeurt met Button2 en Button3, wel op andere pinnen.

De seinsleutel wordt hier (na debounce) doorgegeven naar een lampje.

code:


   digitalWrite( LED_BUILTIN, Button4.MorseKey() );
blackdog

Golden Member

Hi deKees, :-) :+

Dank voor je inzet!

Hier onder een plaatje van een Nano op een breadboard om je code te testen.
Morgen lees ik je code door en ga het proberen te begrijpen.
Ik heb een beetje met je code gespeeld wat betreft de "Threshold" waarde.

Het rode draadje is mijn denderende schakelaar voor de vier ingangen bovenaan, die een 12K weerstand naar de +5V hebben. :+

https://www.bramcam.nl/Diversen/Debounce-03.png

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Op 20 juni 2020 18:41:21 schreef deKees:
Die funktie moet je zelf maken, en dan kun je ook een pin kiezen.
En als je wilt kun je ook parameters toevoegen. Dan wordt het

code:


  k = getkey(ButtonPin);

Precies. Ik had het bedoeld als:

code:


uint8_t getkey (void)
{
  return digitalRead (4); // 4 is the D4 where the key is connected.
}

En als dit de enige plek is waar die "4" terugkomt, dan vind ik het zo acceptabel. Maar dat is niet zo: je moet die pin initializeren.

Dus om het dan netjes te doen wordt het:

code:


#define KEYPIN 4 // 4 is the D4 where the key is 
...
void setup (void)
{

... 

// This is AVR specific: We want the pin to be INPUT with pullup. 
// On AVR that is achieved by setting the pin to INPUT and writing
// a 1 to the output register. 
// I don't know how the arduino IDE does this on other processors --REW
pinMode (KEYPIN, INPUT);
digitalWrite (KEYPIN, 1);  
...
}

uint8_t getkey (void)
{
  return digitalRead (KEYPIN); // 4 is the D4 where the key is connected.
}
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

// I don't know how the arduino IDE does this on other processors --REW
pinMode (KEYPIN, INPUT);
digitalWrite (KEYPIN, 1);

Wordt dan (ook op AVR) :

code:


   pinMode (KEYPIN, INPUT_PULLUP);
blackdog

Golden Member

Hi deKees,

Als eerste.
Ik heb wat zitten lezen wat een class is e.d. om dat wat duidelijker te krijgen in mijn hoofd. :)

Probeer het hier in mijn woorden weer te geven wat er gebeurd in jouw code, ik hoor graag waar mijn uileg strand.

Bovenaan heb je dus een soort Library gemaakt die voor de in jouw code vier stuks drukknoppen en vier stuks uitgangen gebruikt gaan worden.
Bij de regels code die begint met => DEBOUNCE_HANDLER Button1( 2, A0); geef je op hoeveel ingangen/uitgangen je gaat gebruiken en aan welke poorten deze functie geknoopt gaan worden.
Bij dit voorbeeld hangt de Button1 aan pin-2 en de uitgang hangt aan pin-A0

Het testen van de ingangen
Hier kijk je als eerste of een ingang lang genoeg "0" is geweest, de tijd die je hier voor neemt is 1mSec, is de tijd korten dan wordt het "0" worden van de ingang genegeert.

En dan raak ik de weg kwijt :)
Bij het testen met een wat langere Threshold lijkt het er op dat de counter gereset wordt als de Threshold waarde niet bereikt wordt.

Mijn indruk is dat een schakelaar minstens de Treshold tijd laag moet zijn om waar te zijn, is hij korter dan de Treshold tijd ingedrukt, dan start de Treshold tijd opnieuw.

Klopt mijn beredenering wat dit betreft?

Wat betrteft de Morse Key, ik zie hier geen verschillen, behalve dat dan ook deingebouwde LED op de Nano oplicht en het gebruik van Button4 niet in de serieel monitor gemeld wordt.

Groet,
Bram

You have your way. I have my way. As for the right way, the correct way, and the only way, it does not exist.

Dat klopt helemaal.

Bij het testen met een wat langere Threshold lijkt het er op dat de counter gereset wordt als de Threshold waarde niet bereikt wordt.

Ook dit klopt. Als de thresshold waarde niet bereikt wordt, dan is de ingang blijkbaar nog aan het denderen. De teller start opnieuw en m_State wordt pas aangepast als de pin lang genoeg stabiel blijft.

Dat geldt voor beide toestanden (HIGH / LOW). Als je de toets te kort loslaat dan telt dat niet voor een nieuwe toetsaanslag.

De MorseKey heeft inderdaad dezelfde debouncing. Wat ontbreekt is de edge detect, die bij Button wel is ingebouwd:

Button() geeft alleen 1 x true als de m_State verandert van 1 naar 0. (Edge detect)

MorseKey() geeft telkens true zolang m_State 0 is. (Level detect).
Dat is lastig om te laten zien in de serial monitor want die loopt dan snel vol dus vandaar het lampje. Die funktie gebruikt inderdaad verder wel dezelfde debouncing.

PS: Dit is dus wel C++. In C kun je geen class maken en ook geen member funkties aanmaken. Dus dan krijg je heel andere code. Onze AVR-GCC heeft daar gelukkig geen problemen mee. :)

Rew, zou je nog kunnen reageren op deze reactie: https://www.circuitsonline.net/forum/view/message/2176259#2176259
Het bevat een aantal vragen over een oplossing die jij aandroeg.

Ik begon het net wat te begrijpen en zou eigenlijk wel eens willen proberen het probleem op die manier te benaderen. :-)

Ik denk dat ik het snap...
Je maakt loopjes van 1mS, die elke keer een 16 bits schuifregister 1 positie laten opschuiven.
Verder kijkt hij of alle bits steeds dezelfde waarde behouden. In dat geval wordt deze waarde voor "waar" aangenomen en kan ermee worden gewerkt.

Mocht er een flaw van een paar afwijkende waarden inzitten, door waarschijnlijk denderen, is er geen man overboord omdat het allemaal binnen de tijdseenheid van ca 50mS valt, wat de tijdsspanne van een punt of een pauzemoment is in een morse karakter, bij een snelheid van 30 WPM (en dat is voor een gevorderde al een redelijk hoge snelheid, meende ik.

Dan mijn vervolgvraag...
Als ik een paar regels code in een loop zet van 1mS, kan ik er dan ook vanuit gaan dat na 1000 loopjes ik een seconde heb?
Of vergen de regels binnen een stukje code ook nog tijd, waardoor na 1000 loopjes ik eigenlijk 1,2 secondes verder ben.
(Ik kan me herinneren dat dat met PIC controlers dit nog wel eens lastig was.)

[Bericht gewijzigd door Fantomaz op zondag 21 juni 2020 21:49:54 (62%)

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)
benleentje

Golden Member

c code:


void loop (void)
{
  unsigned char k; 
  static int kk;
  unsigned char key_debounced; 

  k = getkey ();

  kk = (kk << 1) | k;

  if (kk == -1) key_debounced = 1;
  if (kk ==  0) key_debounced = 0;

  // verwerk key_debounced... 


  delay_ms (1);
}

Je maakt loopjes van 1mS,

Nee de cpu is veel sneller dan dat maar onderaan de code staat gewoon wacht 1mS. De loop is dan de tijd voor de paar regels code plus 1mS

Of vergen de regels binnen een stukje code ook nog tijd,

Ja die vergen ook tijd dus daar moet je dan rekening mee houden al ongeveer 1 Seconde goed genoeg is dan is dat geen probleem, moet het precies 1 seconde zijn dan moet je minder dan 1000x bv 980x uitvoeren en als dat nog niet nauwkeurig genoeg is dan moet je met timer interrupts gaan werken.

Verder kijkt hij of alle bits steeds dezelfde waarde behouden.

Eigenlijk kijkt hij of het 16 bits getal FFFF (dus 16 enen op een rij) is geworden maar dat is in een signed interger gelijk aan -1. kijken naar een negatieve vlag is voor een cpu sneller dan vergelijken met FFFF is FFFF

Mensen zijn soms net als een gelijkrichter, ze willen graag hun gelijk hebben.

Op 19 juni 2020 22:28:08 schreef Fantomaz:
[...]
Hoe regel je dat het een 16 bits variabele is?

"int" is een "integer variabele die op deze CPU makkelijk te verwerken is". Dat is wat de C standaard voorschrijft. Dat zou op een AVR een 8 bits zijn. Maar dat is te weinig en dan zijn er te weinig woorden voor 32 en 64-bits. De compiler jongens hebben dus er voor gekozen om "int" 16 bits te maken.

(dit zal ongetwijfeld iets te maken hebben met "static int kk" (static als een standaard waarde in aanvang?)

In een functie is een variabele normaliter een locale variabele: beschikbaar als de functie aangeroepen wordt, en daarbuiten niet. Sterker nog daarbuiten BESTAAT ie niet eens.

In een functie

code:


void loop (void)
{
  int i;
  printf ("i=%d\n", i++); 
  sleep (1);
}

wordt steeds als die functie aangeroepen wordt de variabele i gemaakt met "wat er toevallig in die geheugen locatie staat", geprint en dan 1 opgehoogd. De volgende keer begint ie weer met een random waarde die officieel niet voorspelbaar is, geprint en 1 opgehoogd en... weer vergeten.

Als er verder helemaal niets gebeurt zal in dit eenvoudige voorbeeld TOEVALLIG steeds dezelfde geheugen plek voor "i" gebruikt worden, met als "random waarde" toevallig de vorige waarde van i. Maar dat werkt dus "perongeluk". Als op een dag het niet meer werkt omdat iemand aan de compiler heeft lopen klussen... jou probleem, dit hoort niet te werken.

Door er static voor te zetten maakt ie een variabele die blijft bestaan buiten de functie. Dan is die variabele nog hetzelfde de volgende keer dat de functie wordt aangeroepen. Verder omdat ie binnen de functie wordt gedefinieerd is de naam buiten de functie niet eens bekend. Dus als het goed is, kan geen enkele andere functie aan deze variabele zitten.

(Int als "Integer" Heb ik ooit eens gelezen)?))

Jep.

[...]
En dat gebeurt hier:
kk = (kk << 1) | k; ?
Ofwel de nieuwe waarde KK is de oude waarde Bitshift Left 1 position, aangevuld met waarde (char, dus 1 bit) "k"?

Jep.

Met dien verstande dat "char" een 8 bit variabele is. Maar 7 bitjes daarvan hebben we niet nodig.

[...]
Dit begrijp ik niet...
Ik begrijp dat je met ffff en 0000 2 uiterste waarden bedoelt, maar ik begrijp niet wat dat inhoudt.

Een computer geheugenplek heeft (in moderne computers) geen "tag" met "dit is een integer" of "dit is een string" of .... Het programma bepaalt hoe een waarde in het geheugen geinterpreteerd wordt. En Dat begin je te sturen met de declaratie van de variabele.

Als jij zegt dat een variabele "int" is dan reserveert de AVR compiler 16 bits in het geheugen voor je en de 65536 mogelijke combinaties van die 16 bits representeren de getallen -32768 tot en met 32767.

Vervolgens kan je dat ook nog afdrukken of opschrijven op verschillende manieren. Afdrukken of opschrijven kan in hexadecimaal bijvoorbeeld. Dan zijn de waardes 0x8000 .... 0xffff, 0x0000, ... 0x7fff. Hier schrijf ik er 0x voor om aan te geven dat het hexadecimaal is. Zo schrijf je zo'n getal ook in je C-programma dat de compiler weet dat het hex is.

Als je een getal wilt printen in hex gebruik je het "%x" formaat.

In het onderhavige geval zou het zijn: "0x%04x" om aan te geven dat er een nul, dan een x dan 4 hexadecimale cijfers geprint moeten worden.

Ik vermoed dat je eigenlijk 1111111111111111 versus 0000000000000000 bedoeld, hexadecimaal weergegeven...
Wel overzichtelijk als ik er zo over nadenk.

Jep.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Erg leerzaam allemaal!

Wat ik nog niet begrijp in je uitleg is:

Als je een getal wilt printen in hex gebruik je het "%x" formaat.

In het onderhavige geval zou het zijn: "0x%04x" om aan te geven dat er een nul, dan een x dan 4 hexadecimale cijfers geprint moeten worden.

Dat 0x verhaal... Daarmee doel je nu toch niet op een Hexadecimale weergave?
Ik lees het nu (waarschijnlijk fout) als:

Hexadecimaal printen 04x.

Zou je dat nog wat dader kunnen uitleggen?

Ik moet hier weer vaker komen... Wat kun je zo'n forum als deze gaan missen. :-)