• Arduinoと ATtiny2313で SPI

    気がついたら前回工作してから半年もたってた。
    SN3E0090.jpg

    ArduinoからATtinyに指示を送ってモーターの制御をする、てなことをやるつもり。で、まずはSPIで指示を送り、これに従って何かする、ことをやってみたい。

     ※以下の内容は単にやってみたことの記録です。すべて無保証で、障害・損害・不利益・不都合に対し、筆者は一切の責任を負いません。

    SPI自体についてはこのへんを参照。
    なんでSPIを選んだかというと、
    I2Cよりも、仕組みが単純、転送速度も速くできるみたいだから。

    • Arduinoをマスター、AVR ATtiny2313Vをスレーブとする。
    • ATtiny2313にはSSがないみたいなので、PB4をLOWにしたらスレーブ選択、という体(てい)で。
    • マスターから送ったデータ8ビットを、スレーブ側でLED点灯で表現(面倒だったのでLEDは4つ。下位4ビットだけ・・・)&前回データを反転したものをマスターに返すことで、通信がうまくいったことを確認する。Arduino側はスレーブから受け取ったデータをSerialに書きだす。
    ATtiny2313は、外部クリスタル8Mhzを使用かつCKDIV8を無効にしているので、システムクロックは8Mhz。
    電源はUSBからArduinoに給電。ATtinyはArduinoから出ている5Vを使う。
    spi_test.PNG


    マスター:
    最近公開されたarduino 0022ではSPIが標準ライブラリになっているので、マスター側はこれを利用した。

    #include <SPI.h>
    #include <util/delay.h>

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

    SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setClockDivider(SPI_CLOCK_DIV8);
    SPI.setDataMode(SPI_MODE0);

    pinMode(2, OUTPUT);
    digitalWrite(2, HIGH);

    uint8_t d = 0;
    for (;;)
    {
    digitalWrite(2, LOW);
    uint8_t a = SPI.transfer(d);
    digitalWrite(2, HIGH);

    Serial.print(d, HEX);
    Serial.write(", ");
    Serial.println(a, HEX);
    d++;
    _delay_ms(300);
    }
    }


    void loop()
    {
    }


    スレーブ:

    試しながら学ぶAVR入門―マイコンの基礎と電子工作とWindowsアプリケーションの作り方 (SkiLL up mycomputerシリーズ)
    スレーブ側は、ATtinyのデータシートに、アセンブリ言語で書かれた実装例があるので、ニーモニックの説明を見つつC言語に書き下してみた。
    ニーモニックについてはデータシートに説明がある。

    外部割り込みがどういう挙動か知りたかったこともあり、SS相当のPB4で割り込みがかかるようにした。
    PB4がLOWになったら受信開始。8ビット受信する。受信にあたりマスターへの送信データは、前回受け取ったデータをビット反転したものとした。特に意味はない。
    受け取った8ビットのうち下位4ビットのON/OFFをPB0~PB3につないだLEDに反映する。


    #include <avr/interrupt.h>
    #include <avr/io.h>
    #include <util/delay.h>


    #define USCK PB7
    #define MOSI PB5
    #define MISO PB6


    volatile uint8_t triggered = 0;

    ISR(PCINT_vect)
    {
    if (!bit_is_set(PINB, 4))
    {
    triggered = 1;
    }
    }

    uint8_t spi_slave_receive(uint8_t send)
    {
    USIDR = send;
    USISR = (1<<USIOIF);
    while (!(USISR & (1<<USIOIF)));
    uint8_t receive = USIDR;

    return receive;
    }

    void spi_slave_init()
    {
    USICR = (1<<USIWM0)|(1<<USICS1);

    // MISO(PB6)は出力に
    DDRB |= _BV(MISO);
    // MOSI(PB5)/USCKは入力に
    DDRB &= ~(_BV(MOSI) | _BV(USCK));

    // MOSI(PB5)/USCK(PB7)プルアップ
    PORTB |= (_BV(MOSI) | _BV(USCK));
    }

    int main(void)
    {
    spi_slave_init();

    // LED(PB0..PB3)は出力に
    DDRB |= _BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3);

    // LEDを消灯
    PORTB &= ~(_BV(PB0) | _BV(PB1) | _BV(PB2) | _BV(PB3));

    // PB4プルアップ
    PORTB |= _BV(PB4);

    // PB4の変化割込み
    GIMSK |= _BV(PCIE);
    PCMSK |= _BV(PB4);

    sei();

    uint8_t d = 0x00;
    for (;;)
    {
    while (!triggered)
    {
    }

    // PB4がLOWになった

    // clear
    triggered = 0;


    // 1バイト受信+送信
    d = spi_slave_receive(~d);


    // display bits as LED
    for (int i = 0, check = 1; i < 4; i++, check*=2)
    {
    if (d & check)
    {
    PORTB |= check;
    }
    else
    {
    PORTB &= ~(check);
    }
    }
    }
    }


    おわり:
    ようやくマイコン間で8ビット転送できるようになった。
    普段やってることは、重層な抽象化レイヤの上に成り立っているので、8ビットどころかネットワークを超えて簡単に送り放題だし、RPCでもなんでもいくらでもやりようがある。たまにこうやってプリミティブなところから積み上げるのもいい訓練になるなと思った。

    環境:
     Windows 7 x64 Ultimate
      arduino 0022
      AVR Studio 4.18 + SP3
      WinAVR 20100110
    Arduino Duemilanove
    AVR ATtiny 2313V




  • arduinoと MP4212でモータを回す

    前回の「ラジコン風」ではモーターの駆動に、TA7219Pを使った。
    ネットをうろつくと、モータの駆動にはパワーMOSFETというのを使うそうで、この辺を参考にうなってみた。

    回すモータは、マブチモーターのRE260。
    SN3E0076.JPG

    タミヤのハイスピードギヤボックス。
    これ、ユニバーサルプレートの穴と、ギヤボックスのネジ穴位置がびみょーに合わない。
    カットするしかないのか、とも思ったが今はモータを固定できればいいので、テストベッド的な感じで。


    SN3E0078.JPG

    MP4212は、NchとPchのMOSFETが2つずつパッケージされていて、なんとなく扱いやすそうだと思ってこれにした。4Vで駆動できるしRE260なら定格に収ま りそうだし。

    FETは燃えるぞ壊れるぞ、という話があちこちで見られる。
    チキンなので、正転方向だけマイコン制御ありに、逆転方向のMOSFETはプルアップ・プルダウンで常にOFFになるようにして、PWMで回転数を制御するところだけ試した。

    TA7291Pのときと違ってドライバでの電圧降下が少ないため、エネループ2本で十分よくまわる。

    冒頭の参考ページにあるLow-side-PWMをなんちゃってでまねっこしてみる。
    右側の7セグメントLEDは、analogWrite()の値を示している。
    写真では、MOSFETをトランジスタ1個でスイッチしているけど、のちにプッシュ・プル構成にして高速スイッチングをめざした。けど、arduinoのPWM周波数が約490Hzということで(日本語リファレンスより)、今のところMOSFETのスイッチング速度を活かせる構成ではない。

    写真では付いていないけど、10kΩの半固定抵抗で分圧した電圧をanalogRead()で読ませて回転数が変化するようにした。半固定抵抗を動かすとスムーズに回転数が変化してちょっと楽しかった。調子にのってぐりぐり動かしていたら、ねじ切ってしまった。あぁ。今度はちゃんとボリュームにしよう・・。


    最終的には、モータ制御はATtinyなど小さめのマイコンを使い、arduinoから独立させようと考えている。
    SN3E0079.JPG

    ちょっと検索するとライタを自分で作っちゃう人ばかりで、道は遠いなーと思わざるを得ない。
    が、4000円投資してAVR ISP mkIIを購入。いいんだこれで。

    AVR Studio本体とSPをダウンロードしてインストール。
    ハナっからCで書くつもりなのでWinAVRもDLしてインストール。

    ここの環境はWindows 7 x64だけどドライバも問題なく認識。

    ATtiny 2313Vを2つ購入した。低電圧版を選んだのは、モータ制御とは別にリモコン的なものを考えていて、単三×2で動くようにしてみたかったから(モータ制御用のは5Vで使う予定)。
    とりあえずLチカするところまで進めたいなー、と、電源とGND(とISPに必要なピン)とLED+抵抗だけ結線して、ISPに繋ぐ。

    ISPのコネクタにジャンプワイヤを突っ込んでブレッドボードに挿す、大雑把さ。ISP側のピン配置はこのページを参考にした。後はデータシートを見てAVR側のピンに接続。
    Lチカ用のLEDは、PB0に繋いだ。

    電源はスイッチングなACアダプタ5Vから給電。クリスタルもパスコンもなんにもない状態。内部発振8MHzの1/8で、システムクロックは1MHz。

    AVR Studioを起動して、こんな感じのだらっとしたhello worldをビルドしてAVRに書きこむ。

    #include <avr/io.h>
    #include <util/delay.h>

    int main(void) {

    DDRB = 0xFF;

    const int pin = 0;

    while(1) {
    PORTB |= 1<<pin;
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    PORTB &= ~(1<<pin);
    _delay_ms(100);
    _delay_ms(100);
    _delay_ms(100);
    }
    }
    なんか、ちゃんと点滅してる。
    ブレッドボード上を見てると、ほぼワンチップマイコンだけが載ってる状態でプログラムが動いちゃうんだからおもしろいなー、と感動してしまう。

    次は、arduinoからSPIなりなんなりで、このATtinyに指令を送って何かさせる、ってことをやろう。


    環境:
     Windows 7 x64 Ultimate
      arduino 0018
      AVR Studio 4.18 + SP2
      WinAVR 20100110
    Arduino Duemilanove
    AVR ATtiny 2313V

  • arduinoと xbeeでラジコン的なもの

    先月観に行ったMTM05会場で、スイッチサイエンスの出店で、xbee×2とxbeeシールドを買ってきた。
    ZigBee対応版は在庫がないそうで、シリーズ2を2つ購入。後からファーム更新してZB対応版相当品に。

    xbeeでラジコン的な作例はたくさんあるので、今さら感あふれる感じなんだけど、とにかく自分で実際にやってみたかったのだった。

    機構・構造部品は、少年時代を思い出すTAMIYAの「楽しい工作シリーズ」を使った。
    昔懐かし、ツインモーターギアボックストラック&ホイールセットでクローラ風にしてみる。
    このギアボックス、子供の時は金属フレームかつ完成品だったような気がしたんだけど(はっきり覚えてない)、今はプラスチック製で組み立て式なんだな。

    最初、ユニバーサルプレートという工作界のユニバーサル基板みたいなヤツを一枚しか買ってなくて、ギアボックスとキャタピラを乗せたら、電池も回路も置く場所がなくなってしまった・・・。
    ユニバーサルプレートをもう一枚と、ユニバーサル金具というL字に使える構造材を買い足した。

    で、出来たのがコレ。なんか配線がピンピン飛び出てて危なっかしい・・。
    SN3E0071.JPG

    テーマは、
    • ラジコン的なものなので、当然、電池電源でもって行動できること。
    • Xbeeを使って、PCからリモート操作する。
    • おまけで、測距センサを使って、障害物に近づいたら勝手に停止する。
    ていう感じ。

    モーターは2つで、左右の動輪をそれぞれ駆動している。細かい回転の制御は何もやってなくて、全開かオフかの二択だ。TA7291Pを2つ使っていて正転と逆転のコントロールはかろうじて可能に。

    手持ちの電池ケースが単三×4のしかなくて、勢いが良すぎた。TA7291PのVrefをもっと下げておけばよかった。ギア音うるさいし。

    arduino用の電源は、二階建ての裏面に取り付けた006Pから供給。xbeeシールドを乗せちゃうと、Vinが隠れてしまうが、シールドと本体の隙間から無理やり差し込んだ。

    ユニバーサルプレートはネジ止めだけで構造を乗せていけるので便利なんだけど、穴のピッチが5mm間隔のため、基板と合わなくて難儀する。結局、arduinoの方は2穴だけ使って斜めに配置、モータードライバを載せた基板は、アングルを使って90度立てることに。若干斜めになっているのは、こっちもネジ穴の位置が合わなかったため。

    SN3E0073.JPG
    arduino~xbee(シールド)間の通信は、普通にシリアル通信出来てしまう。便利だ。0ピンと1ピンを使うので、単にSerial.begin(ボーレート)しておいて、読み書きするだけ。

    コード上は、aruduino IDE上のシリアルモニタを使って、コマンドとモータの動作を実装・確認。で、動かす時はXbeeシールドを乗っけるだけ(もちろんxbee間の設定は先に済ませておく必要がある)。

    xbeeの設定は、XbeeエクスプローラUSBとDigi社公式のX-CTUで。

    ここの環境では、2つのXbeeをどっちもFunctionSetを「Zigbee Router/End device AT」にして、お互い相手のシリアルナンバーをDH/DLに指定している。

    1対1の通信では、Xbeeの良さをスポイルしてしまうが、ラジコン風用途で用いる分にはいいだろう、てことで。

    PC側のXbeeは、XbeeエクスプローラUSBによって仮想COMポートとして見えているので、何らかのTerminalからぽちぽちと入力すれば、arduino側のXbee+シールドを通じてシリアル通信で読みだされる。

    SN3E0072.JPG
    シャープ測距モジュール GP2Y0A21YK。秋月電子で購入した。対象、というか壁のようなものとの距離を電圧で得られる。

    距離と電圧の関係はリニアではないけど、近似式を求めた人がいたので、丸パクリしちゃう。ごっちゃんです。arduinoの場合、アナログ入力の分解能が10bitなので、analogRead()で得られた値を、(5/1024)倍して近似式に放り込む。

    室内の蛍光灯下で、「手のひら」を対象に測った感じでは、9cmから50cmぐらいまではそれっぽい値が出ている感じがした。(これ以上遠くは物差しがなかったのでよくわからん)

    本ラジコン風クローラでは、前進中で正面12cm未満に障害物が出てきたときは停止、というコードにしてみた。

    十分加速したところから、検知・制動すると、壁際2~3cmというところで、危なっかしい(^^; が、制御して遊ぶのが目的なのでヨシとする。



    キーボードからの入力で、工作がきーきー動くのはなんとも不思議な感じ。
    やっぱり、モータの制御がON/OFFで大雑把過ぎるな。今度は各種センサからの情報を取り入れて細かく制御することをテーマにしてみたい。

    ひとしきり遊んだ後で、いくらかかったかなーとふと思う。
     ・arduino=3,200円
     ・xbeeシールド=2,200円
     ・XbeeエクスプローラUSB=2,500円
     ・xbeeシリーズ2×2=5,960円
     ・ユニバーサルプレート×2=700円
     ・ツインモーターギアボックス=800円
     ・トラック&ホイールセット=600円
     ・ユニバーサル金具セット×2=800円
     ・測距センサ=400円
     ・TA7291P×2=360円
    あとLEDとかコンデンサとかソケットがあるけど無視して・・・17,520円。
    わぁ。


    環境:
     Windows 7 Ultimate x64
      arduino 0018
     Arduino Duemilanove

  • arduinoで lcd

    SN3E0066.jpg
    しばらく前に秋月電子で20文字×4行のキャラクタ表示液晶(SC2004CSLB。SUNLIKE社 SC2004C)を買った。
    当時、PICで制御してみたいなーともくろんでいてたんだけど、あっさり投げ出していたのだった。

    arduinoの場合、(リファレンスいわくHitachi HD44780とその互換チップセットをベースにした)LCDを制御するライブラリが標準装備なので、print感覚で文字表示できる、はず。。。

    とりあえず、同梱の説明書にある、「バックライトの電源を液晶側を共有」するようにちまちまとハンダづけする。J2にハンダを盛ってショートさせ、R8に添付されてた抵抗100Ω×3を並列に接続。

    同梱されてたピンヘッダを何も考えずにモジュール背面にとりつけたのだけど、ネットで見かけた作例だとピンソケットを全面にとりつけている人もいた。そしたらジャンプワイヤで簡単に接続出来てお試ししやすいのか。そういう考え方もあるんだなー。

    すでに取りつけてしまったものはCTRL+Zでとりはずすこともできず。さりとて電子工作初学者の自分は、ハンダを吸い取るのもおっくうで、このまま進むことにするのだった。

    ユニバーサル基板にソケットとコントラスト調整用の半固定抵抗をのっけた。
    説明書によれば、pin3 コントラスト調整用電源は、「=Vssで最も濃くなる」とあったので、何も考えずにGNDに繋いだら、何も表示していない部分や表示した文字の上下に不必要なドットが現れてしまった。
    手元に500Ωの半固定抵抗があったので、えいやっと繋いだけど、180度中、コントラスト調整として意味があるのは30度ぐらいだけになってしまった。残りの150度ぐらいは何も映らない。。。

    スケッチはただのコピペ。
    使ってる液晶が20桁4行なので、初期化パラメータだけちょびっと変更。

    #include <LiquidCrystal.h>

    LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);

    void setup()
    {
    lcd.begin(20, 4);
    lcd.clear();
    lcd.cursor();
    lcd.blink();
    lcd.setCursor(0, 0);
    lcd.print("ohayo");
    lcd.setCursor(2, 1);
    lcd.print("oyasumi");
    lcd.setCursor(4, 2);
    lcd.print("ore dayo ore ore");
    lcd.setCursor(6, 3);
    lcd.print("moshi moshi");
    }

    void loop()
    {
    }


    もはや制御らしい制御がコードに現れてこないのがすごい。
    リファレンスによれば、blink()の結果はディスプレイ次第だそう。この液晶モジュールではカーソル位置に、下線→黒塗りつぶし四角のアニメーションが表示された。

    環境:
      Windows 7 Ultimate x64
        Arduino 0018 (IDE)
      Arduino Duemilanove 328



  • arduinoをさわってみる

    一か月ぐらい前にamazonで入門キットを購入したのだけど、忙しくてなんとなく放置してた。
    キットに入ってたのは「Arduino Duemilanove 328」。

    準備:

    • Arduinoの公式サイトからIDEをダウンロード。バージョンは0018。
      • JRE6が同梱されてる。
    • B端子のあるUSBケーブルを用意してPCとボードを接続
    • Windows 7の場合、ドライバは自動インストールをじっと待てばOK。そのまま使えるようになる。
      →公式サイトのGetting Startedで「Really, it works!」って書いてあるのがウケる。
      • ここの環境は64ビットだけど普通に使えた。
    • ここの環境では、USB Serial PortにCOM3が割り当てられた。

    実装

    実装、というほどのことはしていないけど、なにかしら入力と出力があるものしたいなと考え、
     スイッチをONにするとLEDが光る (^^;;
    を目指してがんばる。。

    12番ピンを出力としてLEDの点灯制御に。
    11番ピンを入力としてスイッチの入力に。

    タクトスイッチのどの足がどのように繋がるかも知らなかったので、テスタ片手にポチポチと試したり。

    ネットで調べると、デジタルの入力にはプルアップ/プルダウン抵抗というのを付けるのだとか。
    スイッチON→真でコードが書けないと気持ち悪いという理由でプルダウン抵抗にしてみる。
    ※Arduino(というかAVRマイコン?)は内部プルアップを持ってるので、回路的にはプルアップの方がシンプルに。

    Arduino IDEを起動して、ボードの種類とCOMポートを設定。

    コードはこんな感じに。


    void setup() {
    pinMode(12, OUTPUT);
    pinMode(11, INPUT);
    }

    void loop() {
    int sw = digitalRead(11);

    if (sw) {
    digitalWrite(12, HIGH);
    }
    else {
    digitalWrite(12, LOW);
    }

    delay(100);
    }

    SN3E0065.JPG

    コンパイルしてUpload。

    タクトスイッチを押したらLEDが点灯した。わぁ。

    入力にプルアップ/プルダウン抵抗を付けないと、スイッチOFF時の入力値が定まらないというか不安定になる、ということが、ソフトウェア屋からするとなんとも不思議な感じ。

    digitalRead()の後で入力値を、
     Serial.println(sw);
    でシリアルに出力してみると、確かに1だったり0だったりする。

    ソフトウェアってのは多くの抽象化レイヤの上に成り立ってるのだな~と実感する。


    環境:
      Windows 7 Ultimate x64
        Arduino 0018 (IDE)
      Arduino Duemilanove 328

    Arduinoをはじめようキット
    スイッチサイエンス
    売り上げランキング: 1553
    おすすめ度の平均: 4.5
    5 これではじめました
    4 USBはB端子です
    5 ここから大ジャンプは無理だけど