Beste mensen,

Mijn bedoeling is om met 1 drukschakelaar binair te gaan tellen. Dus bij elke druk op de knop wordt er op de ledjes (PICkit1) steeds de volgende waarde binair weergegeven (0001 -> 0010 -> 0011 -> 0100 -> enz.)
Probleem is: debouncen.
Dit werkt:

void main (void)
{
	init(); //latches resetten enz.
 	while(1)
	{
		if (!PORTA.2)
		{
			if (PORTA.4) 
			{
			     PORTA.4=0;
			     PORTA.5=1; //led1 gaat branden
			}
            	else    
		{
		     PORTA.4=1;
		     PORTA.5=0;  //led0 gaat branden
		}
		Debounce();  //schakelaar debouncen                       

		}
	}
}

Doel van deze code: schakelaar indrukken->led0 aan, schakelaar nog een keer indrukken->led1 aan, schakelaar weer indrukken ->led0 aan, enz

Maar, nu wil ik met dezelfde "Debounce" functie ervoor zorgen dat er bij een teller steeds 1 wordt opgeteld (ipv x aantal i.v.m. bouncen van de schakelaar) en dus op mijn ledjes netjes binair 1 verder telt. Daarvoor had ik het volgende bedacht:

void main (void)
{
	char var=0;
	init();        //latches resetten
 	while(1)      //forever loop
	{
		if (!PORTA.2) //als schakelaar wordt ingedrukt
		{
			var++;  //teller+1
			Debounce();  //debouncen
		}
		show(getal); //"show" zet decimale "getal" om naar naar binaire waarde
	}
}

In de functie "Debounce" zit het probleem. Als ik die weghaal, gaat het goed, ware het niet dat er niet 1 opgeteld wordt, maar een willekeurig getal (door het bouncen van de schakelaar). Als ik "Debounce" weer terug zet, gaat het fout.

Wie weet wat de fout is?

(de schakelaar wordt LAAG als die ingedrukt wordt)


+5volt
  |
  -
  R(1,5k)
  -
  |
  |
  ---RA2(microcontroller)
  |
  |
switch
  |
  |
ground

Dat met die teller is goed, alleen die moet eerst.
Je moet ook niet tot oneindig tellen.

De teller moet bestaan uit een getal dat je kunt optellen en aftellen.
Op een '0' aan de ingang moet je een teller laten optellen tot bijvoorbeeld 10.
De tijd per tel (cyclus) kun je op ongeveer 4ms zetten.
Als de teller op 5 of hoger is, dan is de schakelaar 20ms gedrukt en dan kun je de functie van de schakelaar uitvoeren (de binaire teller verhogen).

Na 20ms kun je vrij betrouwbaar aannemen dat de schakelaar daadwerkelijk gedrukt is en dat er geen verstorende bounces meer volgen.

De teller moet je vervolgens door laten lopen tot 2x de debounce-tijd: 10 dus, zolang de ingang '0' blijft.

Als de ingang '1' is of wordt, dan moet je aftellen tot minimaal 0, weer met een tempo van 4ms per stap.

Wat je werkelijk maakt is een laagdoorlaatfilter vergelijkbaar met een condensator over de schakelaar. De RC tijd is 20ms en het omslagpunt ligt op 50%.
Door op en af te tellen werk de debounce zowel op het indrukken als op het loslaten.

je telt je teller wel op

maar die heet var

en je geeft de teller getal weer.

dat werkt neit

void main (void)
{
	char var=0;
	init();        //latches resetten
 	while(1)      //forever loop
	{
		if (!PORTA.2) //als schakelaar wordt ingedrukt
		{
			var++;  //teller+1
			Debounce();  //debouncen
		}
		show(getal); //"show" zet decimale "getal" om naar naar binaire waarde
	}
}

opmerking 1: ik zou show(getal) veranderen in show(var);

verder een aantal vragen:
1) kun je de code van je routine Debounce(); ook posten?
2) hoeveel leds heb je, en dus, tot hoever wil je tellen?

het volgende zou moeten werken, mits Debounce werkt.


#define MAX 15;                  //voorbeeld, teller telt nu van 0 - 15
void main (void){
	char var = 0;
	init();                  //latches resetten
 	while(1){                //forever loop
	    if (!PORTA.2){       //als schakelaar wordt ingedrukt
	        if( var != MAX ) //als var ongelijk aan MAX 
                    var++;       //teller ophogen
                else             //als teller MAX waarde is
                    var = 0;
		Debounce();      //debouncen
	    }
	    show(getal); 
    }
}

Ik denk dat je zoiets bedoeld (als ik het goed begrepen heb):

static bit check;

void main(void)
{
	unsigned char currentValue = 0;
	unsigned char maxValue = 4;
	
	check = 1;
	
	while (1)
	{
		if(!PORTA.2)
		{
			if(check)
			{
				check = 0;
				currentValue++;
				currentValue %= maxValue;
			}	
		} else {
			check = 1;
		}
		show(currentValue);
	}
}

Bij het indrukken van de schakelaar wordt de "check" uitgevoerd, zodra dat is gebeurd wordt de bit "check" op 0 gezet en wordt de waarde niet meer veranderd totdat de schakelaar losgelaten is en weer opnieuw is ingedrukt.
Als de schakelaar losgelaten wordt, word de bit "check" weer op 1 gezet.
Ook is er een maxValue, zodra de teller de maxValue haalt wordt deze weer op 0 gezet met behulp van een restdeling.

@ BernardV, jou voorgestelde code zal ook niet (correct)werken.
wanneer een knop ingedrukt wordt, zal check van 1 naar 0 gaan, maar hierna wordt check ook snel weer 1, onafhankelijk of de knop losgelaten wordt of niet.

een knop is redelijk vervelend wat dat betreft, gedurende ongeveer 20 ms zal deze van 0 naar 1 en weer naar 0 springen, geheel random, hierna is de data enigsinds zeker.

er zal dus een soort delay(20 ms) gebruikt moeten worden.

Op 17 december 2007 14:08:05 schreef hvwieren:
@ BernardV, jou voorgestelde code zal ook niet (correct)werken.
wanneer een knop ingedrukt wordt, zal check van 1 naar 0 gaan, maar hierna wordt check ook snel weer 1, onafhankelijk of de knop losgelaten wordt of niet.

een knop is redelijk vervelend wat dat betreft, gedurende ongeveer 20 ms zal deze van 0 naar 1 en weer naar 0 springen, geheel random, hierna is de data enigsinds zeker.

er zal dus een soort delay(20 ms) gebruikt moeten worden.

Zolang de knop ingedrukt blijft is de !PORTA.2 in werking, dus wordt de check niet op 1 gezet.
Daarbij als de poorten standaard hoog zijn en je de knop dus schakelt naar de GND lijkt het me onwaarschijnlijk dat de poort tijdens het indrukken hoog wordt.
//EDIT: Ik heb nog geen problemen gehad tenminste ;)

Op 17 december 2007 14:11:49 schreef BernardV:
[...]

Zolang de knop ingedrukt blijft is de !PORTA.2 in werking, dus wordt de check niet op 1 gezet.
Daarbij als de poorten standaard hoog zijn en je de knop dus schakelt naar de GND lijkt het me onwaarschijnlijk dat de poort tijdens het indrukken hoog wordt.

dat is dus het mooie van een knop.
ooit eens met een scoop gekeken naar het voltageniveau gekeken als je een knop indrukt?

natuurlijk is dit per knop verschillend.

Op 17 december 2007 14:15:32 schreef hvwieren:
[...]
dat is dus het mooie van een knop.
ooit eens met een scoop gekeken naar het voltageniveau gekeken als je een knop indrukt?

natuurlijk is dit per knop verschillend.

Nee, nog nooit ;) Heb namelijk geen scoop :P
Ik ga het nu gelijk even testen met een 16F648A, misschien werkt het wel beter om de poort standaard laag te hebben en dan hoog als de knop ingedrukt wordt.

maak eens een teller, net als hier.
en dan bij voorkeur of ledjes, of een 7 segments display eraan.
ik hoor je bevindingen wel over een uurtje of wat ;)

Op 17 december 2007 14:20:37 schreef hvwieren:
maak eens een teller, net als hier.
en dan bij voorkeur of ledjes, of een 7 segments display eraan.
ik hoor je bevindingen wel over een uurtje of wat ;)

I stand corrected :)
Inderdaad gaat dat niet lekker, dus de "timer" is de oplossing.

Dank voor alle reacties!

@Bart Hiddink: volgens mij in mijn Debounce-code precies wat jij bedoelt.

@mts plus en hvwieren : je hebt gelijk, in de code die ik hier geplaatst heb is dat inderdaad fout, maar in mijn "testprogramma" is 'getal' 'var' geworden.

@hvwieren 1) Debounce code:

void Debounce(void)
{
	unsigned char COUNT = 20;   //delay counter
	for(;;)
	{
		if(!PORTA.2)       // reset 10 millisecond COUNT if BUTTON pushed
		{
			COUNT = 20;
		}
		else	// decrement timer COUNT for every Timer0 overflow
		{
			if(T0IF)   
			{
				T0IF = 0;  // reset flag
				if(--COUNT == 0) break;	// exit on 10 consecutive milliseconds without BUTTON closure
			}
		}
	}
}

Deze Debounce-code zou goed moeten zijn omdat mijn eerste geposte code wel werkt met dezelfde Debounce-functie.

2)heb totaal 8 leds, dus kan tellen tot 255

Ik heb je code getest, MET Debounce(); werkt het niet, dwz: er gebeurt niks als je op de schakelaar drukt. ZONDER Debounce(); doet hij wel iets wat er ongeveer op lijkt, maar niet zoals het hoort natuurlijk omdat er niet ge-debounced wordt.

Wat misschien nog wel even belangrijk is om te zeggen is dat ik met de PICKit1 van Microchip werk. HIER staat de datasheet. Op pagina 32 staat het schema voor de aansturing van de ledjes.
De schakelaar zit op RA2, en is dus input. In de functie init(); staat dit:

TRISA=0b11001111;  			//al pins are input except  RA4 RA5

Nu komt de aansturing van mijn ledjes, bijvoordeeld die van ledje5:

void D5(void)
	{
	PORTA=0;			//all of
	TRISA=0b11011011;	//RA2 and RA5 output else High impedance
	PORTA=0b00011111;	//RA2=1 RA5=0
	}

Met TRISA worden de poorten op input of output gezet. Bij ledje5 is RA2 output, terwijl mijn schakelaar op RA2 zit als input. De mogelijkheid bestaat dus dat daar iets niet goed gaat. Ikzelf heb alleen geen idee of dat daarwerkelijk zo is.

EDIT: ipv tot 128 tellen, is het natuurlijk tot 255:)

@ peter:
na je verhaal gelezen te hebben denk ik inderdaad dat er iets fout gaat bij het selecteren van Input en Output.
even voor de duidelijkheid:
je hebt de ledjes (8) op port A zitten?
en je hebt de schakelaar op A2 zitten?
dus op A2 zit EN een schakelaar, EN een led?
of lees ik het nu verkeerd?

Heb je de datasheet blz 32 gezien? Dan ga je in 1 keer begrijpen hoe het zit:

De ledjes zitten op port A, en wel: RA4, RA5, RA2 en RA1. Led0 en 1 staan tussen RA4 en RA5
led2 en 3 staan tussen RA4 en RA2
led4 en 5 staan tussen RA5 en RA2
led6 en 7 staan tussen RA2 en RA1

Door nu bijvoorbeeld led 5 aan te zetten moet je RA5 en RA2 als Output selecteren met het TRISA register, vervolgens RA2 hoog maken, en RA5 laag maken zodat het ledje gaat branden (omdat ledje5 "van RA2 naar RA5" staat (doorlaatrichting))

Met init(); (in begin van de code) maak ik dus RA2 als input voor de schakelaar, terwijl ik verderop in de code diezelfde RA2 als output zou kunnen hebben als dat betreffende ledje moet gaan branden.

Maar dan nog: het rare is dat zodra ik Debounce(); bij in de code zet, er niks gebeurt als de schakelaar ingedrukt wordt. 'var' zou na de eerst keer drukken '1' moeten worden, dus zou led0 moeten gaan branden, en die zit op RA4 en RA5, dus zitten de schakelaar en het ledje in dat geval elkaar niet in de weg.

Had je toevallig naar de Debounce-code gekeken? Die moet toch goed zijn?

Na vanmiddag wat getest te hebben met de tips van hvwieren ben ik gekomen tot deze code en die werkt prima bij me:

void main(void)
{
	unsigned char currentValue = 0;
	unsigned char maxValue = 4;

	TRISA = 0;
	PORTA = 0;
	
	TRISB = 0b00000001;
	
	while (1){

		if(!RB0)
		{
			while(RB0);
			DelayMs(20);
			if(!RB0)
			{
				currentValue++;
				currentValue %= maxValue;
				PORTA = currentValue;
			}
			while(!RB0);
		}
		
		DelayMs(5);
		
	}
}

Misschien heb je er iets aan.

@BernardV: telt deze niet continue door,
met een increment iedere (ongeveer) 25ms?

Als je de laatste update van 18:22:02 niet had gezien wel, daar stond de laatste while niet in. Die laatste while houdt de knop "vast".
//EDIT: Ah, ja standaard wel :P
Ik heb de knop naar de +5v met een weerstand en een weerstand tussen de poort en de GND. Heb namelijk ook een knop die standaard open staat en gesloten is bij indrukken..

[Bericht gewijzigd door BernardV op (14%)]

Hier zou ik zelf nooit op gekomen zijn haha! Wat betekent deze combinatie?: %=

Heb het programma hier nog niet kunnen testen, moet eerst even een en ander solderen.....

Op 17 december 2007 19:22:08 schreef Peter:
Hier zou ik zelf nooit op gekomen zijn haha! Wat betekent deze combinatie?: %=

% is modulo (de rest bij deling).

a %= b

is het zelfde als

a = a % b

Verder: lees eens over het read-modify-write probleem!

Op 17 december 2007 19:22:08 schreef Peter:
Hier zou ik zelf nooit op gekomen zijn haha! Wat betekent deze combinatie?: %=

Heb het programma hier nog niet kunnen testen, moet eerst even een en ander solderen.....

die %= (ook wel modulus bewerking genoemd) voert het volgende uit:
z = rest van (x / y)
getallenvoorbeeld:
6 %= 2 (is hetzelfde als x = 6 % 2)
x wordt hier 0, immers, 6/2 is een geheel getal, 3, je houd geen enkele 'rest' over.

Op 17 december 2007 19:44:05 schreef Wouter van Ooijen:
[...]
Verder: lees eens over het read-modify-write probleem!

Daar zul je op dit forum geen zinnige/bruikbare info over vinden/krijgen!

Op 17 december 2007 19:56:57 schreef picsels:
[...]Daar zul je op dit forum geen zinnige/bruikbare info over vinden/krijgen!

er is meer dan dit forum, bv google, maar ik denk dat het ook hier echt wel eens besproken is.

Op 17 december 2007 19:56:57 schreef picsels:
[...]Daar zul je op dit forum geen zinnige/bruikbare info over vinden/krijgen!

gelukkig is er meer dan Circuits online alleen he ;)
2de hit op google helpt al de mist te laten verdwijnen over dit principe...
[edit:] meer mensen denken zo...

Zonder er te diep op in te gaan:
@WvO: in dit forum is het wel eens voorbij gekomen, maar het heeft niet tot bruikbare info geleid.
@hvw: ook op internet, inclusief 'hit 2' op Google, laat de volledigheid van de 'uitleg' te wensen te over.
Beste advies: geen pennen wisselen van input naar output.

Op 17 december 2007 20:18:15 schreef picsels:
Beste advies: geen pennen wisselen van input naar output.

laten we het daar maar op houden ja.
gewoon een kant van de led aan je PIC hangen en de andere kant aan + dan wel GND (ligt eraan waarmee je wilt schakelen, een 1 of een 0)
voor een schema moet je maar even vragen.