TL;DR
A PIR sensor is triggered by itself when using a timer to wait 2 seconds after the sensor is triggered. Without using the timer to wait the sensor works as expected.
Background and setup
I have a PIR sensor connected to an
ATMega328p.
The PIR sensor has three pins; VCC
, GND
and AL
. The AL
pin uses open collector to show that motion is
detected.
What I have done is that I connected the AL pin to PC0 pin on my ATMega and set up the pin as input with internal pull up resistor and a LED connected to PC5 to show when motion is detected:
void setup_default_values()
{
DDRC |= (1 << PC5);
DDRC &= ~(1 << PC0);
PORTC |= (1 << PC0);
}
Then I have a function that checks when the PC0
pin is LOW
:
void check_sensor()
{
if (PINC & (1 << PC0)) {
PORTC &= ~(1 << PC5);
}else{
PORTC |= (1 << PC5);
}
}
This function lights up the LED when PC0
is LOW
and turns it off when PC0
is HIGH
.
This function is run every cycle of my main loop:
int main()
{
setup_default_values();
blink(4);
for (;;) {
check_sensor();
}
return 0;
}
Problem encountered
Everything works as expected, the LED lights up when I wave my hand infront of the sensor and it does not trigger
without motion. The sensor sets the AL
pin LOW
for about 100 - 200 ms.
The thing is that I don't want to use the signal for 2 seconds after motion has been detected. So I implemented a timer and flag logic that ignores the signal during these 2 seconds. The problem is that now the LED lights up by itself after the timer has stop counting and start accepting motion signals
Problematic setup
To use this timer and flag logic I added 2 LEDs, one that shows that the timer is active and one that shows when a signal is registered:
volatile bool motion_detected;
void setup_default_values()
{
DDRC |= (1 << PC5);
DDRC |= (1 << PC4);
DDRC |= (1 << PC3);
DDRC &= ~(1 << PC0);
PORTC |= (1 << PC0);
TCCR1B |= (1 << CS12); // Timer 1B set up to use a prescaler of 256
TCNT1 = 0; // Timer value set to 0
motion_detected = false;
}
Then I new logic to the check_sensor
function:
void check_sensor()
{
if (PINC & (1 << PC0)) {
PORTC &= ~(1 << PC5);
}else{
PORTC |= (1 << PC5);
if (!motion_detected) {
PORTC |= (1 << PC3);
_delay_ms(50);
PORTC &= ~(1 << PC3);
PORTC |= (1 << PC4);
TCNT1 = 0;
motion_detected = true;
}
}
}
When motion is detected the first time, this is what happens:
- LED indicating signal from PIR is lit up
- LED indicating signal acceptance it blinked once
- LED indicating timer is active is lit up
- Timer is reset and flag indicating motion was detected
Then there is a new function which handles the countdown:
#define F_CPU 1000000UL
/*
* Timer increments per second
*
* This value represents how many increments the timer will do to the TCNT1 register
* per second.
*
* To produce this value you divide the clock frequency in hz with the prescaler amount.
* For example:
* 1000000 / 256 = 3906
*/
#define TMR_INC_PER_SEC 3906
void check_timer()
{
if (!motion_detected) return;
if (TCNT1 >= TMR_INC_PER_SEC * 3) {
PORTC &= ~(1 << PC4);
motion_detected = false;
}
}
int main()
{
setup_default_values();
blink(4);
for (;;) {
check_timer();
check_sensor();
}
return 0;
}
This function should be ignored unless there is a motion detected. When countdown has been completed timer indicating LED is turned off and motion flag is reset which indicates that a new signal can be accepted.
Things I have tried
Software debounce
I have tried adding software debounce
functionality where motion is only accepted if PC0
is LOW
for
a defined amount of cycles. This did not change the faulty behavior.
Push button instead of PIR
I have tried removing the PIR and add a push button which is LOW
on push down. When using the push button
the circuit and logic works as expected.
Schematics
Here is the schematics for the power supply. The circuit is connected to a Stabilized DC power supply where the +5V rail is actually around +6.5V (I don't know how to edit the text of a component in gschem). VCC
is what I connect to my microcontroller and PIR-sensor, as you will see in the second schematic.
Here is the schematics for the microcontroller, the LEDs and the PIR-sensor. Some pins are not shown in the schematics: RESET
pin is connected to my programmer, same with MOSI
, MISO
and SCK
.