correct wind calc & use dht22
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
DUMMY_VAR = 2
|
||||
DUMMY_VAR = 1
|
||||
PROJECT_NAME := meteo
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
set(COMPONENT_ADD_INCLUDEDIRS .)
|
||||
|
||||
set(COMPONENT_SRCS "circbuf.c")
|
||||
|
||||
register_component()
|
||||
@@ -0,0 +1,260 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "circbuf.h"
|
||||
|
||||
// --- Circbuf data structure ----
|
||||
|
||||
/** Offset in void* buffer */
|
||||
#define PV_OFFS(pvBuf, elem_size, index) ((uint8_t*)(pvBuf) + ((elem_size)*(index)))
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write data to a CircBuf slot
|
||||
* @param cb : circbuf
|
||||
* @param index : slot index
|
||||
* @param source : data source
|
||||
*/
|
||||
static inline void write_buffer(CircBuf *cb, circbuf_size_t index, const void *source)
|
||||
{
|
||||
memcpy(PV_OFFS(cb->buf, cb->elem_size, index), source, cb->elem_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copy data from a CircBuf slot to a buffer
|
||||
* @param cb : circbuf
|
||||
* @param index : slot index
|
||||
* @param dest : destination buffer
|
||||
*/
|
||||
static inline void read_buffer(const CircBuf *cb, circbuf_size_t index, void *dest)
|
||||
{
|
||||
memcpy(dest, PV_OFFS(cb->buf, cb->elem_size, index), cb->elem_size);
|
||||
}
|
||||
|
||||
/** Get index of the front position (for write) */
|
||||
static inline circbuf_size_t front_writepos(const CircBuf *cb) {
|
||||
return (cb->back + cb->num_used) % cb->cap;
|
||||
}
|
||||
|
||||
|
||||
void cbuf_init(CircBuf *cb, void *buf, circbuf_size_t capacity, circbuf_size_t elem_size)
|
||||
{
|
||||
// allocate the buffer
|
||||
cb->buf = buf;
|
||||
|
||||
// set capacity, clear state
|
||||
cb->elem_size = elem_size;
|
||||
cb->cap = capacity;
|
||||
|
||||
cbuf_clear(cb);
|
||||
}
|
||||
|
||||
|
||||
/** Check if cbuf is full */
|
||||
bool cbuf_full(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return cb->num_used == cb->cap;
|
||||
}
|
||||
|
||||
|
||||
/** Check if cbuf is empty */
|
||||
bool cbuf_empty(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return cb->num_used == 0;
|
||||
}
|
||||
|
||||
|
||||
/** Get the max capacity of the buffer */
|
||||
circbuf_size_t cbuf_capacity(const CircBuf *cb)
|
||||
{
|
||||
return cb->cap;
|
||||
}
|
||||
|
||||
|
||||
/** Get the current number of items in the buffer */
|
||||
circbuf_size_t cbuf_count(const CircBuf *cb)
|
||||
{
|
||||
return cb->num_used;
|
||||
}
|
||||
|
||||
|
||||
/** Push one element to the front_writepos */
|
||||
bool cbuf_push(CircBuf *cb, const void *source)
|
||||
{
|
||||
if (cb == NULL || source == NULL || cb->num_used == cb->cap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
write_buffer(cb, front_writepos(cb), source);
|
||||
|
||||
// increment
|
||||
cb->num_used++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Pop one element from the front_writepos */
|
||||
bool cbuf_pop(CircBuf *cb, void *dest)
|
||||
{
|
||||
if (cb == NULL || cb->num_used == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cb->num_used--;
|
||||
|
||||
circbuf_size_t f = front_writepos(cb);
|
||||
|
||||
if (dest != NULL) {
|
||||
read_buffer(cb, f, dest);
|
||||
}
|
||||
|
||||
#ifdef CIRCBUF_ZERO_FREE_SLOTS
|
||||
memset(PV_OFFS(cb->buf, cb->elem_size, f), 0, cb->elem_size);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Peek at the front_writepos element */
|
||||
bool cbuf_peek(const CircBuf *cb, void *dest)
|
||||
{
|
||||
if (cb == NULL || dest == NULL || cb->num_used == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
circbuf_size_t f = (cb->back + cb->num_used - 1) % cb->cap;
|
||||
read_buffer(cb, f, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void * cbuf_ptr(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL || cb->num_used == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
circbuf_size_t f = (cb->back + cb->num_used - 1) % cb->cap;
|
||||
return PV_OFFS(cb->buf, cb->elem_size, f);
|
||||
}
|
||||
|
||||
|
||||
/** Peek at the nth element (counted from back) */
|
||||
bool cbuf_nth(const CircBuf *cb, circbuf_size_t num, void *dest)
|
||||
{
|
||||
if (cb == NULL || dest == NULL || num > cb->num_used) {
|
||||
return false;
|
||||
}
|
||||
|
||||
circbuf_size_t index = (cb->back + num) % cb->cap;
|
||||
read_buffer(cb, index, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void *cbuf_ptr_nth(const CircBuf *cb, circbuf_size_t num)
|
||||
{
|
||||
if (cb == NULL || num > cb->num_used) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
circbuf_size_t index = (cb->back + num) % cb->cap;
|
||||
return PV_OFFS(cb->buf, cb->elem_size, index);
|
||||
}
|
||||
|
||||
|
||||
/** Push one element to the back */
|
||||
bool cbuf_push_back(CircBuf *cb, const void *source)
|
||||
{
|
||||
if (cb == NULL || source == NULL || cb->num_used == cb->cap) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// move lr back
|
||||
if (cb->back == 0) {
|
||||
cb->back = cb->cap - 1; // wrap to the end
|
||||
} else {
|
||||
cb->back--;
|
||||
}
|
||||
cb->num_used++;
|
||||
|
||||
write_buffer(cb, cb->back, source);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Pop one element from the back */
|
||||
bool cbuf_pop_back(CircBuf *cb, void *dest)
|
||||
{
|
||||
if (cb == NULL || cb->num_used == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dest != NULL) {
|
||||
read_buffer(cb, cb->back, dest);
|
||||
}
|
||||
|
||||
#ifdef CIRCBUF_ZERO_FREE_SLOTS
|
||||
memset(PV_OFFS(cb->buf, cb->elem_size, cb->back), 0, cb->elem_size);
|
||||
#endif
|
||||
|
||||
// increment
|
||||
cb->back++;
|
||||
if (cb->back == cb->cap) {
|
||||
cb->back = 0;
|
||||
}
|
||||
cb->num_used--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Pop one element from the back */
|
||||
bool cbuf_peek_back(const CircBuf *cb, void *dest)
|
||||
{
|
||||
if (cb == NULL || dest == NULL || cb->num_used == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
read_buffer(cb, cb->back, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void* cbuf_ptr_back(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL || cb->num_used == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return PV_OFFS(cb->buf, cb->elem_size, cb->back);
|
||||
}
|
||||
|
||||
|
||||
/** Clear a cbuf */
|
||||
void cbuf_clear(CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cb->num_used = 0;
|
||||
cb->back = 0;
|
||||
|
||||
#ifdef CIRCBUF_ZERO_FREE_SLOTS
|
||||
memset(PV_OFFS(cb->buf, cb->elem_size, 0), 0, cb->cap * cb->elem_size);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* @file circbuf.h
|
||||
* @author Ondřej Hruška, 2016,2023
|
||||
*
|
||||
* Circular buffer / queue / stack.
|
||||
* Slots are pre-allocated, values are copied into the buffer.
|
||||
*
|
||||
* The buffer may be used as a stack, event queue or a simple buffer.
|
||||
*
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
#ifndef CIRCBUF_H
|
||||
#define CIRCBUF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Enable to zero a freed slots after pop, useful for debugging
|
||||
#define CIRCBUF_ZERO_FREE_SLOTS
|
||||
|
||||
// size_t can be replaced by a more suitable type for circbuf, e.g. uint8_t for tiny buffers
|
||||
typedef uint32_t circbuf_size_t;
|
||||
|
||||
/** Instance structure - public to allow static allocation, but consider the structure internal matter */
|
||||
struct circbuf_struct {
|
||||
void *buf;
|
||||
circbuf_size_t num_used;
|
||||
circbuf_size_t elem_size;
|
||||
circbuf_size_t cap;
|
||||
circbuf_size_t back;
|
||||
// circbuf_size_t front;
|
||||
};
|
||||
|
||||
typedef struct circbuf_struct CircBuf;
|
||||
|
||||
/**
|
||||
* @brief Initialize a circular buffer
|
||||
*
|
||||
* @param[in,out] cb - pointer to the buffer to init, can be statically or dynamically allocated
|
||||
* @param buf : backing buffer, can be statically or dynamically allocated
|
||||
* @param capacity : buffer capacity
|
||||
* @param elem_size : size of one element
|
||||
*/
|
||||
void cbuf_init(CircBuf *cb, void *buf, circbuf_size_t capacity, circbuf_size_t elem_size);
|
||||
|
||||
|
||||
/** Test for full buffer */
|
||||
bool cbuf_full(const CircBuf *cb);
|
||||
|
||||
|
||||
/** Test for empty buffer */
|
||||
bool cbuf_empty(const CircBuf *cb);
|
||||
|
||||
|
||||
/** Get the max capacity of the buffer */
|
||||
circbuf_size_t cbuf_capacity(const CircBuf *cb);
|
||||
|
||||
|
||||
/** Get the current number of items in the buffer */
|
||||
circbuf_size_t cbuf_count(const CircBuf *cb);
|
||||
|
||||
|
||||
/** Peek at the nth element (counted from back) */
|
||||
bool cbuf_nth(const CircBuf *cb, circbuf_size_t num, void *dest);
|
||||
|
||||
|
||||
/** Get a mutable reference to nth element (counted from back) */
|
||||
void *cbuf_ptr_nth(const CircBuf *cb, circbuf_size_t num);
|
||||
|
||||
|
||||
/** @brief Remove all data from buffer */
|
||||
void cbuf_clear(CircBuf *cb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Append a value to the buffer (FIFO)
|
||||
* @param cb : buffer
|
||||
* @param source : pointer to a value (will be copied)
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_push(CircBuf *cb, const void *source);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a value from the buffer, return susccess.
|
||||
*
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination. If NULL, value is discarded.
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_pop(CircBuf *cb, void *dest);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copy the frontmost element without changing the buffer
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_peek(const CircBuf *cb, void *dest);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a mutable reference to the front element
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination
|
||||
* @return reference or NULL
|
||||
*/
|
||||
void * cbuf_ptr(const CircBuf *cb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Push a value into the circbuf (LIFO).
|
||||
*
|
||||
* @param cb : buffer
|
||||
* @param source : pointer to a value (will be copied)
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_push_back(CircBuf *cb, const void *source);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a value from the buffer, return susccess.
|
||||
*
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination. If NULL, value is discarded.
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_pop_back(CircBuf *cb, void *dest);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copy the backmost element without changing the buffer
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_peek_back(const CircBuf *cb, void *dest);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a mutable reference to the backmost element
|
||||
* @param cb : buffer
|
||||
* @param dest : read destination
|
||||
* @return reference or NULL
|
||||
*/
|
||||
void* cbuf_ptr_back(const CircBuf *cb);
|
||||
|
||||
#endif // CIRCBUF_H
|
||||
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
|
||||
# this will take the sources in the src/ directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
||||
+66
-62
@@ -11,77 +11,80 @@
|
||||
#include "ds18b20.h"
|
||||
#include "dht.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "circbuf.h"
|
||||
|
||||
static volatile uint32_t timestamp_ms = 0;
|
||||
static volatile uint32_t last_revolution_ts = 0;
|
||||
static volatile uint32_t timestamp = 0;
|
||||
|
||||
#define RPM_BUFFER_LEN 10
|
||||
static volatile uint16_t rpm_buffer[RPM_BUFFER_LEN] = {};
|
||||
static volatile int rpm_buffer_next = 0;
|
||||
static volatile int num_valid_average = 0;
|
||||
#define RPS_BUFFER_LEN (60*10)
|
||||
static volatile uint16_t history[RPS_BUFFER_LEN] = {};
|
||||
static CircBuf rps_cb;
|
||||
|
||||
static volatile float rpm_average = 0;
|
||||
static volatile float rpm_gust = 0;
|
||||
|
||||
static volatile uint16_t cycle_count = 0;
|
||||
|
||||
void calculate_wind();
|
||||
|
||||
static void gpio_isr_handler(void *arg)
|
||||
{
|
||||
uint32_t ts = timestamp_ms;
|
||||
uint32_t cycle_ms = ts - last_revolution_ts;
|
||||
last_revolution_ts = ts;
|
||||
|
||||
if (cycle_ms > 0xFFFF) {
|
||||
cycle_ms = 0xFFFF;
|
||||
}
|
||||
rpm_buffer[rpm_buffer_next++] = (uint16_t) cycle_ms;
|
||||
if (rpm_buffer_next == RPM_BUFFER_LEN) {
|
||||
rpm_buffer_next = 0;
|
||||
}
|
||||
if (num_valid_average < RPM_BUFFER_LEN) {
|
||||
num_valid_average++;
|
||||
if (cycle_count < 0xFFFF) {
|
||||
cycle_count++;
|
||||
}
|
||||
}
|
||||
|
||||
float get_rpm() {
|
||||
float res;
|
||||
float current = (float)(timestamp_ms - last_revolution_ts);
|
||||
|
||||
if (num_valid_average > 0) {
|
||||
// we write num_valid_average only from here, so its safe to assume it stays nonzero
|
||||
float average = 0;
|
||||
int pos = rpm_buffer_next;
|
||||
for (int i = 0; i < num_valid_average; i++) {
|
||||
average += (float) rpm_buffer[pos];
|
||||
pos--;
|
||||
if (pos < 0) {
|
||||
pos = RPM_BUFFER_LEN - 1;
|
||||
}
|
||||
}
|
||||
average /= (float) (num_valid_average);
|
||||
|
||||
// now we have ms per revolution
|
||||
|
||||
if (current > average * 10.0f) {
|
||||
// if wind stopped, invalidate the averaging buffer and use the current time from the last hall event
|
||||
res = current;
|
||||
num_valid_average = 0; // invalidate average results
|
||||
} else {
|
||||
res = average;
|
||||
}
|
||||
} else {
|
||||
res = current;
|
||||
}
|
||||
|
||||
float rpm = 60000.0f / res;
|
||||
if (rpm < 1) {
|
||||
rpm = 0;
|
||||
}
|
||||
return rpm; // RPM
|
||||
}
|
||||
|
||||
void hw_timer_callback1(void *arg)
|
||||
void hw_timer_callback1s(void *arg)
|
||||
{
|
||||
timestamp_ms++;
|
||||
timestamp++;
|
||||
|
||||
// FIXME use a freertos queue and pass this to a thread!
|
||||
if (cbuf_full(&rps_cb)) {
|
||||
cbuf_pop_back(&rps_cb, NULL);
|
||||
}
|
||||
cbuf_push(&rps_cb, (void*) &cycle_count);
|
||||
cycle_count = 0;
|
||||
|
||||
calculate_wind();
|
||||
}
|
||||
|
||||
void calculate_wind()
|
||||
{
|
||||
// Wind speed is average from 10 minutes
|
||||
// Gust is max 3-second average anywhere within the 10 minutes
|
||||
|
||||
float max_gust = 0;
|
||||
|
||||
uint32_t tenmin_sum = 0;
|
||||
uint32_t numsecs = cbuf_count(&rps_cb);
|
||||
uint16_t threesec1 = 0, threesec2 = 0;
|
||||
for(size_t i = 0; i < numsecs; i++) {
|
||||
uint16_t *slot = cbuf_ptr_nth(&rps_cb, i);
|
||||
if (!slot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t slotval = *slot;
|
||||
tenmin_sum += (uint32_t) slotval;
|
||||
|
||||
// gust is max avg from 3 seconds within the 10 minutes
|
||||
uint32_t gust_sum = (uint32_t) threesec1 + (uint32_t) threesec2 + (uint32_t) slotval;
|
||||
threesec1 = threesec2;
|
||||
threesec2 = slotval;
|
||||
|
||||
float gust_avg = (float)gust_sum * (float)20.0f;
|
||||
if (gust_avg > max_gust) {
|
||||
max_gust = gust_avg;
|
||||
}
|
||||
}
|
||||
rpm_gust = max_gust;
|
||||
rpm_average = ((float)tenmin_sum / (float)numsecs) * 60.0f;
|
||||
}
|
||||
|
||||
|
||||
void meteo_task(void* pvParameters)
|
||||
{
|
||||
cbuf_init(&rps_cb, (void*)history, RPS_BUFFER_LEN, 2); // uint16 fields
|
||||
|
||||
// Try to unfuck GPIOs
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);
|
||||
@@ -89,8 +92,8 @@ void meteo_task(void* pvParameters)
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, FUNC_GPIO15);
|
||||
|
||||
// start timer used for timebase
|
||||
hw_timer_init(hw_timer_callback1, NULL);
|
||||
hw_timer_alarm_us(1000, true); // 1 ms timer
|
||||
hw_timer_init(hw_timer_callback1s, NULL);
|
||||
hw_timer_alarm_us(1000000, true); // 1s timer
|
||||
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_POSEDGE;
|
||||
@@ -107,11 +110,12 @@ void meteo_task(void* pvParameters)
|
||||
// this works ...
|
||||
ds_temp = ds18b20_measure_and_read(0, DS18B20_ANY);
|
||||
|
||||
if (!dht_read_float_data(DHT_TYPE_DHT11, 12, &dht_hum, &dht_temp)) {
|
||||
if (!dht_read_float_data(DHT_TYPE_DHT22, 12, &dht_hum, &dht_temp)) {
|
||||
dht_hum = dht_temp = NAN;
|
||||
}
|
||||
|
||||
printf("Dallas: %.2f °C, DHT %.2f °C, %.1f %%r.H, HALL %.1f RPM\n", ds_temp, dht_temp, dht_hum, get_rpm());
|
||||
printf("Dallas: %.2f °C, DHT %.2f °C, %.1f %%r.H, HALL avg %.1f RPM, gust %.1f RPM\n",
|
||||
ds_temp, dht_temp, dht_hum, rpm_average, rpm_gust);
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(500));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user