(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?