フォト
2017年9月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
無料ブログはココログ

arduino

2017年9月20日 (水)

グラフィック描画まわりの実装に苦戦

ここ数日、手がけている豊四季Tiny BASIC for ArduinoのOLED(SSD1309)利用
グラフィックスクロール処理の実装ではまっていました。

画面の向き(縦横の変更)を変えることが出来て、各画面の向きに応じて
画面の任意矩形領域の上下左右1ドット単位スクロールを行うというコマンドの実装です。

いきなりコーディングしていたのですが、上手く動かず。
それで、机上で図やなりやらを書いて、変換式を求めて再度実装すると
期待通りの動きが出来ました。

やはり、コーディング => 実行 => 修正の繰り返しの試行錯誤で「何となく動いた」ではなく
ちぇんとロジックと方式を検討してからコードを書かないとだめですね。効率的にも..

Dscn7032

具体的な数値の変換例から、抽象的な数式を求めて一般化しました。

とりあえず、GSCROLLコマンドが実装出来ました。


デモ動画では全画面スクロールですが、画面上の任意の矩形領域のスクロールも可能です。
あまり用途の無いコマンドですが、まあいいでしょう^^

OLEDだと、スクロールしても残像もなくっ切り表示ですね。
手持ちのモノラルグラフィック液晶はもう、使いたくなくなります。


動画の動作確認のプログラムはつぎのような感じです。

10 'GSCROLL TEST
20 FOR R=0 TO 3
30 SCREEN 1,R
40 FOR D=0 TO 3
50 GOSUB "@DISP"
60 FOR I=1 TO 8
70 GSCROLL 0,0,GW-1,GH-1,D
80 WAIT 200
90 NEXT I
100 NEXT D
110 NEXT R
120 SCREEN 1
130 END
140 "@DISP"
150 CLS:GPRINT 10,10,"GSCROLL"
160 GPRINT 0,0,"A"
170 GPRINT GW-7,0,"B"
180 GPRINT 0,GH-9,"C"
190 GPRINT GW-7,GH-9,"D"
200 RETURN

2017年9月15日 (金)

豊四季 Tiny BASIC でOLEDとグラフィック液晶の対応

現在取り組んでいる豊四季 Tiny BASIC for Arduino STM32、
OLEDディスプレイとグラフィック液晶対応を行っています。

そこそこ、動作するようになってきました。

Dscn7017

OLED (SH1106コントローラ I2C接続)ディスプレイ利用のデモ

TFTグラフィック液晶(ILI9341コントローラ SPI接続)パネル利用のデモ


表示系は、NTSC、ターミナルコンソール、グラフィック液晶、OLEDと複数対応するために
プログラム的には基本クラスを設けて、派生する形で各表示器対応の実装をしています。

ただし、クラス設計が今一だったため、実装が進むにつれて、
非常に分かりにくいプログラムになってしまいました。

思うがままに、機能追加していった割には、良く動いているなぁ



2017年9月14日 (木)

Windowsストア版 Arduino IDEは自動アップデートされる

Windowsストア版 Arduino IDEを起動したら、いつの間にか 1.8.4にアップデートされていました。
常に最新版を利用したい場合には、Windowsストア版の方が良さそうです。


01

2017年9月12日 (火)

SH1106コントローラ使用OLED用ライブラリの作成

以前購入した 次の1.3インチのOLEDモジュール(I2C版とSPI版)、

I2Cインタフェース版
1.3" OLED module white color 128X64 1.3 inch OLED Display Module 1.3" I2C Communicate

02

SPIインタフェース版
1.3" OLED module white color 128X64 1.3 inch OLED Display Module 1.3"  SPI Communicate
03

SH1106というコントローラーが乗っているのですが、Arduino STM32用のライブラリがありません。
そこで、公開されている次のAdafruitベースのライブラリを参考にして作成しました。
(正確には移植ですね^^)

https://github.com/wonho-maker/Adafruit_SH1106
ttps://github.com/rogerclarkmelbourne/Arduino_STM32/tree/master/STM32F1/libraries/Adafruit_SSD1306


SH1106というコントローラーはほぼSSD1306コマンド等はにており、
wonho-makerさんが作成公開しているArduino用のSH1106利用ライブラリの参考にして
Arduino STM32版 SSD1306利用ライブラリを修正しました。
(wonho-makerさんに感謝!)

SSD1306ではSPIのクロック速度が10MHzくらいまでしか出せなかったのですが、
SH1106ではBlue Pillボードで出せる最高速度の36MHzでも動作しました。

作成したライブラリは下記にて公開しました。
https://github.com/Tamakichi/Adafruit_SH1106_STM32


サンプルスケッチを動かした様子
左がSPI版、右がI2C版です。

01

SSD1306とほぼ同じ動作ですが、スクロール機能は未対応です。

2017年9月 4日 (月)

キーボードの作成 その2

前回の続きです。

64キーを次のような感じに割り付けました。
64キーだと足りないため、Fnキーを押すことで、ファンクションキー等の水色キーが
入力できます。

01

押したボタン入力は、PS/2キーボード I/Fの信号に変換します。
とりあえず、IchigoJamにて利用出来ることを確認しました。

Dscn6955

PS/2 キーボードのエミュレーションは ps2devライブラリを利用しました。
・PS2 mouse interface for Arduino
  http://playground.arduino.cc/ComponentLib/Ps2mouse

スケッチは次のような感じです。
Fnキーの処理とキーの長押し時のリピート処理がちょっと面倒でした。

(2017/9/6 スケッチを修正しました)

#include <Arduino.h>
#include <ps2dev.h>

#define KB_CLK      9  // PS/2 CLK  IchigoJamのKBD1に接続
#define KB_DATA     10 // PS/2 DATA IchigoJamのKBD2に接続

#define SOUT_PIN   2 // シリアルアウト
#define CLK_PIN    3 // クロック
#define LATCH_PIN  4 // ラッチ
#define SCN1_PIN   5 // ライン1
#define SCN2_PIN   6 // ライン2
#define SCN3_PIN   7 // ライン3
#define SCN4_PIN   8 // ライン4

#define KEY_NUM 64 // キー数
// キーリピートの定義
#define REPEATTIME      5   // キーを押し続けて、REP_INTERVALxREPEATTIMEmsec後にリピート開始
#define EMPTY           0   // リピート管理テーブルが空状態
#define MAXKEYENTRY     64  // リピート管理テーブルサイズ
#define REP_INTERVAL    10  // リピート間隔 100msec

PS2dev keyboard(KB_CLK, KB_DATA); // PS/2デバイス

// スキャンコードテーブル
const uint8_t scan_table[][4] =  {
 {  0x76,0x00  ,  0x05,0x00  ,  },  // 0 ESC
 {  0x16,0x00  ,  0x06,0x00  ,  },  // 1 1
 {  0x1E,0x00  ,  0x04,0x00  ,  },  // 2 2
 {  0x26,0x00  ,  0x0C,0x00  ,  },  // 3 3
 {  0x25,0x00  ,  0x03,0x00  ,  },  // 4 4
 {  0x2E,0x00  ,  0x0B,0x00  ,  },  // 5 5
 {  0x36,0x00  ,  0x83,0x00  ,  },  // 6 6
 {  0x3D,0x00  ,  0x0A,0x00  ,  },  // 7 7
 {  0x3E,0x00  ,  0x01,0x00  ,  },  // 8 8
 {  0x46,0x00  ,  0x09,0x00  ,  },  // 9 9
 {  0x45,0x00  ,  0x78,0x00  ,  },  // 10 0
 {  0x4E,0x00  ,  0x07,0x00  ,  },  // 11 -
 {  0x55,0x00  ,  0x00,0x00  ,  },  // 12 ^
 {  0x6A,0x00  ,  0x00,0x00  ,  },  // 13 ¥
 {  0xE0,0x6C  ,  0xE0,0x70  ,  },  // 14 Home
 {  0x66,0x00  ,  0xE0,0x71  ,  },  // 15 BS
 {  0x29,0x00  ,  0x0D,0x00  ,  },  // 16 Space
 {  0x15,0x00  ,  0x6C,0x00  ,  },  // 17 q
 {  0x1D,0x00  ,  0x75,0x00  ,  },  // 18 w
 {  0x24,0x00  ,  0x7D,0x00  ,  },  // 19 e
 {  0x2D,0x00  ,  0x7B,0x00  ,  },  // 20 r
 {  0x2C,0x00  ,  0xE0,0x4A  ,  },  // 21 t
 {  0x35,0x00  ,  0x00,0x00  ,  },  // 22 y
 {  0x3C,0x00  ,  0x00,0x00  ,  },  // 23 u
 {  0x43,0x00  ,  0x00,0x00  ,  },  // 24 i
 {  0x44,0x00  ,  0x00,0x00  ,  },  // 25 o
 {  0x4D,0x00  ,  0x00,0x00  ,  },  // 26 p
 {  0x54,0x00  ,  0x00,0x00  ,  },  // 27 @
 {  0x5B,0x00  ,  0x00,0x00  ,  },  // 28 [
 {  0x00,0x00  ,  0x00,0x00  ,  },  // 29 Fn
 {  0xE0,0x69  ,  0x00,0x00  ,  },  // 30 End
 {  0x59,0x00  ,  0x00,0x00  ,  },  // 31 RghtShift
 {  0x12,0x00  ,  0x58,0x00  ,  },  // 32 LeftShift
 {  0x1C,0x00  ,  0x6B,0x00  ,  },  // 33 a
 {  0x1B,0x00  ,  0x73,0x00  ,  },  // 34 s
 {  0x23,0x00  ,  0x74,0x00  ,  },  // 35 d
 {  0x2B,0x00  ,  0x79,0x00  ,  },  // 36 f
 {  0x34,0x00  ,  0x7C,0x00  ,  },  // 37 g
 {  0x33,0x00  ,  0x00,0x00  ,  },  // 38 h
 {  0x3B,0x00  ,  0x00,0x00  ,  },  // 39 j
 {  0x42,0x00  ,  0x00,0x00  ,  },  // 40 k
 {  0x4B,0x00  ,  0x00,0x00  ,  },  // 41 l
 {  0x4C,0x00  ,  0x00,0x00  ,  },  // 42 ;
 {  0x52,0x00  ,  0x00,0x00  ,  },  // 43 :
 {  0x5D,0x00  ,  0x00,0x00  ,  },  // 44 ]
 {  0xE0,0x71  ,  0x00,0x00  ,  },  // 45 PageUp
 {  0xE0,0x75  ,  0x00,0x00  ,  },  // 46 ↑
 {  0xE0,0x7A  ,  0x00,0x00  ,  },  // 47 PageDown
 {  0x14,0x00  ,  0x13,0x00  ,  },  // 48 LeftCtrl
 {  0x1A,0x00  ,  0x69,0x00  ,  },  // 49 z
 {  0x22,0x00  ,  0x72,0x00  ,  },  // 50 x
 {  0x21,0x00  ,  0x7A,0x00  ,  },  // 51 c
 {  0x2A,0x00  ,  0x70,0x00  ,  },  // 52 v
 {  0x32,0x00  ,  0x71,0x00  ,  },  // 53 b
 {  0x31,0x00  ,  0x00,0x00  ,  },  // 54 n
 {  0x3A,0x00  ,  0x00,0x00  ,  },  // 55 m
 {  0x41,0x00  ,  0x00,0x00  ,  },  // 56 ,
 {  0x49,0x00  ,  0x00,0x00  ,  },  // 57 .
 {  0x4A,0x00  ,  0x00,0x00  ,  },  // 58 /
 {  0x51,0x00  ,  0x00,0x00  ,  },  // 59 ¥
 {  0x5A,0x00  ,  0x00,0x00  ,  },  // 60 Enter
 {  0xE0,0x6B  ,  0xE0,0x2F  ,  },  // 61 ←
 {  0xE0,0x72  ,  0xE0,0x1F  ,  },  // 62 ↓
 {  0xE0,0x74  ,  0x11,0x00  ,  },  // 63 →
};            

uint8_t lines[] = { SCN1_PIN, SCN2_PIN, SCN3_PIN, SCN4_PIN }; 
uint16_t scn[4];        // キーボード状態
uint16_t prev_scn[4];   // 前回のキーボード状態
uint8_t enabled =0;               // PS/2 ホスト送信可能状態
uint8_t keyentry[MAXKEYENTRY];    // リピート管理テーブル
uint8_t repeatWait[MAXKEYENTRY];  // リピート開始待ち管理テーブル

// PS/2 ホストにack送信
void ack() {
  while(keyboard.write(0xFA));
}

// PS/2 ホストから送信されるコマンドの処理
int keyboardcommand(int command) {
  unsigned char val;
  uint32_t tm;
  switch (command) {
  case 0xFF:  ack();// Reset: キーボードリセットコマンド。正しく受け取った場合ACKを返す。
    //keyboard.write(0xAA);
    break;
  case 0xFE: // 再送要求
    ack();
    break;
  case 0xF6: // 起動時の状態へ戻す
    //enter stream mode
    ack();
    break;
  case 0xF5: //起動時の状態へ戻し、キースキャンを停止する
    //FM
    enabled = 0;
    ack();
    break;
  case 0xF4: //キースキャンを開始する
    //FM
    enabled = 1;
    ack();
    break;
  case 0xF3: //set typematic rate/delay : 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xF2: //get device id : 
    ack();
    keyboard.write(0xAB);
    keyboard.write(0x83);
    break;
  case 0xF0: //set scan code set
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  case 0xEE: //echo :キーボードが接続されている場合、キーボードはパソコンへ応答(ECHO Responce)を返す。
    //ack();
    keyboard.write(0xEE);
    break;
  case 0xED: //set/reset LEDs :キーボードのLEDの点灯/消灯要求。これに続くオプションバイトでLEDを指定する。 
    ack();
    keyboard.read(&val); //do nothing with the rate
    ack();
    break;
  }
}

//
// PS/2 makeコード送信
// 引数 index    : キーライン   0 ~ 3
//      no       : ライン内番号 0 ~ 15
//      flgFnKey : Fnキーの状態 0 or 1
//
void sendKeyMake(uint8_t index, uint8_t no, uint8_t flgFnkey) {
  uint8_t code1,code2;
  
  // キーコードの取得
  if (flgFnkey) {
    code1 = scan_table[index*16+no][2];
    code2 = scan_table[index*16+no][3];
  } else {
    code1 = scan_table[index*16+no][0];
    code2 = scan_table[index*16+no][1];
  }

  // PS/2キーの発行
  if (code2 == 0) {
    keyboard.write(code1);
  } else {
    keyboard.write(code1);
    keyboard.write(code2);    
  }
}

//
// PS/2 breakコード送信
// 引数 index    : キーライン   0 ~ 3
//      no       : ライン内番号 0 ~ 15
//      flgFnKey : Fnキーの状態 0 or 1
//
void sendKeyBreak(uint8_t index, uint8_t no, uint8_t flgFnkey) {
  uint8_t code1,code2;

  // キーコードの取得
  if (flgFnkey) {
    code1 = scan_table[index*16+no][2];
    code2 = scan_table[index*16+no][3];
  } else {
    code1 = scan_table[index*16+no][0];
    code2 = scan_table[index*16+no][1];
  }

  // PS/2キーの発行
  if (code2 == 0) {
    keyboard.write(0xF0);
    keyboard.write(code1);
  } else {
    keyboard.write(code1);
    keyboard.write(0xF0);
    keyboard.write(code2);    
  }
}

// リピート処理(タイマー割り込み処理から呼ばれる)
void sendRepeat() {
  uint8_t index,no,flgFnKey;
  uint8_t key;
  
  for (uint8_t i=0; i < MAXKEYENTRY; i++) {
    if (keyentry[i] != EMPTY) {
      if (repeatWait[i] == 0) {
        key = keyentry[i]; 
        flgFnKey = key & 0x80 ? 1:0;
        no = key % 16;
        index = (key & 0x7F)/16;      
        sendKeyMake(index,no,flgFnKey);
    } else {
        repeatWait[i]--;          
      }
    }
  }
}

// キーボード状態の取得
void getKeyCode() {
  uint16_t clm = 0x0001;  
  memset(scn, 0, 8);
  for (uint8_t i=0; i < 16; i++) {
    digitalWrite(LATCH_PIN, LOW);
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~clm & 0xff );
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~(clm>>8) & 0xff ); 
    digitalWrite(LATCH_PIN, HIGH);     
    for (uint8_t j=0; j <4; j++) {
        scn[j]<<=1;
        scn[j] |= digitalRead(lines[j]);
     }
     clm<<=1;  
  }
}

// スキャンコードの送信
void sendScanCode() {
  uint8_t scn_bit;      // 現在の状態
  uint8_t prev_scn_bit; // 前回の状態
  uint8_t flgFnKey;     // Fnキーの状態
  uint8_t prevflgFnKey; // Fnキーの状態

  // Fnキーのチェック
  flgFnKey = scn[1]&(0x8000>>13) ? 0:1; 
  prevflgFnKey = prev_scn[1]&(0x8000>>13) ? 0:1; 
  
  for (uint8_t i=0; i < 4; i++) {
    for (uint8_t j=0; j < 16; j++) {     
      scn_bit = scn[i]&(0x8000>>j) ? 0:1;
      prev_scn_bit = prev_scn[i]&(0x8000>>j) ? 0:1;

      // Fnキーの場合
      if (i==1 && j==13) {
        continue;
      }

      // 前回から状態が変化しているキーの処理 
      if (scn_bit != prev_scn_bit) {
        if (scn_bit) {
          // キーが押された
          sendKeyMake(i, j, flgFnKey);
          if ( !(i == 2 && j == 0) &&  !(i == 1 && j == 15)) {
            addKey(i, j, flgFnKey);
          }       
        } else {
          // キーが離された
          sendKeyBreak(i, j, flgFnKey);
          if ( !(i == 2 && j == 0) && !(i == 1 && j == 15)) {
            delKey(i, j, flgFnKey);
          }
        }
      } else {
        if (scn_bit && flgFnKey != prevflgFnKey){
          // キーを押している状態でFnキーが切り替わった
          sendKeyBreak(i, j, prevflgFnKey);
          if ( !(i == 2 && j == 0) && !(i == 1 && j == 15)) {
            delKey(i, j, prevflgFnKey);
            sendKeyMake(i, j, flgFnKey);
            addKey(i, j, flgFnKey);
          }
        }
      }
    }
  }
}

// リピート管理テーブルのクリア
void claerKeyEntry() {
 for (uint8_t i=0; i <MAXKEYENTRY; i++)
    keyentry[i] = EMPTY;
}

// リピート管理テーブルにキーを追加
void addKey(uint8_t index, uint8_t no, uint8_t flgFnkey) {
 uint8_t key = index*16+no | (flgFnkey ? 0x80:0);
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == EMPTY) {
    keyentry[i] = key;  
    repeatWait[i] = REPEATTIME;
    break;
  }
 }
}

// リピート管理テーブルからキーを削除
void delKey(uint8_t index, uint8_t no, uint8_t flgFnkey) {
 uint8_t key = index*16+no | (flgFnkey ? 0x80:0);
 for (uint8_t i=0; i <MAXKEYENTRY; i++) {
  if (keyentry[i] == key) {
    keyentry[i] = EMPTY;
    //break;
  }
 }  
}

void setup() {
  Serial.begin(115200);
  pinMode(SOUT_PIN,  OUTPUT);
  pinMode(CLK_PIN,   OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);  
  pinMode(SCN1_PIN,  INPUT_PULLUP);  
  pinMode(SCN2_PIN,  INPUT_PULLUP);  
  pinMode(SCN3_PIN,  INPUT_PULLUP);  
  pinMode(SCN4_PIN,  INPUT_PULLUP); 

  while(keyboard.write(0xAA)!=0);  
  while(keyboard.write(0x00)!=0);
  
  claerKeyEntry();
  memset(scn, 0xff, 8);
  Serial.println(F("Start."));
}

void loop() {
  static uint32_t tm = 0;
  unsigned char c;  // ホストからの送信データ
  if( (digitalRead(KB_CLK)==LOW) || (digitalRead(KB_DATA) == LOW)) {
    while(keyboard.read(&c)) ;
    keyboardcommand(c);
  } 

  for (uint8_t i=0; i <4; i++)  prev_scn[i] = scn[i];    
  getKeyCode();
  sendScanCode();

  //キーリピート処理
  if (millis() >= tm+100) {
    sendRepeat();
    tm = millis();
  }
}

一点、問題が発覚。
なぜか、同じライン(横一列)の同時入力が出来ません。
シフトキーとの同時押しが出来ないのはちょっと問題です。
ハードウェア的には可能なはずなのですが.. ソフト的な問題?
原因調査中です。

2017/09/05 追記
スイッチを2つにて単純化して検証。
結線して確認しました(左側の回路図)。

K1のボタンを押すとLEDが点灯しますが、K2を同時に押すとVCC→K2→K1→GNDの経路で、

電流が流れてしまいショートしてしまいます。
これはちょっとまずいですね。

右の回路のようにダイオードを入れて対応するしかなさそうです。
このタクトスイッチモジュール、そのまま使うには問題ありですね。
安いですが、あまりお手軽に利用出来ないようです。

回路図

配線もちょっとめんどくさくなりますね。

全体をダイオードを追加する回路図に修正しましました。

01_3

端子を基板に乗せられるものに変更し、実装し直しました。

Dscn6964

再度、IchigoJamに接続して動作確認

Dscn6968

同時押しも出来るようになりました。

Dscn6967

このサイズのキーボード、意外と使い心地良さそうです。
現時点ではArduinoを使っていますが、Atmega328マイコンに置き換えて、
基板実装すれば、小型化は出来ると思います。

キーの刻印を何としたいですね。方法をちょっと考えてみます。

2017/09/09追記

結局、タクトスイッチを基板に並べ5行、12列の60キーで実装することにしました。
キーの刻印は、基板にシールを貼る形にします。

手持ちのタクトスイッチでは足りないため、手ごろな製品をAliexpressにて見つけて発注しました。

100個 $0.79の激安タクトスイッチ 試作に使うにはこれで良いでしょう

07

2ピンタイプのタクトスイッチ 100個 $1.57 はんだ付け楽になるが強度不足になるかも

05

2ピンタイプで通常の1/2幅 100個 $1.50 空いたスーペースにキーの刻印表記出来そう

06

ボタン部分の素材がシリコン 100個 $4.90 (多く買うと割引) 押し心地がよさそう

08

キーが5行×12列の場合、キーの状態をスキャンする端子は17本となります。
これとは別に、PS/2 IF に2本、シリアル通信 2本が必要で合計で21本が必要。

ATmega328をArduinoとして利用する場合、最大22本をデジタル入出力で利用出来ます。
そうすると、シフトレジスタ無しで直接制御も出来そうですね。
結線もさらに簡略化出来ると思います。
1本余るので状況に応じて、1列または1行分キーの追加も出来ます。






2017年8月30日 (水)

キーボードの作成 その1

豊四季 Tiny BASIC for Arduino STM32用やIchigoJamで利用出来る
小型キーボードを作成しよう思いつき、到着したタクトスイッチを調査しました。

1個 $0.66の製品を6個注文

03

到着したのがこれです。

Dscn6929

回路図不明のため、テスターで調べてみると、次のような感じになっているようです。
抵抗等の部品は無く、単純な4x4のマトリックスです。
04

押されているボタンを判定するには、
1~4に順番に電圧を付加し、5~8の出力を読み取れば良いみたいです。

  1、2,3,4が HIGH、LOW、LOW、LOW
の場合、ボタンK1~K4の状態を調べることが出来ます。
K3が押されている場合、端子7の出力はHIGHとなります。

この4x4マトリックスを4つ使って64キー(4行x16列)を仮実装してみます。
4行x16列だと端子が20ピンとなります。Arduino的にI/Oポートが足りません。

そこでシフトレジスタを2つ追加。回路的には次のような感じです。

※2017/09/05 更新 回路図を差し換えました

01_2

実装してみるとこんな感じになります。

Dscn6928

テスト用のスケッチ

#include <Arduino.h>

#define SOUT_PIN   2 // シリアルアウト
#define CLK_PIN    3 // クロック
#define LATCH_PIN  4 // ラッチ
#define SCN1_PIN   5 // 
#define SCN2_PIN   6 //
#define SCN3_PIN   7 //
#define SCN4_PIN   8 //


uint8_t lines[] = { SCN1_PIN, SCN2_PIN, SCN3_PIN, SCN4_PIN };
uint16_t scn[4];

uint8_t getKeyCode() {
  uint16_t clm = 0x0001;  
  memset(scn, 0, 8);
  for (uint8_t i=0; i < 16; i++) {
    digitalWrite(LATCH_PIN, LOW);
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~clm & 0xff );
    shiftOut(SOUT_PIN, CLK_PIN, LSBFIRST, ~(clm>>8) & 0xff ); 
    digitalWrite(LATCH_PIN, HIGH);     
    for (uint8_t j=0; j <4; j++) {
        scn[j]<<=1;
        scn[j] |= digitalRead(lines[j]);
     }
     clm<<=1;  
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(SOUT_PIN,  OUTPUT);
  pinMode(CLK_PIN,   OUTPUT);
  pinMode(LATCH_PIN, OUTPUT);  
  pinMode(SCN1_PIN,  INPUT_PULLUP);  
  pinMode(SCN2_PIN,  INPUT_PULLUP);  
  pinMode(SCN3_PIN,  INPUT_PULLUP);  
  pinMode(SCN4_PIN,  INPUT_PULLUP); 
}

void bitout(uint16_t d) {
  uint16_t tst=0x8000;
  for (uint16_t i=0; i <16; i++) {
    Serial.write(tst&d ? '1' : '0');
    tst>>=1;
  }
  Serial.println();
}

void loop() {
  getKeyCode();
  for (uint8_t i=0; i <4; i++) 
     bitout(scn[i]);
  Serial.println("----");     
  delay(100);  
}

実行すると、4行16列のボタンのON/OFF状態を表示します。
1がOFF、0がONです。

02

取りあえず動いているようです。

次のステップとしては、
・各ボタンにスキャンコードを割当て
・PS/2キーボード インタフェース対応
・シリアル出力対応
をやってみます。

最終的には、ArduinoをPro miniまたはAtmega328単体利用にして小型化もしてみます。

2017年8月23日 (水)

Windowsストア版 Arduino IDEを試してみる

Arduinoの開発環境(IDE) はWindows 10環境をメインに利用しています。
このWindows 10用のArduino IDE、Windowsストア版があるのを最近知り、早速試して見ました。

WindowsストアにてArduinoで検索すると見つけられます。

01

アプリの説明にはバージョン情報等の記載が無く、ちょっと不親切ですが、
インストールすると最新版でした。機能はほぼ同じです。

02

タイトル部に(Windows Store 1.8.6.0)との表示があり、これによりWindowsストア版と
判断できます。

異なる点が若干あります。
環境設定ファイルpreferences.txt及びパッケージ配置場所が、
%ユーザーホーム%\Documents\ArduinoData\でした。

03

Documentsの中なので隠し属性でなく、自由に参照できます。
DocumentsのフォルダはOSの設定で任意に移動できるのでノーマル版より融通がききます。


とりあえず、ボートを追加したり、Arduino STM32モジュールを追加したり、
ライブラリの更新等をやってみました。

Arduino STM32は問題なく追加出来ました。

04

再度確認すると、もう一点異なる点がありました。
ライブラリマネージャーにてラリブラリの更新を行うと、
更新したライブラリはスケッチの保管場所で指定したフォルダのlibrarysに配置されます。

Windowsストア版の方が追加パッケージ、更新ライブラリの配置場所が分かりやすいのです。

また、通常版とWindowsストア版そ同時に起動してみましたが、全く干渉しないようです。
環境の使い分けを行いたい場合には両方入れて使うと良いかもしれません。

通常版のWindowsストア版のArduino IDEはアイコンが異なる形状なので、
同時に利用してもどちらがどのバージョンなのか判断できます。

2017年8月22日 (火)

ブートローダーに任意のスケッチを結合する

Arduino STM32環境利用メモです。

ブートローダーに任意のコンパイル済スケッチのイメージを結合する手順

・利用ツール: mergesketch.exe
https://github.com/rogerclarkmelbourne/STM32duino-bootloader/tree/master/sketch_combiner/bin_merge_tool

・使い方
mergesketch ブートローダイメージファイル スケッチイメージファイル 出力ファイル名
例: mergesketch.exe generic_boot20_pc13.bin ttbasic.bin boot_ttbasic.bin
      Opened bootloader file generic_boot20_pc13.bin : size is 7188

      Opened sketch file ttbasic.bin : size is 82092
      Allocated 90284 bytes for buffer
      Wrote combined file to boot_ttbasic.bin

・作成したブートローダ付きスケッチイメージの書込み(stm32flash利用の場合)
  - Blue Pillボードのboo0を1:boot1を0に設定しリセットしてDFUモード起動する
  - USB-Serialモジュール接続 PB9にTX、PB10にRXを接続
  - stm32flashで書き込む

    stm32flash.exe -f -v -w boot_ttbasic.bin COM5
    stm32flash 0.4
    http://stm32flash.googlecode.com/
    Using Parser : Raw BINARY
    Interface serial_w32: 57600 8E1
    Version      : 0x22
    Option 1     : 0x00
    Option 2     : 0x00
    Device ID    : 0x0410 (Medium-density)
    - RAM        : 20KiB  (512b reserved by bootloader)
    - Flash      : 128KiB (sector size: 4x1024)
    - Option RAM : 16b
    - System RAM : 2KiB
    Write to memory
    Erasing memory
    Wrote and verified address 0x080160ac (100.00%) Done.


2017年8月15日 (火)

OLED(SSD1309)ディスプレイモジュールを試して見る

大き目のOLEDディスプレイをAliExpressで見つけ、ポチりました。
2.42" 12864 OLED Display Module IIC I2C SPI Serial FOR C51 STM32 WHITE SSD1309

Aliexpress

$22.99はちょっとお高いかなぁと思いつつ、製品が到着。
0.96インチのOLEDと比較すると、以外と大きい...値段に納得。

Dscn6854

早速動作確認しました。
下記の情報を参考にしました。参考記事の製品は私の物と全く同じようです。
Arduino Forum >  Using Arduino >  Displays >  2.42" OLED SSD1309 with U8GLIB

SPI接続で利用します。
ライブラリはu8glibではなく、u8g2を使いました。
ライブラリはここから入手しました。

Dscn6842

流石OLED、表示が綺麗です。
画面のサイズも思っていたよりも大きいです。これなら$22.99で十分お得かも..

Dscn6841

参考にした記事ではVCC 5Vで稼働させていますが、3.3Vでも動作しました。
このモジュール、SPI利用の場合のピンの利用がちょっと分かりにくですが、
参考記事にて使い方が判明しました。

Dscn6846

SSD1309はSSD1306と互換性があるようです。u8glibではデバイスとしてSSD1306を
指定しても動作しました。

AdafruitのSSD1306ライブラリも試して見ました。

Dscn6853

問題なく動いていると思いきや、スクロールのデモでスクロールせず..

Dscn6850

ハードウェアスクロールが動かないです。SSD1309は完全互換では無いみたいですね。

次の調査として、Blue Pillボードでも使えるかやってみます。

追記

Blue Pillボードでもu8glib(u8g2)ライブラリを使った表示制御が出来ました。
豊四季Tiny BASICから利用出来るよう、ちょっとやってみます。

Dscn6863


2017年8月11日 (金)

豊四季 Tiny BASIC for Arduino STM32、 V0.84に更新しました

現在メインで取り組んでいる「豊四季 Tiny BASIC for Arduino STM32」、
バージョン 0.84に更新しました。

豊四季タイニーBASIC for Arduino STM32 V0.84(2017/08/11)
https://github.com/Tamakichi/ttbasic_arduino/tree/ttbasic_arduino_ps2_ntsc

従来は、NTSCビデオ画面、PS/2キーボードがほぼ必須だったのですが、
V0.5のターミナルコンソールでのスクリーン編集機能を復活させてました。

Blue Pillボードの小さいメリットを生かした利用にも対応できると思います。

01

03


追記 2017/08/13
ILI9341 TFT液晶モジュールに対応しました。
ただし、表示は遅いです。

より以前の記事一覧