0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PICマイコンと接続して使用するための予備知識2、M5 ATOM Lite2台で ”Host-Client bluetooth通信”

Last updated at Posted at 2024-07-03

ATOM Liteを2台使用して、bluetoothの双方向通信を行います。

IMG_4863.JPG

全体図.jpg

開発環境 VSCODE + PlatformIO

使用したライブラリ
FastLED by Daniel Garcia
M5Atom by M5Stack
LovyanGFX by lovyan03

Macアドレス探索で参考にさせてもらったブログ

今回は、bluetoothのMacアドレスを指定して1対1の通信を行います。
※bluetooth Classicモードでは、マスターは複数接続できるはずです。

マスター(Host)サイドで、ペアリング先のbluetoothデバイスを、bluetoothMacアドレスで指定します。

前もって、スレーブ(Client)サイドのmacアドレスをUSBシリアルに出力して、メモしておきます。

Slave(client)側 自身のbluetooth Macアドレスを出力するコード
  uint8_t bt_mac[6];
  //bluetoothクライアントアドレスの表示
  esp_read_mac(bt_mac, ESP_MAC_BT);
  Serial.printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
                 bt_mac[0], bt_mac[1], bt_mac[2], bt_mac[3], bt_mac[4], bt_mac[5]);

マスターサイドの接続関数で、相手先のmacアドレスを指定します。

master(Host)側コード通信相手を探索、接続

    uint8_t ClientAtomlite_address[6]={0xA1,0xB1,0x09,0xC1,0x76,0xB8};
    //bluetoothデバイスサーチと接続
    //advertisingパケット受信。
    //Client 側のアドバタイズは停止していないはず。
    
    int times=0;
    bool connected;
    int btConnectCounter;

    //相手先探索
    do
    {
        connected = SerialBT.connect(ClientAtomlite_address);//10秒でタイムアウト
        Serial.printf("%d connected=%d ",times,connected);
        times++;
        if(times==30)
        {
            Serial.println("error:connect timeout");
            break;
        }
    }while(!connected);

相手先とのペアリングシーケンスが成功すれば、接続完了です。

Master(Host)サイドのコード

platformIOの設定と使用ライブラリ
[env:m5stack-atom]
platform = espressif32
board = m5stack-atom
framework = arduino
lib_deps =
m5stack/M5Atom@^0.1.2
fastled/FastLED@^3.7.0
lovyan03/LovyanGFX@^1.1.16
upload_port = COM7

Master側 main.cpp
/*
**********************************************************************************
M5 ATOM Lite 
SK6812 LED グラデーション表示
   ※using libratries=> M5ATOM, FastLED
**********************************************************************************
*/
#include <M5Atom.h>
#include "mySerialBT.hpp"
#include "myTask.hpp"

/// @brief セットアップ
void setup() 
{
  int i;

  // 本体初期化(UART有効, I2C無効, LED有効)
  M5.begin(true,false,true);
  delay(50);
  Serial.println("Start");
  uint8_t bt_mac[6];
  
  //自身のbluetooth macアドレス表示
  esp_read_mac(bt_mac, ESP_MAC_BT);
  Serial.printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
                 bt_mac[0], bt_mac[1], bt_mac[2], bt_mac[3], bt_mac[4], bt_mac[5]);
  
  //起動を示すLED点滅
  for(i=0; i<=1; i++)
  {
    M5.dis.drawpix(0, 0x0F0000);
    delay(500);
    M5.dis.drawpix(0, 0x000000);
    delay(500); 
  }

  //bluetooth開始 Master MODE-----------------
  bluetoothMasterBegin(ClientAtomlite_address);
  
  //タスク開始---------------------
  setupRxTask();
  
}

int counter;
/// @brief メインループ
void loop() 
{
  M5.dis.drawpix(0, 0x00000F);
  SerialBT.printf("cnt=%d\n",counter++);
  delay(500);
  M5.dis.drawpix(0, 0x0F0F00);
  SerialBT.printf("cnt=%d\n",counter++);
  delay(500); 
}


Master側 mySerialBT.hpp
#ifndef MYSERIALBT_HPP
#define MYSERIALBT_HPP

#include <BluetoothSerial.h>

extern uint8_t ClientAtomlite_address[6];

extern BluetoothSerial SerialBT;
extern void bluetoothMasterBegin(uint8_t *address);
#endif
Master側 mySerialBT.cpp
#include "mySerialBT.hpp"

BluetoothSerial SerialBT;

//相手先bluetooth MACアドレス
uint8_t ClientAtomlite_address[6]={0x??,0x??,0x??,0xA1,0xC6,0x13};


/// @brief bluetoothマスターシリアル通信初期化
/// @param address 
void bluetoothMasterBegin(uint8_t *address)
{
    //bluetoothモジュールの起動
    SerialBT.begin("M5 ATOM master", true);
    Serial.println("begin connect");
   
    //bluetoothデバイスサーチと接続
    //advertisingパケット受信。
    //ATOMLite側のアドバタイズは停止していない。
    int times=0;
    bool connected;
    int btConnectCounter;

    //相手先探索
    do
    {
        connected = SerialBT.connect(address);//10秒でタイムアウト
        Serial.printf("%d connected=%d ",times,connected);
        times++;
        if(times==30)
        {
            Serial.println("error:connect timeout");
            break;
        }
    }while(!connected);

    Serial.println("");
    delay(30);
    
    if (connected) 
    {//接続成功
        btConnectCounter++;
        Serial.printf("Connected Succesfully! %d\n\r",btConnectCounter);
    } else 
    {//接続失敗
        while (!SerialBT.connected(10000))
        {
            Serial.println("Failed to connect.");
        }
    }

}
Master側 myTask.hpp
#ifndef MYTASK_HPP
#define MYTASK_HPP

#include <stdint.h>
#include <M5ATOM.h>

#define INTERVAL_TASK 33

extern void setupRxTask(void);
extern void bluetoothRXtask(void *arg);
#endif
Master側 myTask.cpp
#include "myTask.hpp"
#include "mySerialBT.hpp"

void setupRxTask()
{
    xTaskCreate(bluetoothRXtask, "bluetoothRXtask", 2048, NULL, 1, NULL);
}

void bluetoothRXtask(void *arg) 
{
  while (1) 
  {
    if(SerialBT.available()>1)
    {
        String str = SerialBT.readStringUntil('\n');
        uint length = str.length();
        Serial.print("echo=> ");
        Serial.print(str);
        Serial.printf("length=%d\r",length);
    }
    vTaskDelay(INTERVAL_TASK / portTICK_RATE_MS);
  }
}

Slave(Client)サイドのコード

PlatformIOの環境と、使用ライブラリ
[env:m5stack-atom]
platform = espressif32
board = m5stack-atom
framework = arduino
lib_deps =
fastled/FastLED@^3.7.0
m5stack/M5Atom@^0.1.2
lovyan03/LovyanGFX@^1.1.16
upload_port = COM19

Slave側 mainClinet.cpp
#include <M5Atom.h>
#include "mySerialBT.hpp"
#include "myGraphics.hpp"
#include "myTask.hpp"

CRGB color[3]={0x000F00,0x00000F,0x000000};

void setup(void)
{
  uint8_t bt_mac[6];
  M5.begin(true,false,true);
  pinMode(22,OUTPUT); //Lチカ用

  //bluetoothクライアントアドレスの表示
  esp_read_mac(bt_mac, ESP_MAC_BT);
  Serial.printf("%02X:%02X:%02X:%02X:%02X:%02X\n",
                 bt_mac[0], bt_mac[1], bt_mac[2], bt_mac[3], bt_mac[4], bt_mac[5]);
  
  //bluetooth クライアントとして初期化開始
  bluetoothClientBegin();
  
  //SSD1306初期化-----------------
  lcd.init();
  canvas.createSprite(lcd.width(), lcd.height());
  canvas.setTextWrap(true);      //自動折返し:無し
  canvas.fillScreen(TFT_BLACK);   //背景塗りつぶし
  canvas.setTextColor(TFT_WHITE); //文字色

  SerialBT.println("Start\n");
  //シリアル通信受信タスクスタート
  setUPserialRxTask();
}
 
void loop(void)
{
  //GP22のLEDと、本体LEDの点滅
  digitalWrite(22,HIGH);
  M5.dis.drawpix(0,color[0]);
  delay(500);

  digitalWrite(22,LOW);
  M5.dis.drawpix(0,color[1]);
  delay(500);
}
Slave側 mySerialBT.hpp
#ifndef MYSERIALBT_HPP
#define MYSERIALBT_HPP

#include <BluetoothSerial.h>

extern BluetoothSerial SerialBT;    //bluetoothインスタンス
extern void bluetoothClientBegin(void);  

#endif
Slave側 mySerialBT.cpp
#include "mySerialBT.hpp"

/// @brief bluetoothインスタンス
BluetoothSerial SerialBT;

/// @brief bluetooth初期化関数
/// @param address 
void bluetoothClientBegin(void)
{
    SerialBT.begin("M5 ATOM01",false);
    Serial.println("begin connect");
}
Slave側 myTask.hpp
#ifndef MYTASK_HPP
#define MYTASK_HPP

#include <stdint.h>
#include <M5ATOM.h>

#define INTERVAL_TASK 33

extern void setUPserialRxTask(void);
extern void serialRxTask(void *arg);
#endif
Slave側 myTask.cpp
#include "myTask.hpp"
#include "mySerialBT.hpp"
#include "myGraphics.hpp"

/// @brief シリアル通信受信タスク初期化
void setUPserialRxTask()
{
    xTaskCreate(serialRxTask, "serialRxTask", 2048, NULL, 1, NULL);
}

/// @brief Bluetoothシリアル通信受信タスク
/// @param arg 
void serialRxTask(void *arg) 
{
  while (1) 
  {
    if(SerialBT.available()>1)
    {
        String str = SerialBT.readStringUntil('\n');
        uint length = str.length();
        SerialBT.print("echo=> ");
        SerialBT.print(str);
        SerialBT.printf("length=%d\n",length);
        Serial.printf("%s\n",str);
        //SSD1306 表示------------------------------------
        canvas.startWrite();//通信を開始する。(ペリフェラルを占有する)
        canvas.fillScreen(TFT_BLACK);    // 背景塗り潰し
        canvas.setTextSize(1);
        canvas.setCursor(0,0, &Font4);
        canvas.println("BT Client");
        canvas.setCursor(0,20, &Font4);
        canvas.printf("%s\n",str);
        canvas.pushSprite(0,0);
        canvas.endWrite();//通信を終了する。(ペリフェラルの占有を終了する)
    }
    vTaskDelay(INTERVAL_TASK / portTICK_RATE_MS);
  }
}
Slave側 myGraphics.hpp
#ifndef __MYGRAPHICS_HPP__
#define __MYGRAPHICS_HPP__

#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include <Wire.h>

class LGFX_SSD1306 : public lgfx::LGFX_Device
{
  lgfx::Panel_SSD1306 _panel_instance;  // SSD1306
  lgfx::Bus_I2C       _bus_instance;    // バス設定用構造体

  //コンストラクタ
  public:
    LGFX_SSD1306()
    {
      //I2Cバスクラス構造体
      {
        auto cfg = _bus_instance.config();  //I2Cバス構造体インスタンスの取得
        cfg.i2c_port = 1; //Wire1を選択
        cfg.freq_write  = 400000;     // 送信時のクロック クロック周波数
        cfg.freq_read   = 400000;     // 受信時のクロック クロック周波数
        cfg.pin_sda     = 25;         // SDAを接続しているピン番号 SDAピン
        cfg.pin_scl     = 21;         // SCLを接続しているピン番号 SCLピン
        cfg.i2c_addr    = 0x3C;       // I2Cデバイスのアドレス スレーブアドレス
        _bus_instance.config(cfg);
        _panel_instance.setBus(&_bus_instance);
      }
      {
        auto cfg = _panel_instance.config();
        cfg.offset_rotation = 2;
        _panel_instance.config(cfg);
      }
      setPanel(&_panel_instance);
    }
};

Slave側 myGraphics.cpp
#include "myGraphics.hpp"

//LovyanGFXインスタンス***********************************************
LGFX_SSD1306 lcd;
LGFX_Sprite  canvas(&lcd);
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?