problems with tiny GPS on esp32

cjd7734
Posts: 2
Joined: Tue Mar 20, 2018 4:05 am

problems with tiny GPS on esp32

Postby cjd7734 » Tue Mar 20, 2018 4:19 am

so I am moving from esp8266 to esp32 hardware and I am running a problem

on esp8266 I used software serial to connect the GPS and this code below works fine

Code: Select all

void loop() {
 //run GPS till a valid date is received

  while (ss.available() > 0){
    if (gps.encode(ss.read())){
        displayInfo();
    }
   }
}

on esp32 the same section of code is not working, when i switch it over to read hardware serial

Code: Select all

#include <HardwareSerial.h>
#include <TinyGPS++.h>

HardwareSerial MySerial(1);
TinyGPSPlus gps;

void setup() {
MySerial.begin(4800, SERIAL_8N1, 17, 99);
}

void loop()
{
  
  while (MySerial.available() > 0){ 
      if (gps.encode(MySerial.read())){
        displayInfo();
        }
  }
}

I am getting data back when I do a MySerial.read() so I am trying to figure out if what the difference between the software serial.read and the esp32 hardwareserial.read

gps.encode should keep getting called ingesting data from the serial port until it hit a termination character and then should evaluate as true and run display info, but right now it is never evaluating as true

what is killing me is this works perfectly on the esp8266

I could try switching to software serial instead on the esp32 but when I tried the board was crashing repeatedly, has anyone had luck getting software serial to work on the eps 32 ?

anyone have any thoughts ?

Thank You
Calvin

davidlg
Posts: 1
Joined: Mon Nov 05, 2018 9:54 pm

Re: problems with tiny GPS on esp32

Postby davidlg » Mon Nov 05, 2018 10:02 pm

Hello Calvin,

I have exactly the same issue.

Did you figure out a suitable workarround ?

Best regards

David

Zee_jim
Posts: 7
Joined: Wed Dec 05, 2018 9:07 am

Re: problems with tiny GPS on esp32

Postby Zee_jim » Wed Dec 05, 2018 9:24 am

guys try this code out

Code: Select all

#include <TinyGPS++.h>
//#include <SoftwareSerial.h>

HardwareSerial uart(1);
TinyGPSPlus gps;

void setup()
{
  uart.begin(9600, SERIAL_8N1, 17, 16);
  Serial.begin(9600);
  
  Serial.println(F("DeviceExample.ino"));
  Serial.println(F("A simple demonstration of TinyGPS++ with an attached GPS module"));
  Serial.print(F("Testing TinyGPS++ library v. ")); Serial.println(TinyGPSPlus::libraryVersion());
  Serial.println(F("by Mikal Hart"));
  Serial.println();
}

void loop()
{
  // This sketch displays information every time a new sentence is correctly encoded.
  while (uart.available() > 0)
    if (gps.encode(uart.read()))
      displayInfo();

  if (millis() > 5000 && gps.charsProcessed() < 10)
  {
    Serial.println(F("No GPS detected: check wiring."));
    while(true);
  }
}

void displayInfo()
{
  Serial.print(F("Location: ")); 
  if (gps.location.isValid())
  {
    Serial.print(gps.location.lat(), 6);
    Serial.print(F(","));
    Serial.print(gps.location.lng(), 6);
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F("  Date/Time: "));
  if (gps.date.isValid())
  {
    Serial.print(gps.date.month());
    Serial.print(F("/"));
    Serial.print(gps.date.day());
    Serial.print(F("/"));
    Serial.print(gps.date.year());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.print(F(" "));
  if (gps.time.isValid())
  {
    if (gps.time.hour() < 10) Serial.print(F("0"));
    Serial.print(gps.time.hour());
    Serial.print(F(":"));
    if (gps.time.minute() < 10) Serial.print(F("0"));
    Serial.print(gps.time.minute());
    Serial.print(F(":"));
    if (gps.time.second() < 10) Serial.print(F("0"));
    Serial.print(gps.time.second());
    Serial.print(F("."));
    if (gps.time.centisecond() < 10) Serial.print(F("0"));
    Serial.print(gps.time.centisecond());
  }
  else
  {
    Serial.print(F("INVALID"));
  }

  Serial.println();
}

if still have problems try doing this
https://community.platformio.org/t/tiny ... thers/5186

idahowalker
Posts: 166
Joined: Wed Aug 01, 2018 12:06 pm

Re: problems with tiny GPS on esp32

Postby idahowalker » Thu Dec 13, 2018 9:52 pm

I, yesterday, switched from using the Adafruit Ultimate GPS library to using TinyGPS++. I use hardware serial.
Here is what I came up with:

Code: Select all

#include <driver/adc.h>
#include <Adafruit_BMP280.h>
#include <SPI.h>
#include "UTM.h"
#include <U8g2lib.h>
#include <stdio.h> //for function sprintf
#include <TinyGPS++.h>
#include <HardwareSerial.h>
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
/* define event bits */
#define CalDistance               ( 1 << 0 ) //1
#define AnalogVoltReadTask        ( 1 << 1 ) //10
#define DO_UTM_TASK_BIT           ( 1 << 2 ) //100
#define UPDATE_DISPLAY_TASK_BIT   ( 1 << 3 ) //1000
#define GPS_Parse                 ( 1 << 4 ) //10000 
#define NotUsed                ( 1 << 5 ) //100000
#define PressureEvent             ( 1 << 6 ) //1000000
#define DoPressureDataCollectionEvent ( 1 << 7 ) //10000000
#define RunTimeEvent              ( 1 << 8 ) //100000000
#define OneSecondGroupBits ( UPDATE_DISPLAY_TASK_BIT | RunTimeEvent )
////////////////////////////////////////////////////////////////////////////////////
/* create a hardware timer */
hw_timer_t * timer = NULL;
/* create event group */
EventGroupHandle_t eg;
//////////////////////////////////
SemaphoreHandle_t sema_CalDistance;
SemaphoreHandle_t sema_PressureDataCollection;
SemaphoreHandle_t sema_UTM;
SemaphoreHandle_t sema_RunTime;
SemaphoreHandle_t sema_AnalogVoltRead;
SemaphoreHandle_t sema_CheckPressure;
SemaphoreHandle_t sema_GPS_Gate;
SemaphoreHandle_t sema_Time;
SemaphoreHandle_t sema_Date;
SemaphoreHandle_t sema_Posit;
SemaphoreHandle_t sema_Sats;
SemaphoreHandle_t sema_Alti;
SemaphoreHandle_t sema_Hdg;
//SemaphoreHandle_t sema_UTM_Posit;
////
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
////
#define TimerDivider 80
#define TaskCore1 1
#define TaskCore0 0
// #define A0Pin 36 //analog pin
// #define A1Pin 39 //analog pin
#define BlinkLED 2
#define FiveHundred 500
#define EightHundred 800
#define OneK 1000
#define OneKfive 1500
#define TwoK 2000
#define ThreeThreeK 3300
#define BlinkBuiltInK 10000
#define TwentyK 20000
#define UpdateDisplayK 20500
#define Priority1 1
#define Priority2 2
#define Priority3 3
#define Priority4 4
#define Priority5 5
// #define uPvolts 3.3
// #define ADbits 4095
#define SerialDataBits 115200
#define GPS_DataBits 9600
#define TIMER_FOUR 3
#define PressureDataArrayCount 8
/////////////////////////////////
TickType_t xTicksToWait0 = 0;
TickType_t QueueReceiveDelayTime = 10;
TickType_t xTicksToWait20 = 20;
TickType_t xSemaphoreTicksToWait = 12;
////////////////////////////////
HardwareSerial GPSSerial(2);
// Connect to the GPS on the hardware port
// The TinyGPS++ object
TinyGPSPlus GPS;
// UltimateGPS rx to ESP32 I017 - Serial2
// UltimateGPS tx to ESP32 IO16 - Serial2
// pin 16=RX, pin 17=TX
//?????????????????????????????????????????
volatile int iTicCount = 0; //counts milliseconds
bool bLED_On = false;
///////////////////////////////////////////
QueueHandle_t xQ_DistanceMessage;
struct stuDistance
{
  double iDistance = 0; //meters
  float Speed = 0.0; // m.p.h.
} xDistanceMessage;
////
QueueHandle_t xQ_PowerMessage;
struct stuPower
{
  float Vbatt = 0.0;
  float BattPercent = 0;
} xPowerMessage;
/////////////////////////////////////
// from lat long to UTM conversion, shared data between two functions
QueueHandle_t xQ_UTM_Message;
struct stuUTM
{
  float UTM_North = 0.0; // holds northing info
  float UTM_West = 0.0; // holds easting info
  int iZone = 0; // holds zone info
} xUTM_Message;
////////////////////////////////////////////////////////////////
//temperature, pressure, altitude, sealevelpressure
#define DEVICE_PIN 5
// BME_SCK 18 // keep for reference info
// BME_MISO 19
// BME_MOSI 23
Adafruit_BMP280 bme(DEVICE_PIN); // hardware SPI
// Adafruit_BMP280 bme(DEVICE_PIN, BME_MOSI, BME_MISO,  BME_SCK); // keep for reference
QueueHandle_t xQ_PressureMessage;
struct stuPressureMessage
{
  float BMEpressure = 0.0;
  float BMEtemperature = 0.0;
} xPressureMessage;
// float BMEpressure = 0.0;
// float BMEtemperature = 0.0;
////////////////////////////////////////////////////////////////
QueueHandle_t xQ_PressureDataMessage;
struct stuPressureData
{
  int mmHg_Hourly[8] =
  {
    0, 0, 0, 0, 0, 0, 0, 0
  };
  int BMEpressure = 0;
} xPressureData;
//
QueueHandle_t xQ_RunTimeMessage;
struct stuRunTimeData
{
  int iSeconds;
  int iMinutes;
  int iHours;
} xRunTimeData;
//
QueueHandle_t xQ_Time;
struct stuTime
{
  int iSeconds;
  int iMinutes;
  int iHours;
} xTime;
////
QueueHandle_t xQ_Date;
struct stuDate
{
  int iDay;
  int iMonth;
  int iYear;
} xDate;
////
QueueHandle_t xQ_Posit;
struct stuPosit
{
  double Lat;
  double Lon;
} xPosit;
////
QueueHandle_t xQ_Sats;
////
QueueHandle_t xQ_Alti;
////
QueueHandle_t xQ_UTM_Posit;
struct stuUTM_Posit
{
  float Lat;
  float Lon;
} xUTM_Posit;
////
QueueHandle_t xQ_Hdg;
////
////////////////////////////////////////////////////////////////
// timer ISR callback set at 1000X a second
void IRAM_ATTR onTimer()
{
  BaseType_t xHigherPriorityTaskWoken;
  iTicCount++;
  //
  if ( iTicCount == OneK )
  {
    xEventGroupSetBitsFromISR(eg, OneSecondGroupBits, &xHigherPriorityTaskWoken); // trigger every 1X a second
  }
  //
  if ( (xSemaphoreTakeFromISR(sema_GPS_Gate, &xHigherPriorityTaskWoken)) == pdTRUE ) // grab semaphore, no wait
  {
    xEventGroupSetBitsFromISR(eg, GPS_Parse, &xHigherPriorityTaskWoken); // trigger every 1mS, if not already processing
  }  //
  if ( iTicCount == OneK )
  {
    // reset counter to start again
    iTicCount = 0;
  }
} // void IRAM_ATTR onTimer()
////
////
void setup()
{
  ////
  Serial.begin( SerialDataBits );
  pinMode( BlinkLED, OUTPUT ); // for blink LED
  SPI.begin();
  while (!bme.begin())
  {
    Serial.println("Could not find BME280 sensor!");
    vTaskDelay( pdMS_TO_TICKS( OneK ) );
  }
  //
  u8g2.begin();
  ////
  eg = xEventGroupCreate();
  //
  GPSSerial.begin( GPS_DataBits ); // begin GPS hardwareware serial
  //
  vTaskDelay( pdMS_TO_TICKS( OneK ) ); // delay one second
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // set up A:D channels
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_11db);
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_1, ADC_ATTEN_11db);
  /*
     When VDD_A is 3.3V: 11dB attenuation (ADC_ATTEN_11db) gives full-scale voltage 3.9V
  */
  ////
  /* Use 4th timer of 4.
    1 tick 1/(80MHZ/80) = 1us set divider 80 and count up.
    Attach onTimer function to timer
    Set alarm to call timer ISR, every 10000uS and repeat / reset ISR (true) after each alarm
    Start an timer alarm
  */
  timer = timerBegin( TIMER_FOUR, TimerDivider, true );
  timerAttachInterrupt( timer, &onTimer, true );
  timerAlarmWrite(timer, OneK, true);
  timerAlarmEnable(timer);
  ////
  ///////////// create queues
  // queue length, queue item size
  xQ_PressureMessage = xQueueCreate( 1, sizeof(struct stuPressureMessage*) ); // sends a queue pointer to the structure
  xQ_PressureDataMessage = xQueueCreate( 1, sizeof(struct stuPressureData*) ); // sends a queue pointer to the structure
  xQ_DistanceMessage = xQueueCreate( 3, sizeof(struct stuDistance) ); // sends a copy of the structure
  xQ_PowerMessage = xQueueCreate( 1, sizeof(struct stuPower*) ); // sends a queue pointer to the structure
  xQ_UTM_Message = xQueueCreate( 1, sizeof(struct stuUTM) ); //sends copy of the structure
  xQ_RunTimeMessage = xQueueCreate( 1, sizeof(struct stuRunTimeData*) ); //sends a queue pointer to the structure
  xQ_Time = xQueueCreate( 1, sizeof(struct stuTime*) );
  xQ_Date = xQueueCreate( 5, sizeof(struct stuDate*) );
  xQ_Posit = xQueueCreate( 5, sizeof(struct stuPosit*) );
  xQ_Sats = xQueueCreate( 1, sizeof(int) );
  xQ_Alti = xQueueCreate( 1, sizeof(float) );
  xQ_UTM_Posit = xQueueCreate( 1, sizeof(stuUTM_Posit*) );
  xQ_Hdg = xQueueCreate( 1, sizeof(float) );
  ////////////////////////////
  //  Task function, name of task, Stack size of task, parameter of the task, priority of the task, Task handle to keep track of created task, task core
  /////////////////////////// TASK CORE 0
  xTaskCreatePinnedToCore( fBlinkBuiltIn, "fBlinkBuiltIn", BlinkBuiltInK, NULL, Priority4, NULL, TaskCore0 ); //assigned to core 0
  //
  xTaskCreatePinnedToCore( fGPS_Parse, "fGPS_Parse", 10200, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
  sema_Time = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Time );
  sema_Date = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Date );
  sema_Posit = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Posit);
  sema_Sats = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Sats );
  sema_Alti = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Alti );
  xQ_UTM_Posit = xSemaphoreCreateMutex();
  xSemaphoreGive( xQ_UTM_Posit );
  sema_CalDistance = xSemaphoreCreateMutex(); // create Semaphore
  xSemaphoreGive( sema_CalDistance );
  sema_Hdg = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_Hdg );
  //
  xTaskCreatePinnedToCore( TaskAnalogVoltRead, "fTaskAnalogVoltRead", BlinkBuiltInK, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
  sema_AnalogVoltRead = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_AnalogVoltRead );
  //
  xTaskCreatePinnedToCore( fGetUTM, "fGetUTM", 15000, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
  sema_UTM = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_UTM );
  //
  xTaskCreatePinnedToCore( fRunTime, "fRunTime", 10200, NULL, Priority4, NULL, TaskCore0 ); //assigned to core 0 keep opposite from fUpdateDisplay
  sema_RunTime = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_RunTime );
  //
  xTaskCreatePinnedToCore( fDoPressureDataCollection, "fDoPressureDataCollection", BlinkBuiltInK, NULL, Priority4, NULL, TaskCore0 ); // assigned to core 0
  sema_PressureDataCollection = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_PressureDataCollection );
  //////////////////////////////// TASK CORE 1
  xTaskCreatePinnedToCore( fUpdateDisplay, "fUpdateDisplay", UpdateDisplayK, NULL, Priority4, NULL, TaskCore1 ); // assigned to core 1
  //
  sema_GPS_Gate = xSemaphoreCreateMutex();
  xSemaphoreGive( sema_GPS_Gate );
  //
  xTaskCreatePinnedToCore( fCheck_Pressure, "fCheck_Pressure", BlinkBuiltInK, NULL, Priority3, NULL, TaskCore1 ); //assigned to core 1
  sema_CheckPressure = xSemaphoreCreateMutex(); // create Semaphore
  xSemaphoreGive( sema_CheckPressure );
  //////
} //void setup() // runs on core 1
///////////////////////////
void loop() {} // runs on core 1
//////////////////////////
/////////////////////////
//
void fRunTime( void * parameter )
{
  struct stuRunTimeData *pxMessage;
  for (;;)
  {
    xEventGroupWaitBits (eg, RunTimeEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( xSemaphoreTake( sema_RunTime, xSemaphoreTicksToWait ) == pdTRUE )
    {
      xRunTimeData.iSeconds++;
      // Serial.println(  xRunTimeData.iSeconds );
      if ( xRunTimeData.iSeconds == 60 )
      {
        xRunTimeData.iMinutes++;
        xRunTimeData.iSeconds = 0;
      }
      if ( xRunTimeData.iMinutes == 60 )
      {
        xRunTimeData.iHours++;
        xRunTimeData.iMinutes = 0;
      }
        pxMessage = &xRunTimeData;
    xQueueOverwrite( xQ_RunTimeMessage, (void *) &pxMessage );
    xSemaphoreGive( sema_RunTime );
    }
    // Serial.println( "fRunTime" );
    //    Serial.print( "fRunTime " );
    //    Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //    Serial.println();
    //    Serial.flush();
  }
  vTaskDelete( NULL );
} // void fRunTime( void * parameter )
//
void fDoPressureDataCollection( void * parameter )
{
  struct stuPressureData *pxMessage;
  int iArrayCell = 0;
  bool bDidInitialArray = false;
  int iPast = 0;
  for (;;)
  {
    xEventGroupWaitBits (eg, DoPressureDataCollectionEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
    //seed initial value and hour cell
    if ( bDidInitialArray == false )
    {
      if ( xPressureData.BMEpressure != 0 )
      {
        if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to get minute data
        {
          iPast = xTime.iMinutes; // store periodic
          xSemaphoreGive( sema_Time ); // give up semaphore
          xPressureData.mmHg_Hourly[iArrayCell] = xPressureData.BMEpressure;
          iArrayCell++;
          pxMessage = &xPressureData;
          xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage );
          bDidInitialArray = true;
        }
      }
    } //  if ( bDidInitialArray == fasle )
    else
    {
      if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to get minute data
      {
        int iCurrentMinute = xTime.iMinutes;
        xSemaphoreGive( sema_Time ); // give up semaphore
        if ( iPast != iCurrentMinute )
        {
          if ( ((iCurrentMinute % 15) == 0) )
          {
            if ( xSemaphoreTake( sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
            {
              iPast = iCurrentMinute; // keep current minute
              ////
              xPressureData.mmHg_Hourly[iArrayCell] = xPressureData.BMEpressure; //add new periodic reading to array
              ////
              iArrayCell++; // go to the next cell
              pxMessage = &xPressureData;
              xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage );
              if ( iArrayCell == PressureDataArrayCount )
              {
                iArrayCell = 0; // start array count over
              } // if ( iArrayCell == PressureDataArrayCount )
              xSemaphoreGive( sema_PressureDataCollection );
            } // if( xSemaphoreTake( s_Pressure, xTicksToWait20 ) == pdTRUE )
          } //  if ( ((GPS.minute % 15) == 0) )
          else // if ( iPast != GPS.minute )
          {
            // if message present in queue do not send
            if ( xSemaphoreTake( sema_PressureDataCollection, xTicksToWait0 ) == pdTRUE )
            {
              pxMessage = &xPressureData;
              xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage ); // just send the collected data without adding any new data
              xSemaphoreGive( sema_PressureDataCollection );
            } // if( xSemaphoreTake( s_Pressure, ( TickType_t ) TicDe
          } // if ( iPast != GPS.minute )
        } // else if ( iPast != GPS.minute )
      }
      else // if ( iPast != GPS.minute )
      {
        // if message present in queue do not send
        if ( xSemaphoreTake( sema_PressureDataCollection, xTicksToWait0 ) == pdTRUE )
        {
          pxMessage = &xPressureData;
          xQueueOverwrite( xQ_PressureDataMessage, (void *) &pxMessage ); // just send the collected data without adding any new data
          xSemaphoreGive( sema_PressureDataCollection );
        } // if( xSemaphoreTake( s_Pressure, ( TickType_t ) TicDe
      }
    }
    //    Serial.print( "fDoPressureDataGather " );
    //    Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //    Serial.println();
    //    Serial.flush();
  }
  vTaskDelete( NULL );
} // void fDoPressureDataCollection
/* The display routine will trigger the UTN update when needed.
    The display runs once per second
    the display will only call on the UTM update as needed
    the UTM runs on the other core from the display
*/
void fGetUTM(  void * parameter )
{
  struct stuUTM pxMessage;
  float tmpUTM_North = 0.0; // holds northing info
  float tmpUTM_West = 0.0; // holds easting info
  int tmpZone = 0; // holds zone info
  // struct stuPosit *pxPosit;

  int TicDelayTime = 20;
  for (;;)
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, DO_UTM_TASK_BIT, pdTRUE, pdTRUE, portMAX_DELAY) ;
    // int LatLonToUTMXY (FLOAT lat, FLOAT lon, int zone, FLOAT& x, FLOAT& y)
    //    if ( GPS.fix )
    //    {
    if ( xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ) == pdTRUE )
    {
      tmpZone = LatLonToUTMXY(xUTM_Posit.Lat, xUTM_Posit.Lon, 0, tmpUTM_North, tmpUTM_West );
      pxMessage.UTM_North = tmpUTM_North;
      pxMessage.UTM_West = tmpUTM_West;
      pxMessage.iZone = tmpZone;
      xQueueOverwrite( xQ_UTM_Message, (void *) &pxMessage );
      xSemaphoreGive( sema_UTM );
    }
  }
  vTaskDelete( NULL );
}
////
void fUpdateDisplay( void * parameter )
{
  struct stuPressureMessage *pxRxedPressureMessage; // a pointer to a structure
  struct stuDistance Distance_Received; // a copy of the queue sent
  struct stuPower *pxRxedPowerMessage; // a pointer to a structure
  struct stuUTM UTM_MessageReceiced; // a copy of the queue sent
  struct stuPressureData *pxPressureDataMessage; // a pointer to a structure
  struct stuRunTimeData *RunTimeDataMessage; // a pointer to a structure
  struct stuTime *pxTime;
  struct stuDate *pxDate;
  struct stuPosit *pxPosit;

  int iSats = 0;
  static int iCount = 0;
  float Alti = 0.0;
  float Hdg = 0.0;
  float f = 0.0;
  static char buf[20];
  int iYposition = 61;
  int iLeftPosition = 0;
  int iTotalCount = 30;
  // int startTime = 0; // used to measure task ticks
  u8g2.setFont( u8g2_font_t0_11_mr );
  for (;;)
  {
    /* wait forever until event bit of task 1 is set */
    EventBits_t xbit = xEventGroupWaitBits (eg, UPDATE_DISPLAY_TASK_BIT, pdTRUE, pdTRUE, portMAX_DELAY) ;
    // startTime = xTaskGetTickCount(); // used to measure task ticks
    //    Serial.println( "fUpdateDisplay");
    //    Serial.flush();
    u8g2.clearBuffer(); // clear the internal memory
    //
    //
    if ( (xQ_Time != NULL) && (uxQueueMessagesWaiting(xQ_Time)) ) // if queue not null and something is waiting in queue
    {
      if (xQueueReceive ( xQ_Time, &(pxTime), QueueReceiveDelayTime ) ) // receive queue info
      {
        if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
        {
          sprintf(buf, "UTC: %02d:%02d:%02d", pxTime->iHours, pxTime->iMinutes, pxTime->iSeconds);
          xSemaphoreGive( sema_Time ); // give up semaphore
          u8g2.setCursor(1, 10); u8g2.print(buf); // place data in display buffer
        } //  if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
      } // if (xQueueReceive ( xQ_RunTimeMessage, &(RunTimeDataMessage), QueueReceiveDelayTime ) )
    } // if ( (xQ_Time not NULL) && (uxQueueMessagesWaiting(xQ_Time)) )

    if ( uxQueueMessagesWaiting(xQ_Sats) )
    {
      xSemaphoreTake( sema_Sats, xSemaphoreTicksToWait );
      xQueueReceive(xQ_Sats, &iSats, QueueReceiveDelayTime );
      xSemaphoreGive( sema_Sats );
    }
    u8g2.drawStr(85, 10, "^");
    u8g2.setCursor(95, 10); u8g2.print( iSats );
    if ( (iCount >= 0) &&  (iCount <= 9) )
    {
      if ( (xQ_Date != NULL) && (uxQueueMessagesWaiting(xQ_Date)) ) // if queue not null and something is waiting in queue
      {
        if (xQueueReceive ( xQ_Date, &(pxDate), QueueReceiveDelayTime ) ) // receive queue info
        {
          if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
          {
            sprintf( buf, "Date: %02d/%02d/%02d", pxDate->iMonth, pxDate->iDay, pxDate->iYear );
            xSemaphoreGive( sema_Date ); // give up semaphore
            u8g2.setCursor(0, 21); u8g2.print(buf);
          } //  if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
        } //  if (xQueueReceive ( xQ_Date, &(pxDate), QueueReceiveDelayTime ) )
      } //  if ( (xQ_Date != NULL) && (uxQueueMessagesWaiting(xQ_Date)) )
    } //  if ( (iCount >= 0) &&  (iCount <= 9) )
    else
    {
      // is the queue not NULL && is there a queue message waiting? 0 = no messages
      if ( (xQ_RunTimeMessage != NULL) && (uxQueueMessagesWaiting(xQ_RunTimeMessage) > 0) )
      {
        if (xQueueReceive ( xQ_RunTimeMessage, &(RunTimeDataMessage), QueueReceiveDelayTime ) )
        {
          if ( xSemaphoreTake( sema_RunTime, xSemaphoreTicksToWait ) == pdTRUE )
          {
            sprintf(buf, "Run: %03d:%02d:%02d", RunTimeDataMessage->iHours, RunTimeDataMessage->iMinutes, RunTimeDataMessage->iSeconds);
            xSemaphoreGive( sema_RunTime );
            u8g2.setCursor(0, 23); u8g2.print(buf);
          }
        }
      }
    } // else  if ( (iCount >= 0) &&  (iCount <= 9) )
    //    //    //
    u8g2.drawHLine(3, 27, 100);
    u8g2.drawVLine(3, 27, 22);
    u8g2.drawHLine(3, 49, 100);
    u8g2.drawVLine(103, 27, 23);
    //    //    //
    //    // Display Lat and long
    if ( (iCount >= 0) &&  (iCount <= 9) )
    {
      if ( (xQ_Posit != NULL) && (uxQueueMessagesWaiting(xQ_Posit)) ) // if queue not null and something is waiting in queue
      {
        if (xQueueReceive ( xQ_Posit, &(pxPosit), QueueReceiveDelayTime ) ) // receive queue info
        {
          if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore and place data
          {
            sprintf( buf, "%0.6f", pxPosit->Lat );
            u8g2.setCursor(20, 37 ); u8g2.print(buf);
            sprintf( buf, "%0.6f", pxPosit->Lon );
            u8g2.setCursor(20, 47); u8g2.print( buf );
            xSemaphoreGive( sema_Posit ); // give up semaphore
          } //  if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
        } //  if (xQueueReceive ( xQ_Posit, &(pxPosit), QueueReceiveDelayTime ) )
      } //  (xQ_Posit != NULL) && (uxQueueMessagesWaiting(xQ_Posit))
      //      f = (GPS.latitude / 100);
      //      u8g2.setCursor(20, 37) ; u8g2.print(int(f));
      //      f = GPS.latitude - (int(f) * 100);
      //      u8g2.setCursor(40, 37); u8g2.print(f);
      //      u8g2.setCursor(83, 37); u8g2.print(GPS.lat);
      //      //
      //      f = (GPS.longitude / 100);
      //      u8g2.setCursor(20, 47); u8g2.print(int(f));
      //      f = GPS.longitude - (int(f) * 100);
      //      u8g2.setCursor(40, 47); u8g2.print(f);
      //      //u8g2.drawCircle(45, 47, 1,u8g2_DRAW_ALL);
      //      u8g2.setCursor(83, 47); u8g2.print(GPS.lon);
    } // if ( (iCount >= 0) &&  (iCount <= 9) )
    if ( (iCount >= 10) &&  (iCount <= 19) )
    {
      if ( (xQ_UTM_Message != NULL ) && (uxQueueMessagesWaiting(xQ_UTM_Message)) )
      {
        if (xQueueReceive ( xQ_UTM_Message, &(UTM_MessageReceiced), QueueReceiveDelayTime ) )
        {
          if ( xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ) == pdTRUE )
          {
            //display UTM northing, easting, and zone
            u8g2.setCursor(12, 37); u8g2.print( UTM_MessageReceiced.UTM_North );
            u8g2.setCursor(12, 47); u8g2.print( UTM_MessageReceiced.UTM_West);
            u8g2.setCursor(75, 37); u8g2.print( UTM_MessageReceiced.iZone);
            xSemaphoreGive( sema_UTM );
          }
        }
      }
    } // if ( (iCount >= 10) &&  (iCount <= 19) )
    if ( (iCount >= 20) &&  (iCount <= iTotalCount) )
    {
      //// portMAX_DELAY will cause a wait forever for something to show up in the buffer. time of portMAX_DELAY is 47 days
      //// wait for 10 clock tics for data to arrive in the queue buffer
      if ( (xQ_PressureDataMessage) != 0  && (uxQueueMessagesWaiting(xQ_PressureDataMessage)) )
      {
        if (xQueueReceive ( xQ_PressureDataMessage, &(pxPressureDataMessage), QueueReceiveDelayTime ) )
        {
          if ( pxPressureDataMessage != 0) // check if structure is null
          {
            if ( xSemaphoreTake( sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
            {
              int x = 30; // set x position
              int yBase = 38;
              // int y1 = yBase;
              int x2 = 5;
              int pressureBase = 0;
              int iBaseLineReading = pxPressureDataMessage->mmHg_Hourly[0];
              u8g2.drawHLine( x, yBase, x2);
              for (int i = 1; i <= (PressureDataArrayCount - 1); i++)
              {
                if ( pxPressureDataMessage->mmHg_Hourly[i] != 0 )
                {
                  x = x + 9; // position next x
                  u8g2.drawHLine( x, yBase - (iBaseLineReading - pxPressureDataMessage->mmHg_Hourly[i] ), x2);
                }
                sprintf( buf, "%d", iBaseLineReading ) ; // display basy line reading to the left
                u8g2.setCursor( 9, 43 ); u8g2.print( buf );
              } // for (int i = 1; i <= (PressureDataArrayCount - 1); i++)
              xSemaphoreGive( sema_PressureDataCollection );
            } //  if ( xSemaphoreTake( s_Pressure, ( TickType_t ) 10 ) == pdTRUE )
          }
          else
          {
            Serial.println( "pxPressureDataMessage" );
          }
        } //  if (xQueueReceive ( xQ_PressureDataMessage, &(pxPressureDataMessage), ( TickType_t ) QueueReceiveDelayTime ) )
      } // if ( xQ_PressureDataMessage != 0 )
    } //  if ( (iCount >= 20) &&  (iCount <= 30) )
    if ( (iCount >= 0) &&  (iCount <= 4) )
    {
      if ( uxQueueMessagesWaiting(xQ_Hdg) )
      {
        xSemaphoreTake( sema_Hdg, xSemaphoreTicksToWait );
        xQueueReceive(xQ_Hdg, &Hdg, QueueReceiveDelayTime );
        xSemaphoreGive( sema_Hdg );
      }
      u8g2.drawStr(iLeftPosition, iYposition, "Hdg: ");
      u8g2.setCursor(28, iYposition); u8g2.print( Hdg );
    } // if ( (iCount >= 0) &&  (iCount <= 4) )
    if ( (iCount >= 5) &&  (iCount <= 9) )
    {
      if ( uxQueueMessagesWaiting(xQ_Alti) )
      {
        xSemaphoreTake( sema_Alti, xSemaphoreTicksToWait );
        xQueueReceive(xQ_Alti, &Alti, QueueReceiveDelayTime );
        xSemaphoreGive( sema_Alti );
      }
      u8g2.drawStr(iLeftPosition, iYposition, "Alti: ");
      u8g2.setCursor(30, iYposition); u8g2.print( (Alti * 3.2808) );
    } // if ( (iCount >= 5) &&  (iCount <= 9) )
    if ( (iCount >= 10) &&  (iCount <= 14) )
    {
      if ( (xQ_DistanceMessage != 0) && (uxQueueMessagesWaiting(xQ_DistanceMessage)) ) // if queue not null and something is waiting in queue
      {
        if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE ) // grab semaphore to stop the queue from being over wrote
        {
          if (xQueueReceive ( xQ_DistanceMessage, &(Distance_Received), QueueReceiveDelayTime ) ) // receive queue
          {
            sprintf( buf, "Dst:%03dKm %.2f" , Distance_Received.iDistance, Distance_Received.Speed );
            u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
            xSemaphoreGive( sema_CalDistance ); // release semaphore
          } // if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE )
        } // if (xQueueReceive ( xQ_DistanceMessage , &(Distance_Received), ( TickType_t ) QueueReceiveDelayTime ) )
      } // if ( xQ_DistanceMessage != 0 )
    } // if ( (iCount >= 10) &&  (iCount <= 14) )
    if ( (iCount >= 15) &&  (iCount <= 19) )
    {
      if ( xQ_PowerMessage != 0 )
      {
        if ( xQueueReceive( xQ_PowerMessage, &( pxRxedPowerMessage ), QueueReceiveDelayTime ) )
        {
          if ( pxRxedPowerMessage != 0) // check if structure is null
          {
            if ( xSemaphoreTake( sema_AnalogVoltRead, xSemaphoreTicksToWait ) == pdTRUE )
            {
              sprintf( buf, "V: %.2f %.2f% ", pxRxedPowerMessage->Vbatt, pxRxedPowerMessage->BattPercent );
              u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
              xSemaphoreGive( sema_AnalogVoltRead );
            }
          }
          else
          {
            Serial.println( "pxRxedPowerMessage" );
          }
        }
      } // if ( xQ_PowerMessage != 0 )
    } // if ( (iCount >= 15) &&  (iCount <= 19) )
    if ( (iCount >= 20) &&  (iCount <= 24) )
    {
      // Receive a message on the created queue.
      if ( xQ_PressureMessage != 0 )
      {
        if ( xQueueReceive( xQ_PressureMessage, &( pxRxedPressureMessage ), QueueReceiveDelayTime ) )
        {
          if ( pxRxedPressureMessage != 0) // check if structure is null
          {
            if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
            {
              sprintf( buf, "%.2fC %.2fF", pxRxedPressureMessage->BMEtemperature, ((pxRxedPressureMessage->BMEtemperature * 1.8) + 32) );
              u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
              xSemaphoreGive( sema_CheckPressure );
            }
          }
          else
          {
            Serial.println( "pxRxedPressureMessage 1" );
          }
        }
      }
    } // if ( (iCount >= 20) &&  (iCount <= 24) )
    if ( (iCount >= 25) &&  (iCount <= 29) )
    {
      if ( xQ_PressureMessage != 0 )
      {
        if ( xQueueReceive( xQ_PressureMessage, &( pxRxedPressureMessage ), QueueReceiveDelayTime ) )
        {
          if ( pxRxedPressureMessage != 0) // check if structure is null
          {
            if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
            {
              sprintf( buf, "%.2fmmHg", pxRxedPressureMessage->BMEpressure );
              u8g2.setCursor( iLeftPosition, iYposition ); u8g2.print( buf );
              xSemaphoreGive( sema_CheckPressure );
            }
          }
          else
          {
            Serial.println( "pxRxedPressureMessage 2" );
          }
        }
      }
    } // if ( (iCount >= 25) &&  (iCount <= 29) )
    u8g2.sendBuffer(); // transfer internal memory to the display
    if (  (iCount >= 24) &&  (iCount <= 28) )
    {
      xEventGroupSetBits( eg, PressureEvent ); // trigger pressure readings
    } // if (  (iCount >= 24) &&  (iCount <= 28) )
    if (  (iCount >= 19) &&  (iCount <= 23) )
    {
      xEventGroupSetBits( eg, PressureEvent ); // trigger pressure readings
    } // if (  (iCount >= 19) &&  (iCount <= 23) )
    if ( (iCount >= 8) &&  (iCount <= 18) )
    {
      // trigger UTM update, update utm just before its used as a display value
      xEventGroupSetBits( eg, DO_UTM_TASK_BIT ); // trigger UTM calculations
    } //  if ( (iCount >= 9) &&  (iCount <= 18) )
    if ( (iCount >= 14) &&  (iCount <= 18) )
    {
      xEventGroupSetBits( eg, AnalogVoltReadTask ); // trigger analog voltage read and calculation
    } // if ( (iCount >= 19) &&  (iCount <= 23) )
    iCount++;
    if ( iCount >= iTotalCount )
    {
      iCount = 0;
    }
    //        Serial.print( "fUpdateDisplay " );
    //        Serial.print( " " );
    //        Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //        Serial.println();
    //        Serial.flush();
  }
  vTaskDelete( NULL );
} // void fUpdateDisplay( void * parameter )
//////
void fGPS_Parse( void * parameter )
{
  TickType_t xDoDistanceExpireTicks;
  struct stuTime *pxTime;
  struct stuDate *pxDate;
  struct stuPosit *pxPosit;
  struct stuDistance pxDistance;
  float Alti;
  float Hdg;
  int Sats;
  double LatNow;
  double LonNow;
  double LatPast;
  double LonPast;
  int DoDistanceTicks = 1000;
  ////
  xDoDistanceExpireTicks = xTaskGetTickCount() + pdMS_TO_TICKS( 1000 ); // add 1000 mS worth of ticks to current tick count
  for (;;)
  {
    xEventGroupWaitBits (eg, GPS_Parse, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( GPSSerial.available() > 1 )
    {
      if ( GPS.encode(GPSSerial.read()) )
      {
        if (  GPS.location.isValid())
        {
          //used for distance calculation
          LatNow = GPS.location.lat();
          LonNow = GPS.location.lng();
          //
          xPosit.Lat = LatNow;
          xPosit.Lon = LonNow;
          xSemaphoreTake( sema_UTM, xSemaphoreTicksToWait ); // place lat lon for utm calculation
          xUTM_Posit.Lat = xPosit.Lat;
          xUTM_Posit.Lon = xPosit.Lon;
          xSemaphoreGive( sema_UTM );
          if ( xSemaphoreTake( sema_Posit, xSemaphoreTicksToWait ) == pdTRUE )
          {
            pxPosit = &xPosit;
            xQueueSendToBack( xQ_Posit, (void *) &pxPosit, QueueReceiveDelayTime );
            xSemaphoreGive( sema_Posit );
          }
        }
        if (GPS.time.isValid())
        {
          xTime.iSeconds = GPS.time.second();
          xTime.iMinutes = GPS.time.minute();
          xTime.iHours = GPS.time.hour();
          if ( xSemaphoreTake( sema_Time, xSemaphoreTicksToWait ) == pdTRUE )
          {
            pxTime = &xTime;
            xQueueOverwrite( xQ_Time, (void *) &pxTime );
            xSemaphoreGive( sema_Time );
          }
        }
        if (GPS.date.isValid())
        {
          xDate.iMonth = GPS.date. month();
          xDate.iDay = GPS.date.day();
          xDate.iYear = GPS.date.year();
          if ( xSemaphoreTake( sema_Date, xSemaphoreTicksToWait ) == pdTRUE )
          {
            pxDate = &xDate;
            xQueueSendToBack( xQ_Date, (void *) &pxDate, QueueReceiveDelayTime );
            xSemaphoreGive( sema_Date );
          }
        }
        if (  GPS.satellites.isValid() )
        {
          if ( xSemaphoreTake( sema_Sats, xSemaphoreTicksToWait ) == pdTRUE )
          {
            Sats = GPS.satellites.value();
            xQueueOverwrite( xQ_Sats, ( void * ) &Sats );
            xSemaphoreGive( sema_Sats );
          }
        }
        if (  GPS.altitude.isValid() )
        {
          if ( xSemaphoreTake( sema_Alti, xSemaphoreTicksToWait ) == pdTRUE )
          {
            Alti = GPS.altitude.meters();
            xQueueOverwrite( xQ_Alti, ( void * ) &Alti );
            xSemaphoreGive( sema_Alti );
          }
        }
        if (GPS.location.isValid())
        {
          if ( LatPast = 0.0 )
          {
            LatPast = LatNow;
            LonPast = LonNow;
          }
          if ( xTaskGetTickCount() >= xDoDistanceExpireTicks ) // do only once every 1000mS
          {
            if ( xSemaphoreTake( sema_CalDistance, xSemaphoreTicksToWait ) == pdTRUE )
            {
              // xDoDistancePastTicks
              // has tick count expired
              xDistanceMessage.iDistance = ( TinyGPSPlus::distanceBetween( LatNow, LonNow, LatPast, LonPast) / 100 ); // in Kilometers
              if (GPS.speed.isUpdated())
              {
                xDistanceMessage.Speed = GPS.speed.mph();
              }
              xQueueSendToBack( xQ_DistanceMessage, (void *) &pxDistance, QueueReceiveDelayTime ); // sends a copy of the structure in the queue
              xQueueSendToBack( xQ_DistanceMessage, (void *) &pxDistance, QueueReceiveDelayTime ); // sends a copy of the structure in the queue
              xQueueSendToBack( xQ_DistanceMessage, (void *) &pxDistance, QueueReceiveDelayTime ); // sends a copy of the structure in the queue
              xSemaphoreGive( sema_CalDistance );
              LatPast = LatNow; // update past lat n lon with now lat lon for next calculation
              LonPast = LonNow;
            }
            xDoDistanceExpireTicks = xTaskGetTickCount() + pdMS_TO_TICKS( DoDistanceTicks );
          }
        } // if (gps.location.isValid())
        if ( GPS.course.isUpdated() )
        {
          if ( xSemaphoreTake( sema_Hdg, xSemaphoreTicksToWait ) == pdTRUE )
          {
            Hdg = GPS.course.deg();
            xQueueOverwrite( xQ_Hdg, ( void * ) &Hdg );
            xSemaphoreGive( sema_Hdg );
          }
        }
        //                Serial.print( "fGPS_Parse " );
        //                Serial.print( " " );
        //                Serial.print(uxTaskGetStackHighWaterMark( NULL ));
        //                Serial.println();
        //                Serial.flush();
      } // if ( GPS.encode(GPSSerial.read()))
    } // if ( GPSSerial.available() > 0 )
     xSemaphoreGive( sema_GPS_Gate );
  } // for (;;)
  vTaskDelete( NULL );
} // void fGPS_Parse( void *pdata )
//////////////////////////////////////////////////
void fBlinkBuiltIn( void* pvParameters )
{
  // toggle built in LED off/on
  for (;;)
  {
    vTaskDelay( pdMS_TO_TICKS( 10 ) );
    REG_WRITE( GPIO_OUT_W1TC_REG, BIT2 ); // GPIO2 LOW (clear)
    vTaskDelay( pdMS_TO_TICKS( OneK ) );
    REG_WRITE( GPIO_OUT_W1TS_REG, BIT2 ); //GPIO2 HIGH (set)
  }
  vTaskDelete( NULL );
}
////////////////////////////////////////////////
// example of a ticks to wait use
void TaskAnalogVoltRead( void *pvParameters )
{
  struct stuPower *pxMessage;
  float ADbits = 4095.0;
  float  uPvolts = 3.3;
  float r1 = 27000.0; // R1 in ohm, 27k = 27000.0 //actual resistor size 27K
  float r2 = 10000.0;                       // R2 in ohm, 10k = 10000.0 //actual 10K
  // ADC1 channel 0 is GPIO36
  // ADC1 channel 1 is GPIO37
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  for (;;)
  {
    // group handle, WaitForBits, ClearOnExitBit, WaitForAllBits, TicksToWait
    xEventGroupWaitBits( eg, AnalogVoltReadTask, pdTRUE, pdTRUE, portMAX_DELAY );
    // read the input
    //     ADC1 channel 1 input is ground, any ground noise readings get substracted from voltage reading
    if ( xSemaphoreTake( sema_AnalogVoltRead, xSemaphoreTicksToWait ) == pdTRUE )
    {
      xPowerMessage.Vbatt = ( (( uPvolts * float(adc1_get_raw(ADC1_CHANNEL_0) - adc1_get_raw(ADC1_CHANNEL_1))) / ADbits) / r2 * ( r1 + r2) );
      fBatteryPercentRemaingCharge();
      pxMessage = &xPowerMessage;
      xQueueOverwrite( xQ_PowerMessage, (void *) &pxMessage );
      xSemaphoreGive( sema_AnalogVoltRead );
    }
    //            Serial.print( "TaskAnalogVoltRead " );
    //    Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //        Serial.println();
    //        Serial.flush();
  }
  vTaskDelete( NULL );
}
/////////////////////////////////////////////////////////
void fBatteryPercentRemaingCharge()
{
  byte V_BattNominal = 8;
  byte V_MinRange = 6; //volts is lowest recomemded operating voltage
  ////
  if ( xPowerMessage.Vbatt >= V_BattNominal)
  {
    xPowerMessage.BattPercent = 100.00;
  }
  else
  {
    xPowerMessage.BattPercent = ( ((xPowerMessage.Vbatt - V_MinRange) * 100.0) / (V_BattNominal - V_MinRange) );
  }
}// end fBatteryPercentRemaingCharge()
///////////////////////////////////////////////////////////////////////////////////////////
void fCheck_Pressure( void * parameter )
{
  struct stuPressureMessage *pxMessage;
  while (1)
  {
    xEventGroupWaitBits (eg, PressureEvent, pdTRUE, pdTRUE, portMAX_DELAY) ;
    if ( xSemaphoreTake( sema_CheckPressure, xSemaphoreTicksToWait ) == pdTRUE )
    {
      xPressureMessage.BMEtemperature = bme.readTemperature();
      xPressureMessage.BMEpressure = bme.readPressure() / 133.3223684; // mmHg
       if ( xSemaphoreTake(sema_PressureDataCollection, xSemaphoreTicksToWait ) == pdTRUE )
    {
      xPressureData.BMEpressure = int( xPressureMessage.BMEpressure ); // transfer pressure reading into xPressureData.BMEpressure
      xSemaphoreGive( sema_PressureDataCollection );
    }
      //// BMEpressure = bme.readPressure() *  0.0002952998751 ; // inHg
      pxMessage = &xPressureMessage;
      xQueueOverwrite( xQ_PressureMessage,  (void *) &pxMessage ); // sends a copy of the structure in the queue
      xEventGroupSetBits( eg, DoPressureDataCollectionEvent ); // trigger fDoPressureDataCollection
      xSemaphoreGive( sema_CheckPressure );
    }
    //    Serial.print( "fCheck_Pressure " );
    //    Serial.print(uxTaskGetStackHighWaterMark( NULL ));
    //    Serial.println();
    //    Serial.flush();
  }
  vTaskDelete( NULL );
} // void fCheck_Pressure( void * parameter )
//}
Still a work in progress.

Who is online

Users browsing this forum: No registered users and 50 guests