Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

2 Digit up Counter PIC 16F84A

Status
Not open for further replies.

Gayan Soyza

Active Member
I built a 2digit up counter from pic16f84a..when the RB0 button pressed each time the display counts up one by one....it can counts up to 99....

RB0-switch
RB1-Rb7 -7 segmants
RA0-Digit 2 driving transistor
RA1-Digit 1 driving transistor

My problem is its counting in a messy way (not in the proper order 1,2,3....).
so I changed my Delay when higher delays its counting correctly.but the two displays are blinking....

here I didn't debounce the button(I dont know the debounce codings).I think the delay is too fast for the switch.

How to prevent this I need a smooth count when a button is pressed.

I have attached the cct & the codings......
 

Attachments

  • COUNTER.txt
    1.6 KB · Views: 2,388
  • Schematic.jpg
    Schematic.jpg
    38.7 KB · Views: 2,584
Hi,

Firstly: hardware. It all looks 'ok', but you could use some resistors on portb (one for each segment/pin) to the segment LED's. From that it appears PORTB is driving the segment LED's directly, which is probably drawing a fair amount of current from the pins. 100-600 ohms should do (depending on your supply voltage), just to limit the current.

Ok, software. Again, I just skimmed it. The reason increasing your 'delay' is making the display flash is becase that delay is used between displaying numbers on each display. So if the delay is longer than, say, 40ms, you'll see it flash. I don't tihnk the delay time is the problem, reduce it to a value where you cannot percieve flashing.

Now...what happens if you HOLD the button down? I'll tell you what..every time it checks the button..its pressed, so it increments the counter, meaning your counter will count VERY quickly. Releasing the button it would stop at a seemingly random number. You need a way to check that the button has been released so that it only increments by 1, every time the button is pressed THEN released. THis can be done with a simple 'flag'...a single bit of a register. I often include a 'TEMP' register for this exact reason.

As for 'debouncing' I usually just check if a button is pressed, if it is, wait 20ms, then check again. If its not pressed the second time, then its a false trigger, if it is still pressed then the user has in fact pressed it. Releasing the button usually doesn't cause me any problems, but another small delay can't hurt.

A quick bit of debouncing code:

PRESS BTFSC PORTB,0 ;Button Pressed
GOTO LOOP ;Back to Loop (we checked if its 0, its not)
; its a 0, its pressed
CALL DELAY1 ; call a delay, just used 'delay1' here as a reference.
BTFSC PORTB,0 ;Button Pressed
GOTO LOOP ;Back to Loop (false alarm!)
; it is still pressed, so now you do what you want to do
COUNTUP ......

As I said, 20ms is just a rough guide, you might get away with a lower value, you might need a higher value. Remeber this is NOT the same delay as is used for displaying the digits, although you could try it. So...just to recap..add a flag, thats set when the button is pressed, and cleared when the button isn't pressed. Your 'check button routine' sohuld check this flag...if its set, then the button is still held down from the last time it incremented...and so should be ignored...back to the loop. If its clear then its a 'new button press', so you go through your debounce routine, if its sitll pressed, then set the flag, do your COUNTUP routine, and back to the loop.


My two cents.

Blueteeth
 
Last edited:
Blueteeth said:
Hi,

Firstly: hardware. It all looks 'ok', but you could use some resistors on portb (one for each segment/pin) to the segment LED's. From that it appears PORTB is driving the segment LED's directly, which is probably drawing a fair amount of current from the pins. 100-600 ohms should do (depending on your supply voltage), just to limit the current.

Ok, software. Again, I just skimmed it. The reason increasing your 'delay' is making the display flash is becase that delay is used between displaying numbers on each display. So if the delay is longer than, say, 40ms, you'll see it flash. I don't tihnk the delay time is the problem, reduce it to a value where you cannot percieve flashing.

Now...what happens if you HOLD the button down? I'll tell you what..every time it checks the button..its pressed, so it increments the counter, meaning your counter will count VERY quickly. Releasing the button it would stop at a seemingly random number. You need a way to check that the button has been released so that it only increments by 1, every time the button is pressed THEN released. THis can be done with a simple 'flag'...a single bit of a register. I often include a 'TEMP' register for this exact reason.

As for 'debouncing' I usually just check if a button is pressed, if it is, wait 20ms, then check again. If its not pressed the second time, then its a false trigger, if it is still pressed then the user has in fact pressed it. Releasing the button usually doesn't cause me any problems, but another small delay can't hurt.

A quick bit of debouncing code:

PRESS BTFSC PORTB,0 ;Button Pressed
GOTO LOOP ;Back to Loop (we checked if its 0, its not)
; its a 0, its pressed
CALL DELAY1 ; call a delay, just used 'delay1' here as a reference.
BTFSC PORTB,0 ;Button Pressed
GOTO LOOP ;Back to Loop (false alarm!)
; it is still pressed, so now you do what you want to do
COUNTUP ......

As I said, 20ms is just a rough guide, you might get away with a lower value, you might need a higher value. Remeber this is NOT the same delay as is used for displaying the digits, although you could try it. So...just to recap..add a flag, thats set when the button is pressed, and cleared when the button isn't pressed. Your 'check button routine' sohuld check this flag...if its set, then the button is still held down from the last time it incremented...and so should be ignored...back to the loop. If its clear then its a 'new button press', so you go through your debounce routine, if its sitll pressed, then set the flag, do your COUNTUP routine, and back to the loop.


My two cents.

Blueteeth


Ya.. I didn't mentioned the portB output resisters Bcuz to reduce my drawing.already I have 220 ohm resisters with port B......I must try ur Debounce codings u gave to my SW1.I'll change the DELAY1 & see.
 
Don't forget to check if the button has been released! Even with the debounce routine, it'll do that same thing, I only included that bit because you said you didn't know how to 'debounce' in code. Read over it, if needds be, if I get round to it I'll post another 'button check' code snippet, with a flag, so it only increments when the button is pressed, NOT continuously when the button is held down.
 
I already add a flag...

In this method I added a small debounce method to give a correct counting in my 2digit display.the button debounce really worked well by giving a correct counting.but the problem is its displaying the output when u release the button.when u long press the button the display is going off and when u release only its displaying.

how to prevent this I need to display the output when u press the button with a correct counting.
 

Attachments

  • button.txt
    844 bytes · Views: 713
Good call with the 'txt' file pseudo code...saves us having to wade though lots of code :D And means I can see what you're doing without including the code thats working fine.

Hmm it seems you are not debouncing the button.

In order to debounce a button, it must be checked twice. Once, then a small delay, then again to see if its still pressed or if its a false trigger. In your routine, you are indeed checking the flag, but only checking the button once.

The debounce routine is simply used in place of 'btfsc PORTA,4'. It is just used to 'read' a buttons state twice, with a delay inbetween to make sure its on, or off.

The reason your display is going off when you hold the button down is because it never gets to the 'Stay' subroutine, which if I'm not mistaken you use to display the digits.

I don't like to complicate what should be a fairly straight forward problem, but, if you tihnk about it, with reading a button (debounced or otherwise) there are only two posibilities. On, or Off. But...when we add our flag, theres four posibilities:

Flag Button
0 0 - (1) displaying the digits, key isn't pressed
0 1 - (2) new key press (flag =0, wasn't pressed before)
1 0 - (3) key released (flag = 1, WAS pressed, but now its not)
1 1 - (4) key was pressed before, and is STILL pressed.

So, for (1) we go to the 'stay routine' and clear flag.
(2) we go to the 'Countup' routine and set flag.
(3) we go to the 'stay routine', and clear flag
and (4) we go to the 'stay routine', with the flag still set.

So, as you can see, we only go to the 'coutup' routine when the flag is 0 and the button (after debouncing) is 1. Because the flag represents the buttons previous state, last time it was checked, we can say that we only do something other than go to 'stay' if the button has gone from 0 to 1. Not 1 to 0.

I modified your little txt file :D Try and work out what I did, and WHY I did it. Thats the problem with loops, its easy to lose track of where the program is going under certain conditions.

GOod Luck

Blueteeth
 

Attachments

  • button-1.txt
    1.4 KB · Views: 612
Blueteeth said:
Good call with the 'txt' file pseudo code...saves us having to wade though lots of code :D And means I can see what you're doing without including the code thats working fine.

Hmm it seems you are not debouncing the button.

In order to debounce a button, it must be checked twice. Once, then a small delay, then again to see if its still pressed or if its a false trigger. In your routine, you are indeed checking the flag, but only checking the button once.

The debounce routine is simply used in place of 'btfsc PORTA,4'. It is just used to 'read' a buttons state twice, with a delay inbetween to make sure its on, or off.

The reason your display is going off when you hold the button down is because it never gets to the 'Stay' subroutine, which if I'm not mistaken you use to display the digits.

I don't like to complicate what should be a fairly straight forward problem, but, if you tihnk about it, with reading a button (debounced or otherwise) there are only two posibilities. On, or Off. But...when we add our flag, theres four posibilities:

Flag Button
0 0 - (1) displaying the digits, key isn't pressed
0 1 - (2) new key press (flag =0, wasn't pressed before)
1 0 - (3) key released (flag = 1, WAS pressed, but now its not)
1 1 - (4) key was pressed before, and is STILL pressed.

So, for (1) we go to the 'stay routine' and clear flag.
(2) we go to the 'Countup' routine and set flag.
(3) we go to the 'stay routine', and clear flag
and (4) we go to the 'stay routine', with the flag still set.

So, as you can see, we only go to the 'coutup' routine when the flag is 0 and the button (after debouncing) is 1. Because the flag represents the buttons previous state, last time it was checked, we can say that we only do something other than go to 'stay' if the button has gone from 0 to 1. Not 1 to 0.

I modified your little txt file :D Try and work out what I did, and WHY I did it. Thats the problem with loops, its easy to lose track of where the program is going under certain conditions.

GOod Luck

Blueteeth

Wow nice piece of codings it will work for surely.....thanks blueteeth very much.I was thinking all the time with this prob sitting near the computer in the weekend......If dont get solution for this debounce prob I planned to give a input via a trigger IC like NE 555 (clean pulse).now already I got the solution.

Thankx a lot.. :)
 
Hi, I saw there is two transistors are attached,what if we don't attach transistor with Port A0 and Port A1, is there any other way to join these segment display to the PIC because lecturer didn't give us transistors.


Thanks
 
Hi, I saw there is two transistors are attached,what if we don't attach transistor with Port A0 and Port A1, is there any other way to join these segment display to the PIC because lecturer didn't give us transistors.


Thanks

Without transistors you connect the segment displays common pin to direct RA0 & RA1 & make them as logic "LOW" from your software while giving logic "HIGH" segment pattern from the PORTB.

BTW its not a good idea to drive them without transistors.The display will be very dim.
 
There are four button states of which I usually only worry about the "new press" state and ignore the "still pressed", "still released", and "new release" states. Use a switch state latch or memory or flip-flop, what ever you'd like to call it, and some simple logic (example below).

If you're using a long enough delay (the display delay) between sampling switches you probably don't need a debounce delay within the "press" routine.

Regards, Mike

Code:
LOOP    clrf    PORTB           ; blank the display
        movlw   b'00000011'     ;
        xorwf   PORTA,F         ; flip digit select bits
        movf    DIGIT1,W        ; 
        btfss   PORTA,1         ; display 1? yes, skip, else
        movf    DIGIT2,W        ;
        call    TABLE           ; get segment data
        movwf   PORTB           ; display new digit
        call    Delay           ;

PRESS   comf    PORTB,W         ; sample active low switch
        andlw   b'00000001'     ; filter out all but the RB0 switch bit
        xorwf   swlatch,W       ; changes (press or release)
        xorwf   swlatch,F       ; update switch state latch
        andlw   swlatch,W       ; filter out "new release" bits
        skpnz                   ; a "new press"? yes, skip, else
        goto    LOOP            ; go back to display loop
;
COUNTUP
 
Last edited:
I probably should have explained that switch state logic. Here's a quick summary of the four states we can detect when using a memory or latch. Consider the fresh sample as the "new" bit and the latch or memory as the "old" bit.

Code:
 new^old  result (changes)
  0 ^ 0    0   still released
  0 ^ 1    1   new release
  1 ^ 0    1   new press
  1 ^ 1    0   still pressed
There's quite a bit of magic in those few lines of code in the previous example. First we load the compliment of the switch port into WREG and mask off the unused bits. Then we exclusive-or WREG with the swlatch variable to get the exclusive-or bit result shown in the table above. WREG will contain '1' bits for any changes, either "new press" or "new release", so we've effectively filtered out the "still pressed" or "still released" switch states. You can test for "new press" or "new release" states like so; a "new press" = change bit (xor result bit) & "new" bit and a "new release" = change bit (xor result bit) & "old" bit. Since we've updated the swlatch variable to the value of the new sample using the xorwf swlatch,F instruction, swlatch contains the current sample (the "new" bits) so we just AND it with WREG which contains the change bits and any '1' bits left in WREG after the AND operation are "new press" bits. Now all we need to do is test the 'Z' status bit. If WREG = 0 then no "new press" states were detected.

The exciting part about those few lines of code is that they can process up to 8 switches in parallel.

Good luck. Mike
 
Here is a routine that incorporates a flag file to keep track of the condition of the push-button:

(delete the last CALL Delay instruction.)
 

Attachments

  • Button-A.doc
    25.5 KB · Views: 498
Last edited:
Thanks everyone and specialy Gayan for your quick reply its really appreciable. :)
Here is my coding for my program,actually I need to make a 2x7 segment display which can count from 0-99 in a random like lottery machine display.Please check my coding correct it if is possible.I have also some problems in making this circuit on breadboard. Please reply me soon :)
 

Attachments

  • hunainnnnnn.asm
    3.9 KB · Views: 424
remember I didn't put any transistor in my circuit because we are not allowed to that ;) and thts why i joined my ao and a1 port to the display (cathode common)
 
hi i am high school student trying to design ,a library place control system using pic16f716 ,the pic has two switch input ,one at the entering the second on the exit door of the library .the thing i faced is how to program the pic using picbasic to display the actual number of library users in seven segment Led display by comparing the two switches.please reply to as much as you can on the (mbirukm@yahoo.com)
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top