(this answer may not be accurate, please feel free to comment and edit)
After 2 days' looking into it, finally I have found several issues related and solved the problem.
When a microcontroller doesn't seem to work properly like the situation here, you might wanna check the following:
- Is all digital and analog supply and ground pins are properly connected?
- Is the microcontroller resetting itself repeatedly?
- Is oscillator working?
- Is the microcontroller in the programming mode instead of executing code?
After some testing and checking, I found the problem I had here is because I didn't implement reset and turned on the LVP(Low-volatge programming).
MCLR Reset
On some PICmirco devices, the MCLR(master clear) signal can be internally tied to VDD through a configuration bit MCLRE. If this bit is set, then the MCLR function is enabled. And then if the voltage on the pin is low, the microcontroller will have to reset. If this bit is clear, then the MCLR pin can be used as an I/O pin.
As for my problem here, I set the MCLRE bit but had MCLR pin floating. Since MCLRE bit is set, so the pin should function as input. But floating the pin made it hard to predict what's the voltage on it.
On PIC16F887 datasheet page 217, it suggests us tie a 1k(or greater) resistor to VDD and a 0.1uF(optional, not critical) capacitor to ground. Then microcontroller should never be resetting itself except POR,BOR and WDT timeout reset etc.
I actually replaced the capacitor with a switch, so I can manually reset the device whenever I want.
Low-voltage programming
I didn't realize that there is this LVP thing troubled me until I came across this post on Microchip forum.
Microchip provides us two programming mode: high-voltage programming and low-voltage programming.
High-voltage programming needed three things in sequence(according to PICmirco Device Programming: What You Always Wanted to Know (But Didn't Know Who To Ask) page 2) :
- Applying the appropriate power source and ground (VDD and VSS) to the device;
- Raising the voltage on the MCLR pin to the programming voltage level (in general, around 13V), while at the same time:
- Pulling the two designated I/O port to logic low and holding them there.
In case you haven't connected all the VDD and VSS appropriately, you should have. More info on this, check out If a PIC MCU provides multiple Vdd/Vss should you provide power to them all?.
The differences between the requirements on Low-voltage programming(also called Single-supply programming) and High-voltage programming is:
- Only VDD on the MCLR pin is required.
- LVP uses PGM as an additional programming pin, while other pins (PGC-Program Clock, PGD Program Data) in the High-voltage programming mode is still in use.
In my case, because in the configuration bits I set the LVP bit. As per the datasheet:
LVP: Low Voltage Programming Enable bit
1 = RB3/PGM pin has PGM function, low voltage programming enabled
0 = RB3 pin is digital I/O, HV on MCLR must be used for programming
And this is how the device enters LVP mode as per PICmirco Device Programming page 5:
When PGC and PGD pins are held to logic low at the same time as VDD is applied to both PGM and MCLR, the microcontroller enters Programming mode.
So I unintentionally set the LVP and floated PGC, PGD and PGM before I get to know what LVP is. Because LVP is on and PGC, PGC, PGM are all floating, after I implemented reset which solved the resetting problem but also brought MCLR pin to VDD, the device would go into the Low-voltage programming mode instead of running the code.
related question:
PIC circuit won't stay powered
Seemingly unstable basic PIC18F2550 circuit
Is it really a bad idea to leave an MCU input pin floating?
Yes, you seem to understand correctly how MPASM processes numeric expressions.
While using the bit names is way better than the hard coded HEX values most people use, I think there is yet a better way. The problem with the bit names is that they can be cryptic, and you are relying on the name only to explain what each bit does. This method also doesn't work well with multi-bit fields, as you demonstrate with the b'111' at the end. I had to look in the datasheet to find that these are the prescaler divider selection bits.
I like to show each field on a separate line so that each gets its own end of line comment. Here is a example of setting the OPTION register in some 12F508 code from 2009:
movlw b'01000010' ;set OPTION register
; 0------- wake-up on change enabled
; -1------ weak pullups disabled on GP0,GP1,GP3
; --0----- timer 0 clocked from instruction clock
; ---0---- timer 0 inc on rising edge of T0CKI (not used)
; ----0--- prescaler assigned to timer 0
; -----010 prescaler = 1:8
option
I use this method for most SFR settings.
Best Answer
The operand of the PIC instruction is evaluated to a constant at assembly time- the code emitted will contain a constant in that position. For example:
1 << 1 is evaluated as b'00000010' (b'00000001' left-shifted by 1 - it is understood that a 0 is shifted in)
The the complement is applied (all 8 bits are flipped), so you get
b'11111101'
and the code emitted is
movlw b'11111101'
It's the same as directly writing the above except you might find it more readable to write it in the way shown.