'PIC Startup Troubles'
I have a simple 16F84 LED flasher that is starting up weird. It's
running off +5V from my PC, 4MHz resonator and has 8 LEDs via 330 ohm
resistors to +5V (hooked to PortB).
My code increments an 8 bit count every 256 timer interrupts. The main
loop writes it to PORT.
The code is rough and has a few bugs (LP O/c instead of XT), div256
instead of div16 like I wanted, but I figured it's hardware acting up.
Here's what happens on applying power:
1. The Leeds show a normal binary countdown (expected as the LED's
2. The LED's show a normal binary countdown, with random Leeds much
dimmer than the others.
3. The Leeds show a normal binary count UP, with all Leeds quite dim.
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_ON & _LP_OSC
I replaced the PIC, tried MHz crystal, tried a MC34164 on MCLR, tried
manually pulling MCLR low. There is good decoupling etc. Read AN522
and still puzzled. Help is appreciated.
> I have a simple 16F84 LED flasher that is starting up weird.
All your problems seem to be due to register bank confusion. In
particular, your InitPorts and InitTimers routines both leave bank 1
selected, so your main loop:
movf counter, W ; Output 'counter' to port B.
is not doing at all what you think it is. That reference to 'counter' is
picking the right value only by accident (it's at an address that's shared
between the two banks), and you're actually storing it into the TRISB
register (in bank 1 at the same address as PORTB in bank 0). In other
words, instead of switching between low and high levels at your outputs,
you're switching between the random initial state of the PORTB latch and a
high impedance input state. You might think that you're clearing PORTB, so
there wouldn't be any randomness to the behavior:
InitPorts: bsf STATUS, RP0 ; Select Bank 1.
clrf PORTB ; All outputs low.
movlw B'00000000' ; Set Port B is all outputs.
movwf TRISB ;
but that's not so: the references to PORTB and TRISB (same address,
different banks) are both setting TRISB, since bank 1 is selected during
It appears that the PIC assembers' handling of register banks simply sucks
- the problems you're having (but not every such problem) could have easily
been detected by a simple data flow analysis pass in the assembler. Until
such time as somebody writes an assembler that works right, you'll just
have to be more careful about register banks - check EVERY register access,
and make sure that the bank select bits are set appropriately (unless
you're using register that's duplicated across all banks). This brings up
another problem I think your code has - you need to move the definition of
status_temp up a little bit, so that it's in one of the register addresses
that is duplicated between banks, OR you need to move that "bcf STATUS,RP0"
(4th line of INT_SERV) up one line. As it is, status_temp may be written
to and read from different places, causing unexpected changes to the STATUS
register in your main program every time an interrupt occurs.
Jason Harper wrote:
> All your problems seem to be due to register bank confusion. In
> particular, your InitPorts and InitTimers routines both leave bank 1
> selected, so your main loop:
> MAIN: NOP
> movf counter, W ; Output 'counter' to port B.
> movwf PORTB
> GOTO MAIN
> is not doing at all what you think it is. That reference to 'counter'
> is picking the right value only by accident (it's at an address that's
> shared between the two banks), and you're actually storing it into the
> TRISB register (in bank 1 at the same address as PORTB in bank 0).
That's it in a nutshell. May I suggest a little lesson to be learnt
early in the piece? Though the ability to swap register banks and
access TRIS and OPTION directly is a neat party trick, for the vast
majority of the time, it's an darn nuisance. The cleanest way to avoid
this problem for the moment in the code given is the following:
Edit P16F84.INC to include the statement
somewhere, say just before the register definitions, after the ENDIF
statement. This will avoid certain rudeness from the assembler telling
you how to suck eggs. If you ever use another 14-bit core part, you
will have to edit its include file also.
and similarly for PORTB. Also hange
movwf OPTION_REG ; TMR0 prescale=(Fosc/4)= ???
OPTION ; TMR0 prescale=(Fosc/4)= ???
bsf STATUS, RP0 ; Select Bank 1.
from the two places it *is* in your present code.
In general, you will find it appropriate to ensure RP0 is zero for
most of your code, setting it briefly where you *really* need to to
access bank 1, and clearing it immediately afterward. But to access the
TRIS and OPTION registers, a far better method has been provided to
cover 99.8% of circumstances, and that's the one you should use.
Finally, though this is a nice exercise in interrupt coding, and I
should point out that the more common part of your interrupt routine can
be executed much faster, entirely without context saving (if you don't
see how, ask!), I do believe that many if not most applications can be
more easily implemented using code without interrupts and that
interrupts are more appropriately used for unpredictable events than
More... (looser matching)
- Last day of these posts
- In 2000
, 2001 only
- New search...