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 Tom Maier » Thu Sep 04, 2014 4:47 pm

All the advice people have been giving you is good stuff, but I was trying to get you to just take a small step because I realized you are just starting out.

The small step method of solving the problem is to write your own delay loop that includes a scan of the input. When the input comes true, you bail out of the loop and take your action.

delaycounter = 0
loop:
inc delaycounter
if delaycounter = 193
jmp to endloop // standard delay has completed, no button
if input_but = true
set buttflag
jmp to endloop // bail out with memory that a button press was seen
endloop:

if buttflag = true
do whatever you want for this condition

When you are writing your code, start out with a plain language description of where you are going. The fact that you know a high level language helps a lot. The description above is called pseudocode and it allows you to focus on the structure of the problem rather than the syntax of the language you will use. Then once the structure seems right, you look at your language and figure out how to impliment it.

Writing a program is often like creating a shopping list of things to do. List the things that need to be done, throw in the details of the logic structure, and then fill in the code later. When you see that your shopping list has the same thing happening over and over again, it should be encapsuated into a substructure, such as a function, subroutine, or procedure, or whatever the common terminology is of the language you are using. Sometimes you will want to create a subroutine out of something that is not called often, and it it just to get that ugly blob of code out of your main line code to keep the main code clean to read. That's called complexity hiding. The main code should be clean and readable so you can continue to grow it later on.

Interrupts are an abstraction for you right now, and you can solve this using interrupts if you want to learn something new now, but you have the skills already to solve it with straightline code by creating your own delay function.
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 MMcLaren » Fri Sep 05, 2014 9:39 am

Hi stef_r,

I apologize for the sloppy code example. I imagine the shift left arithmetic operator ("<<") may have thrown you off, or perhaps the xorwf instruction. I hope the modified listing below makes more sense. You can look up the "<<" arithmetic operator in MPASM help.

Code: Select all
;******************************************************************
;  main loop                                                      *
;******************************************************************
;
;  #define newpress ((swnew.0==1)&&(swold.0==0))
;  #define newrelease ((swnew.0==0)&&(swold.0==1))
;
;  while(1)
;  { delay_ms(25);              // 25-ms debounce/loop interval
;    swnew = ~portb;            // invert active lo switch (RB0)
;
;    if(newpress)               //
;    { porte ^= 0b00000100;     // toggle LED on RE2 and
;      ontimer = 800/25+1;      // reset 800-ms timer var
;    }                          //
;
;    swold = swnew;             // update switch state latch
;
;    if(porte.2 == 1)           // if LED 'on' (timer running)
;    { ontimer--;               // decrement timer
;      if(ontimer == 0)         // if "timed out"
;        porte.2 = 0;           // turn RE2 LED 'off'
;    }                          //
;  }                            //
;
loop
        call    delay25ms       ; 25-ms debounce/loop interval    |00
        comf    PORTB,W         ; sample active lo RB0 switch     |00
        movwf   swnew           ; save new sample                 |00
;
;  test for "new release" (new = 0 and old = 1)
;
newrelease
        btfsc   swnew,0         ; new = 0? yes, skip, else        |00
        bra     newpress        ; branch (not a "new release")    |00
        btfss   swold,0         ; old = 1? yes, skip, else        |00
        bra     newpress        ; branch (not a "new release")    |00
;
;  add code here for a "new release"
;
        nop                     ;                                 |00
        nop                     ;                                 |00
;
;  test for "new press" (new = 1 and old = 0)
;
newpress
        btfss   swnew,0         ; new = 1? yes, skip, else        |00
        bra     swlatch         ; branch (not a "new press")      |00
        btfsc   swold,0         ; old = 0? yes, skip, else        |00
        bra     swlatch         ; branch (not a "new press")      |00
;
;  we have a "new press" so toggle LED from on-to-off or from
;  off-to-on and reset the 800-ms timer
;
        movlw   b'00000100'     ; bit mask for LED on RE2         |00
        xorwf   PORTE,F         ; toggle LED (RE2)                |00
        movlw   800/25+1        ; 800-ms / 25-ms loop time        |00
        movwf   ledtmr          ; reset 800-msec LED timer        |00
;
;  update the switch state latch for next pass through the loop
;
swlatch
        movf    swnew,W         ; update switch state latch       |00
        movwf   swold           ;                                 |00
;
;  if LED 'on' (timer running), decrement the timer and if the
;  the timer "times out", turn the LED 'off'
;
ontimer
        btfsc   PORTE,RE2       ; LED on? no, skip (exit), else   |00
        decfsz  ledtmr,F        ; 800-ms time out? yes, skip      |00
        bra     loop            ;                                 |00
        bcf     PORTE,RE2       ; turn LED off                    |00
        bra     loop            ;                                 |00

;******************************************************************

I used a 25 millisecond loop because 25 milliseconds is a pretty good debounce interval for the switches. The non-blocking LED "ontimer" happily counts off 25-ms each time through the loop and shuts off the RE2 LED after 800 milliseconds. You can get delays of up to 255 * 25-ms (6.375 seconds) using 8-bit timer variables. Non-blocking switch logic keeps the loop moving and detects a "new press" to trigger your LED control function. The LED control function simply toggles the LED on or off (you said if the LED was on that you wanted a new press to turn it off).

This kind of loop structure can support multiple non-blocking functions/events. For example, you could easily add another switch and another timed LED function (how about a 1-Hz flasher) working independently from the other switch and LED.

Yes, you have to setup variables and create a delay routine (or use code from one of the delay generators). The delay subsystem I use is setup for clocks that are multiples of 4-MHz.

Hope this helps.

Cheerful 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 DavidBLit » Fri Sep 05, 2014 12:54 pm

Tom Maier wrote:...
set buttflag
...
if buttflag = true
do whatever you want for this condition

When you are writing your code, start out with a plain language description of where you are going.


"Huhuhuh...he said "buttflag"..."

Couldn't resist. :lol:
User avatar
DavidBLit
 
Posts: 11
Joined: Fri May 30, 2014 12:37 pm
Location: The Land of Confusion
PIC experience: Professional 2-5 years with MCHP products

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

Postby Tom Maier » Fri Sep 05, 2014 2:16 pm

Most all of my source code has some form of humor in it. It keeps me from getting too bored. :lol:

I also had to develop a kind of schtick to keep my students awake.

Remember that this OP is at the very begininng stages of learning the basic instructions. One thing to keep in mind when teaching is that you need to lead in an incremental way, and avoid jumping ahead or presenting too much information that may cause confusion. If the person gets lost and frustrated they will turn away from it. Learning needs to be a series of small wins, following a logical path.
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 MMcLaren » Fri Sep 05, 2014 3:27 pm

Of course you're right, Tom. I was trying to come up with a way to help him get past blocking switch methods and I think the "baby step" i presented was too big. Hey, take a look at what I originally was going to post and then try to explain (lol);

Code: Select all
;******************************************************************
;  main loop                                                      *
;******************************************************************

main
        DelayCy(25*msecs)       ; 25-ms debounce/loop interval    |00
;
;  K8LH parallel switch state logic (a "new press" filter)
;
;  wreg  ___---___---___---____   invert active lo switches
; swold  ____---___---___---___   switch state latch
;  wreg  ___-__-__-__-__-__-___   changes, press or release
;  wreg  ___-_____-_____-______   filter out 'release' bits
;
        comf    PORTB,W         ; sample active lo switches       |00
        xorwf   swold,W         ; changes, press or release       |00
        xorwf   swold,F         ; update switch state latch       |00
        andwf   swold,W         ; filter out 'release' bits       |00
        movwf   swnew           ; save 'new press' bits           |00

newsw0
        btfsc   swnew,0         ; sw0 press? no, skip, else       |00
        bra     toggle          ; branch (toggle LED)             |00
tmrsw0
        btfsc   PORTE,RE2       ; LED on? no, skip (exit), else   |00
        decfsz  ledtmr,F        ; timed out? yes, skip, else      |00
        bra     main            ;                                 |00
toggle
        movlw   1<<RE2          ; RE2 LED bit mask                |00
        xorwf   PORTE,F         ; toggle LED (RE2)                |00
        movlw   800/25          ; 800-ms / 25-ms loop time        |00
        movwf   ledtmr          ; reset 800-msec LED timer        |00
        bra     main            ;                                 |00

;******************************************************************
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 Tom Maier » Fri Sep 05, 2014 3:51 pm

He's not ready for state machines and interrupts yet. :D

The classic method of teaching programming follows these lines...

1.) Give them a skeletal program with "hello world" (blink an LED in the simpliest manner).

2.) Breifly explain how the program works. (they actually will not understand all of it for quite a while, but just repeat it every day until you see their lights come on :D )

3.) Let them compile (assemble) it and blow the code in and watch it run. That's a "win". Now they want more.

4.) Show them some tweakable parts of the existing program and let them play with that for a while. Now they see that THEY control the machine. It's getting exciting now.

5.) Introduce conditional branching (the OP was asking about the test and branch instructions, he is at this point of learning).

6.) Challenge them to come up with conditional branches of their own. At this time they will become tied in knots, as they are just learning how to create loops and then get out of them cleanly. Their code is jumping all over and they can't control it.

7.) The program is getting longer now, so introduce modularity with subroutine calls. Also introduce the concept of a "main thread". Introduce the concept of pseudocode and structure.

8.) Introduce the idea of primitive multitasking using flow-through scans of a task list and using flags to remember status. Now they can juggle two or more balls. Possibly introduce state machines.

9.) NOW comes interrupts and the idea of background processes.

The OP is at level 5. People have been showing him level 9.
Last edited by Tom Maier on Fri Sep 05, 2014 4:38 pm, edited 1 time in total.
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 MMcLaren » Fri Sep 05, 2014 4:36 pm

Tom Maier wrote:He's not ready for state machines and interrupts yet.

I agree, and that's part of the reason why I jumped in. No one answered his original question and told him that he doesn't really need interrupts to perform the task he was describing. Instead, there was quite a bit of momentum from the group trying to help him with timers and interrupts. I think Tunnelabguy noticed that, too.
Last edited by MMcLaren on Fri Sep 05, 2014 4:51 pm, edited 1 time in total.
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 Tom Maier » Fri Sep 05, 2014 4:45 pm

How did you learn to program? You seem to really understand very well for a "hobbiest".

I was classically trained in college, so I had somebody hold my hand and walk me through the classical instruction that I outlined above. It's a lot easier when you are sitting in front of the development system and a teacher is drawing on the board and will immediately answer your questions. I puzzle over how hobbiests can get started without becoming totally overwhelmed and lost and give up.
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 » Fri Sep 05, 2014 10:08 pm

Well, first of all thanks for all the comments.
I agree my 'trapdoor' is willing to jump too far and too fast forward sometimes.
Also, I would wish I could be in a collega-way of study this, but unfortunately that isn't the case. I have to learn by teaching myself :-)
Luckely, many people here are willing to share their knowledge and help beginners to explore their way into PIC's! MANY, MANY thanks for that!! -respect!-

I'm not the kind of person who quits when it gets tough; altough sometimes "I can't see any tree through the forrest"... :-) (Dutch proverb)
And I apriciate all the help even sometimes the answer is (yet) way above my current skills.

So.....
I have read and re-read the first chapters of the tutorials again and again.
Have written some code in plain text down on a piece of paper.
went back to my laptop and started to write from scratch -again- :mrgreen:

Finally, after some late nights and lots of coffe, I came up with this:

Code: Select all
PROG1   ; wait for and bebounce input @ RB0

OUT1_off
        ; turn OFF RE2
        banksel LATE                ;
        bcf     LATE,RE2            ; turn OFF output @ RE2
        banksel LATC                ; and
        bcf     LATC,RC0            ; turn OFF output @ RC0

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 4ms debounce time elapsed?
        xorlw   .32                 ; ( 4 ms = 32 * 64us)
        btfss   STATUS,Z            ; if not, continue to scan input @ RB0
        goto    RB0_chk_dn          ;

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   .32                 ; ( 4 ms = 32 * 64us)
        btfss   STATUS,Z            ; if not, continue to scan input @ RB0
        goto    RB0_chk_up          ;
        goto    OUT1_on             ; else turn ON output 1

OUT1_on
        ; turn ON output @ RE2 & RC0
        banksel LATE                ;
        bsf     LATE,RE2            ; turn ON output @ RE2
        banksel LATC                ;
        bsf     LATC,RC0            ; turn ON output @ RC0

        movlw   .50                 ; # of outer loops
        movwf   RB0_dc2             ;

        ; delay loop 256 x 32us (@ 125KHz oscillator frequency)
        clrf    RB0_dc1             ; 256 cycles
RB0_dly1
        ; inner delay loop         
        decfsz  RB0_dc1,f           ; decrement variable from 256
        goto    RB0_dly1            ; if not zero yet, continue to decrement
        banksel PORTB               ; else
        btfsc   PORTB,RB0           ; check if input signal @ RB0 is present
        goto    OUT1_off            ; if not,
        decfsz  RB0_dc2,f           ; continue with delay loop
        goto    RB0_dly1            ; else goto start and switch output OFF

        ; program 1 END
        goto    PROG1


It looks at the input @ RB0 and debounce it when the input is present.
When the input is cleared, the input is debounced again before going to the delay loop.

Inside the delay loop, I have implemented a routine that looks at the state @ RB0.
When it see the input get active again, the program start to the begin - starting with all the LED's OFF.

This might be not the best solution, but hey... IT WORKS! :P

I have run the processor at 125KHz, and set the prescaler to 1:2.
Maybe you are willing to look at the code (and maybe the comments behind it) and tell me if I did a good job or not :-)
If not, please don't hesitate to tell me; I'm not easily offended.

The next step I want to do is to implement a routine that does exactly the same, but instead of only looking to input @ RB0, it has to look to two inputs the same time.
So it needs to scan (and debounce) both inputs at RB0 and RB2 and sets the corresponding outputs with the delayed function. (RB0 -> output 1 / RB2 -> output 2)
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 » Sat Sep 06, 2014 2:11 pm

I see your comments have greatly improved since your first post. Your comments are starting to read like high level psuedo code and the assembly is just folowing along and doing the work.

One thing I would lie to suggest now that it is working, is to learn how to tidy up and make a neat structure. It's kind of like buidling a house, once you have finished the foundation you want to tidy up before trying to add the ground floor to it.

Have you learned how to make subroutines yet?

Your program has the main label of prog1, and there is nothing wrong with that, but how about if we call in "main"?

Code: Select all
main:                   // this is my perpetual loop
     blah
     blah
     blah

endmain:
     jmp to main                   // this is my perpetual loop


There's my main loop.

There is "stuff" you normally only want to do once on bootup of the machine, and we normally call these the initialization routines, or "init" for short.


Code: Select all
init:
    go set up the machine

main:                      // this is my perpetual loop
     blah
     blah
     blah

endmain:
     jmp to main                  // this is my perpetual loop


As the world gets more complicated, you can make multiple init sections...


Code: Select all
initports:
    go set up the ports
inittimer:
    go set up the timer

main:                             // this is my perpetual loop
     blah
     blah
     blah

endmain:
     jmp to main        // this is my perpetual loop


Now my main has to much blah blah in it, and I get lost when I try to read it. I will make some subroutine calls to make my main clean and easy to read. This main is like the control console of my car, I don't want it all cluttered up with confusing wires and stuff, so I hide them away...

Code: Select all

Delare variables, defines other stuff...

---------- INIT THE MACHINE -----------------
initports:
    go set up the ports
inittimer:
    go set up the timer

;------- THE MAIN LINE CODE ----------------------

main:                             // this is my perpetual loop
     wait_for_butt                 // go wait for the button
     delay1msec                // wait a bit

endmain:
     jmp to main        // this is my perpetual loop

;------------ My Subroutines  ----------
; my subroutine for waiting until the button is pressed and then released. Don't come back until it is found.

wait_for_butt
     blah                       // I put all my blah, blah down here so my main code "reads clean"
     blah
end_wait_for_butt:
     return
;--------------------------
; my subroutine to make a fixed delay
delay1msec:
     spin wheels for 1 millisecond
end_delay_1msec:
     return
;----------------------------
; more subroutines for complexity hiding...




So my suggestion is that if your code is working, tidy up the place before starting more construction... :D

you are moving to section number 7 in my list of classical learning mentioned above...
User avatar
Tom Maier
Verified identity
 
Posts: 179
Joined: Mon May 26, 2014 2:37 pm
PIC experience: Professional 5+ years with MCHP products

PreviousNext

Return to 14-Bit Core (enhanced)

Who is online

Users browsing this forum: Bing [Bot] and 1 guest