Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PIC16F18877 — HC-SR501 PIR motion sensor always reads low on PORTD pin

I’m working on a PIC16F18877 project where I’m trying to read a digital motion signal from an HC-SR501 PIR sensor.

I’ve run into an issue where my PIR sensor seems to always read LOW (0) on my PIC input pin, even when I wave my hand in front of it.

My hardware setup: • PIR sensor HC-SR501 • OUT pin connected to RD2 on PIC16F18877 • PIR sensor powered with 5V • Measured the PIR sensor OUT pin: • When idle → 0V • When motion detected → jumps to ~3.3V • Sensor warm-up completed (~60 seconds) • Interrupt is firing, because RA2 is toggling • No loose wiring

void initSysPins(void) {
   ANSELD = 0x00;               // set PORTD digital
   TRISDbits.TRISD2 = 1;        // RD2 as input
   TRISAbits.TRISA1 = 0;        // RA1 as output LED
}
void dspTask_TimerMotion(void) {
   if (PORTDbits.RD2 == 1) {
      PORTAbits.RA1 = ~PORTAbits.RA1;
      det = 1;
   } else {
      PORTAbits.RA1 = 0;
   }
}
void dspTask_Danger(void) {
   if (det) {
      lcdCtrl_SetPos(1, 1);
      lcdDspAllData(message3);
      lcdCtrl_SetPos(2, 1);
      lcdDspAllData(message4);
      det = 0;
      __delay_ms(3);
   } else {
      lcdCtrl_SetPos(1, 1);
      lcdDspAllData(message1);
      lcdCtrl_SetPos(2, 1);
      lcdDspAllData(message2);
   }
} 
void lcdCtrl_SetPos(unsigned char row, unsigned char col) {
   // row values are 1 to 2
   // col values are 1 to 16
   unsigned char ramAddr;
   if (row == 1) {
      ramAddr = col - 1;
   } else {
      ramAddr = 0x40 + col - 1;
   }
   lcdWriteCtrlWord(0x80 + ramAddr);
}
void lcdDspAllData(char *msg) { 
   while (*msg) { // Testing the while loop pointer
      lcdWriteDspData(*msg);
      msg++;
   }
}

In my interrupt, I run:

void __interrupt() isr() {
   if (PIR0bits.TMR0IF == 1) {
       PIR0bits.TMR0IF = 0;
       PORTAbits.RA2 = ~PORTAbits.RA2;
       dspTask_TimerDanger();
       TMR0H = 0x48; // 3 second
       TMR0L = 0xE5; // 3 second
   } 
}

In my main loop, I run:

while (1) {
   dspTask_TimerMotion();
}

However, PORTDbits.RD2 always reads zero. My LED never toggles.

What I’ve tried:

✅ Measured the sensor output with a multimeter → confirmed voltage changes from 0V (idle) to ~3.3V (motion)

✅ Added ANSELD = 0x00 to ensure digital input

✅ Configured RD2 as input

✅ Checked that the PIC16F18877 project is correctly selected in MPLAB

✅ Tested other projects reading RD2 → works fine there

✅ Tried both logic checks:

if (PORTDbits.RD2 == 1)

and

if (PORTDbits.RD2 == 0)

✅ Checked no peripheral conflicts using RD2

✅ Waited through sensor warm-up

Still, my code reads zero on RD2. It’s as if the pin never sees the HIGH pulse from the PIR sensor.

Questions: • Is the issue regarding the structure of code? • Why is the interrupt firing but motion sensor always read LOW (0)? • Is the ~3.3V output from the PIR sensor too low for the PIC16F18877 digital input to reliably detect HIGH when running at 5V? • Is there a better way to reliably detect motion with this sensor and the PIC16F18877?

Any advice on reliably reading the HC-SR501 output on this PIC would be much appreciated!

like image 376
boy Avatar asked Jan 19 '26 03:01

boy


1 Answers

Is the ~3.3V output from the PIR sensor too low for the PIC16F18877 digital input to reliably detect HIGH when running at 5V?

Looking at this datasheet, I see the digital inputs can be set to use TTL (transistor-transistor logic) or ST (Schmitt Trigger) levels. On page 635, Figures 38-81, 38-82, and 38-83 show the threshold voltages for those modes at various operating voltages.

In TTL mode, it looks like it should work as you'd expect.

In ST mode, operating at 5.0 V, a true 3.3 V should be sufficient to read high, but it's very close. If you're actually operating a little above 5.0 V and/or your input is slightly below 3.3 V, it could be unreliable. And if the chip is running hot (> 40 °C), it could be even less reliable.

The INLVLD register (page 223) controls which input levels are used for digital reads on the port D pins. I would first check to see which mode you're in. If you decide to change it, it appears you should do so right at the beginning of the program.

If you suspect the out voltage is too low, and you can't get it to work reliably by setting the input level mode on the i/o pin, you could consider an external level shifter to boost the sensor signal to 5 V.

like image 139
Adrian McCarthy Avatar answered Jan 20 '26 19:01

Adrian McCarthy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!