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 » Mon Aug 18, 2014 12:13 pm

Ok, I get the point here.
I defenitly must learn more about Timers and how they differ from each other and how to use them for each application.

I did noticed from the datasheet that Timer0 and Timer2 that they are both 8-bit timers but only Timer2 has a postscaler...
And that Timer0 has a 8-bit prescaler while Timer2 has a 1:64 prescaler and a 1:16 (max) postscaler.
Also, that Timer2 could be used for the clock signal for the I2C bus...

So, to get back to my main question, on how to let the switch respond while in the delay loop of 800msec:
I need to set up a routine that is monitoring the switch after it has been pressed and released for 800msec.
While monitoring, the LED output is HIGH.
If the switch is pressed, the LED must go LOW and the program starts again when the switch is released again.

Let's see if I can do that.... :-)
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 Dimebag » Mon Aug 18, 2014 1:49 pm

Dimebag
 
Posts: 109
Joined: Sun Jun 29, 2014 7:51 am
Location: Sydney, Australia

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

Postby Dimebag » Mon Aug 18, 2014 3:33 pm

Dimebag
 
Posts: 109
Joined: Sun Jun 29, 2014 7:51 am
Location: Sydney, Australia

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

Postby Olin Lathrop » Mon Aug 18, 2014 4:52 pm

Ian.M wrote:OTOH the requirement for a periodic interrupt may not include accurate timekeeping with a power of 10 time interval. Other timers can be used if you need to reserve Timer 2 for PWM, either accepting the inevitable inaccuracy of reloading a timer with an active prescaler, or simply using the natural overflow period of a free running timer, and keeping track of the elapsed time in units of the rollover period.

Its also possible to use Timer 1 + a CCP module special event trigger for precision time keeping.

Yes, any of the timers can be used to create a perodic interrupt. The reason I said to use timer 2 is because it is the simplest one to use for that purpose due to it being the only one with a period register. It is also the only one that can provide the period for a CCP module in PWM mode, so sometimes these are competing requirements. Usually, you can arrange the PWM frequency to be a multiple of the clock tick frequency by the timer 2 postscaler value, so you can have timer 2 serve both needs.

If you've got a CCP module free, you can use timer 1 to generate the clock tick. This has the advantage that the timer and its period register are both 16 bits, so you can very accurately pick a long period.

There is no need to lose time when using timer 0 for the clock tick, even when just letting it roll over (256 cycle period) isn't what you want. The trick is to ADD the offset value into the timer each interrupt instead of outright resetting the timer. You have to be careful in that adding into the timer causes it to stop counting for a few cycles, which you have to take into account in deciding the value to add. Also, as you mention, you can't use the prescaler, since your action isn't synchronized with it and you can lose a unpredictable number of cycles when timer 0 is paused due to be written to.

To simplify using timer 0 to create a periodic interrupt, I use my TIMER0_PER macro:

Code: Select all
;********************
;
;   Macro TIMER0_PER cy
;
;   Update timer 0 so that it next wraps CY cycles from the previous wrap.  This
;   can be useful in a timer 0 interrupt routine to set the exact number of
;   cycles until the next timer 0 interrupt.  Timer 0 is assumed to be running
;   from the instruction clock.  The appropriate value is added into timer 0,
;   so this macro does not need to be invoked a fixed delay after the last
;   timer 0 wrap.  CY must be a constant.
;
;   The timer sets its interrupt flag when counting from 255, which wraps back
;   to 0.  If left alone, the timer therefore has a period of 256 instruction
;   cycles.  When adding a value into the timer, the increment is lost during
;   the add instruction, and the timer is not incremented for two additional
;   cycles when the TMR0 register is written to.  This effectively adds 3 more
;   cycles to the timer 0 wrap period.  These additional cycles are taken
;   into account in computing the value to add to TMR0.
;
timer0_per macro cy
         dbankif tmr0
         movlw   256 + 3 - (cy)
         addwf   tmr0
         endm


It's not complicated, but alleviates having to look up the details, keep them all in mind, and figure out exactly how much to add to the timer each interrupt. This macro is from STD.INS.ASPIC, which is part of my PIC development environment.

Therefore, all in all, use timer 2 unless you know enough about the PIC and know of a good reason to use one of the other timers. Of course if you knew all that, you don't need someone telling you to set up a periodic interrupt with timer 2 in the first place.
Last edited by Olin Lathrop on Mon Aug 18, 2014 10:59 pm, edited 2 times in total.
User avatar
Olin Lathrop
Verified identity
 
Posts: 48
Joined: Fri May 30, 2014 3:38 pm
Location: Littleton, MA USA
PIC experience: Professional 5+ years with MCHP products

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

Postby Olin Lathrop » Mon Aug 18, 2014 4:56 pm

Roche wrote:The only stupid question is the one that doesn't get asked...

This is a totally absurd assertion. Of course there are stupid question.
User avatar
Olin Lathrop
Verified identity
 
Posts: 48
Joined: Fri May 30, 2014 3:38 pm
Location: Littleton, MA USA
PIC experience: Professional 5+ years with MCHP products

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

Postby Olin Lathrop » Mon Aug 18, 2014 5:44 pm

stef_r wrote:I defenitly must learn more about Timers and how they differ from each other and how to use them for each application.

As with all the peripherals, you have to read the datasheet. This must be done before architecting the firmware. You don't need to remember all the details of all the peripherals, just their capabilities. You keep these in mind when architecting the firmware, trading off which peripheral to use for what in what way.

I did noticed from the datasheet that Timer0 and Timer2 that they are both 8-bit timers but only Timer2 has a postscaler... And that Timer0 has a 8-bit prescaler while Timer2 has a 1:64 prescaler and a 1:16 (max) postscaler.
Also, that Timer2 could be used for the clock signal for the I2C bus...

Those are all good things to remember about the timers. However you missed the salient feature of timer 2 for this application, which is that it has a built-in period register. That makes it particularly easy to have it generate a periodic clock tick with a period of your chosing.

Note that even with the prescaler, selectable period, and postscaler, there are still limits to the period. The largest possible period is 65536 instruction cycles, and there are gaps in the possible periods after 256 cycles. Fortunately, these are not usually had constraints to get around. For long periods, you set up a shorter interrupt and count multiple of these interrupts. Or put another way, the interrupt routine itself can effectively be another postscaler of any arbitrary integer value. Once the interrupt period is "long" (a few 100 cycles), the added overhead is a small fraction of the total cycles spent by the CPU.

To make the process of setting up timer 2 more automatic and less error prone, I long ago created a bunch of macros for this purpose. These make the assembler do the complicated process of figuring out the prescaler, period, and postscaler values at build time. For example, here is one of these macros:

Code: Select all
;********************
;
;   Macro TIMER2_CYCLES tmr2ncy
;
;   Calculate a timer 2 setup to achieve the interrupt period of TMR2NCY
;   instruction cycles.  This macro generates no code, but sets the following
;   assembler variables:
;
;     TMR2_PRE  -  timer 2 prescaler value: 1, 4, or 16
;
;     TMR2_PER  -  timer 2 period divide value: 1 - 256
;
;     TMR2_POS  -  timer 2 postscaler value: 1 - 16
;
;   The postscaler is set to the maximum possible value that results in the
;   specified period.  This minimizes the PWM period for the given overall
;   period.  Within this constraint, the smallest possible prescaler is used,
;   thereby maximizing the PWM frequency.  This results in the maximum possible
;   PWM resolution given the overall interrupt period constraint.
;
;   The hardware PWM period, if used, is defined by the prescaler and period
;   values only.  The number of instructions per PWM period is therefore
;   TMR2_PRE * TMR2_PER, whereas the number of instructions per timer 2
;   interrupt (if enabled) is TMR2_PRE * TMR2_PER * TMR2_POS.
;
;   An error is generated if the indicated period can not be attained exactly
;   within the constraints of the timer 2 hardware.
;
timer2_cycles macro tmr2ncy

tmr2_pos set     16          ;init the postscaler to maximum
  while tmr2_pos >= 1        ;loop thru decreasing postscaler values
tmr2_pre set     1           ;init the prescaler to minimum
    while tmr2_pre <= 16     ;loop thru increasing prescaler values
tmr2_per set     tmr2ncy / (tmr2_pre * tmr2_pos) ;make period value with this pre/post
      if (tmr2_per >= 1) && (tmr2_per <= 256) ;period within range ?
        if (tmr2_pre * tmr2_per * tmr2_pos) == tmr2ncy ;result achieved exactly ?
         exitm               ;found exact result, all done
          endif
        endif
tmr2_pre set     tmr2_pre * 4 ;advance to next prescaler value to try
      endw                   ;back to try with this new prescaler value
tmr2_pos set     tmr2_pos - 1 ;advance to next postscaler value to try
    endw                     ;back to try with this new postscaler value

         error   "Requested timer 2 period can not be achieved in TIMER2_CYCLES."
         endm


This and many other macros are included in my STD.INS.ASPIC file, which is part of my PIC development environment, which is described at http://www.embedinc.com/pic.

So, to get back to my main question, on how to let the switch respond while in the delay loop of 800msec:
I need to set up a routine that is monitoring the switch after it has been pressed and released for 800msec.
While monitoring, the LED output is HIGH. If the switch is pressed, the LED must go LOW and the program starts again when the switch is released again.

That's probably not going to work due to bouncing of the switch. Again, you need a proper architecture, not a bandaid on a failed one.
User avatar
Olin Lathrop
Verified identity
 
Posts: 48
Joined: Fri May 30, 2014 3:38 pm
Location: Littleton, MA USA
PIC experience: Professional 5+ years with MCHP products

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

Postby Ian.M » Mon Aug 18, 2014 8:28 pm

Olin Lathrop wrote: The reason I said to use timer 2 is because it is the simplest one to use for that purpose due to it being the only one with a prescaler.


Don't you mean period register? Its other unique feature is a postscaler, but that scarecly makes it simpler.

I skimmed over Timer 0 without a prescaler as the context saving uses too many cycles on the standard midrange core devices I usually use, so its a last resort. Of course the Enhanced Midrange core has fast context saving so the overhead of an interrupt every few hundred cycles is far less.
Ian.M
Verified identity
 
Posts: 95
Joined: Wed May 28, 2014 12:47 am
PIC experience: Professional 1+ years with MCHP products

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

Postby Olin Lathrop » Mon Aug 18, 2014 11:01 pm

Ian.M wrote:
Olin Lathrop wrote: The reason I said to use timer 2 is because it is the simplest one to use for that purpose due to it being the only one with a prescaler.


Don't you mean period register?


Doh! Yes, I meant period register, and have edited my post accordingly.
User avatar
Olin Lathrop
Verified identity
 
Posts: 48
Joined: Fri May 30, 2014 3:38 pm
Location: Littleton, MA USA
PIC experience: Professional 5+ years with MCHP products

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

Postby Olin Lathrop » Mon Aug 18, 2014 11:18 pm

Ian.M wrote:I skimmed over Timer 0 without a prescaler as the context saving uses too many cycles on the standard midrange core devices I usually use, so its a last resort. Of course the Enhanced Midrange core has fast context saving so the overhead of an interrupt every few hundred cycles is far less.


To put some numbers on this, it takes 12 cycles to get into and out of a interrupt on a small standard 14 bit core part. If you need to deal with paging, then it takes another 5 cycles, for a total of 17. If you have timer 0 interrupting every 250 instructions, then just the basic interrupt overhead is 7%. Of course that interrupt routine has to actually do something, so let's say another 20 cycles on average to be generous. That's 37/250 = 15% of the CPU. That's equivalent to getting 17 MHz usable when running from a 20 MHz oscillator. Most of the time that's going to be OK. However, I agree that this isn't the first choice. I have actually used this technique a few times when timer 2 needed to do something else.
User avatar
Olin Lathrop
Verified identity
 
Posts: 48
Joined: Fri May 30, 2014 3:38 pm
Location: Littleton, MA USA
PIC experience: Professional 5+ years with MCHP products

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

Postby Bmd » Wed Aug 20, 2014 8:57 am

aaahhhh, I've missed Olin.....
regards

Brandon
Bmd
Verified identity
 
Posts: 2
Joined: Tue May 27, 2014 7:40 pm
Location: Bedfordshire, UK
PIC experience: Professional 5+ years with MCHP products

PreviousNext

Return to 14-Bit Core (enhanced)

Who is online

Users browsing this forum: No registered users and 1 guest