フォト
2025年3月
            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 31          
無料ブログはココログ

« 2016年2月 | トップページ | 2016年4月 »

2016年3月の10件の記事

2016年3月30日 (水)

Arduino - TV出力(TVoutLibrary使用)で漢字表示

前回、美咲フォントを使って日本語表示をやってみたのですが、さすがに8x8ドットは
フォントが潰れます。

そこで、作業ついでに以前作成した漢字フォントROMとライブラリを使って大き目の
フォント表示を試してみました。どれくらいのサイズがよろしいのかと..

  関連記事
    Arduino用美咲フォントライブラリを作成しました(2)
    arduinoで利用可能な漢字フォントROMの製作
    arduinoで利用可能な漢字フォントROMの製作(2)

Dscn5053

表示の様子(動画)



画面キャプチャした画像

8x8ドットのフォント(美咲フォント)
8

10x10ドットのフォント1(naga10フォント)
10

12x12ドットのフォント(東雲フォント)
12

14x14ドットのフォント(東雲フォント)
14

16x16ドットのフォント(東雲フォント)
16

20x20ドットのフォント(kappa20フォント)
20

24x24ドットのフォント(jiskan24フォント)
24

情報量と見た目の兼ね合いで、10~14ドットが実用的でしょうかね。
20、24ドットは実用性無さそうでTVout用途としては削ても良いかも..

TVoutライブラリはお手軽に使えるのですが、SRAMメモリー不足に悩まされます。
多用する場合、文字列はフラッシュメモリに乗せないといけませんね。
SRAMが4倍のArduino Megaを使えば快適かもしれません。

回路的には次のような感じです。

02
漢字フォントを突っ込んでいるSPIフラッシュメモリ W25Q64が3.3V稼働のため、
レベルシフトのためにCD4050を使っています。
他のCMOS 4050(東芝製のTC4050など)でもいけるでしょう。


電源部の0.22μFのパスコン、正規品Arduinoまたは、品質の良い互換機では
多分不要です。手持ちの中華製格安Arduinoは入れないとSPI通信でデータ化けが
発生しました。3.3V生成周りがよろしくないようです。SainSmart製互換機では
無くても安定動作しました。

「安物Arduonoでもいけるやん」と使っていたのですが、やはり安い理由がありそうです。


スケッチ

//
// TVOutでマルチフォント表示 by たま吉さん 2016/03/30
//  

#include <SPI.h>
#include <W25Q64.h>
#include <exfonts.h>
#include <TVout.h>

// TVoutの派生クラスの定義し、
// bitmapメソッドをフラッシュメモリではなく、SRAM対応させる
class exTVout : public TVout {
  public:
    void bitmap(uint8_t x, uint8_t y, const uint8_t* bmp, 
                uint16_t i, uint8_t width, uint8_t lines);
};

// bitmapメソッド
void exTVout::bitmap(uint8_t x, uint8_t y, const uint8_t* bmp,
                     uint16_t i, uint8_t width, uint8_t lines) {

  uint8_t temp, lshift, rshift, save, xtra;
  uint16_t si = 0;
	
  rshift = x&7;
  lshift = 8-rshift;		
  if ( width & 7 ) {
    xtra = width & 7; width = width / 8; width++;
  } else {
    xtra = 8; width = width/8;
  }	
  for ( uint8_t l = 0; l < lines; l++ ) {
    si = (y + l)*display.hres + x/8;
    if (width == 1)
      temp = 0xff >> rshift + xtra;
    else
      temp = 0;
    save = screen[si];
    screen[si] &= ((0xff << lshift) | temp);
    temp = *(bmp+ i++); screen[si++] |= temp >> rshift;
    for ( uint16_t b = i + width-1; i < b; i++ ) {
      save = screen[si]; screen[si] = temp << lshift;
      temp = *(bmp + i); screen[si++] |= temp >> rshift;
    }
    if ( rshift + xtra < 8 )
      screen[si-1] |= (save & (0xff >> rshift + xtra));
    if ( rshift + xtra - 8 > 0 )
      screen[si] &= (0xff >> rshift + xtra - 8);
      screen[si] |= temp << lshift;
    }
}

exTVout TV;  // TV出力オブジェクト
exfonts ft;  // フォント管理オブジェクト

// 指定位置に1文字表示
void mputc(uint8_t x, uint8_t y, uint16_t code) {
  byte buf[MAXFONTLEN]; 
  ft.getFontData(buf,code); // フォントデータの取得  
  TV.bitmap(x,y, buf ,0,ft.getWidth(), ft.getHeight());
}

// 指定位置に文字列表示
void mprint(uint8_t x, uint8_t y, char* str) {
  
  uint16_t wstr[64];
  int8_t   len;
  
  len = exfonts::Utf8ToUtf16(wstr, str);  // UTF8からUTF16に変換する
  for (uint8_t i=0; i <len; i++) {
    mputc(x, y, wstr[i]);
    if (x + ft.getWidth()*2 < 120) {
      x += ft.getWidth();  
    } else {  
      x = 0;
      if (y+ft.getHeight()*2 < 80) {
        y+=ft.getHeight();
      } else {  
        break;
      }
    }
  }      
}

void setup () {
  ft.init();  // フォント管理の初期化
  TV.begin(NTSC, 120, 80); // TVOut開始
  
  //7種類のフォントサイズで文字列表示
  while(1)
    for (uint8_t i =0 ; i <7; i++) {
      TV.fill(0);
      ft.setFontSize(i);
      mprint(0,0,"春はるはあけぼのやうやう白くなりゆく山際、少し明かりて、紫だちたる雲の細くたなびきたる");
      delay(1000*10);
    }
}

void loop () {

}

プログラム的には、TVoutからの派生クラスexTVoutを作成してbitmapメソッドを再定義しています。
TVoutライブラリのフォントを表示を行うbitmapメソッドがフラッシュメモリ上のフォント
データにしか対応していないためです。基本クラスのbitmapメソッドをコピペして、
SRAM上の領域を参照するよう、修正しました。

こういった差分プログラミング、C++を使う利点ですね。

フォント周りは自作のライブラリexfontを使っています。

画面出力のサイズ指定をsetup()内の TV.begin(NTSC, 120, 80) で行っているのですが、
縦を90から80へとちょっとだけ小さくしてメモリ消費を抑えました。
これで150バイト消費を抑えられます。これをしないと画面にごみが表示されます。
多分、メモリ不足です。

Arduinoがあと2kバイト多くRAMがあればTVoutで色々と出来そうなのですが、
メモリ不足でシリアル通信等が出来ません。
一方、プログラム領域の利用は7,842バイトとまだ24kバイトも余っています。

2016年3月16日 (水)

Arduino用美咲フォントライブラリを作成しました(2)

先日作成したライブラリを、以前試してみたTV出力(TVoutLibrary使用)で利用してみました。

TVout Library の入手先等の情報
  ・The Arduino Playground - TVout Libraty http://playground.arduino.cc/Main/TVout
  ・GitHub Arduino-TVout - https://github.com/Avamander/arduino-tvout
  ・arduino-tvout  - https://code.google.com/archive/p/arduino-tvout

スケッチは表示する文字列を直接指定出来ます。
(スケッチはライブラリのサンプルスケッチとして添付しています)

01

使用する部品は抵抗2本とAV端子のみです。お手軽に表示出来ます。
(下記の写真のブレッドボード上の黒いのは別目的で利用している圧電スピーカーです)

Dscn5014

画面解像度は120x96ドットです。
やはり8x8ドット フォントは文字が少々粗いですね。表示は鮮明で綺麗です。

Dscn5011

このTVout、RAMを結構消費します(120x96ドットで1,440バイト使います)。
シリアルライブラリ(Serial)を使おうとすると、メモリが足らないようで実行できませんでした。

フォントライブラリもちょっとダイエット(RAMの消費を抑える)しないとダメそうです。
ちょっと処理を見直したいと思います。

スケッチ(プログラムソース) 2016/07/10 修正しました

#include <misakiUTF16.h>
#include <TVout.h>

TVout TV;

// 指定位置に1文字表示
void mputc(uint8_t x, uint8_t y, uint16_t code) {
  int16_t pos; // フォントデータテーブルコード
  if ( (pos = findcode(code)) < 0) 
    return;
  TV.bitmap(x,y, getFontTableAddress()+pos*8 ,0,8,8); 
}

// 指定位置に文字列表示
void mprint(uint8_t x, uint8_t y, char* str) {
  uint16_t utf16;
  int8_t   len;
  
  while(1) {
    len = charUFT8toUTF16(str, &utf16); // 先頭文字のutf16コードの取得
    if (!len) 
      break;  // コードエラー   
    mputc(x, y, utf16); // 1文字表示
    x+=8;
    if (x >= 120) {
      x = 0; y+=8;
    }
    str+=len;
    if (!*str)
      break; // 文末に達した
  }
}

void setup() {
  TV.begin(NTSC, 120, 96);
  mprint(0,0,"【みさきフォント表示テスト】");
  mprint(15,14,"今日は3月16日です。");
  mprint(5,30,"ねこにコ・ン・バ・ン・ワ");  
  mprint(0,45,"ArduinoでTV出力です。");  
  mprint(0,60,"TVOUTライブラリ使用です。");
  mprint(0,75,"そこそこ読めますね!");  
}

void loop() {
}

TVout libraryのフォントとして組み込みこもうとも思ったのですが、標準フォントは
の文字コードが1バイトなので無理っぽいです。

2016年3月15日 (火)

Arduino用美咲フォントライブラリを作成しました

2016/07/05 更新、2018/05/18 追記

先日aitendo I2Cマトリックスキットで利用していたフォント周りの関数を取り出して
ライブラリ化しました。フォントデータは美咲フォントを利用してます。

フォントを教育漢字1,006字(小学校で習う漢字)+ひらがな・カタカナ・記号・半角等の
1,710字に絞って Arduino Uno(Atmega328)のフラッシュメモリ上に格納しました。
UTF16・UTF8対応です。

取りあえず公開します。自由に使って下さい。
   Arduino用 美咲フォントライブラリ 教育漢字・内部フラッシュメモリ乗せ版
     ダウンロード misakiUTF16.zip (24.8K)   2016/07/05 修正更新しました。
   
    ※以後最新版は下記にて随時更新公開いたします。
    ・Arduino-misakiUTF16
      https://github.com/Tamakichi/Arduino-misakiUTF16

利用は解凍してarduinoのlibrariesフォルダに入れて下さい。
Arduino IDEを再起動後、メニューにライブラリとして"misakiUTF16"の名称で登録されます。
2つのサンプルプログラムを用意しています。"スケッチの例"にて選択して利用できます。

サンプルの一つ、"banner" はシリアルコンソール上に表示するプログラムなので、
用意する部品も不要で、直ぐ動作確認出来ます。
もう一つは、先日のaitendo I2Cマトリックスキット用のプログラムです。

bannerのスケッチ 2016/07/10 修正しました

#include <misakiUTF16.h>

//
// フォントパターンをコンソールに表示する
// 引数
//  pUTF8 表示する文字列
//  fore  ドットに使用するキャラクタ
//  back  空白に使用するキャラクタ
//
// ※半角文字は全角文字に置き換えを行う
//
void banner(char * pUTF8, char* fore, char* back) {
  int n=0;
  byte buf[20][8];  //160x8ドットのバナー表示パターン

  // バナー用パターン作成
  while(*pUTF8)
    pUTF8 = getFontData(&buf[n++][0], pUTF8);  // フォントデータの取得
    
  // バナー表示
  for (byte i=0; i < 8; i++) {
    for (byte j=0; j < n; j++) 
        for (byte k=0; k<8;k++)
          Serial.print(bitRead(buf[j][i],7-k) ? fore: back);
    Serial.println();    
  }
  Serial.println();
}

void setup() {
    Serial.begin(115200);
    banner("abcdef","$"," ");
    banner("misakiUTF16ライブラリ","$"," ");    
    banner("あいうえお","##","  ");
    banner("埼玉☆さいたま","[]","  ");
    banner("みさきフォント","@"," ");    
}

void loop() {
}

実行例

01

8x8なので複雑な漢字は当然潰れます。雰囲気で読んで下さい。

仕様等について
  ライブラリの仕様のついては以下の通りです。

  ・フォントサイズ                    8x8ドッド(美咲フォント)
  ・利用可能フォント数        1,710字(Arduinoのフラッシュメモリ上に格納)
        内訳
           漢字 教育漢字 1,006字(小学校で習う漢字)
           非漢字 全角        546字(全角英数字、ひらがな、かたかな、記号)
           半角フォント        158字(半角記号、半角英数、半角カタカナ)

  ・文字コード   UTF16、UTF8

  ・利用可能API
    ・UTF8文字列をUTF16文字列に変換する。
     byte Utf8ToUtf16(uint16_t* pUTF16, char *pUTF8)

    ・UTF8文字をUTF16に変換する
      byte charUFT8toUTF16(char *pUTF8, uint16_t *pUTF16)

    ・UTF16半角コードをUTF16全角コードに変換する。半角でない場合はutf16の値を返す。
      uint16_t utf16_HantoZen(uint16_t utf16)

    ・半角カナを全角に変換する。半角カタカナでない場合はucodeの値を返す。
     uint16_t hkana2kana(uint16_t ucode)
      
    ・UTF16に対応するフォントデータ取得する。
     boolean getFontDataByUTF16(byte* fontdata, uint16_t utf16)

    ・指定したUTF8文字列の先頭文字のフォントデータを指定したアドレスに返す。
      戻り値として、次のUTF8文字列のアドレスを返す。
      char* getFontData(byte* fontdata,char *pUTF8)


  指定した文字に対するフォントが存在しない場合、getFontDataByUTF16()はエラーを
  返します(サンプルプログラムではその処理は行っていません)。
   => 2019/01/30 修正
         フォントが存在しない場合は、豆腐("□")フォントを取得し正常終了します。
         何らかの異常発生時のみエラー(false)を返します。

文字コードとしてUTF16を利用しているのは、Arduino IDEがUTF-8を利用しているためです。
シフトJISを採用するとライブラリの実装的には楽なのですが、Arduino IDEにて全角を利用する場合、
文字列を可読性のないシフトJISコード(16進数)バイナリデータとして定義する必要があります(たぶん)。
そこで、UTF16を採用しました。

UTF-8の場合、1文字のサイズが可変長になり、インデックステーブルの構造が面倒に
なるので、1ワードで扱えるUTF16にしました。

UTF8・UTF16間のコード変換は計算で出来でき、UTF16を採用することでユニコードの処理
が楽になります。

関連記事
  ・OLED(SSD1306)で美咲フォントを使った漢字表示
  ・Arduino用フォントライブラリを更新しました (本ライブラリの更新の記事)
  ・Arduino用美咲フォントライブラリを作成しました(2) (本記事の続き)
  ・Arduino用美咲フォントライブラリを作成しました(本記事です)
  ・itendo I2CマトリックスキットをArduino動かしてみました
 
  ・Arduino-misakiSJIS(本ライブラリのシフトJISバージョン)
   https://github.com/Tamakichi/Arduino-misakiSJIS

aitendo I2CマトリックスキットをArduino動かしてみました (2)

前回の続きです。美咲フォントを使って漢字表示をしていました。
美咲フォントは、Little Limitさんが公開している8x8ドットフォントです)

Dscn5009

フォントを教育漢字(1,006文字)+記号・半角文字 の合計1,710文字に絞って、
Arduinoのフラッシュメモリ内に乗せて使えるようにしました。

2016/03/15 訂正
  訂正 フォントテーブルの一部にミスがあり、公開ソースを修正しました。
  利用可能フォント数は1,718文字から1,710文字に訂正しました。

02

プログラムソースを置いておきます。

  ダウンロード aitendo_ht16k33_3.zip (21.1K)
  (※ arduino IDE 1.06 と 1.6.7での動作を確認しました)

動いている様子



まあ、8x8ドットですし、複雑な漢字は崩れて読みにくいので教育漢字くらいが
ちょうどよい感じです。

プログラムは、3つのファイルに分かれています。
   aitendo_ht16k33_3.ino  :  LEDマトリック表示
   getFontData.ino          :  フォントドライバ
   kyoiku_font.ino            :  フォントデータ定義(UTF16コード体系の美咲フォント)

漢字コードはUTF8に変換しやすいよう、UTF16で管理しています。
指定した文字のフォントデータを取り出すには、用意している関数Utf8ToUtf16()を使って
UTF8文字列からUTF16文字列に変換し、関数getFontDataByUTF16()でフォントデータを
得ます。

フォントデータは1文字8バイトのデータとなっています。

取りあえず、aitendo_ht16k33_3.ino だけ掲載します。

//
// aitendoドットマトリックスデモ by たま吉さん
// 

#include <Wire.h>

// アドレス
#define HT_I2C_ADDRESS 0x70

// コマンド
#define HT_CMS_DATA       0x00
#define HT_CMD_SYSSET     0x20
#define HT_CMD_BLINK      0x80
#define HT_CMD_BRIGHTNESS 0xE0

// System Setup レジスタ設定値
#define HT_SYSSET_OSC_ON  1

// Display setup 設定値
#define HT_BLINK_DISPLAY_ON B00000001
#define HT_BLINK_OFF        B00000000
#define HT_BLINK_2HZ        B00000010
#define HT_BLINK_1HZ        B00000100
#define HT_BLINK_05HZ       B00000110

// 表示パターン用バッファ(R16xC8)
uint8_t buf[8];  

// テスト用パターン('さ','い','た','ま')
uint8_t msg_saitama[4][8] = {
  {0x08,0x08,0x7E,0x04,0x24,0x40,0x3C,0x00},  // さ
  {0x00,0x88,0x84,0x82,0x82,0x50,0x20,0x00},  // い
  {0x20,0xF0,0x2E,0x40,0x48,0x50,0x8E,0x00},  // た
  {0x08,0x7E,0x08,0x7E,0x08,0x7C,0x7A,0x00}   // ま
};

// テスト用文字列
uint8_t msg_str[] = "あいうえお、今日は3月14日です。かんたんなかんじの表示ができます。";

// HT16K33の初期化
void ht_init() {
  Wire.begin();
  ht_system_Seup(HT_I2C_ADDRESS, HT_SYSSET_OSC_ON);  // システムオシレータをONにする
  ht_display_setup(HT_I2C_ADDRESS,HT_BLINK_OFF) ;    // 点滅表示周期の設定
  ht_setBrightness(HT_I2C_ADDRESS,1);                // 明るさの設定
}

// SystemSetup Registerの設定
// (システムオシレータのモード設定)
void ht_system_Seup(uint8_t addr, uint8_t p) {
  Wire.beginTransmission(addr);
  Wire.write(HT_CMD_SYSSET | p);
  Wire.endTransmission(); 
} 

// 明るさの設定
void  ht_setBrightness(uint8_t addr, uint8_t p) {
  if (p > 15) p = 15;
  Wire.beginTransmission(addr);
  Wire.write(HT_CMD_BRIGHTNESS | p);
  Wire.endTransmission(); 
}

// Display setup(点滅周期の設定)
void ht_display_setup(uint8_t addr, uint8_t p) {
  if (p > 3) p = 0;
  Wire.beginTransmission(addr);  
  Wire.write(HT_CMD_BLINK | HT_BLINK_DISPLAY_ON | p); 
  Wire.endTransmission();
}

// 左右ビット入れ替え
uint8_t revRL(uint8_t d) {
  uint8_t rc = 0;
  for (uint8_t i=0; i<8; i++) { 
    rc <<=1;
    rc |= ( d>>i ) & 1;
  }
  return rc;
}

// 表示パターンの送信
void ht_update(void) {
  uint8_t d;
  
  // HT16K33  にデータ転送
  Wire.beginTransmission(HT_I2C_ADDRESS);
  Wire.write(HT_CMS_DATA);

  for (uint8_t i = 0; i<8; i++) {
 
    // モジュールの設置向きに応じて回転・反転の調整
    d = buf[7-i]; // 上下反転
    d = revRL(d); // 左右反転
    
    // データの送信
    Wire.write(d);    
    Wire.write(0);    
  }
  Wire.endTransmission();  
}

// バッファのクリア
void ht_clear_buffer() {
    for (uint8_t i = 0; i <8; i++) 
      buf[i] = 0;
}

// 表示のクリア
void ht_clear() {
  ht_clear_buffer();
  ht_update();
}

// バッファの指定座標のON/OFF
void ht_set_dot(int8_t x, int8_t y, uint8_t d) {
  if ( (x > 7) || (y > 7) || (x < 0) || (y < 0) ) 
     return;     
  if (d)
    buf[y] |= 0x80 >> x;
  else
    buf[y] &= ~(0x80 >>x);  
}

// バッファ上の指定座標に8x8パターンをセット(負座標指定可能)
void ht_write_at(uint8_t* p, int8_t x, int8_t y) {
    int8_t i; 
    if ((x > 7) || (y > 7) || (x < -7) || (y < -7) ) 
        return;
    for (i = 0; i <8; i++) {
        if ((i+y >= 0) && (i+y < 8) ) {
           if (x >= 0)
              buf[i+y] |= p[i]>>x;
           else
              buf[i+y] |= p[i]<<(-x);
        }
    }
}

// バッファ左スクロール
void scroll() {
   for (uint8_t i = 0; i < 8; i++) {
      buf[i]<<=1;  // 各行を左にシフトする
   }
}

// 1文字左スクロール挿入
void ht_scrollIn(uint8_t* p, int wt) {
    int8_t i,j;
    for (j = 0; j < 8; j++) {
        for (i = 0; i < 8; i++) {
            buf[i]<<=1;
        }
        ht_write_at(p, 7-j, 0);
        ht_update();
        delay(wt);
    }
}

void setup() {
  Serial.begin(115200);
   ht_init();
   ht_clear();

#ifdef MY_DEBUG   
   I2CBusScanTest();
   dump(256) ;
#endif
}

// デモ1 ドット表示チェック
void demo1() {
  ht_clear();
  for (int8_t d = 1; d >= 1; d--) {
    for (int8_t y = 0; y <8; y++) {
      for (int8_t x = 0; x <8;  x++) {
         ht_set_dot(x, y, d);
         ht_update();
         delay(75);
      }
    } 
    delay(500);
  }
  for (int8_t i = 0; i <8; i++) {
    scroll();
    ht_update();
    delay(100);    
  }
}  

// デモ2 パターンを指定座標の表示
void demo2() {
   ht_clear();
   for (uint8_t i = 0; i <4; i++) {
        ht_clear_buffer();
        ht_write_at(msg_saitama[i], 0, 0);
        ht_update();
        delay(1000);  
   }
}

// デモ3 パターンをスクロールイン表示
void demo3() {
   ht_clear();
   for (uint8_t i = 0; i <4; i++) {
        ht_scrollIn(msg_saitama[i], 150);  
   }
}

// デモ4 漢字フォント利用
void demo4() {
  uint16_t wstr[256];
  uint8_t  fnt[8];
  int8_t   len;

  len = Utf8ToUtf16(wstr, msg_str);  // UTF8文字列をUTF16に変換 
  Serial.print("len=");
  Serial.println(len);
  ht_clear();
   for (uint8_t i = 0; i <len; i++) {
       Serial.print("code=");
       Serial.println(wstr[i],HEX); 
       if (getFontDataByUTF16(fnt, wstr[i]) == false) {
         Serial.println("Error"); 
       }  
       ht_scrollIn(fnt, 150);  
   }
}

void loop() {  
   demo4();
   delay(1000);    
   demo1();
   delay(1000); 
   demo2();
   delay(1000); 
   demo3();
   delay(1000); 
}

getFontData.ino 、kyoiku_font.inoを取り出して別のスケッチに突っ込んで利用も出来ると
思います。グラフィック液晶やTVOUTなんかにも使えるかも。

2016年3月11日 (金)

普通のUSBコネクタをmicroUSB化するパーツ

なんか面白そうな製品を見つけたのでゲットしました。

Micro USB to Anroid Phone Tablet PC OTG Adapter Converter USB adapter for
Samsung HTC Oneplus Xiaomi For Lenovo Sony OTG Adapter

02

5個購入で届いた製品がこれ。

Dscn4999

USBメモリに装着

Dscn5000

Windows タブレット Lenovo Miix 2 8 に装着すると問題なく認識しました。

Dscn5002

手持ちUSBハブにも装着して利用出来ます。

Dscn5001

パソコン用USB機器がタブレットで使えるようになります。この発想は素晴らしい。
ただし、若干抜き差しが固いです。

2016年3月 9日 (水)

Ichigojamのファームウェアを1.2b12の動作確認

Ichigojamのファームウェアを1.2b12にアップデートしました。
1.2系ではいくつかの機能が追加されており、ついでにその一部の機能を試してみました。

試したこと
  ・COPY命令 ・・・ 指定したメモリ領域のコピーを行う
    COPY コピー先アドレス、コピー元アドレス、コピーバイトサイズ
  ・ラベル
   行にラベル(@hogeohoge)を付けて、GOTO、GOSUBで飛び先を指定でこる
  ・VIDEO 2 ・・・ 画面を反転表示
   従来のVIDEO命令に画面反転機能と追加。VIDEO 1で元に戻る

更に、マシン語を使った場合の文字列の受け渡し方法について調べてみました。
プログラム中で、
  A="Hello!":   U=USR(#700,A)

とやって、
マシン語側で受け取った文字列を疑似グラフィック文字で拡大表示する処理の実装
で調べてみました。

調査にて作成したプログラム(赤字は1.2系で追加された機能)

10 'draw font2
20 CLS:CLV:CLP:P=#700
30 LET [0],#B5F7,#2380,#9201,#2290,#11B,#5ACB,#112,#189A,#4B21,#5ACB,#15B,#18D3,#1808,#18C9,#7805,#2D22
40 LET [16],#D036,#9B01,#ED,#195D,#1C2B,#1C0F,#3308,#9300,#2600,#2406,#782A,#73,#1AE3,#411A,#469C,#2301
50 LET [32],#612,#E12,#3C03,#4013,#4022,#4664,#852,#5B,#4313,#3B80,#61B,#E1B,#55BB,#786A,#4122,#2401
60 LET [48],#612,#E12,#4014,#64,#46A4,#2403,#4022,#4664,#852,#4322,#92,#189B,#55BB,#3601,#2E04,#D1D8
70 LET [64],#9B00,#3502,#3720,#429D,#D1D2,#3104,#3001,#E7C5,#2000,#BCFE,#BC02,#4708,#802,0
80 COPY P,#800,156
90 A="Hello!":B="Jam":C="World":D="Thank":E="you!":F=""
100 @LOOP
110 [0]=0:[1]=0:U=USR(P,A)
120 [1]=5:U=USR(P,B)
130 [0]=4:[1]=10:U=USR(P,C)
140 [0]=12:[1]=15:U=USR(P,D)
150 [1]=20:U=USR(P,E)
160 WAIT 150
170 FOR I=0 TO 5:VIDEO 2:WAIT 10:VIDEO 1:WAIT 10:NEXT:CLS
180 FOR I=0 TO 23 STEP4:FOR J=0 TO 31 STEP 4
190 [0]=J:[1]=I:U=USR(P,F)
200 WAIT 10
210 NEXT:NEXT
220 FOR I=0 TO 5:VIDEO 2:WAIT 10:VIDEO 1:WAIT 10:NEXT:CLS
230 WAIT 150:CLS
240 GOTO @LOOP

マシン語側のプログラム(C言語で実装) 2016/03/27 修正 define文を追記

#include <stdint.h>

#define VRAM_ADR	0x900 // VRAM先頭アドレス
#define VAR_ADR		0x800 // 変数格納アドレス
#define PRG_ADR		0xc00 // プログラム格納アドレス
#define CHR_BNK		0x80  // 疑似グラフィックの空白文字
#define CHR_END		0x22  // 文字(") 

// 疑似フォント文字列表示
//  引数
//    argv : 文字列格納アドレス(USR関数の第2パラメタ)
//    m_p  : 仮想アドレスの先頭実アドレス (BASICの#000の実アドレス)
//    f_p  : フォントデータの先頭実アドレス
//
uint16_t draw_font(uint16_t argv, uint8_t* m_p,  uint8_t* f_p) {
	
	uint16_t* 	h_p = m_p + VAR_ADR; 	// 変数格納アドレス
	uint8_t* 	s_p = m_p + argv;		// 文字列格納アドレスを実アドレスに変換
	uint8_t* 	v_p = m_p + VRAM_ADR; 	// VRAMアドレス
	uint8_t*	d_p;					// フォントパターン参照用
	uint8_t		d;						// 疑似フォント作成用
	int i,j;

	v_p+= *h_p;							// [0]の値加算 横分
	v_p+= *(h_p+1)*32;					// [1]の値加算 縦分
	
	while(*s_p != CHR_END) {
		d_p = f_p + (*s_p)*8; 			// 指定フォント格納アドレス
		for (i=0; i<4;i++) {
			for (j=0;j<4;j++) {
				d = ( *d_p >> (6-(j<<1)) ) &3;
				*v_p = (d>>1 | (d&1)<<1) + CHR_BNK;
				d = ( *(d_p+1) >> (6-(j<<1)) ) &3;
				*v_p += (d>>1 | (d&1)<<1)<<2;
				v_p++;
			}
			v_p+=28;
			d_p+=2;
		}
		v_p -= 124;
		s_p++;
	}
	return 0;
}

プログラム実行の様子


※動画はビデオキャプチャした画面を「BB FlashBack Express 4 日本語版 (フリー版)」を使って
    動画作成しました。


プログラムの簡単な説明
マシン語コード部分(30~80行)の定義はプログラムを短くするため一旦、配列に格納してから
COPY命令で、PCG領域にコピーしています。通常のPOKE文を使うよりも218バイト節約出来ました。
ただし、配列領域を使わないのであれば、コピーしないでそのまま配列領域のマシン語を
呼び出しても良いですね。

マシン語部は、
  A="Hello!"
  [0]=0
  [1]=1
  U=USR(#700, A)

てな感じで、[0]に横座標(0~31)、[1]に縦座標(0~23)を指定し、Aに文字列をセットして
呼び出すと、画面の指定位置から疑似グラフィックにて文字を表示します。

ちなみに変数Aには文字列"Hello!"が格納されているアドレス(仮想アドレス)が格納されています。
  PRINT A
とやっても、"Hello!"は表示せず、アドレス(整数)が表示されます。
PRINT STR$(A)
とやることで、"Hello!"が表示されます。

マシン語部はC言語にて作成しています。
Cソースからマシン語部の作成はIJBin2Pokeを使ています。良いツールです。
プログラムでは複数の領域を参照するので、ちょっとDFD(データーフローダイアグラム)
にて図式化してみました。

Photo
     ※DFDはdiaを使って作成しました。

文字列の実体はプログラムリスト(プログラム領域)の"Hello"の変数代入部となります。
そこから文字を取り出し、そのコードに該当するフォントパターンを取り出して、
疑似グラフィックフォントに変換して、表示用メモリ(VRAM)に書き込んで表示をします。

ややこしいのが、各領域の先頭アドレスには仮想アドレスと実アドレスがあり、
マシン語中では仮想アドレスを実アドレスに変換して利用する必要があります。
その実アドレス先頭はマシン語呼び出し時に引数として渡される(m_p)のでそれを利用
します。

次に追加されたVIDEOコマンドによる反転表示ですが、ゲームなのど効果には良さそうです。
また、ラベルも行番号を意識する必要が無くなり、サブルーチンを多用する場合はかなり
効率よくプログラミングが出来ると思います。
RENUM命令によって行番号を付け直す際、手作業でGOTO分の飛び先の修正もなくなります。





2016年3月 8日 (火)

PIC24FJ64GB002を使ったUSBホストの実験 5

*** 2017/02/22 更新 公開プログラムに不具合がありました。差し換えました。
*** 2017/02/22 更新 記事を追記しました。

ソフト的な問題(システムエクスクルシブの処理の不具合)が解決できたので、基板実装しました。

MIDI-INとシリアル入力でUSB接続のMIDI音源機器の制御が出来ます。
取りあえず、今回の実験の成果物とします。

Dscn4988

ポケット・ミクを接続してMIDI-IN経由で演奏している様子

Dscn4987


回路図的なもの(画像をダウンロードして表示すると大きい図になります)

02_2

基板実装図

01

プログラムソース
未熟なソースですが置いておきます。

ダウンロード UsbMidi.X.zip (141.6K) (不具合があり差し換えました)

2017/02/22 追記

かずぽんさんのご指摘で、動作確認したところ、システムエクスルシブメッセージの処理に
ミスがありました。かずぽんさんをはじめ、ご利用頂い方々に対しまして、ご迷惑おかけしました。修正して差し換えました。

IchigoJamで動作確認しました。

01

IchigoJam用の演奏プログラムは、IchigoJam開発者の福野さんのブログ
「福野泰介の一日一創」「YAMAHA NSX-1 x IchigoJam eVY1とBASICを使ったお手軽DTM」
にて公開しているプログラムを改造して利用しました。

福野さんの記事ではeVY1を使ってIchigoJamで演奏させています。


プログラムソース
CC BY 福野泰介 - Taisuke Fukuno / @taisukef

1 'KAERU's song (MIDI)
5 BPS31250
10 M="CDEFEDC EFGAGFE C C C C CDEFEDC "
20 D="0-0-0-0C0-0-0-0C0P0P0P0P0-0-0- 1"
21 LET [0],#F0,#43,#79,#09,#11,#0a,#00,#05,#03,#71
22 LET [10],#43,#02,#29,#0a,#06,#09,#03,#2c,#07,#71
23 LET [20],#6e,#0a,#0a,#0a,#0a,#01,#36,#0e,#24,#66
24 LET [30],#02,#29,#f7
27 UART1:LC0,-1:FOR I=0TO 32:?CHR$([I]);:NEXT
30 GOSUB @PLAY
40 BPS0:END
200 @MIDI:UART1:LC0,-1:IF N ?CHR$(#90+H,N,V);:WAITW:?CHR$(#80+H,N,0); ELSE WAIT W
210 UART0:LC0,0:RTN
300 @PLAY:CLS:W=5:P=0:LET[0],69,71,60,62,64,65,67
310 C=ASC(M+P):?CHR$(C)
315 B=ASC(D+P):?CHR$(B)
320 IF C=ASC("2") WAIT W
330 IF C>=ASC("A") AND C<=ASC("G") N=[C-ASC("A")]:H=0:V=127:GOSUB@MIDI
334 IF B!=ASC(" ") N=B:H=9:V=50:GOSUB@MIDI
338 WAIT 30
340 P=P+1:IF P<LEN(M) GOTO 310
350 RTN


21行から24行が歌詞用でデータです。27行でそのデータをポケットミクに送っています。
データの作成は下記のサイトを利用しました。
・ポケットミクで好きな歌詞を歌ってくれるMIDIファイルを作成
  http://aisot.org/39/mikuex
上記のサイトの「歌詞入力」にて、
  かえるのうたがきこえてくるよががががいちごじゃむうた
と入力して、対応する歌詞データを作成します。
  05:03:71:43:02:29:0a:06:09:03:2c:07:71:6e:0a:0a:0a:0a:01:36:0e:24:66:02:29:
これをテキストエディタで置換等の加工します。

歌詞の登録は次のコマンド(システムエクスルシブメッセージ)を送ります。
  F0 43 79 09 11 0A 歌詞スロット 歌詞データ F7

歌詞スロットは0,歌詞データ分は作成したデータを指定します。
本当は歌詞データの参照位置を指定したりする必要がありますが省略しています。
何回か再生すると、歌詞がずれたりします。

2016年3月 4日 (金)

ルミちゃん vs. ちっちゃなミーニャ

カワイイちっちゃなミーニャに嫉妬心を抱いている ルミちゃん 

Dscn4951

ミーニャを見るや豹変し、激しい攻撃をします。

勝負の結果はいかに!?


さてこのおもちゃ、何年も前に1,000円弱で買ったのですがかなり丈夫な製品です。
それに値段以上に良い動きをします。ルミちゃんも飽きずに遊びます。

Dscn4954

縫製というか、生地がしっかりしていてルミちゃんの激しいキックや噛みつき攻撃を
受けてもダメージがありません。

Dscn4952

この製品を販売しているメーカーはイワヤ株式会社というところです。
幼児向けのおもちゃのため安全に配慮が随所に見られますね。
良い仕事をしています。

怪我しそうな尖った部分もなく丈夫な作りです。幼児が噛んだりしても危険はないでしょう。
万が一踏んづけても壊れわするも、丈夫な生地のお蔭て破片が飛び出て足にけがをしたり
しないでしょう。

猫を飼ったことがある方は分かると思いますが、猫用の動くおもちゃってすぐ壊れます。
高いわりに作りがペット用だから手を抜いている感がありありで作りが華奢です。

というか、ルミちゃんの攻撃が激しすぎるのかもしれません。
一方、タマちゃんはおもちゃにはあまり全く関心を持ちません。

2016年3月 3日 (木)

PIC24FJ64GB002を使ったUSBホストの実験 4

MIDI-IN端子を取り付けて、シーケンサーソフトを使った動作テストを出来るようにしました。

08

Dscn4932

回路的には、MIDIの作法に従って間にフォトカプラを入れています。
MIDIのプロトコル自体はシリアル通信ですが、物理層的にUARTとは違いますね(たぶん)。
カレントループという方式(電流の大小を1、0とする)なのでその対処が必要です。

取りあえず、回路図を作成してから結線しました。

07
TXDをPICマイコンのRxDに接続してデータを拾います。

この端子にamazonで購入した安いUSB-MIDI変換アダプタを取り付けてパソコンに
接続しました。

早速、Dominoにて適当なmidiファイルを使って演奏させると、ポケット・ミクから
音が出ました。

ただし、ミク声を出すためのシステムエクスクルシブ命令を使うと、ミクの声が
出るものの、奇声でなんか違う。全体的な演奏も怪しくなります。
演奏を止めても、音が鳴りっぱなしになったりもします。

システムエクスクルシブの処理がダメそうです。可変長データの処理がまずそうです。
MIDIメッセージからMIDIイベントパケット4バイトずつに分割する箇所が怪しいかも..

デバッグはやるとして、異常時の音の鳴りっぱなしはマズイですね。
自動・手動でポケット・ミクをリセットする機能も欲しい。

PIC24FJ64GB002を使ったUSBホストの実験 3

方向的にMIDIコンバーターの実装に進んでいます。

シリアル通信で外部MIDIメッセージを受信し、USB-MIDIインターフェスのMID音源I機器に
演奏データを送信します。下図のように真ん中でインタフェース変換を行います。

04

取りあえず実装し、動作確認としてIchigoJamからMIDIメッセージを送信してみました。
IchigoJam間はGNDとTX-RX接続の2本だけです。

03

MIDI端子(IN/OUT)ってピンが5本あるのでてっきり双方向かと思っていたのですが、
一方向だったんですね。この接続で初めて知りました。
相手からの応答の通信仕様が無いので疑問に思っていました。

実際にやってみて初めて理解出来ることってありますね。

動作の様子



IchigoJam用の演奏プログラムは、IchigoJam開発者の福野さんのブログ「福野泰介の一日一創」
の記事「YAMAHA NSX-1 x IchigoJam eVY1とBASICを使ったお手軽DTM」にて公開している
プログラムをそのまま利用しました。福野さんの記事ではeVY1を使ってIchigoJamで演奏
させています。

IchigoJamは単体で動作し、プログラム修正が容易なので実験や動作確認には良いですね。

今回の実験において、
  「4MHzの外部クロック供給、内部オシレータ(FRC)でもいけるんじゃね?」
と思い、試してたところ動いちゃいました。

システムクロックの精度に敏感なUSB、シリアル通信とも取りあえず動作しているので
以後これでいっちゃいます。

01

4MHzのセラミック発振子を取り外せてちょっとすっきりしました。

回路図(電源供給の三端子レギュレータとmicroUSBコネクタを除く)的にも、
パスコンと抵抗とコネクタだけです。

(2016/03/08 修正 回路図のD+とD-の接続が間違っており、修正しました)

02


ソフト的に追加した機能は、
・シリアル通信周りの機能の実装
・MIDIメッセージ→MIDIイベントパケットに変換処理の実装
・USB周りの異常系(USBデバイスの抜き差し、USBデバイス電源落ち等)
・電源管理(USB機器が未接続の場合はアイドル状態にする)
です。

まだまだ、動作不安定なところがあります。
・USBデバイスを切断した場合に割り込みで呼ばれる関数から復帰後、フリーズした
  ような状態になります。全く原因が分からず、仮対処として割り込み発生時に
  ソフトウェアリセットをして復旧しするようにしました。
  これは後々何とかしたい。

・でたらめなMIDIメッセージ(内容が正しくない)を流し続けるとポケット・ミクで
  演奏できなくなる。
  IchigoJamのシリアル出力は、画面に表示される内容も垂れ流しとなるので、
  接続している間、MIDIメッセージとしてでたらめなメッセージも送ってきます。
  MIDIメッセージ→MIDIイベントパケットの変換で不正メッセージは取り除いて
  いるのですが、何故か演奏出来なくなります。こうなると手動でリセットしないと
  復旧で出来ない。これは原因を見つけて対処が必要。

ソフト的な問題なのでハードとしてはMIDI端子を付けて、基板実装いたしましょう。

« 2016年2月 | トップページ | 2016年4月 »