概要
仕事で多数の電圧測定したいと思う時があり安価にできそうなXIAOを使ってみました。
XIAO単体利用でも良いのですが他のマイコンで利用できるようになればと思い、
I2C接続してみました。XIAO SAMD21には12bitADCが11chありますが、
2ch(A4、A5)はI2C通信に使用するのでADCとしては9ch分が使用できます。
プログラムとしては1秒毎にATOMLiteからXIAOに対してリクエストを行い、
XIAOはその都度AD値を文字列で返信しています。
3.3Vを接続しているA0、A10については最大値の4095で取得できました。
その他のchについてはopen状態なので値は不定となっています。
環境
エディタ:VisualStudioCode(拡張機能:PlatformIO)
マイコン:①ADC送信側:Seeed Studio XIAO SAMD21
②データ受信、ディスプレイ表示側:M5stack ATOM Lite
ディスプレイ:GROVE - I2C OLEDディスプレイ128×64(I2C接続)
接続
XIAOとATOM Lite、ディスプレイをそれぞれI2C接続
プログラム
ATOM Lite側プログラム
#include <Arduino.h>
#include <M5Atom.h>
#include <Wire.h>
#include <U8g2lib.h>
#include <FastLED.h>
//初期設定
String gdata;
uint32_t i = 0;
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0,/* reset=*/ U8X8_PIN_NONE) ;
#define I2C_DEV_ADDR 0x55 //スレーブ側に指定するI2Cアドレス
// FastLEDライブラリの設定(CRGB構造体)
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b) {
return (CRGB)((r << 16) | (g << 8) | b);
}
String cmds[9] ; // 分割された文字列を格納する配列
int split(String data, char delimiter, String *dst){
int index = 0;
int datalength = data.length();
for (int i = 0; i < datalength; i++) {
char tmp = data.charAt(i);
if ( tmp == delimiter ) {
index++;
}
else dst[index] += tmp;
}
return (index + 1);
}
void setup() {
M5.begin(true,false,true);
Wire.begin(26,32);
Serial.begin(115200);
// LED(赤, 緑, 青)
M5.dis.drawpix(0,dispColor(0, 0, 50));
//OLED関連設定
u8g2.begin() ;
u8g2.setFlipMode(0); // 画面表示向き設定
u8g2.setFont(u8g2_font_unifont_tf);
}
void loop() {
//i2cリクエスト
uint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 100);
//i2c受信
if (Wire.available() > 0) {
gdata = Wire.readStringUntil('\n'); //「」を検出したら終了
}
//カンマ区切り文字を配列変換
// 分割数 = 分割処理(文字列, 区切り文字, 配列)
int index = split(gdata, ',', cmds);
//OLED表示
u8g2.clearBuffer();
u8g2.setCursor(0, 10) ;
u8g2.print("A0:"+cmds[0]);
u8g2.setCursor(0, 22) ;
u8g2.print("A1:"+cmds[1]);
u8g2.setCursor(0, 34) ;
u8g2.print("A2:"+cmds[2]);
u8g2.setCursor(0, 46) ;
u8g2.print("A3:"+cmds[3]);
u8g2.setCursor(0, 58) ;
u8g2.print("A6:"+cmds[4]);
u8g2.setCursor(60, 10) ;
u8g2.print("A7:"+cmds[5]);
u8g2.setCursor(60, 22) ;
u8g2.print("A8:"+cmds[6]);
u8g2.setCursor(60, 34) ;
u8g2.print("A9:"+cmds[7]);
u8g2.setCursor(60, 46) ;
u8g2.print("A10:"+cmds[8]);
u8g2.sendBuffer();
//配列クリア
memset(cmds, '\0', sizeof(cmds));
delay(1000);
}
XIAO側プログラム
#include <Arduino.h>
#include <Wire.h>
int adc_ch[]={0,1,2,3,6,7,8,9,10};
String msg;
char sndmsg[100];
//スレーブとしてのi2cアドレス設定
#define I2C_DEV_ADDR 0x55
//マスター要求返答
void onRequest()
{
//adc値取得
for(int i=0;i<9;i++){
msg+=String(analogRead(adc_ch[i]))+",";
}
//カンマ区切り文字列整形
msg.remove(msg.length() -1,1);//最後のカンマ削除
Wire.write(strcpy(sndmsg, msg.c_str()));//ADC生データ送信
Wire.write("\n");//改行コード送信
msg="";
}
//マスターからデータ読み取り
void onReceive(int len)
{
}
void setup()
{
//電圧入力ピン設定
for(int i=0;i<9;i++){
pinMode(adc_ch[i],INPUT);
}
//アナログ入力12bit(0~4095)設定
analogReadResolution(12);
//I2Cスレーブの設定
Wire.onReceive(onReceive); //マスターからデータを受信したときに呼び出される関数の登録
Wire.onRequest(onRequest); //マスターからデータを要求されたときに呼び出される関数の登録
Wire.begin((uint8_t)I2C_DEV_ADDR); //スレーブとしてのアドレス設定
}
void loop()
{
}
参考にさせていただいたサイト
文字列を区切り文字で分割:https://algorithm.joho.info/arduino/string-split-delimiter/
OLEDディスプレイ表示:http://zattouka.net/GarageHouse/micon/Arduino/XIAO/ExpansionBoard/DevelopedArduino1.htm
マイコン同士のI2C通信:http://tamanegi.digick.jp/computer-embedded/communication/i2c-mcu-to-mcu/