2023年7月8日 星期六

ESP32 I2C Bus Scanner – BMP180 section

Fundamental:

II2C communication protocol uses two wires to share information. One is used for the clock signal (SCL) and the other is used to send and receive data (SDA). The ESP32 supports I2C communication through its two I2C bus interfaces that can serve as I2C master or slave, depending on the user’s configuration.  Accordingly to the ESP32 datasheet, the I2C interfaces of the ESP32 supports:

1. Standard mode (100 Kbit/s) 
2. Fast mode (400 Kbit/s) 
3. Up to 5 MHz, yet constrained by SDA pull-up strength 
4. 7-bit/10-bit addressing mode 
5. Dual addressing mode. Users can program command registers to control I²C interfaces, so      that they have more flexibility

BMP180 general description 

The BMP180 is the function compatible successor of the BMP085, a new generation of high precision digital pressure sensors for consumer applications. The ultra-low power, low voltage electronics of the BMP180 is optimized for use in mobile phones, PDAs, GPS navigation devices and outdoor equipment. With a low altitude noise of merely 0.25m at fast conversion time, 
the BMP180 offers superior performance. The I2C interface allows for easy system integration with a microcontroller. The BMP180 is based on piezo-resistive technology for EMC robustness, high accuracy and linearity as well as long term stability. Robert Bosch is the world market leader for pressure sensors in automotive applications. Based on the experience of over 400 million pressure sensors in the field, the BMP180 continues a new generation of micro-machined pressure sensors.

Purpose:

We’ll take a look at the I2C communication protocol with the ESP32 using Arduino IDE 2. This very simple sketch scans the I2C-bus for devices. If a device is found, it is reported to the Arduino serial monitor and to driver bmp180 of I2C Bus for some information.

Circuit:

ESP32 Code Introduce:
#include <Wire.h>
#include <Adafruit_BMP085.h>
//--------- Flag structure --------------------------------------
typedef struct _vFlag
{
  uint8_t BTFlag = 0;
  uint8_t DC_Flag = 0;
  uint8_t CANFlag = 0;
  uint8_t I2C_Flag = 0;
  uint8_t BMP180Flag = 0;
  uint8_t JSONFlag = 0;
  uint8_t Radar_L_Flag = 0;
  uint8_t Radar_R_Flag = 0;
  uint8_t sensor_Flag = 0;
  uint8_t sensor1_Flag = 0;
  uint8_t initial_Flag = 0;
  uint8_t Tone_Flag = -1;
  uint8_t IR_RECV_Flag=0;
  uint8_t IR_SEND_Flag=0;
  uint8_t FunctionFlag = 3;
  uint8_t SendFlag = 0;
  uint8_t BMPCnt = 0;
} vFlag;
vFlag *flag_Ptr;
vFlag flag;

//-----   BMP085  ------------------
Adafruit_BMP085 bmp;

//----------uart--------------
#define LINE_BUFFER_LENGTH 64
//--------- uart structure --------------------------------------
typedef struct _vUart
{
  char c;
  int lineIndex = 0;
  int line1Index = 0;
  int BTlineIndex = 0;
  bool lineIsComment;
  bool lineSemiColon;
  //char *line;
  char line[128];
  //char line1[128];
  char BTline[20];
  //char R_line[20];
  //char L_line[20];
  String inputString;
  String BTinputString;
  String S1inputString;
  int V[16];
  char ctemp[30];
  char I2C_Data[80];
  int DC_Spped = 50;
  float Voltage[16];
  int Buffer[128];
  int StartCnt = 0;
  int ReadCnt = 0;
  int sensorValue = 0;
} vUart;
vUart *Uart_Ptr;
vUart Uart;

//-------------------------------------------------
void setup()
{
  Serial.begin(9600);
  Serial.println(F("init"));

  Wire.begin(); //--i2c scanner
  //-------bmp180----------------------
  if (!bmp.begin())
  {
     Serial.println(F("Could not find a valid BMP085 sensor, check wiring!"));
     //while (1);
  }
  else{
    Serial.println(F("find a valid BMP085 sensor"));
  }

}
//-----------------------------------------
void loop()
{
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());
  while(1)
  {
    while (Serial.available() > 0)
    {
      Uart.c = Serial.read();

      if ((Uart.c == '\n') || (Uart.c == '\r'))
      { // End of line reached
        if (Uart.lineIndex > 0)
        { // Line is complete. Then execute!
          Uart.line[Uart.lineIndex] = '\0'; // Terminate string
          //Serial.println( F("Debug") );
          //Serial.println( Uart.inputString );
          processCommand(Uart.line); // do something with the command
          //傳輸給藍芽
         
          Uart.lineIndex = 0;
          Uart.inputString = "";
        }
        else
        {
          // Empty or comment line. Skip block.
        }
        Uart.lineIsComment = false;
        Uart.lineSemiColon = false;
        Serial.println(F("ok>"));
      }
      else
      {
        //Serial.println( c );
        if ((Uart.lineIsComment) || (Uart.lineSemiColon))
        {
          if (Uart.c == ')')
            Uart.lineIsComment = false; // End of comment. Resume line.
        }
        else
        {
          if (Uart.c == '/')
          { // Block delete not supported. Ignore character.
          }
          else if (Uart.c == '~')
          { // Enable comments flag and ignore all characters until ')' or EOL.
            Uart.lineIsComment = true;
          }
          else if (Uart.c == ';')
          {
            Uart.lineSemiColon = true;
          }
          else if (Uart.lineIndex >= LINE_BUFFER_LENGTH - 1)
          {
            Serial.println("ERROR - lineBuffer overflow");
            Uart.lineIsComment = false;
            Uart.lineSemiColon = false;
          }
          else if (Uart.c >= 'a' && Uart.c <= 'z')
          { // Upcase lowercase
            Uart.line[Uart.lineIndex] = Uart.c - 'a' + 'A';
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += (char)(Uart.c - 'a' + 'A');
          }
          else
          {
            Uart.line[Uart.lineIndex] = Uart.c;
            Uart.lineIndex = Uart.lineIndex + 1;
            Uart.inputString += Uart.c;
          }
        }
      }
    } //while (Serial.available() > 0)
    if(flag.I2C_Flag == 1)
    {
      vI2C_0_Task();
    }
    if(flag.BMP180Flag == 1)
    {
      vBMPTask();
    }

  }
}
//----------------------------------------
void processCommand(char *data)
{
  int len, xlen, ylen, zlen, alen;
  int tempDIO;
  String stemp;

  len = Uart.inputString.length();
  //---------------------------------------
  if (strstr(data, "VER") != NULL)
  {
    Serial.println(F("ESP32_20230626"));
  }
 

  //-------------- I2C --------------------
  if (strstr(data, "I2C_SCAN") != NULL)
  {
    flag.I2C_Flag = 1;
    Serial.println(F("I2C_SCAN"));

  }

  if (strstr(data, "I2C_SCAN_OFF")!= NULL)
  {
    flag.I2C_Flag = 0;
    Serial.println(F("I2C_SCAN_OFF"));
  }
  //
  if (strstr(data, "BMP180_ON")!= NULL)
  {
    flag.BMP180Flag = 1;
    flag.BMPCnt = 0;
    Serial.println(F("BMP180_ON"));
  }
  if (strstr(data, "BMP180_OFF")!= NULL)
  {
    flag.BMP180Flag = 0;
    Serial.println(F("BMP180_OFF"));
  }
}
//-----------------------------------------
void vI2C_0_Task()
{
  byte count = 0;

  Serial.println(F("I2C scanner. Scanning ..."));
  for (byte i = 1; i < 127; i++) //---scan address
  {
    Wire.beginTransmission(i);
    if (Wire.endTransmission() == 0)
    {
      Serial.print("Found_address:" + String(count + 1) + "_");
      Serial.print(i, DEC);
      Serial.print("_(0x");
      Serial.print(i, HEX);
      Serial.println(F(")"));
      count++;
      delay(5);
    }
    else
    {
      continue;
    }
  }
  Serial.println(F("Done."));
  Serial.print(F("Found: "));
  Serial.print(count, DEC);
  Serial.println(F(" device(s)."));
  flag.I2C_Flag = 0;
}
//-------------------------------------------
void vBMPTask()
{
  Serial.print(F("Temperature = "));
  Serial.print(bmp.readTemperature());
  Serial.println(" *C");
  Serial.print(F("Pressure = "));
  Serial.print(bmp.readPressure());
  Serial.println(" Pa");
  Serial.print(F("Approx altitude = "));
  Serial.print(bmp.readAltitude(1013.25));
  Serial.println(" m");
  flag.BMP180Flag = 0;
}
YouTube :





延伸閱讀

2023年7月6日 星期四

Arduino IDE 2 + ESP32 multiTask sample -- LED Section

Porpose:

The ESP32 comes with 2 Xtensa 32-bit LX6 microprocessors: core 0 and core 1. So, it is dual core. When we run code on Arduino IDE, by default, it runs on core 1. In this post we’ll show you how to run code on the ESP32 second core by creating tasks. You can run pieces of code simultaneously on both cores, and make your ESP32 multitasking.

Introduction:

The ESP32 comes with 2 Xtensa 32-bit LX6 microprocessors, so it’s dual core:

Core 0

Core 1

Some features to remember:

xTaskCreate() to create a task

xTaskCreatePinnedToCore() to create a task on a particular core

vTaskDelayUntil() to activate a task periodically

vTaskDelay() blocks a task for a certain number of clock ticks (uses pdMS_TO_TICKS to convert a duration into a number of ticks)

vTaskPrioritySet() changes the priority of a task

vTaskDelete() to delete a task

main.cpp

#include "main.h"

//-------------------------------------------------
void setup()
{
  Serial.begin(9600);

  Serial.println(F("init"));

  #ifdef ENABLE_LEDTASK
  initledTask();
  #endif

}

void loop()
{
  vTaskDelay(200);
  Serial.print(F("Main at core:"));
  Serial.println(xPortGetCoreID());

  while(1)
  {
    vTaskDelay(200);
  }

}

main.h

#ifndef __MAIN_H
#define __MAIN_H

#include <Arduino.h>

#include "configuration.h"
#include "public_structure.h"

// led Task stuff
#define ENABLE_LEDTASK
void initledTask(void);

//-----------------------------------------
#endif

ledtask.cpp

#include "main.h"
#include "ledTask.h"
#include "public_structure.h"

#ifdef ENABLE_LEDTASK
/** Forward dedclaration of the task handling LED */
TaskHandle_t hled;  //TaskHandler  -----   main extern

void ledTask(void *pvParameters);

int Led::addTwoInts(int a, int b)
{
  return a + b;
}

Led::Led(byte pin)
{
  this->pin = pin;
  init();
}

void Led::init()
{
  pinMode(pin, OUTPUT);
  off();
}

void Led::on()
{
  digitalWrite(pin, HIGH);
}

void Led::off()
{
  digitalWrite(pin, LOW);
}

Led led(LED_PIN);  //---need to using

void initledTask(void)
{
  // Create the task for the led flash
  xTaskCreatePinnedToCore(
    ledTask, "LED Task" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &hled //handle
    ,
    0);

  // Check the results
  if (hled == NULL)
  {
    Serial.println("Create Led task failed");
  }
  else
  {
    Serial.println("Led task up and running");
  }
}
//------------------------------------------------------------------------------
// Task blinking LED
void ledTask(void *pvParameters)
{
  Serial.print(F("LED Task at core:"));
  Serial.println(xPortGetCoreID());

  while(1)
  {
    led.on();
    //vTaskDelay((150L * configTICK_RATE_HZ) / 1000L);
    vTaskDelay(200);
    led.off();
    //vTaskDelay((150L * configTICK_RATE_HZ) / 1000L);
    vTaskDelay(200);
  }
}

#endif

ledtask.h

#ifndef __LEDTASK_H
#define __LEDTASK_H
#include <Arduino.h>

class Led
{
  private:
    byte pin;
    int a, b;
   
  public:
    // Setup pin LED and call init()
    Led(byte pin);

    // Setup the pin led as OUTPUT
    // and power off the LED - default state
    void init();
   
    // Power on the LED
    void on();

    // Power off the LED
    void off();

    int addTwoInts(int a, int b);
};

#endif

public_structure.h

#ifndef __MESSAGE_H
#define __MESSAGE_H

#include <Arduino.h>
#include "configuration.h"

//----------------------------------------------------------
typedef struct _vMessage_Type
{
  uint8_t messageId;
  //char *messageString;   //不行用會當機
  char messageString[128];
  char FWString[60];
} vMessage_Type;

extern vMessage_Type *message_Ptr;
extern vMessage_Type message;

typedef struct _vFlag
{
  uint8_t BTFlag = 0;
  uint8_t DC_Flag = 0;
  uint8_t CANFlag = 0;
  uint8_t I2C_Flag = 0;
  uint8_t JSONFlag = 0;
  uint8_t Radar_L_Flag = 0;
  uint8_t Radar_R_Flag = 0;
  uint8_t sensor_Flag = 0;
  uint8_t sensor1_Flag = 0;
  uint8_t initial_Flag = 0;
  uint8_t Tone_Flag = -1;
  uint8_t IR_RECV_Flag=0;
  uint8_t IR_SEND_Flag=0;
  uint8_t FunctionFlag = 1;
  uint8_t SendFlag = 0;
} vFlag;

extern vFlag *flag_Ptr;
extern vFlag flag;

//------------------------------------------------------------------------------
#endif

YouTube:







延伸閱讀

Application of solar panels

Purpose:

The energy received by the solar panel is stored in the lithium battery and provided to the ESP32 for use.

圖一:充電圖
圖二:整體架構圖
圖三: 太陽能板
圖四:升壓模組(DC-DC升壓模組(0.9V~5V)升5V 600MA USB 升壓電路板 移動電源升壓 5V輸出)
圖五:充電模組(TP4056 1A 鋰電池充電板模組 TYPE-C USB介面充電保護二合一充電模組)
圖六:ESP32用電組合


2023年7月1日 星期六

ESP32 WiFi painlessmesh network Application

Scheme:

Use four ESP32 to construct a mesh network, when one of them connect with each other the build-in blue led will light up flashing. 


Reference
https://randomnerdtutorials.com/esp-mesh-esp32-esp8266-painlessmesh/

Open painlessmesh sample Code:
Modify painlessmesh Task:
Use multitask function, add a led task at core 0 to show The led blinks when there is a new connection
code show:
//************************************************************
// this is a simple example that uses the painlessMesh library
//
// 1. sends a silly message to every node on the mesh at a random time between 1 and 5 seconds
// 2. prints anything it receives to Serial.print
//
//
//************************************************************
#include "painlessMesh.h"

#define   MESH_PREFIX     "Peter1015"
#define   MESH_PASSWORD   "No18141814"
#define   MESH_PORT       5555

Scheduler userScheduler; // to control your personal task
painlessMesh  mesh;
//------------led task--------------------------------------
#define LED_BUILTIN 2
TaskHandle_t hled;
void vLEDFlashTask(void *pvParameters);

// User stub
void sendMessage() ; // Prototype so PlatformIO doesn't complain

Task taskSendMessage( TASK_SECOND * 1 , TASK_FOREVER, &sendMessage );

/*--------------------------------------------------*/
void vLEDFlashTask(void *pvParameters) // This is a task.
{
  (void)pvParameters;

  // initialize digital LED_BUILTIN on pin 2 as an output.
  Serial.print(F("LEDTask at core:"));
  Serial.println(xPortGetCoreID());
  pinMode(LED_BUILTIN, OUTPUT);
  for (;;) // A Task shall never return or exit.
  {
    digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
    vTaskDelay(200);
    digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
    vTaskDelay(200);
  }
}

void sendMessage() {
  String msg = "Hello from node ";
  msg += mesh.getNodeId();
  mesh.sendBroadcast( msg );
  taskSendMessage.setInterval( random( TASK_SECOND * 1, TASK_SECOND * 5 ));
}

// Needed for painless library
void receivedCallback( uint32_t from, String &msg ) {
  Serial.printf("startHere: Received from %u msg=%s\n", from, msg.c_str());
}

void newConnectionCallback(uint32_t nodeId) {
    Serial.printf("--> startHere: New Connection, nodeId = %u\n", nodeId);
    vTaskResume(hled);
}

void changedConnectionCallback() {
  Serial.printf("Changed connections\n");
}

void nodeTimeAdjustedCallback(int32_t offset) {
    Serial.printf("Adjusted time %u. Offset = %d\n", mesh.getNodeTime(),offset);
}

void setup() {
  Serial.begin(115200);

  xTaskCreatePinnedToCore(
    vLEDFlashTask, "LEDTask" // A name just for humans
    ,
    1024 // This stack size can be checked & adjusted by reading the Stack Highwater
    ,
    NULL, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,
    &hled //handle
    ,
    0);  //core 0

  pinMode(LED_BUILTIN, INPUT);
  vTaskSuspend(hled);
 
//mesh.setDebugMsgTypes( ERROR | MESH_STATUS | CONNECTION | SYNC | COMMUNICATION | GENERAL | MSG_TYPES | REMOTE ); // all types on
  mesh.setDebugMsgTypes( ERROR | STARTUP );  // set before init() so that you can see startup messages

  mesh.init( MESH_PREFIX, MESH_PASSWORD, &userScheduler, MESH_PORT );
  mesh.onReceive(&receivedCallback);
  mesh.onNewConnection(&newConnectionCallback);
  mesh.onChangedConnections(&changedConnectionCallback);
  mesh.onNodeTimeAdjusted(&nodeTimeAdjustedCallback);

  userScheduler.addTask( taskSendMessage );
  taskSendMessage.enable();
}

void loop() {
  // it will run the user scheduler as well
  mesh.update();
}

Achievement Demonstration:
YouTube:









延伸閱讀