Hi,
I already tried a few libraries that I found on the internet about asyn functions.
I know that the esp32 has 3 cores, but only 2 can be used. The setup() and the loop() functions uses the core #1 and in should be the core #0 free to use.
The problem is that i'm not able start a function (that has a for(;;)) in parallel.
I don't share my code because it would be useless.
My goal is that in the main loop something is going in loop, and in a parallel function, something else is happening in loop.
Sorry for my english.
Thanks.
Has it ?
Please post what you tried and describe what happens when you run it and exactly what you are trying to do
I think, because a pakistan youtuber said this.
I have tried this library: GitHub - MatheusAlvesA/ArduinoAsync: A simple Arduino library that allows asynchronous function execution
But it gives me errors even following the tutorial in the github page.
I tried this video tutorial (of the pakistan): https://www.youtube.com/watch?v=uropxCRJ7pA&t=113s&ab_channel=ElectronicJunkies
But when i try this every function will be signed as not declared. So i declare them above the setup(), but other libraries will not work. For example the GFX and SSD1306 will not work saying that thid object:
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
is not declared anywhere. Even if it is declared.
I'm trying to have 2 loop working parallel.
Check FreeRTOS if you would like to use multicore on the ESP32...
Wait that means that the esp32 will not be able to connect to wifi? Because my esp32 is connected to wifi, and what I understand is that the wifi "runs" on core #0
I will check
You can run multi-task code on a single core (usually Core 1) with FreeRTOS. You can also run tasks on Core 0, if you do it correctly.
The most useful reason to run the WiFi on core 0 is to avoid messing it up because of problems with user code. As others have said, its best to use core 1 for user code and FreeRTOS.
Each core runs very fast, and FreeRTOS running on core 1 still allows the user to give different priorities to different tasks if needed.
And something to remember is that ESP32-S2 has only one core (in their logic, 2 = 1
)
The ESP32 has 2 processors with one processor having 2 cores.
if using freeRTOS loop() should NOT have any code to run.
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <driver/adc.h>
#include "sdkconfig.h" // used for log printing
////
const int evtTakeA_Reading = ( 1 << 10 ); // 10 event handle
//
EventGroupHandle_t eg; // create event group
////
QueueHandle_t xQ_Display;
////
int dispValueCellCount = 128;
////
void setup()
{
pinMode( 2, OUTPUT );
//
xQ_Display = xQueueCreate( dispValueCellCount, sizeof(int) ); // sends a queue copy
//
// set up A:D channels
adc1_config_width(ADC_WIDTH_12Bit); // set 12 bit
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11); // use 3.3V as reference
eg = xEventGroupCreate(); // assign event groups a handle
// create a task, assign task a function name, a name, some stack space, no parameters, priority of 3, do not return a task handle, assign to core 0
xTaskCreatePinnedToCore( fBlinkBuiltIn, "fBlinkBuiltIn", 5000, NULL, 3, NULL, 0 );
xTaskCreatePinnedToCore( TaskAnalogRead_MyoWare, "TaskAnalogRead_MyoWare", 10, NULL, 3, NULL, 1 ); // assigned to core 1
}
void fBlinkBuiltIn( void* pvParameters )
{
// toggle built in LED off/on
for (;;)
{
vTaskDelay( 10 ); //delay for 10 mS
xEventGroupSetBits( eg, evtTakeA_Reading ); // trigger task event
REG_WRITE( GPIO_OUT_W1TC_REG, BIT2 ); // set GPIO2 LOW (clear)
vTaskDelay( 1000 ); //delay for 1000mS.
REG_WRITE( GPIO_OUT_W1TS_REG, BIT2 ); //set GPIO2 HIGH (set)
}
vTaskDelete( NULL ); // incase task jumpe loop destroy task
}
//
void TaskAnalogRead_MyoWare( void *pvParameters )
{
float vMyoWare0 = 0.0f;
int temp;
float ADscale = 3.3f / 4096;
// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
int j = 0;
for (;;)
{
xEventGroupWaitBits (eg, evtTakeA_Reading, pdTRUE, pdTRUE, portMAX_DELAY) ; // wait till task is triggered by an event
if ( j <= dispValueCellCount )
{
for ( j = 1; j <= dispValueCellCount; j++)
{
vMyoWare0 = ( adc1_get_raw(ADC1_CHANNEL_0) * ADscale ); // read AD
vMyoWare0 *= 10.0f;
temp = (int)vMyoWare0;
//xQueueSendToBack( xQ_Display, &temp, 0 );
vTaskDelay(1);
}
j++;
log_i( "j number is %d", j );
} else {
vTaskDelay( 1 );
vMyoWare0 = ( adc1_get_raw(ADC1_CHANNEL_0) * ADscale );
vMyoWare0 *= 10.0f;
temp = (int)vMyoWare0;
xQueueSendToBack( xQ_Display, &temp, 1 );
}
//xEventGroupSetBits( eg, evtUPDATE_DISPLAY ); << not used in this exercise
}
vTaskDelete( NULL );
} //void TaskAnalogVoltRead_MyoWare( void *pvParameters )
//
void loop() {}
An example of a freeRTOS program using both cores.
/*
Chappie Weather upgrade/addition
process wind speed direction and rain fall.
*/
#include "esp32/ulp.h"
//#include "ulptool.h"
#include "driver/rtc_io.h"
#include <WiFi.h>
#include <PubSubClient.h>
#include "certs.h"
#include "sdkconfig.h"
#include "esp_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <driver/pcnt.h>
#include <driver/adc.h>
#include <SimpleKalmanFilter.h>
#include <ESP32Time.h>
////
ESP32Time rtc;
WiFiClient wifiClient;
PubSubClient MQTTclient(mqtt_server, mqtt_port, wifiClient);
////
float CalculatedVoltage = 0.0f;
float kph = 0.0f;
float rain = 0.0f;
/*
PCNT PCNT_UNIT_0, PCNT_CHANNEL_0 GPIO_NUM_15 = pulse input pin
PCNT PCNT_UNIT_1, PCNT_CHANNEL_0 GPIO_NUM_4 = pulse input pin
*/
pcnt_unit_t pcnt_unit00 = PCNT_UNIT_0; //pcnt unit 0 channel 0
pcnt_unit_t pcnt_unit10 = PCNT_UNIT_1; //pcnt unit 1 channel 0
//
//
hw_timer_t * timer = NULL;
//
#define evtAnemometer ( 1 << 0 )
#define evtRainFall ( 1 << 1 )
#define evtParseMQTT ( 1 << 2 )
EventGroupHandle_t eg;
#define OneMinuteGroup ( evtAnemometer | evtRainFall )
////
QueueHandle_t xQ_Message; // payload and topic queue of MQTT payload and topic
const int payloadSize = 100;
struct stu_message
{
char payload [payloadSize] = {'\0'};
String topic ;
} x_message;
////
SemaphoreHandle_t sema_MQTT_KeepAlive; // used to stop all other MQTT thing do's
SemaphoreHandle_t sema_mqttOK; // protect the mqttOK variable.
SemaphoreHandle_t sema_CalculatedVoltage; // protects the CalculatedVoltage variable.
////
int mqttOK = 0; // stores a count value that is used to cause an esp reset
volatile bool TimeSet = false;
////
/*
Topic topicOK has been subscribed to, the mqtt broker sends out "OK" messages if the client receives an OK message the mqttOK value is set back to zero.
If the mqttOK count reaches a set point the ESP32 will reset.
*/
////
void IRAM_ATTR mqttCallback(char* topic, byte * payload, unsigned int length)
{
memset( x_message.payload, '\0', payloadSize ); // clear payload char buffer
x_message.topic = ""; //clear topic string buffer
x_message.topic = topic; //store new topic
int i = 0; // extract payload
for ( i; i < length; i++)
{
x_message.payload[i] = (char)payload[i];
}
x_message.payload[i] = '\0';
xQueueOverwrite( xQ_Message, (void *) &x_message );// send data to queue
} // void mqttCallback(char* topic, byte* payload, unsigned int length)
////
// interrupt service routine for WiFi events put into IRAM
void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_STA_CONNECTED:
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
log_i("Disconnected from WiFi access point");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
log_i("WiFi client disconnected");
break;
default: break;
}
} // void IRAM_ATTR WiFiEvent(WiFiEvent_t event)
////
void IRAM_ATTR onTimer()
{
BaseType_t xHigherPriorityTaskWoken;
xEventGroupSetBitsFromISR(eg, OneMinuteGroup, &xHigherPriorityTaskWoken);
} // void IRAM_ATTR onTimer()
////
void setup()
{
eg = xEventGroupCreate(); // get an event group handle
x_message.topic.reserve(100);
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);// using GPIO 34 wind direction
adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);// using GPIO 39 current
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);// using GPIO 36 battery volts
// hardware timer 4 set for one minute alarm
timer = timerBegin( 3, 80, true );
timerAttachInterrupt( timer, &onTimer, true );
timerAlarmWrite(timer, 60000000, true);
timerAlarmEnable(timer);
/* Initialize PCNT's counter */
int PCNT_H_LIM_VAL = 3000;
int PCNT_L_LIM_VAL = -10;
// 1st PCNT counter
// Anemometer
pcnt_config_t pcnt_config = {};
pcnt_config.pulse_gpio_num = GPIO_NUM_15;// Set PCNT input signal and control GPIOs
pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.unit = PCNT_UNIT_0;
// What to do on the positive / negative edge of pulse input?
pcnt_config.pos_mode = PCNT_COUNT_INC; // Count up on the positive edge
pcnt_config.neg_mode = PCNT_COUNT_DIS; // Count down disable
// What to do when control input is low or high?
pcnt_config.lctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if low
pcnt_config.hctrl_mode = PCNT_MODE_KEEP; // Keep the primary counter mode if high
// Set the maximum and minimum limit values to watch
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config); // Initialize PCNT unit
// 12.5ns is one APB_CLK cycle 12.5*500, debounce time
pcnt_set_filter_value( PCNT_UNIT_0, 500); //Configure and enable the input filter, debounce
pcnt_filter_enable( PCNT_UNIT_0 );
pcnt_counter_pause( PCNT_UNIT_0 );
pcnt_counter_clear( PCNT_UNIT_0 );
pcnt_counter_resume( PCNT_UNIT_0); // start the show
// setup 2nd PCNT
pcnt_config = {};
pcnt_config.pulse_gpio_num = GPIO_NUM_4;
pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
pcnt_config.channel = PCNT_CHANNEL_0;
pcnt_config.unit = PCNT_UNIT_1;
pcnt_config.pos_mode = PCNT_COUNT_INC;
pcnt_config.neg_mode = PCNT_COUNT_DIS;
pcnt_config.lctrl_mode = PCNT_MODE_KEEP;
pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
pcnt_unit_config(&pcnt_config);
pcnt_set_filter_value( PCNT_UNIT_1, 500 );
pcnt_filter_enable ( PCNT_UNIT_1 );
pcnt_counter_pause ( PCNT_UNIT_1 );
pcnt_counter_clear ( PCNT_UNIT_1 );
pcnt_counter_resume ( PCNT_UNIT_1 );
//
xQ_Message = xQueueCreate( 1, sizeof(stu_message) );
//
sema_CalculatedVoltage = xSemaphoreCreateBinary();
xSemaphoreGive( sema_CalculatedVoltage );
sema_mqttOK = xSemaphoreCreateBinary();
xSemaphoreGive( sema_mqttOK );
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
///
xTaskCreatePinnedToCore( MQTTkeepalive, "MQTTkeepalive", 10000, NULL, 5, NULL, 1 );
xTaskCreatePinnedToCore( fparseMQTT, "fparseMQTT", 10000, NULL, 5, NULL, 1 ); // assign all to core 1, WiFi in use.
xTaskCreatePinnedToCore( fReadBattery, "fReadBattery", 4000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fReadCurrent, "fReadCurrent", 4000, NULL, 3, NULL, 1 );
xTaskCreatePinnedToCore( fWindDirection, "fWindDirection", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fAnemometer, "fAnemometer", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fRainFall, "fRainFall", 10000, NULL, 4, NULL, 1 );
xTaskCreatePinnedToCore( fmqttWatchDog, "fmqttWatchDog", 3000, NULL, 3, NULL, 1 ); // assign all to core 1
} //void setup()
static void init_ulp_program()
{
// not sharing this code.
}
////
void fWindDirection( void *pvParameters )
// read the wind direction sensor, return heading in degrees
{
SimpleKalmanFilter KF_ADC( 1.0f, 1.0f, .01f );
const TickType_t xFrequency = 100; //delay for mS
float adcValue = 0.0f;
uint64_t TimePastKalman = esp_timer_get_time();
float high = 0.0f;
float low = 2000.0f;
float ADscale = 3.3f / 4096.0f;
int count = 0;
String windDirection;
String MQTTinfo = "";
windDirection.reserve(20);
MQTTinfo.reserve( 150 );
TickType_t xLastWakeTime = xTaskGetTickCount();
while ( !MQTTclient.connected() )
{
vTaskDelay( 250 );
}
for (;;)
{
windDirection = "";
adcValue = float( adc1_get_raw(ADC1_CHANNEL_6) ); //take a raw ADC reading
KF_ADC.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
adcValue = KF_ADC.updateEstimate( adcValue ); // apply simple Kalman filter
TimePastKalman = esp_timer_get_time(); // time of update complete
adcValue = adcValue * ADscale;
if ( (adcValue >= 0.0f) & (adcValue <= .25f ) )
{
// log_i( " n" );
windDirection.concat( "N" );
}
if ( (adcValue > .25f) & (adcValue <= .6f ) )
{
// log_i( " e" );
windDirection.concat( "E" );
}
if ( (adcValue > 2.0f) & ( adcValue < 3.3f) )
{
// log_i( " s" );
windDirection.concat( "S");
}
if ( (adcValue >= 1.7f) & (adcValue < 2.0f ) )
{
// log_i( " w" );
windDirection.concat( "W" );
}
if ( count >= 30 )
{
MQTTinfo.concat( String(kph, 2) );
MQTTinfo.concat( ",");
MQTTinfo.concat( windDirection );
MQTTinfo.concat( ",");
MQTTinfo.concat( String(rain, 2) );
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
MQTTclient.publish( topicWSWDRF, MQTTinfo.c_str() );
xSemaphoreGive( sema_MQTT_KeepAlive );
count = 0;
}
count++;
MQTTinfo = "";
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete ( NULL );
}
// read rainfall
void fRainFall( void *pvParemeters )
{
int16_t click = 0; //count tipping bucket clicks
pcnt_counter_pause( PCNT_UNIT_1 );
pcnt_counter_clear( PCNT_UNIT_1 );
pcnt_counter_resume( PCNT_UNIT_1 );
for (;;)
{
xEventGroupWaitBits (eg, evtRainFall, pdTRUE, pdTRUE, portMAX_DELAY);
if ( (rtc.getHour(true) == 23) && (rtc.getMinute() == 59) )
{
pcnt_counter_pause( PCNT_UNIT_1 );
rain = 0.0f;
pcnt_counter_clear( PCNT_UNIT_1 );
pcnt_counter_resume( PCNT_UNIT_1 );
} else {
pcnt_counter_pause( PCNT_UNIT_1 );
pcnt_get_counter_value( PCNT_UNIT_1, &click );
if ( click != 0 )
{
rain = rain + (0.2794f * (float)click);// 0.2794mm of rain per click
pcnt_counter_clear( PCNT_UNIT_1 );
log_i( "count %d, rain rain = %f mm", click, rain );
}
pcnt_counter_resume( PCNT_UNIT_1 );
click = 0;
}
}
vTaskDelete ( NULL );
}
////
void fAnemometer( void *pvParameters )
{
int16_t count = 0;
pcnt_counter_clear(PCNT_UNIT_0);
pcnt_counter_resume(PCNT_UNIT_0);
for (;;)
{
xEventGroupWaitBits (eg, evtAnemometer, pdTRUE, pdTRUE, portMAX_DELAY);
pcnt_counter_pause( PCNT_UNIT_0 );
pcnt_get_counter_value( PCNT_UNIT_0, &count);
kph = 2.4f * ((float)count / 60.0f);// A wind speed of 2.4km/h causes the switch to close once per second
//log_i( "%f", kph );
pcnt_counter_clear( PCNT_UNIT_0 );
pcnt_counter_resume( PCNT_UNIT_0 );
}
vTaskDelete ( NULL );
}
//////
void fmqttWatchDog( void * paramater )
{
int UpdateImeTrigger = 86400; //seconds in a day
int UpdateTimeInterval = 86300; // 1st time update in 100 counts
int maxNonMQTTresponse = 60;
for (;;)
{
vTaskDelay( 1000 );
if ( mqttOK >= maxNonMQTTresponse )
{
ESP.restart();
}
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK++;
xSemaphoreGive( sema_mqttOK );
UpdateTimeInterval++; // trigger new time get
if ( UpdateTimeInterval >= UpdateImeTrigger )
{
TimeSet = false; // sets doneTime to false to get an updated time after a days count of seconds
UpdateTimeInterval = 0;
}
}
vTaskDelete( NULL );
}
//////
void fparseMQTT( void *pvParameters )
{
struct stu_message px_message;
for (;;)
{
if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
{
// parse the time from the OK message and update MCU time
if ( String(px_message.topic) == topicOK )
{
if ( !TimeSet)
{
String temp = "";
temp = px_message.payload[0];
temp += px_message.payload[1];
temp += px_message.payload[2];
temp += px_message.payload[3];
int year = temp.toInt();
temp = "";
temp = px_message.payload[5];
temp += px_message.payload[6];
int month = temp.toInt();
temp = "";
temp = px_message.payload[8];
temp += px_message.payload[9];
int day = temp.toInt();
temp = "";
temp = px_message.payload[11];
temp += px_message.payload[12];
int hour = temp.toInt();
temp = "";
temp = px_message.payload[14];
temp += px_message.payload[15];
int min = temp.toInt();
rtc.setTime( 0, min, hour, day, month, year );
log_i( "rtc %s ", rtc.getTime() );
TimeSet = true;
}
}
//
} //if ( xQueueReceive(xQ_Message, &px_message, portMAX_DELAY) == pdTRUE )
xSemaphoreTake( sema_mqttOK, portMAX_DELAY );
mqttOK = 0;
xSemaphoreGive( sema_mqttOK );
}
} // void fparseMQTT( void *pvParameters )#include <ESP32Time.h>
//////
void fReadCurrent( void * parameter )
{
const TickType_t xFrequency = 1000; //delay for mS
const float mVperAmp = 185.0f;
float ADbits = 4096.0f;
float ref_voltage = 3.3f;
float mA = 0.0f;
float adcValue = 0.0f;
float Voltage = 0.0f;
float Power = 0.0f;
float offSET = 0.0f;
int printCount = 0;
uint64_t TimePastKalman = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
SimpleKalmanFilter KF_I( 1.0f, 1.0f, .01f );
/*
185mv/A = 5 AMP MODULE
100mv/A = 20 amp module
66mv/A = 30 amp module
*/
String powerInfo = "";
powerInfo.reserve( 150 );
while ( !MQTTclient.connected() )
{
vTaskDelay( 250 );
}
TickType_t xLastWakeTime = xTaskGetTickCount();
for (;;)
{
adc1_get_raw(ADC1_CHANNEL_3); // read once discard reading
adcValue = ( (float)adc1_get_raw(ADC1_CHANNEL_3) );
//log_i( "adcValue I = %f", adcValue );
Voltage = ( (adcValue * ref_voltage) / ADbits ) + offSET; // Gets you mV
mA = Voltage / mVperAmp; // get amps
KF_I.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
mA = KF_I.updateEstimate( mA ); // apply simple Kalman filter
TimePastKalman = esp_timer_get_time(); // time of update complete
printCount++;
if ( printCount == 60 )
{
xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY);
Power = CalculatedVoltage * mA;
//log_i( "Voltage=%f mA=%f Power=%f", CalculatedVoltage, mA, Power );
printCount = 0;
powerInfo.concat( String(CalculatedVoltage, 2) );
xSemaphoreGive( sema_CalculatedVoltage );
powerInfo.concat( ",");
powerInfo.concat( String(mA, 4) );
powerInfo.concat( ",");
powerInfo.concat( String(Power, 4) );
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY );
MQTTclient.publish( topicPower, powerInfo.c_str() );
xSemaphoreGive( sema_MQTT_KeepAlive );
powerInfo = "";
}
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
}
vTaskDelete( NULL );
} //void fReadCurrent( void * parameter )
////
void fReadBattery( void * parameter )
{
const float r1 = 50500.0f; // R1 in ohm, 50K
const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
const TickType_t xFrequency = 1000; //delay for mS
float adcValue = 0.0f;
float Vbatt = 0.0f;
int printCount = 0;
float vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
uint64_t TimePastKalman = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
TickType_t xLastWakeTime = xTaskGetTickCount();
for (;;)
{
adc1_get_raw(ADC1_CHANNEL_0); //read and discard
adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
Vbatt = adcValue * vRefScale;
xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
CalculatedVoltage = Vbatt;
xSemaphoreGive( sema_CalculatedVoltage );
printCount++;
if ( printCount == 3 )
{
//log_i( "Vbatt %f", Vbatt );
printCount = 0;
}
TimePastKalman = esp_timer_get_time(); // time of update complete
xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil( &xLastWakeTime, xFrequency );
//log_i( "fReadBattery %d", uxTaskGetStackHighWaterMark( NULL ) );
}
vTaskDelete( NULL );
}
////
void MQTTkeepalive( void *pvParameters )
{
sema_MQTT_KeepAlive = xSemaphoreCreateBinary();
xSemaphoreGive( sema_MQTT_KeepAlive ); // found keep alive can mess with a publish, stop keep alive during publish
// setting must be set before a mqtt connection is made
MQTTclient.setKeepAlive( 90 ); // setting keep alive to 90 seconds makes for a very reliable connection, must be set before the 1st connection is made.
for (;;)
{
//check for a is-connected and if the WiFi 'thinks' its connected, found checking on both is more realible than just a single check
if ( (wifiClient.connected()) && (WiFi.status() == WL_CONNECTED) )
{
xSemaphoreTake( sema_MQTT_KeepAlive, portMAX_DELAY ); // whiles MQTTlient.loop() is running no other mqtt operations should be in process
MQTTclient.loop();
xSemaphoreGive( sema_MQTT_KeepAlive );
}
else {
log_i( "MQTT keep alive found MQTT status %s WiFi status %s", String(wifiClient.connected()), String(WiFi.status()) );
if ( !(wifiClient.connected()) || !(WiFi.status() == WL_CONNECTED) )
{
connectToWiFi();
}
connectToMQTT();
}
vTaskDelay( 250 ); //task runs approx every 250 mS
}
vTaskDelete ( NULL );
}
////
void connectToWiFi()
{
int TryCount = 0;
while ( WiFi.status() != WL_CONNECTED )
{
TryCount++;
WiFi.disconnect();
WiFi.begin( SSID, PASSWORD );
vTaskDelay( 4000 );
if ( TryCount == 10 )
{
ESP.restart();
}
}
WiFi.onEvent( WiFiEvent );
} // void connectToWiFi()
////
void connectToMQTT()
{
MQTTclient.setKeepAlive( 90 ); // needs be made before connecting
byte mac[5];
WiFi.macAddress(mac);
String clientID = String(mac[0]) + String(mac[4]) ; // use mac address to create clientID
while ( !MQTTclient.connected() )
{
// boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
MQTTclient.connect( clientID.c_str(), mqtt_username, mqtt_password, NULL , 1, true, NULL );
vTaskDelay( 250 );
}
MQTTclient.setCallback( mqttCallback );
MQTTclient.subscribe( topicOK );
} // void connectToMQTT()
////
void loop() {}
An example of a program using freeRTOS on one core to multask.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
