2009年11月19日木曜日

Ardunio ベースの AVR プログラマブル・ワンボード風マイコン計画

世界のどこかでだれかが作っていそうなものだが,今のところ見あたらない.
Altair 8800 とか,日本でいう TK-80 とか,に相当する教育用マイコン開発ボードがほしいらしい.時代はマイコン Micro-computer (あるいは My コンピュータ)から Micro-controller へかわっている.

個人がホビーで買ったり,一人が長く使うものではないから,すべてが簡単で安価であることが優先.

(1)Arduino は,プログラミング・インターフェースに徹する.Arduino のCPUをプログラミング可能にするわけではない.それも不可能ではないが,Arduino 標準ブート・ローダからセルフ・プログラミングとモニタ機能つきのブートローダに置き換えたりがめんどくさそうだ.
(2)Arduino のシールドとして,ワンボード・マイコン風の機械語プログラミング用入出力をつける.AVRのアーキテクチャからすると,16ビットアドレス,8/16ビットデータが,表示・変更できればよい.プログラマブルCPUはシールドの上につける.ATTiny 2313 とか ATmega8 から ATmega168 ぐらいにしておく.スイッチ類は大変高価なので,入力機構は工夫する.ビット表示・操作は学習用途として必要である.LCDやキーパッドはケーブルで接続可能であればじゅうぶん.
(3)プログラム・コードは,Arduino がデータとして保持する.最低フラッシュ・メモリ2ページ分のバッファがあればいいだろう.4Kぐらいのメモリ・チップを使ってもいい.
Arduino のSPIがマスタになり,プログラマブルCPUのICSPをSPIスレーブとして使い,プログラミングする.コードは,Arduino をISPにする programmer2 とか mega-isp を流用する.
(4)クロックは,Arduino から外部供給してステップ実行や低速実行する.フルスピード実行は,ヒューズビットを書き換えて内蔵オシレータをアクティブにして行う.
(5)プログラマブルCPUのレジスタやメモリ内容などのステータスは,プログラマブルCPU上の割り込みルーチンやブートストラップコードでArduino 側に応答する.2Kワードまでのコードなら完全リロケータブルなので,また ATmega168クラス以上はブートローダ領域とアプリケーション領域がわけられるので,これらの存在は問題にならないだろう.

Programmer2 のコードで ATTiny 2313 のフラッシュ内容をダンプすることができた.今一番の問題は,(5)のためのコードだ.ATTiny だとアセンブラで書かねばならない.かもしれない.

2009年11月13日金曜日

ZigBee モデム・シールド

ASURA先生からZigBeeシールドとUSBシリアル・コンバータ SparkFun XBee Explorer USB(?),ZigBeeモジュール2コのペア・セットをかりてためしてみた.アシュラ阿修羅ってアフラマズダと関係あるんですかね.

シールドは,デジタル0−7番ピンソケット,アナログ0−5番ピンソケット,ICSPソケットで接続固定する設計で,さらにシールドをかさねることはできない.回路図によるとICSPソケットを通して5V, GND, Resetが接続され,ほかはデジタルピン0番と1番でRXとTXをつないでいる.(写真ではその5本をケーブルでつないでいる.)
モデムは一対一で自身と宛先の番号を設定することになる.詳細は Making Things to Talk を参照.シリアル・ターミナル・プログラムを引っ張り出したりするのがすこし面倒.Arduinoから設定を書き込んでしまうスケッチなど,だれか作っていそうなものだが.
利用は,プログラム済みのArduinoに装着し,PCなどとシリアル通信を無線で行う,というものになる.シールドをつけると無線でスケッチがアップロードできるようになる,わけではない.(実際リセット用のDTRなどが出ていない.)
TX/RXの切り替えジャンパ・ピンがあり,スケッチ・プログラムのコードをアップロード中は,無線モデムと切り離し(USB側をショート),予期しないモデム設定の変更が起きないようにする.
モデムを通した速度は9600bpsのみ.シリアル通信を使う動作確認済みのアプリケーションを,無線化するのにつかおう.SoftwareSerialとかSoftNewSerialで他のピンを接続に使えると,もっと使えそうだが.普通のBreakout boardがあればよかったのにですね.

2009年11月8日日曜日

Knapsacker おやつは500円までコンピュータ

「おやつは500まで」問題(学術的には組合せ最適化問題 Knapsack Problem)をお買い物の現場で解決できる「今週のアルゴリズム・メカ」1号プロトタイプである.

説明しよう.ダイヤル一つとボタン一つの操作だけで10アイテムまでお菓子の価格を登録でき,2の10乗の組合せすべてをあっという間にチェックして,500円以内でもっとも総額が高くなる組合せをLEDの点滅で教えてくれるのだ.バー型LEDやブレッドボードサイズの制約で,10アイテムまでの組合せとなっている.
私は500円じゃなくて200円だった?大丈夫.ソフトウェア・アップデートとモード・セレクトスイッチの追加で,200円など,500円以外の制限額も利用可能になる(予定).

二進数で値段を確認するのが苦手な人は,オプションでLCDディスプレイ装置(シリアル接続)が使え,テキストメッセージで入力額,それまでに入力したアイテムの合計金額も出るようになっている.私も苦手だ.
作り方は,画像でわかるとおりだ.
装置は大きくなっていくが,アイテム数を増やすのは簡単だ.Arduino のピン数がたりなくなっても,I2CやSPIを使うI/Oエクスパンダや7セグメントLEDコントローラを使って駆動LED数を増やすことができる.

難しい話まですると,アルゴリズムとその効率を学んでいるなら,部分集合すべてをつくして合計金額を確かめる方法では,10個ぐらいが限度だと気づくはずだ.1個増えるごとに,計算時間は2倍以上になっていくからだ(O(n 2^n)).16個で,すでに数十秒またされることになるだろう.


//Knapsacker.pde

#include 
#include 
#include "SerLCD.h"

SerLCD slcd(19);

const int ItemNumLimit = 10;
int prices[ItemNumLimit];
byte best[ItemNumLimit];

void setup() {
  slcd.begin(9600);

  pinMode(12,INPUT);
  
  for (int ic = 0; ic < ItemNumLimit; ic++) {
    pinMode(0+ic, OUTPUT);
    digitalWrite(0+ic, LOW);
  }
  
  for (int ic = 0; ic < ItemNumLimit; ic++) {
    prices[ic] = 0;
  }

  slcd.clear();
}

int analog0 = 0;
int itemNo = 0, tally = 0;
boolean clicked = false;
void loop() {
  int bestPrice;
  
  showBinary(analog0);
  if (digitalRead(12) == LOW && !clicked) {
    clicked = true;
    //
    prices[itemNo] = analog0;
    tally += prices[itemNo];
    itemNo++;
    for (int ic = 0; ic < 2; ic++) {
      showBinary(0);
      slcd.noDisplay();
      delay(250);
      showBinary(analog0);
      slcd.display();
      delay(250);
    }
  } else if (digitalRead(12) == HIGH && clicked) {
    clicked = false;
  }
  
  if (itemNo >= ItemNumLimit ) {
    slcd.clear();
    for (int ic = 0; ic < ItemNumLimit && prices[ic] != 0; ic++) {
      
      slcd.setCursor(0,1);
      slcd.print("#");
      slcd.print(1+ic);
      slcd.print(" ");
      slcd.print(prices[ic]);
      
      showBinary(0);
      delay(100);
      showBinary(prices[ic]);
      delay(500);
    }
    bestPrice = computeBest(prices, best);
    showBinary(best);
    slcd.clear();
    slcd.print("Buy ");
    slcd.setCursor(0,1);
    slcd.print("Total ");
    slcd.print(bestPrice);
    for (int ic = 0; ic < 2; ic++) {
      delay(500);
      slcd.noDisplay();
      delay(500);
      slcd.display();
    }
    while (digitalRead(12) == HIGH);
    for (int ic = 0; ic < ItemNumLimit; ic++) {
      prices[ic]= 0;
    }
    itemNo = 0;
    tally = 0;
  }
  
  analog0 = (analog0 + (analogRead(0)>>1))>>1;

  slcd.home();  
  slcd.print("#");
  slcd.print(1+itemNo);
  slcd.print(" Price ");
  slcd.print(analog0);
  slcd.print("  ");
  slcd.setCursor(0,1);
  slcd.print("Total: ");
  slcd.print(tally);
  slcd.print("  ");
  
}

void showBinary(byte b[]) {
  for (int i = 0; i < ItemNumLimit; i++) {
    if ( b[i] != 0)
      digitalWrite(i, HIGH);
    else
      digitalWrite(i, LOW);
  }
}

void showBinary(int v) {
  for (int i = 0; i < ItemNumLimit; i++) {
    if ( (v & 1 << i) != 0)
      digitalWrite(i, HIGH);
    else
      digitalWrite(i, LOW);
  }
}

int computeBest(int value[], byte best[]) {
  int bestPrice = 0, total, i;
  byte buy[ItemNumLimit];

  for (int i = 0; i < ItemNumLimit; i++) {
    buy[i] = 0;
    best[i] = 0;
  }
  while (true) {
    total = 0;
    showBinary(buy);
    for (i = 0; i < ItemNumLimit; i++) {
      if ( buy[i] != 0 ) {
        total += value[i];
      }
    }
    if (total <= 500 && total > bestPrice) {
      bestPrice = total;
      for (int i = 0; i < ItemNumLimit; i++) {
        best[i] = buy[i];
      }
      // the best is updated
      slcd.setCursor(0,1);
      slcd.print("Best Price: ");
      slcd.print(bestPrice);
    }
    // next buying list
    for (i = 0; i < ItemNumLimit; i++) {
      if (buy[i] == 0) {
        buy[i] = 1;
        break;
      } else {
        buy[i] = 0;
      }
    }
    if (i == ItemNumLimit)
      break;
  }
  return bestPrice;
}

2009年11月7日土曜日

Arduino 用I2C/Serial接続タイプLCDライブラリ

ストロベリー・リナックスが販売するST7032iコントローラ使用のI2C接続LCDを使うためのコード.初期化とコントラスト値設定が適切になされないと,電源を入れても表示にまったく変化がなく,おそろしいパーツである.
i2cLCD_ST7032i.zip

一般的なLCDモジュールをI/OエクスパンダMCP23009で接続するI2C接続LCD用ライブラリ.一般的なミニサイズの5VバックライトつきLCDをMCP23009と接続して,MCP23009のライブラリと共に使用する.データ制御に7ピン使用するので,バックライト用に1ピンつかってTrやFETでバックライトをスイッチする.(調光は無理.)0017から標準になったLiquidCrystal.hを参照し定数を利用する.
xLCD.zip
MCP23009.zip

SparkFun Electronics の Serial Enabled LCD (SerLCD) のライブラリ別バージョン.ハードウェア・シリアル(ピン0, 1)を使うとアップロードされるプログラムのコードがLCDにも流れ,ボーレートやスタートアップ・メッセージなどが変わりもとにもどすのに苦労することになる.そこでソフトウェア・シリアルを使う.0017から標準になったLiquidCrystal.hを参照し定数を利用する.
SparkfunSerLCD.zip

2009年11月3日火曜日

SPI ライブラリ for Arduino

Arduino のSPIライブラリは標準になっていない.いろいろモードがありペリフェラル側もさまざまだからだろうか.それで,既存のものを書き直しつつ使用中.1/4クロック(4MHz)各モードでDataFlashチップが動作している.

SPI.zip (仕様は予告なく変更されることがあります)

ライブラリ形態のソースコードを使用するには,圧縮ファイルからもどしたフォルダ(ヘッダ,ソースコード,キーワード,example コードなどが入っている)を
(1)Arduino 0017 (あるいはそれ以降の)開発環境ソフトウェアの場合,Arduinoソフトウェアを使うと自分のドキュメントディレクトリ(MyDocumentsとか書類とか)にArduinoフォルダ(Arduino home)ができる.この中に libraries フォルダ(ディレクトリ)を作り,入れる.
(2)Arduino 0016あるいはそれ以前のバージョンの場合,Arduino開発環境ソフトウェアのディレクトリ(パッケージ)の hardware/libraries に入れる.これは 0017 でも使えるが,ソフトのアップデートなど再インストールのたびに入れ直さねばならない.
いずれの場合も,Arduino ソフトウェアは起動しなおす.

16Mbit SPI DataFlash AT45DB161D by Atmel

Atmel 社の2MBytes フラッシュメモリ AT45DB161D を使用するためのライブラリ・コードとサンプル・スケッチ,SPIライブラリと平行して作成・修正中.チップはスイッチ・サイエンスで一個360円.ただしSOIC8ピン形状なので,DIPへの変換基板とかをつかおう.

DataFlash.zip(仕様は予告なく変更されることがあります)

2.5V-3.6Vの低電圧仕様だが,SPIやリセットなど入力信号ピンは5Vトレラント.テストではSOピンのみ,3.3Vから5Vへの変換回路の動作確認をかねて使っている.データシート上は電源電圧Vcc = 3.3Vでの出力Hiレベルは3.1Vで5V仕様のArduinoの最低入力Hi電圧3.0VをクリアしているのでブレッドボードにあるFETと抵抗2本は不要ということか.
Arduino Playground などでは同系列旧タイプ・チップのライブラリや動作確認できないライブラリしか見つけられず,しようがないので旧型チップ用ライブラリを書き直して,ごく基本的な読み書きで試用中.EEPROMよりはずっと速いので,センサのデータログを記録するのに使おう.