Hi,
Does anyone have a code example of the am312 PIR sensor? I've found them to be very reliable in MicroPython, but I can't get them to work in an ESP-IDF/FreeRTOS app written in C. Keep getting random motion detection for no reason (even when the sensor is completely covered).
Since this PIR sensor is so popular, I'm hoping someone would have a working example out there.
For the curious, here is my (randomly triggering) code. Any suggestions would be welcome.
Thanks,
-T
AM312 PIR Sensor?
-
- Posts: 1724
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: AM312 PIR Sensor?
Apart from the overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic, and the use of ESP_LOGx inside an ISR which should be avoided, the code looks all right to me.
Could you be having an issue with wiring/an unreliable connection (breadboard?) between the sensor and the ESP?
Could you be having an issue with wiring/an unreliable connection (breadboard?) between the sensor and the ESP?
Re: AM312 PIR Sensor?
Thanks for the response. Its much appreciated. I'll make the change you suggested, but not sure what was meant by "overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic". Could you expand on that?MicroController wrote: ↑Fri Jul 19, 2024 1:26 pmApart from the overflow of FreeRTOS's tick count after a long time running which isn't really handled in the debounce logic, and the use of ESP_LOGx inside an ISR which should be avoided, the code looks all right to me.
Could you be having an issue with wiring/an unreliable connection (breadboard?) between the sensor and the ESP?
As for the breadboard + connections, I've tried this same code on 2 completely different setups (breadboard, wires, sensor, microprocessor, everything). Still get the same behavior.
This is so puzzling. The am312 obviously works in C because MicroPython works (which is written in C). So, wtf?
Thanks again,
-T
-
- Posts: 1724
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: AM312 PIR Sensor?
It's likely only a theoretical problem, but FreeRTOS's 32-bit tick counter will overflow at some point after the system has been running without a restart for a long time (months, or a year, depending on tick rate).
To correctly handle that situation it is advisable to do
Code: Select all
if( (now - previous) > SOME_TIME ) { ... }
Code: Select all
if ( now > (previous + SOME_TIME) ) {...}
-
- Posts: 1724
- Joined: Mon Oct 17, 2022 7:38 pm
- Location: Europe, Germany
Re: AM312 PIR Sensor?
Great point! I'll try that.MicroController wrote: ↑Fri Jul 19, 2024 7:43 pmYou could try disabling the ESP's pull-up resistor. Datasheets seem to imply that the sensor doesn't need it.
Thanks!
Re: AM312 PIR Sensor?
MicroController wrote: ↑Fri Jul 19, 2024 7:43 pmYou could try disabling the ESP's pull-up resistor. Datasheets seem to imply that the sensor doesn't need it.
Tried the disable. The behavior is better, but not yet fixed. There are still random "motion detected" events, but fewer.
Here's the code:
Code: Select all
#include "motion_sensor.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/semphr.h" // Include semaphore header
#include "freertos/task.h"
#define DEBOUNCE_PERIOD_MS 1000
static const char* TAG = "MOTION_SENSOR";
extern QueueHandle_t motion_event_queue; // Declare the queue handle
static volatile uint32_t last_motion_time = 0;
static volatile uint32_t debounce_end_time = 0;
static volatile bool log_event_queue_full = false;
static volatile bool log_debounce_event = false;
static volatile bool log_motion_detected = false;
static void IRAM_ATTR motion_sensor_isr_handler(void* arg) {
uint32_t motion_detected = 1;
uint32_t current_time = xTaskGetTickCountFromISR();
// Software debounce logic
if (current_time > debounce_end_time) {
debounce_end_time = current_time + pdMS_TO_TICKS(DEBOUNCE_PERIOD_MS);
last_motion_time = current_time;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xQueueSendFromISR(motion_event_queue, &motion_detected, &xHigherPriorityTaskWoken) !=
pdPASS) {
log_event_queue_full = true;
} else {
log_motion_detected = true;
}
} else {
log_debounce_event = true;
}
}
void motion_logging_task(void* pvParameters) {
while (1) {
if (log_motion_detected) {
ESP_LOGW(TAG, "Motion detected!");
log_motion_detected = false;
}
if (log_event_queue_full) {
ESP_LOGW(TAG, "Motion event queue full, event lost.");
log_event_queue_full = false;
}
if (log_debounce_event) {
ESP_LOGI(TAG, "Motion event debounced.");
log_debounce_event = false;
}
vTaskDelay(pdMS_TO_TICKS(100)); // Adjust the delay as needed
}
}
void motion_sensor_init(void) {
gpio_config_t io_conf = {.intr_type = GPIO_INTR_POSEDGE, // Trigger on rising edge
.mode = GPIO_MODE_INPUT, // Set as input mode
.pin_bit_mask = (1ULL << MOTION_SENSOR_PIN),
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE};
gpio_config(&io_conf);
// Install ISR service with default configuration
gpio_install_isr_service(0);
// Attach the interrupt service routine
gpio_isr_handler_add(MOTION_SENSOR_PIN, motion_sensor_isr_handler, NULL);
ESP_LOGI(TAG, "PIR sensor initialized.");
// Create the logging task
xTaskCreate(motion_logging_task, "motion_logging_task", 2048, NULL, 10, NULL);
}
Who is online
Users browsing this forum: Google [Bot] and 145 guests