TRYGEAR-AVRのArduinoプログラミング

はじめに

Arduino UNOの形状とコネクタ配置に準拠し、稼働電圧を3.3Vに設定し、最近のセンサーやディスプレイを電圧変換回路を追加することなく直接接続できるTRYGEAR-AVRでのArduinoプログラミングを紹介します。

Arduino IDEのボード選択

TRYGEAR-AVRとUNO-TRYGEAR-STACKの利用環境の整備では、Arduino IDEに標準実装されている純正のツールチェーン(コンパイラや書き込みツール)をそのまま利用可能なのが大きな特徴であり利点です。Arduino IDEがすでにインストールされているPCならば、追加のツール等のインストールは必要ありません。

学校のPC演習室などで導入する際も、アカウント権限の制限等でトラブルになりがちな「専用ドライバーやサードパーティ製ツールの追加インストール」が一切不要です。

TRYGEAR-AVR

[ツール]->[ボード]->[Arduino AVR Boards]から[Arduino Pro orPro Mini]を選択してください。すると[ツール]メニューの下の方に[Processor: xxxx]というメニューが出てくるので、[ATmega328P (3.3V, 8MHz)]を選択してください。

UNO-TRYGEAR-STACK

ベースに使用しているUNO R3/R4をいつも通り選択してください。

端子の機能表

端子番号デジタル端子名アナログ端子名機能名機能補足
0D0-RX
1D1-TX
2D2-SW1タクトスイッチ1プルアップなし
3D3-SW2タクトスイッチ2PWM, プルアップなし
4D4-SW3タクトスイッチ3プルアップなし
5D5-LED2, SRV1, DACPWM, LEDでプルダウン
6D6-LED3, SRV2, RGBPWM, LEDでプルダウン
7D7-
8D8-
9D9-PWM
10D10-TFT_CSSPI/CS
11D11-TFT_MOSISPI/MOSIPWM
12D12-TFT_MISOSPI/MISO
13D13-TFT_SCK, LED1SPI/SCK
14D14A0
15D15A1
16D16A2SPK圧電スピーカー
17D17A3TFT_DC
18D18A4I2C/SDASDA
19D19A5I2C/SCLSCL
--A6
--A7

端子名を定義した互換ヘッダー TRYGEAR.h

TRYGEAR-AVRとUNO-TRYGEAR-STACKを装着したArduino UNO R3/R4で、共通で利用できるTRYGEAR.hを示します。

#if defined(ARDUINO_AVR_PRO)
// TRYGEAR-AVR
//#pragma message "TRYGEAR-AVR"

#if (F_CPU != 8000000L)
#error "クロック設定エラー"
#endif

#define SW1 2
#define SW2 3
#define SW3 4

#define SRV1 5
#define LED2 5
#define DAC 5
#define SRV2 6
#define LED3 6
#define RGB 6

#define LED1 13
#define SPK 16

#define TFT_DC 17
#define TFT_CS 10
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_SCK 13

#else
// UNO-TRYGEAR-STACK
//#pragma message "UNO R3/R4 with UNO-TRYGEAR-STACK"

#define SW1 2
#define SW2 3
#define SW3 4

#define SRV1 5
#define LED2 5
#define DAC 5
#define SRV2 6
#define LED3 6
#define RGB 6

#define LED1 13
#define SPK 9

#define TFT_DC 8
#define TFT_CS 10
#define TFT_MOSI 11
#define TFT_MISO 12
#define TFT_SCK 13

#endif

プログラム例

スイッチとLED

SW1,SW2,SW3を押すと、それぞれ対応するLEDが点灯するスケッチ例です。

#include "TRYGEAR.h"

void setup() {
  pinMode(SW1, INPUT_PULLUP) ;
  pinMode(SW2, INPUT_PULLUP) ;
  pinMode(SW3, INPUT_PULLUP) ;

  pinMode(LED1, OUTPUT) ;
  pinMode(LED2, OUTPUT) ;
  pinMode(LED3, OUTPUT) ;
}

void loop() {
  int hz = 0 ;

  if (digitalRead(SW1) == LOW)
     digitalWrite(LED1, HIGH) ;
  else
     digitalWrite(LED1, LOW) ;

  if (digitalRead(SW2) == LOW)
     digitalWrite(LED2, HIGH) ;
  else
     digitalWrite(LED2, LOW) ;

  if (digitalRead(SW3) == LOW)
     digitalWrite(LED3, HIGH) ;
  else
     digitalWrite(LED3, LOW) ;

  delay(100) ;
}

スイッチと圧電スピーカー

SW1,SW2,SW3を押すと、それぞれ異なる音を鳴らすスケッチ例です。

#include "TRYGEAR.h"

void setup() {
  pinMode(SW1, INPUT_PULLUP) ;
  pinMode(SW2, INPUT_PULLUP) ;
  pinMode(SW3, INPUT_PULLUP) ;
}

void loop() {
  int hz = 0 ;

  if (digitalRead(SW1) == LOW)
     hz += 220 ;
  if (digitalRead(SW2) == LOW)
     hz += 440 ;
  if (digitalRead(SW3) == LOW)
     hz += 880 ;

  if (hz != 0)
    tone(SPK, hz) ;
  else
    noTone(SPK) ;

  delay(100) ;
}

OLEDディスプレイでの文字表示

OLEDディスプレイに文字列を表示するスケッチ例を示します。

ここでは、コントローラとしてSSD1306が使用されているOLEDディスプレイを接続する例を示します。OLEDディスプレイの制御ライブラリは、様々なものが提供されていますが、ここではU8g2ライブラリを使用した例を示します。

U8g2 ライブラリの使用法は、以下のWEBページに紹介されています。

ライブラリマネージャを使用してU8g2ライブラリを導入して使用してください。

#include "TRYGEAR.h"

#include <U8x8lib.h>

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);

void setup() {
  u8x8.begin();
  u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
  u8x8.clearDisplay();
}

char tstr[20];

void loop() {
  u8x8.drawString(1, 0, "- TRYGEAR-AVR -");
  u8x8.drawString(4, 1, "MicroFan");
  u8x8.drawString(0, 2, "ATmega328P 3.3V");
  u8x8.drawString(1, 3, "SW x3, LED x3");
  u8x8.drawString(1, 4, "Piezo Speaker");
  u8x8.drawString(0, 5, "RC Servo Conn x2");
  u8x8.drawString(1, 6, "TFT/OLED Conn");
  u8x8.drawString(2, 7, "I2C Conn x2");
  delay(1000);

  u8x8.clearDisplay();
  delay(1000);
}

OLEDディスプレイでのグラフィックス表示

#include "TRYGEAR.h"

#include <U8g2lib.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

void setup(void) {
  u8g2.begin();
}

void loop(void) {
  int x, y, r;

  u8g2.clearBuffer();
  for (y = 0; y < 64; y += 8) {
    u8g2.drawLine(0, 0, 127, y);
  }
  for (x = 127; x > 0; x -= 8) {
    u8g2.drawLine(0, 0, x, 63);
  }
  u8g2.sendBuffer();
  delay(1000);

  u8g2.clearBuffer();
  for (y = 0; y < 64; y += 8) {
    u8g2.drawLine(0, 0, 127, y);
    u8g2.sendBuffer();
  }
  for (x = 127; x > 0; x -= 8) {
    u8g2.drawLine(0, 0, x, 63);
    u8g2.sendBuffer();
  }
  delay(1000);

  u8g2.clearBuffer();
  for (r = 5; r < 60; r +=2) {
    u8g2.drawCircle(64, 32, r);
    u8g2.sendBuffer();
  }
  delay(1000);

  u8g2.clearBuffer();
  u8g2.sendBuffer();
  delay(1000);
}

WS2812カラーLED

WS2812はNeoPixelライブラリで操作できます。

NeoPixelライブラリがインストールされると、メニューバーの[ファイル] -> [スケッチ例...]を選択すると、メニューの下の方の[カスタムライブラリのスケッチ例]の中にインストールされたNeoPixelライブラリに関する項目が追加されていることがわかります。

その項目を選択すると、いくつかのデモスケッチが表示されます。

カラーLEDの動作テストとしては、カラーLEDの鮮やかな色の変化を楽しめるstrandtestがよいでしょう。スケッチを開いたら、図に示す様に2つの定数をRGBLED-FUNXの接続に合わせて設定します。

#include "TRYGEAR.h"

strandtestをコンパイル・実行させると、RGBLED-FUNXのカラーLEDが、様々に色を変えながら点滅します。

#include "TRYGEAR.h"

#include <Adafruit_NeoPixel.h>
#define LED_COUNT  13
#define BRIGHTNESS  5 // Set BRIGHTNESS (max = 255)

Adafruit_NeoPixel strip(LED_COUNT, RGB, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);

  strip.setPixelColor(0, strip.Color(255,   0,   0));
  strip.setPixelColor(1, strip.Color(  0, 255,   0));
  strip.setPixelColor(2, strip.Color(  0,   0, 255));
  strip.setPixelColor(3, strip.Color(255, 255,   0));
  strip.setPixelColor(4, strip.Color(  0, 255, 255));
  strip.setPixelColor(5, strip.Color(255,   0, 255));
  strip.setPixelColor(6, strip.Color(255, 255, 255));
  strip.setPixelColor(7, strip.Color(255,   0,   0));
  strip.setPixelColor(8, strip.Color(  0, 255,   0));
  strip.setPixelColor(9, strip.Color(  0,   0, 255));
  strip.setPixelColor(10, strip.Color(255, 255,   0));
  strip.setPixelColor(11, strip.Color(  0, 255, 255));

  strip.setPixelColor(12, strip.Color(255,   255,   255));

  strip.show(); // Update strip with new contents
}

void loop() {
  // put your main code here, to run repeatedly:

}
#include "TRYGEAR.h"

#include <Adafruit_NeoPixel.h>
#define LED_COUNT  13
#define BRIGHTNESS 5 // max = 255

Adafruit_NeoPixel strip(LED_COUNT, RGB, NEO_GRB + NEO_KHZ800);

void setup() {
  strip.begin();           // INITIALIZE NeoPixel strip object (REQUIRED)
  strip.show();            // Turn OFF all pixels ASAP
  strip.setBrightness(BRIGHTNESS);

  pinMode(SW1, INPUT_PULLUP) ;
  pinMode(SW2, INPUT_PULLUP) ;
  pinMode(SW3, INPUT_PULLUP) ;
}

void loop() {
  int r = 0, g = 0, b = 0 ;

  if (digitalRead(SW1) == LOW)
     r = 255 ;
  if (digitalRead(SW2) == LOW)
     g = 255 ;
  if (digitalRead(SW3) == LOW)
     b = 255 ;

  strip.setPixelColor(0, strip.Color(127, 127, 127));
  strip.setPixelColor(6, strip.Color(  r,   g,   b));
  strip.setPixelColor(12, strip.Color( r,   g,   b));
  strip.show(); // Update strip with new contents
  delay(100) ;
}

気温・湿度・明るさセンサー

OLEDディスプレイにSENSOR-FUNXの気温・湿度センサーAHT21で得られた気温と湿度と、明るさセンサー(フォトトランジスタ)で得られた明るさを表示するスケッチ例を示します。

SENSOR-FUNXの気温・湿度センサーには、AHT21が使用されています。AHT21の制御には、AHT20用のライブラリを使用することができます。ここでは、Adafruit AHTX0ライブラリを使用した例を示します。ライブラリマネージャを使用してAdafruit AHTX0ライブラリを導入して使用してください。

#include "TRYGEAR.h"

#include <U8x8lib.h>
#include <Adafruit_AHTX0.h>

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);
Adafruit_AHTX0 aht;

void setup() {
  u8x8.begin();
  u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
  u8x8.clearDisplay();
  aht.begin(); // AHT21の初期化
}

char tstr[20];

void loop() {
  sensors_event_t humidity, temp;

  aht.getEvent(&humidity, &temp); // AHT21から湿度と温度の取得

  u8x8.draw1x2String(0, 0, "TEMP: ");
  dtostrf(temp.temperature, 4, 1, tstr);  // sprintf は実数の変換ができない
  u8x8.draw1x2String(6, 0, tstr);
  u8x8.draw1x2String(10, 0, "'C");
  sprintf(tstr, "%2d%%", (int)humidity.relative_humidity);
  u8x8.draw1x2String(0, 2, "HUM: ");
  u8x8.draw1x2String(5, 2, tstr);
  u8x8.draw1x2String(0, 4, "BRT: ") ;
  dtostrf(analogRead(7)/1023.0, 4, 2, tstr);  // sprintf は実数の変換ができない
  u8x8.draw1x2String(5, 4, tstr);

  delay(1000);
}

加速度センサー

OLEDディスプレイに3軸の加速度と、基板の傾きを表示するスケッチ例を示します。

SENSOR-FUNXの加速度センサーには、XKTJ3-1057が使用されています。ここでは、XKTJ3-1057ライブラリを使用した例を示します。ライブラリマネージャを使用してXKTJ3-1057ライブラリを導入して使用してください。

まずは文字で情報を表示するバージョンを示します。

#include <U8x8lib.h>

U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);

// Accelerometer provides different Power modes by changing output bit resolution
#define LOW_POWER
//#define HIGH_RESOLUTION

#include <kxtj3-1057.h>
#include <math.h>

float sampleRate = 6.25;  // HZ - Samples per second - 0.781, 1.563, 3.125, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600Hz
uint8_t accelRange = 2;   // Accelerometer range = 2, 4, 8, 16g

KXTJ3 myIMU(0x0E);  // Address can be 0x0E or 0x0F

void setup() {
  u8x8.begin();
  u8x8.setFont(u8x8_font_amstrad_cpc_extended_r);
  u8x8.clearDisplay();

  myIMU.begin(sampleRate, accelRange, true);
  // Detection threshold, movement duration and polarity
  myIMU.intConf(123, 1, 10, HIGH);
}

char tstr[20];

void loop() {
  float x, y, t ;

  u8x8.draw1x2String(0, 0, "X: ");
  dtostrf(x = myIMU.axisAccel(X), 6, 3, tstr);  // sprintf は実数の変換ができない
  u8x8.draw1x2String(3, 0, tstr);
  u8x8.draw1x2String(0, 2, "Y: ");
  dtostrf(y = myIMU.axisAccel(Y), 6, 3, tstr);
  u8x8.draw1x2String(3, 2, tstr);
  u8x8.draw1x2String(0, 4, "Z: ");
  dtostrf(myIMU.axisAccel(Z), 6, 3, tstr);
  u8x8.draw1x2String(3, 4, tstr);

  t = atan2(-y, x) * 180 / 3.14 ;
  u8x8.draw1x2String(0, 6, "DEG: ");
  dtostrf(t, 6, 1, tstr);
  u8x8.draw1x2String(5, 6, tstr);

  delay(200);
}

次に、傾きをグラフィックスで表示するバージョンを示します。

#include <U8g2lib.h>
#include <kxtj3-1057.h>
#include <math.h>

U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);

float sampleRate = 12.5;  // HZ - Samples per second - 0.781, 1.563, 3.125, 6.25, 12.5, 25, 50, 100, 200, 400, 800, 1600Hz
uint8_t accelRange = 2;   // Accelerometer range = 2, 4, 8, 16g

KXTJ3 myIMU(0x0E);  // Address can be 0x0E or 0x0F

void setup(void) {
  u8g2.begin();
  u8g2.setFont(u8g2_font_9x15_tr);

  myIMU.begin(sampleRate, accelRange, true);
  // Detection threshold, movement duration and polarity
  myIMU.intConf(123, 1, 10, HIGH);
}

char tstr[20];

void loop() {
  float x, y, t ;

  x = myIMU.axisAccel(X);
  y = myIMU.axisAccel(Y);

  u8g2.clearBuffer();

  t = atan2(-y, x) * 180 / 3.14 ;
  dtostrf(t, 6, 1, tstr);
  u8g2.drawStr(30, 50, tstr);
  u8g2.drawLine(64-x*32, 32+y*32, 64+x*32, 32-y*32);
  u8g2.drawCircle(64, 32, 32);

  u8g2.sendBuffer();

  delay(100);
}