some help/advice with a program with 16F1789

Enhanced mid-range devices. PIC12F1xxx and PIC16F1xxx

Re: some help/advice with a program with 16F1789

Postby stef_r » Sun Sep 07, 2014 12:01 pm

Ok, first let me explain why I used "PROG1" instead of "MAIN"
Fot the project I write this software, it has a 5-pos DIP switch incorporated.
Simply said, DIPswitch 1 ON => program 1 ...... DIPswitch 5 ON => program 5.
That's why I used PROG1 :-)

Now, as you suggest I must make some impovements to the code step by step.
First make shorter by removing the delay loops and use Timer0 instead to create a ~1sec delay.
This removes the nesesarry variables for the delay loop.
I changed the prescaler to 1:128 to get a maximum time of ~1sec. when Timer0 overflows.
This mean I first have to change the debounce delay. (128ms for debounce is a 'little' too much)

Code: Select all
        movf    TMR0,w              ; has ~20ms debounce time elapsed?
        xorlw   .5                 ; ( 20 ms = 5 * 4.096ms)


then removing the delay loops and use Timer0 instead to create a ~1sec delay:
(initially without responding to stwitch input)

Code: Select all
        ; delay 1000ms
        banksel TMR0
        clrf    TMR0                ; clear Timer0
w_tmr0
        banksel TMR0
        movf    TMR0,w              ; copy the current value of TMR0 to W
        xorlw   .255                ; Check if approx. 1000ms has elapsed
        btfss   STATUS,Z            ; 244*4.096 = 999,5ms
        goto    w_tmr0


Now I need the program to respond to the input switch while inside the delay loop:

Code: Select all
        ; delay 1000ms
        banksel TMR0
        clrf    TMR0                ; clear Timer0
w_tmr0
        banksel PORTB
        btfsc   PORTB,RB0           ; check if RB0 input is active
        goto    PROG1
        banksel TMR0
        movf    TMR0,w              ; copy the current value of TMR0 to W
        xorlw   .255                ; Check if approx. 1000ms has elapsed
        btfss   STATUS,Z            ; 244*4.096 = 999,5ms
        goto    w_tmr0


Still, however, all the code is still inside the MAIN...
So first I will try to do is trying to get the delay loop and debounce routine in a subroutine.

This is what I'm goint to do right now, so when I finish this, I will continue here :-)
stef_r
 
Posts: 15
Joined: Thu Aug 14, 2014 12:16 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby stef_r » Sun Sep 07, 2014 1:25 pm

I'm back and I have made my MAIN LOOP (PROG1) much more compact and (hopefully) more readable.

First thing I did was palce the delay loop of ~1sec into a subroutine.
After testing it if the program still works, I noticed that the program DIDN'T work as before.
After going through the code, I noticed I forgot the "return" code in my subroutine.
When I've added the return at the end of my subroutine, the code worked fine again!
So go to the next step and to place the 'scan & debounce routine for RB0" into the subroutine.

All went fine and I kept on going until all of the seperate code was into the subroutine:

Code: Select all

;*******************************************************************************
; SUBROUTINES
;*******************************************************************************

;****delay ~1sec while still responding to input @ RB0
delay_out1
        banksel TMR0
        clrf    TMR0                ; clear Timer0
w_tmr0
        banksel PORTB
        btfsc   PORTB,RB0           ; check if RB0 input is active
        goto    PROG1
        banksel TMR0
        movf    TMR0,w              ; copy the current value of TMR0 to W
        xorlw   .255                ; Check if approx. 1000ms has elapsed
        btfss   STATUS,Z            ; 244*4.096 = 999,5ms
        goto    w_tmr0

        return

;****Scan and debounce input @ RB0 (active)
RB0_dbnce_active

RB0_wait_dn
        ; wait for input @ RB0
        banksel TMR0                ;
        clrf    TMR0                ; clear Timer0
RB0_chk_dn
        ; check input @ RB0 (signal present)
        banksel PORTB               ;
        btfss   PORTB,RB0           ; scan input @ RB0
        goto    RB0_wait_dn         ; continue to reset TMR0 while RB0 => LOW
        movf    TMR0,w              ; has ~20ms debounce time elapsed?
        xorlw   .5                 ; ( 20 ms = 5 * 4.096ms)
        btfss   STATUS,Z            ; if not, continue to scan input @ RB0
        goto    RB0_chk_dn          ;

        return

;****Scan and debounce input @ RB0 (released)
RB0_dbnce_release

RB0_wait_up
        ; wait for input @ RB0
        banksel TMR0                ;
        clrf    TMR0                ; clear Timer0
RB0_chk_up
        ; check input @ RB0 (signal cleared)
        banksel PORTB               ;
        btfsc   PORTB,RB0           ; scan input @ RB0
        goto    RB0_wait_up         ; continue to reset TMR0 while RB0 => HIGH
        movf    TMR0,w              ; has 4ms debounce time elapsed?
        xorlw   .5                 ; ( 20 ms = 5 * 4.096ms)
        btfss   STATUS,Z            ; if not, continue to scan input @ RB0
        goto    RB0_chk_up          ;
        goto    OUT1_on             ; else turn ON output 1

        return


;****Turn off OUTPUT 1 (RE2 & RC0)
output1_off
        ; turn OFF RE2 & RC0
        banksel LATE                ;
        bcf     LATE,RE2            ; turn OFF output @ RE2
        banksel LATC                ; and
        bcf     LATC,RC0            ; turn OFF output @ RC0

        return

;****Turn on OUTPUT 1 (RE2 & RC0)
output1_on
        ; turn ON output @ RE2 & RC0
        banksel LATE                ;
        bsf     LATE,RE2            ; turn ON output @ RE2
        banksel LATC                ;
        bsf     LATC,RC0            ; turn ON output @ RC0

        return

    END


after putting everything into the subroutine, my main code looks like this now:

Code: Select all
PROG1   ; invert output to input with ~1sec delay

OUT1_off
        ;turn off output 1
        pagesel output1_off
        call    output1_off
        pagesel $

        ;check and debounce for active input @ RB0
        pagesel RB0_dbnce_active
        call    RB0_dbnce_active
        pagesel $

        ; check and debounce for input release @ RB0
        pagesel RB0_dbnce_release
        call    RB0_dbnce_release
        pagesel $

OUT1_on
        ;turn on output 1
        pagesel output1_on
        call    output1_on
        pagesel $

        ;delay loop for output 1 to stay ON while responing to input @ RB0
        pagesel delay_out1
        call    delay_out1
        pagesel $

        ; program 1 END
        goto    PROG1


much more compact, right? :mrgreen:
stef_r
 
Posts: 15
Joined: Thu Aug 14, 2014 12:16 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby Tom Maier » Sun Sep 07, 2014 3:01 pm

Yes, not only more compact, but also more readable, right? And that is the important thing, because when you want to modify or add to this program it becomes easier.

I see why you are doing the prog1 now. That's cool that you have a selector switch for what program is run.

As you learn to modularize your code you will learn more tricks about how to make the modules more flexible for future use. In the future you can be writing some code and then you will remember "I already wrote something like that", and then you go back to the old code and use that old subroutine.

I would tell my students that trying to build things with lines of code is like gluing sand grains together to build a castle. When you start using modular programming it is more like using pre-fab windows, doors, and walls to build the castle, and you can put a large achitecture together much faster in the long run. But first you need to make the model of your pre-fab components with subroutines.

Each time you start a new program you will start with a fresh view and refined appraoch about how it will come together. Normally you will start with writing a plain language psuedocode description of the main program, then make that become a bunch of subroutines that do what you have described, then code the subroutines. Soetimes I'm not really sure about the flow of the main line code, but I see some of the subroutines I might be using, so while I'm thinking over the big-picture structure, I code out the subroutines. I made the doors and windows before I know how they will come together.

Staying organized like this helps to go farther with a program without becoming entangled in small details.
User avatar
Tom Maier
Verified identity
 
Posts: 179
Joined: Mon May 26, 2014 2:37 pm
PIC experience: Professional 5+ years with MCHP products

Re: some help/advice with a program with 16F1789

Postby stef_r » Sun Sep 07, 2014 6:47 pm

It looks a lot cleaner indeed, altough (for now) I do have to scroll up and down from the main loop PROG1 to the subroutine section.
I'll try to read the program as the PIC core would do; if I read a "if RB0 is active, then goto..." I actually would scroll to the "then goto..."section to read what's happening.
If I become more experienced with the Assembler, maybe I find another, better way but for now this seemds to work fine for me.

So.... Now I have this working properly...
I have used Timer0 for both debounce routines and delay loops.
What if I want to add a similar routine that does almost the same, but instead of checking only one input @ RB0, I want to add a second input @ RB2.
RB0 switches output 1 (RE2 & RC0) and RB2 would switch output 2 (RC6 & RD3).

More important input2 has to operate 'independently' from input 1.
what ever point the RB0 routine is, if I activate input 2 @ RB2 it has to do his thing while the RB0 routine continious to do that routine.

1) can I do that with the type of code I have right now?
2) what would you suggest I do to get two inputs working?

Many thanks in advance!
stef_r
 
Posts: 15
Joined: Thu Aug 14, 2014 12:16 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby MMcLaren » Mon Sep 08, 2014 8:15 am

Hi stef_r,

I'm not sure your current program structure will support what you're trying to do. Perhaps some of the other members will jump in with suggestions.

Have you had an opportunity to study the code in projects published on the internet? I got a lot of great examples and ideas (and some not so great examples) this way when I started many years ago. I also found lots of code examples in the PICLIST source code library.

I've published a few beginner projects like the one pictured below but the programs were written in C so I'm not sure they would be very good examples for you.

Good luck on your project.

Cheerful regards, Mike
Attachments
4-Digit #2.jpg
4-Digit #2.jpg (77.74 KiB) Viewed 1534 times
MMcLaren
 
Posts: 18
Joined: Sun Aug 31, 2014 10:08 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby stef_r » Mon Sep 08, 2014 1:29 pm

Hi Mike,

Thank you for the tip of the PIClist code library.
I did noticed this site, but as you mentioned... Much examples out there are writen for / in C.
And since I didn't have any experience with the C programming language, Assembler seemds to be easier to begin with.
I have seen comparisations of examples both is C and assembler and C ideed looked much 'shorter' then assembler.
(If I see how easy a delay loop is written in C compared the code in Assembler...)

However, I will try to avoid to learn assembler by looking at the output files from different compilers.
My thought is that they put to much 'overhead' in the assembler code that confuses me only more.
I do however like to learn the hardware side of the PIC's while writing Assembler, so that's a good thing!

I am at the learning stage that I know how to write simple delay loops, both with and without the use of Timers, how to read and debounce switches and to switch outputs on and off.
But still, only one switch per program.
I now need to 'scan' for two or more inputs and have the program respond to them.
What I need is something like this:
if switch @ RB0 is pressed, the program label A must be executed
If switch @ RB2 is pressed, the program label B must be executed.
However, if both RB0 and RB2 are pressed the same time (within a time span of 10~20ms) program label C has to be executed.

I'm beginning to think, as you allready mentioned, that the code I have writen so far isn't quite suitable for this sort of work.

Maybe I do have to overlook the chapters of the tutorial I've been following once again to be sure I understand everything, and then move to the next level and use interrupts for this kind of task.
Anyhow, I'm afraid it's going to take much more time to get my program working (and understanding the code!) than I initially thought it would take... :-(
But that doesn't scared me to give up; it only encourage me to try harder to understand it all better and better.
stef_r
 
Posts: 15
Joined: Thu Aug 14, 2014 12:16 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby MMcLaren » Mon Sep 08, 2014 3:14 pm

I don't think you necessarily need interrupts to accomplish your current task, though they are worth learning about at some time.

May I ask if you looked at the examples I posted earlier? They had a structure that would support sampling switches while at the same time supporting multiple output delay functions. Is there a way I could have explained them better or have you dismissed them for some reason?

I've cobbled together a program that does what you've described, except for the "both RB0 & RB2 at the same time" function, but I hesitate to post it if there's a risk of causing more confusion.

Best regards, Mike
MMcLaren
 
Posts: 18
Joined: Sun Aug 31, 2014 10:08 pm
PIC experience: Experienced Hobbyist

Re: some help/advice with a program with 16F1789

Postby stef_r » Mon Sep 08, 2014 9:17 pm

MMcLaren wrote:I've cobbled together a program that does what you've described, except for the "both RB0 & RB2 at the same time" function, but I hesitate to post it if there's a risk of causing more confusion.


Hi Mike,
Thanks for the trouble to write a similar function of the program I want.
Don't get me wrong, the last thing I want is someone else writing the porgram for me!
Altough looking to sample code is indeed very usefull; it's the same way I do it now while following the titorials.

Maybe I haven't looked good enough to the sample code you provided earlier, my appoligies for that!
I will look at them tomorrow because it's getting late now and my eyes are getting 16:9 :mrgreen:

One thing I will try out tomorrow is also found in the Gooligum tutorial, chapter 5 on Timer0.
There is a sample program that demonstrates a simple reaction timer.
It lights up a LED to indicate START and if the user succeeds to press the button within 200ms, a SUCCESS led will lit.

I think I can use that structure, but instead of light a LED to indicate START, I will wait for input RB0 to get HIGH.
If input RB2 becomes active within 10-20ms (also a nice debounce time), then the program jumps to 'label C'.
If 200ms passes without any signal from RB2, the program continues to scan both RB0 and RB2 inputs.

But again, thats\'s something I need to look at in more detail tomorrow.
Just as I will do to your previous code.

Anyway, thanks a lot for thinking with me and give me some 'handles' to build with!
stef_r
 
Posts: 15
Joined: Thu Aug 14, 2014 12:16 pm
PIC experience: Experienced Hobbyist

Previous

Return to 14-Bit Core (enhanced)

Who is online

Users browsing this forum: No registered users and 1 guest