こんにちは、ENGかぴです。
GroveモジュールのGrove-Thumb JoystickでスティックをX方向とY方向にスティックを回すと位置に応じたアナログ電圧を取得することができます。OLEDに取得したアナログ値を表示して動作確認を行いました。
OLEDは0.95インチ(HiLetgo製)を使用しています。Arduinoのライブラリを使用して動作確認したことをまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
以下では、Arduino UNOをArduinoと表記します。
Grove-Thumb Joystickを使用する
Grove-Thumb JoystickはSeeed Studioが製作しているGroveモジュールです。X方向とY方向にスティックを回すと操作位置に応じた電圧を出力します。詳細は下記のリンクを参考にしてください。
Grove – Thumb Joystick | Seeed Studio Wiki
ArduinoのアナログピンにGrove-Thumb Joystickの電圧を入力すると電圧値を取得することができます。本記事ではOLEDに取得したアナログ値とスティックの位置を座標に換算して表示します。
Grove-Thumb Joystickを以下ではジョイスティックとします。
PR:わからないを放置せず、あなたにあったスキルを身に着けるコツを教える テックジム 「書けるが先で、理解が後」を体験しよう!
モジュールの特性の確認

ジョイスティックのWikiページに標準値が記載されていますが、使用するモジュールによって中央値と最大/最小値は若干変化することから使用するモジュールの特性を確認します。
シリアルモニターにジョイスティックを±X方向と±Y方向に倒したときの値を表示して確認します。

X軸のシリアルモニターの結果と同様にしてY軸もシリアルモニターで値を確認しました。X軸とY軸の結果をまとめると以下の通りになりました。
軸 | 最小値(-側) | 中央値(操作なし) | 最大値(+側) |
---|---|---|---|
X軸 | 242 | 515 | 779 |
Y軸 | 258 | 513 | 764 |
シリアルモニタでの確認の結果から本記事で使用するジョイスティックの基準値はX軸:515、Y軸:513とします。これらの値は基準値及び最小値/最大値を使ってOLED表示用のジョイスティックの座標に換算に使用します。
X軸方向の基準値に対する最小値と最大値の振れ幅は-側で273+側で264と少しずれていますが平均すると268になるためX軸方向の振れ幅を±268とします。Y軸方向も同様にして最大の振れ幅を±253とします。
アナログ値をフィルタリングする
void TimerCnt(void){
uint8_t i;
uint16_t sumx=0;
uint16_t sumy=0;
meas.bufx[meas.wp] = analogRead(JOY_AO_X); //X軸の値を取得
meas.bufy[meas.wp] = analogRead(JOY_AO_Y); //Y軸の値を取得
if( ++meas.wp >= AIFILT_MAX ){ //保管先を更新
meas.wp = 0;
}
for( i=0; i < AIFILT_MAX; i++ ){ //平均をとるため合計値を算出
sumx += meas.bufx[i];
sumy += meas.bufy[i];
}
meas.x = sumx / AIFILT_MAX; //平均値を計算
meas.y = sumy / AIFILT_MAX; //平均値を計算
}
アナログ値は外来ノイズの影響を受けるため取得したデータを平均化(ローパスフィルタの効果)して使用します。
TimerInt()関数は10ms毎にタイマー割り込みでコールされる自作の関数です。アナログ値のサンプリングタイミングを一定に保つため割り込みでアナログ値の取得と平均値を計算します。
analogRead()関数は引数で指定したピンのアナログ変換値を取得します。X軸、Y軸のアナログ値をそれぞれmeas.bufx[]、meas.bufy[]に格納します。
meas.wpはmeas.bufx[]及びmeas.bufy[]の配列にアナログ値を格納する場所を示したポインタ値です。meas.wpを更新することで配列に順番にアナログ値を格納します。
アナログ値の平均値を計算するため配列の合計値を計算し、配列の数(AIFILT_MAX)で割っています。meas.xとmeas.yに平均値を格納しアナログ値として使用します。
OLEDライブラリを使用する
HiLetgo製の0.95インチ7ピン 65kカラー対応のOLEDディスプレイモジュールを使用しています。通信方式は3線のSPI通信を使用します。下記リンクにモジュールに関する情報が記載されています。
0.95″ Inch 7 Pin Colorful 65K SPI OLED Display Module
OLED用のドライバーICはSSD1331でありArduino環境に対応しているのでライブラリを追加して文字や記号を表示することができます。Arduino IDEでライブラリを追加して使用する方法を説明します。
Adafruit SSD1331 OLED Driverライブラリを追加する

Arduino IDEのライブラリマネージャの検索欄にssd1331を入力するとライブラリの候補が表示されます。候補の中から「Adafruit SSD1331 OLED Driver Library for Arduino」をインストールします。
インストールする際にライブラリの依存関係をインストールするかを尋ねられることがあります。ライブラリの依存関係が不足しているとうまく動作しないことがあるためすべてをインストールすることをお勧めします。
OLEDライブラリの使用例
#include <Adafruit_SSD1331.h>
#define cs 10 //チップセレクト
#define rst 9 //リセット
#define dc 8 //DATA COMMAND
#define BLACK 0x0000
Adafruit_SSD1331 oled = Adafruit_SSD1331(&SPI, cs, dc, rst);
void setup() {
oled.begin();
oled.fillScreen(BLACK);
}
Adafruit_SSD1331.hをインクルードします。Adafruit_SSD1331クラスの変数としてoled(任意でよい)をインスタンス化します。第1引数にSPIクラスの変数のアドレスを指定します。Arduino環境ではSPIが標準で定義されているのでSPIを指定します。
第2引数にチップセレクトで使用するピン番号を指定します。
第3引数にData/Commandピン番号を指定します。SPI通信を3線で行うためData/Commandピンでデータの方向を選択して送受信します。
第4引数にRESピン番号を指定します。RESピンはHIGHにするとモジュールのリセットを解除します。LOWにするとリセット状態になります。
setup()内でAdafruit_SSD1331クラスのメンバー関数であるbegin()関数でOLEDの初期化を行います。fillScreen()関数は画面全体のカラーを指定した色で塗りつぶします。例ではBLACK(0x0000)を指定しています。色の指定は16bitデータ(0~65535の範囲)で行います。
oled.setTextSize(1); //5×7フォント
oled.setCursor(5, 10);
oled.setTextColor(RED); //テキストの色を指定
oled.print("X:");
oled.setCursor(10, 20);
oled.print(meas.x);
setTextSize()関数でフォントの大きさを指定します。1を指定すると5×7のフォントになります。2以上を指定すると1のフォント基準に倍数したフォントになります。0を指定すると1と同じフォントになります。
setCursor()関数で文字表示する座標を指定します。第1引数にX座標、第2引数にY座標を指定します。座標はピン側を上に見た時OLEDの左上の座標が(X,Y)=(0,0)になります。
setTextColor()関数はテキストの色を指定します。16ビットの値で色を指定します。
print()関数で文字を書き込んで表示します。例ではX:を表示後カーソルを移動してアナログ値を文字列で出力しています。次にジョイスティックの位置を表示する図形の表示方法を説明します。
oled.drawRect(40, 5, 50, 50, WHITE );
oled.drawCircle(65, 30, 24, YELLOW);
oled.drawLine(35, 30, 95, 30, WHITE);
oled.drawLine(65, 0, 65, 60, WHITE);
x = (meas.x - BASE_VALUE_X);
y = (meas.y - BASE_VALUE_Y);
x /= 11;
y /= 10;
oled.fillCircle(65+x, 30-y, 3, MAGENTA);
drawRect()関数は四角形を描きます。第1引数にX座標、第2引数にY座標、第3引数に幅、第4引数に高さ、第5引数に色を指定します。
drawCircle()関数は円を描きます。第1引数に円の中心のX座標、第2引数に円の中心のY座標、第3引数に円の半径、第4引数に円の色を指定します。
drawLine()関数は基準のポイントから次点のポイントまで線を描きます。第1引数に基準のX座標、第2引数に基準のY座標、第3引数に次点のX座標、第4引数に次点の座標、第5引数に色を指定します。
ジョイスティックの操作位置を表示するため図形の大きさに合わせてアナログ値の換算を行います。モジュールの特性の確認の結果からX軸方向の最大振れ幅は±268程度となります。図形中の半径を25としているので、この範囲に収めるため11で割った商を図形中での座標の指定に使用します。
同様にY軸方向の基準からのアナログ値の最大振れ幅は±253程度であり半径の25の範囲に収めるため10で割った商を図形中での座標の指定に使用します。
fillCircle()関数は円の中心の座標から指定する半径の塗りつぶしの円を描きます。第1引数に円の中心のX座標、第2引数に円の中心のY座標、第3引数に円の半径、第4引数に色を指定します。例では図形の中心座標に換算したアナログ値を加えて円の中心座標を表示しています。
ジョイスティックを操作するとアナログ値が更新されるため図形中を円が移動しているように表示できます。
動作確認

OLEDはSPI通信を3線式で行うためArduinoのMISO(12ピン)は使用しません。MOSI(11ピン)で送信と受信をDCピンでデータとコマンドを切り替えながら通信を行います。RESピンはリセットを使用しない場合はHIGHに固定しても問題ありません。CSピンはLアクティブとなるのでモジュールを常に使用する場合はLOWに固定しても問題ありません。
ArduinoのボードにGrove端子がないためワイヤーでGrove端子とArduinoを接続しました。
電源を入れるとOLEDにジョイスティックから取得したX軸及びY軸のアナログ値を表示します。ジョイスティックを操作すると図形上の円が移動します。

ジョイスティックを+X,+Y方向に最大になるように操作すると図形の右上に円が表示されます。また-X,-Y方向に最小になるように操作すると図形の左下に円が表示されます。
ソースコード全体
ソースコードは記事作成時点において動作確認できていますが、使用しているライブラリの更新により動作が保証できなくなる可能性があります。また、ソースコードを使用したことによって生じた不利益などの一切の責任を負いかねます。参考資料としてお使いください。
リンクからZIPファイル形式のファイルをダウンロードし、任意の場所に展開していただくとテキストファイルが生成されます。
関連リンク
Arduinoのライブラリを使って動作確認を行ったことを下記リンクにまとめています。
Arduinoで学べるマイコンのソフト開発と標準ライブラリの使い方
Seeeduino XIAOで学べるソフト開発と標準ライブラリの使い方
ESP32-WROOM-32Eで学べるソフト開発と標準ライブラリの使い方
最後まで、読んでいただきありがとうございました。
私が使用しているOLEDモジュールは初期不良なのか分かりませんが、モニターの中央部の液晶が変色しており、変色している部分の色が表現できなかったのが残念でした。OELDの表示の中央部付近の白色の線が青味が強く出ています。