So-net無料ブログ作成
検索選択

Arduino ISP を3.3Vでも使えるように [Arduino]

例えばBluetoothのモジュールをAVRマイコンに接続してしまった場合など、すでに3.3Vで周辺回路を作ってしまったときに、AVRマイコン書き換え時のISPの信号レベルが5Vだと心配です。
ISPのレベルを3.3Vにシフトすることを考えました。
調べてみると、、

RadioAgeCom:Arduino ISPによるArduinoのAVRライター化(3V対応)
http://radio-age.com/make/Arduino-ISP/index.html

こちらにまるまるそのままありました。
BSS138というFETを4個使うそうです。

bss138.png

Logic Level Converter Bi-Directional - BOB-12009 - SparkFun Electronics
https://www.sparkfun.com/products/12009

levelshift_fet.png

さて、つくろうかどうしようかと思ったところで、うちにはSeeeduinoが眠っていたことを思い出しました。
FTDIのUSBシリアル変換チップが載っていて、電源切り替えスライドスイッチ(USB/外部)やオートリセットの切り替えスライドスイッチのほかに電圧選択スライドスイッチ(5V/3.3V)がついています。

seeeduino2120.jpg

16MHzで3.3Vは保障外ですがこれでいけそうです。(まだ確認していません。)




秋月の「SDカードスロットDIP化モジュール」とArduinoをつなぐ [Arduino]

SDカードスロットとレギュレーターがセットになって2.54mmピッチのピンがついたものです。

k05818.jpg
SDカードスロットDIP化モジュール: 組み立てキット 秋月電子通商 電子部品 ネット通販
http://akizukidenshi.com/catalog/g/gK-05818/

DIP化モジュールとありますが、DIPとはDual Inline Package のことなので、本来はSIP (Single Inline Package) が正しいのではないかと思います。

特徴としては、、
(1) SPI接続するためのピンだけでている
(2) 表面にピンが出ている
(3) 入出力ともに3.3Vでプルアップされる

(1) については、SDモードを使うにはライセンスなど必要らしいのでSPIモードで十分。
(2) については、裏返しにしないと、ブレッドボードに刺さりません。シルク印刷は表面にあるので、ブレッドボードに挿してしまうとピンアサインがわからなくなってしまいます。事前にメモしておくか、ブレッドボードの端っこに挿してシルク印刷が見えるようにするかしないといけません。裏返す利点としては、ヘッダピンの根本の黒いプラスチック部品の高さと、カードスロットの厚みとが近いのでやや安定はします。
(3) については、ちょっと悩みました。いろいろ調べたところ、SDカードからの信号(SDOのみ)はArduino
のHレベル(5V)よりは電圧が低いですがそのままArduinoにつないでOK。逆の信号(SDI, CLK, CS)はそのままだと、5VがSDカードにかかってしまいSDカードが壊れてしまうかもしれません。そこでダイオードのカソードをArduino側にして間に挟んで接続します。Arduino側の信号がHのときは、ダイオードのおかげでSDカード方向には電流は流れないものの3.3VでプルアップされているのでSDカードの信号もHになります。Arduino側の信号がLのときは、SDカード側からダイオードを通ってArduinoの方に電流がながれていくのでSDカード側もLになります。(といっても順方向電圧降下があるので、0.6Vですが、Lと見なします。)

つないでみるとこんな感じ。
k05818_bb1.jpg

Arduino Leonardo と UNO で確認しました。
k05818_bb2.jpg

タグ:SDカード

USBasp使ってみた。 [Arduino]

USBaspという書込装置があります。
USBコネクタ直結タイプのものは10ピンタイプのものがほとんどですが、6ピンタイプのものを見つけたのでゲットしました。
usbasp_6p.jpg
Aliexpress内のお店で $4.40 (送料込み)、2週間ほどで届きました。

あと問題となるのはドライバ
64bit版でwindows8 ということでドライバのインストールが非常に厳しくなっています。
そこで次のソフトを使うと、いとも簡単にインストールできました。

Zadig - USB driver installation made easy
http://zadig.akeo.ie/

ここから、ソフトをダウンロードして実行するだけ。
あらかじめ別にドライバをダウンロードしておく必要もありませんでした。

実行すると、、
zadig_1.png

このブツをUSBコネクタにさしこみ、ドライバを指定。
zadig_2.png

AVRISP mkII と違って電源がきているので ATtiny45 をこんな感じでつないで、、
usbasp_pc.jpg

マイコンボードをATtiny45、書込装置をUSBaspに指定。
LチカのスケッチのLEDのピン(13番ピン)だけ書き換えて書き込みます。

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: warning: cannot set sck period. please check for usbasp firmware update.

こんな注意を受けますが、ちゃんと書き込めていました。

タグ:USBasp

GR-SAKURA、GR-KURUMI 買おうかどうしようか。

GR-SAKURA、GR-KURUMI は日本のRenesasが作っているCPUを使った Arduino と類似のマイコンボートとなっています。
日本のメーカーが作っているのでぜひ使いたいところではありますが、ちょっと特徴をしらべてみました。

がじぇっとるねさす | ルネサス エレクトロニクス
http://japan.renesas.com/gr

gadget_rene.jpg
・高性能32bit CPU 表面実装
・LAN、USBホスト、microSD(MMCカード)に初めから対応
・安価(Arduino本体と各種シールドを合わせたものと比較して)
・クラウドWebコンパイラ
・GR-KURUMIボードは乾電池1本(1.5V)で動く

簡単にはこんな感じ。

以下、あくまで個人的なArduinoとGR-SAKURAとに対する印象です。
Arduinoは、プロトタイピングが目的であり、そのプロトタイピングが早いというのが利点。
最後までArduinoを使うというものではなく最終的には、自作の基板でつくったり、Pro mini のようなボートを組み込むという用途に向いているのではないかなぁと思っています。
イーサネットシールドやUSBホストシールドなど各種シールドもありますが、これは他のマイコンボードであれば初めから搭載していて価格面でも劣っています。このシールドと同様のものを自作するのも大抵困難だと思います。
イーサネットシールドとかUSBホストシールドなどを必要とするような工作は、GR-SAKURA などといった初めから機能を搭載し、しかも安価なもので作ったほうがいいのだと思います。
GR-SAKURAは、ハード的にはだいたい利点がほとんどなのですが、表面実装CPUであり自作はほぼ困難(KURUMIならいける?)、互換機がないなどの欠点があります。
ただホビーユースとして使う上で一番気になるのは、ライセンスの注意しないといけないようです。
Arduinoはハードもソフトも基本的になにをやってもOKという感じで面倒なことを考えなくてもいいのですが、GR-SAKURAではライブラリなどは特殊電子回路株式会社という会社が作ったものでありフリーではありません。そのためGR-SAKURAという枠でのみArduinoライクなシステムの使用が許可され、Webコンパイラが使えるというかローカル環境での使用はできないといった制限があります。
逆にArduinoはGPLなのでプログラムも公開しなければならないようですが、企業の人にとってはこの点が使いにくいものになっているのかもしれません。
つまりGR-SAKURAは、ハード・ソフト・開発環境はホビーユースとして設計されているのに、ライセンスは企業向けとなっているところに違和感を感じてしまいます。
そうはいってもGR-SAKURAという枠組みを超える(外れる)ものを個人レベルで作るのは無理そうなので実質問題ないのだと思います。

RXduinoのライセンス
http://rx.tokudenkairo.co.jp/license.html


国産マイコンボードGR‐SAKURAではじめる電子工作 (I・O BOOKS)

国産マイコンボードGR‐SAKURAではじめる電子工作 (I・O BOOKS)

  • 作者: 倉内 誠
  • 出版社/メーカー: 工学社
  • 発売日: 2013/09
  • メディア: 単行本


手っ取り早くマトリックスLEDを使う その3 [Arduino]

マトリックスLEDで表示ができるようになったので、それで何かしてみようと思いました。
とりあえず、ジャンケンをしてみます。
jkp.jpg
スイッチを取り付けるのも面倒だったので、リセット毎にランダムで表示することとしました。
横スライドしやすいようにイメージデータは列毎1バイトとして作成しました。

また恥ずかしながらソースは下記のとおり。
// Arduino Pro Miniで手っ取り早くマトリックスLEDを使うスケッチ (Arduino Pro Mini専用)
//   (SZ420788K: 8x8, 0.8inch, カソードコモン)
//   を応用してジャンケンをする。
#include <avr/sleep.h>
const uint8_t MATRIX_ROW[] = {  2,  7, 17,  5, 10, 16, 11, 14 };  // 行 → デジタルピン番号
const uint8_t MATRIX_COL[] = {  6, 12, 13,  3, 15,  4,  8,  9 };  // 列 → デジタルピン番号 (左からLSB->MSB)
uint8_t *MATRIX_IMAGE;        // イメージのポインタ

uint8_t jkp_ready[] = {       // 横にスライドしやすいようにイメージは列毎にデータを作成
  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  // じゃん
  B00111111,  B01000000,  B10000000,  B10000000,  B10000010,  B01000100,  B01000001,  B00100010,
  B00000000,  B00010000,  B00010000,  B00011100,  B00110000,  B11001000,  B00001110,  B00101000,
  B00101000,  B00010000,  B00000000,  B11000000,  B00100000,  B00011000,  B00010110,  B00010001,
  B01100000,  B10000000,  B10000000,  B01000000,  B00100000,  B00000000,  B00000000,  B00000000,

  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  // けん
  B01111100,  B10000011,  B00000000,  B00000000,  B00000100,  B00000100,  B10000100,  B01111111,
  B00000100,  B00000100,  B00000000,  B11000000,  B00100000,  B00011000,  B00010110,  B00010001,
  B01100000,  B10000000,  B10000000,  B01000000,  B00100000,  B00000000,  B00000000,  B00000000,
  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  B00000000,  
};
uint8_t jkp_image[3][8] = {
  { B00111000,  B01111100,  B11111110,  B11111110,  B11111110,  B11111110,  B00111110,  B00011100 },  // グー
  { B00110000,  B01111111,  B11111111,  B11110000,  B11111111,  B11111111,  B01111000,  B00110000 },  // チョキ
  { B00110000,  B01111110,  B11110000,  B11111111,  B11110000,  B11111111,  B01110000,  B00011000 }   // パー
};
  
void setup() {
  for( int i = 2; i <= 17; i++ ) pinMode( i, OUTPUT );
  pinMode( A4, INPUT );       // ランダムな値の発生源として未接続のピンをアナログ入力にする
  TCCR2A = B00000000;         // Timer2 (8bit) のオーバーフローで割り込む。ちらつきがない分周比は
  TCCR2B = B00000010;         // dot毎なら010(8分周まで),line毎なら101(128分周まで)くらい。
  TIMSK2 = B00000001;         // TOIE2 (オーバーフロー割り込み許可)
}

void loop() {
  for( int i = 0; i < 72; i++ ) {
    MATRIX_IMAGE = jkp_ready + i;
    delay(30);
  }
  delay(200);
  MATRIX_IMAGE = jkp_image[ analogRead( A4 ) % 3 ];
  delay(2000);
  MATRIX_IMAGE = jkp_ready;   // 消灯
  delay(1);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
  sleep_mode();               // リセットするまで動作停止
}

ISR( TIMER2_OVF_vect ) {
  static uint8_t row, col;
  digitalWrite( MATRIX_COL[ col ], LOW  );
  if( ++col == 8 ) {
    col = 0;
    digitalWrite( MATRIX_ROW[ row ], HIGH );
    row = ( row + 1 ) % 8;
    digitalWrite( MATRIX_ROW[ row ], LOW  );
  }
  digitalWrite( MATRIX_COL[ col ], ( MATRIX_IMAGE[ col ] >> row ) & 1 );  // データの都合で行と列を変更
}

未使用のA4ピンをアナログ入力でランダムな値の発生源としましたが、入力端子をオープン(未接続)状態にするのはどうやら本当は良くないらしい、、、。

こんな感じです。



初めてのYou Tubeへのアップロードでした。

Arduinoでの時間管理 [Arduino]

Arduinoにおける時間の扱いを Arduino IDE 1.0.5-r2 (Windows版) で調べてみました。
time.png
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino にある wiring.c を覗いてみます。

ArduinoはTimer0という8ビットのタイマ/カウンタを使用して時間の管理をしています。
CPUクロックを64分周して0から255までカウントしていきオーバーフローで割り込んで時間を計算していっているようです。

64分周でさらに256回に1回割り込むと、割り込みがかかるのにかかるクロック数は、64 x 256 clkです。
16MHzだと、割り込みがかかるのにかかる時間は、(64 x 256) / 16000000 sec = 1024 μsec となります。
割り込みのたびに、この 1024 を 1000で割った商(=1)をミリ秒のところに足していきます。
また余り(=24)を別に足していき、1000をになったらミリ秒に1を足す、、と思いきや、、余りを3ビット右シフト(=8で割る)したもの(=3)が、1000を3ビット右シフト(=8で割る)したもの(=125)になったらミリ秒に1を足していく。(3ビット右にシフト(=8で割る)しても整数であることと、8ビットでの処理ができるのでこのようにしたのだと思います。)
こんな感じで、mills()はできています。

micros() は、Timer0がオーバーフローした回数と、Timer0のカウンタを使ってできています。
CPUクロックの64分周ごと、つまり (1/16000000) x 64 sec = 4μsecごとにカウントアップしていくわけで、
micros()関数が呼ばれたときにはトータルで「(オーバーフローした回数 x 256) + 現在のカウンタ」回カウントされているので、これに4μsecをかけると、経過したμ秒が得られる。これが micros() の正体のようです。

さて、delay() はどうなっているのかというと、呼び出された時間と現在の時間をμ秒単位で(micros()を呼び出して)比較し、1000以上になったらカウントダウンしていき0になるまでループするというあんばいです。

問題は、delayMicroseconds() です。
CPUクロックが 20MHz, 16MHz, 8MHzの場合しかまともに動作しません。
これは、1サイクルで4クロック消費するループ(つまり、20MHzなら 1/5 μsec, 16MHzなら 1/4 μsec, 8MHzなら 1/2 μsecを消費するループ)をそれぞれ、必要とするμ秒数の5倍、4倍、2倍回すことでできています。
ですから ATtiny45 の 1MHz など 16MHz未満のものはすべて 8MHz として動作当然するようになっていうるので、うまいくはずがありません。
関数の呼び出しなどに伴うオーバーヘッドなども考慮された作りにはなっています。

同じような時間を止める関数がArduinoのシステムとは別にAVRのライブラリにあります。
C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\util にある delay.h , dalay_basic.h を覗いてみます。

dalay_basic.h には、_delay_loop_1() と _delay_loop_2() という2つの関数が定義されています。

_delay_loop_1() は、パラメータに8ビットの符号なし整数型でループ回数を指定、1ループあたり3クロック消費。
_delay_loop_2() は、パラメータに16ビットの符号なし整数型でループ回数を指定、1ループあたり4クロック消費。
オーバーヘッドは、1MHz動作のCPUだとそれぞれ、768μsec, 262.1msecに達するとコメントにありました。

dalay.h には、_delay_us() と _delay_ms() という2つの関数が定義されています。

_delay_us() は、F_CPU を 3000000 で割ったものに、μ秒をかけたものが、1未満なら _delay_loop_1() を1回ループ。255より大きければ(8ビットに収まらないならば)精度をミリ秒に落として _delay_ms() で処理。それ以外なら、_delay_loop_1() で処理するというもの。
つまり、16MHz の場合、256 x 3 / 16 = 48 μ秒以上だとミリ秒単位に制度がおちて、さらにオーバーヘッドについては無考慮です。
ArduinoのdelayMicroseconds()だと使えるクロックが限定されますが、よっぽど正確です。

_delay_ms() は、F_CPU を 4000 で割ったものに、ミリ秒をかけたものが、1未満なら(パラメータが1以上でF_CPUが4kHz以上ならあり得ませんが、、) _delay_loop_2() を1回ループ。65535より大きければ(16ビットに収まらないならば)F_CPUを40000で割ったものを _delay_loop_2() でループさせ(=1/10msec消費する)、それをさらにμ秒の10倍でループするという処理。それ以外なら、_delay_loop_2() でそのまま処理するというもの。_delay_loop_2() には、16bit(=65535)までしかパラメータに渡せないので、16MHzの場合、65536 x 40000 / 16000000 = 16.384 秒未満しか使えないようです。

あと、時間に関係する関数としては、pulseIn() があります。
C:\Program Files (x86)\Arduino\hardware\arduino\cores\arduino にある wiring_pulse.c を覗いてみます。
こちらも信号が変化するまでループをします。ループの回数を測定しそのループにかかるクロック数をかけることでパルスの長さを得ることができます。

消費クロック数から時間を測る方法は、割り込みによる影響で誤差がでるので注意が必要なようです。

タグ:時間 Delay

Arduino TVout Library セットアップ [Arduino]

いわゆるビデオ出力(NTSC)について調べてみました。

いろいろ調べるとAVRでのカラービデオ出力は大変ということがわかりました。
AVRを14.318MHzのクリスタルで動かして、1クロック単位で出力を切り替えることで基準となる波形(バースト信号)を作り出し、その波形との位相のずれで色を作り出すというもののようです。
ArduinoとC言語だけでなんとかなるものではなさそうだということがわかりました。
モノクロの出力については同期の問題だけでなんとかなるようでした。
NTSCの規格?(RS-170A)については、

RS-170A NTSCビデオ信号タイミング規格の概要
http://elm-chan.org/docs/rs170a/spec_j.html

ここが一番正確なようでした。
AVRでビデオ出力をしているサイトをいくつか見てみると、あまりこの規格通りにやっているところはなさそうで、テレビの調整力に頼っている印象でした。
Arduinoでちょっくらこの規格通りやってみるかと頑張ってみましたが、ちょっと試したところで挫折しました。

そこで本家に行きます。TVout Library というものがあります。

Arduino Playground - TVout
http://playground.arduino.cc/Main/TVout

ただ、これどうしたらいいの?ということで、ライブラリの設定などを映像にしてくれているところを見つけました。
英語で話していて、Windowsではありませんでしたが、なんとか設定できました。

Arduino TVout Library Setup - YouTube
http://www.youtube.com/watch?v=LMu7EASMfUY

この映像を再生、停止、早送りをしながら自分がやったことを文章にしてみます。
Uno + Arduino 1.0.5-r2 で動作確認しました。

1. ライブラリをダウンロードする
  ( http://code.google.com/p/arduino-tvout/ → Dounloads → TVoutBeta1.zip )
  そして展開する
2. Arduino IDEを起動し、スケッチブックの保存場所を確認する
  (ファイル → 環境設定 → スケッチブックの保存場所)
  そして一旦Arduino IDEは終了
3. 先ほど確認したスケッチブックの保存場所に「libraries」というフォルダを作成する
4. librariesフォルダに展開した3つのフォルダをコピーする
5. Arduino IDEを再度起動
6. スケッチ → ライブラリを使用 で、ユーザ提供 以下にライブラリが追加されていることを確認
7. ファイル → スケッチブック → libraries → TVout → DemoNTSC を開いてみる

という感じです。
Arduinoでここまでできるのかと感心いたしました。

ところで、ブレッドボードで実験の際に、

RCAジャックDIP化キット(黄): 組み立てキット 秋月電子通商 電子部品 ネット通販
http://akizukidenshi.com/catalog/g/gK-06522/
k-06522.jpg
こんなものを使ってみました。
ちょっと残念だったのは、細ピンヘッダが付属しており、通常のピンヘッダは使えないということです。
ビデオコードとつなぐとテコの原理でブレッドボードから抜けやすいのです。




手っ取り早くマトリックスLEDを使う その2 [Arduino]

前回のスケッチだと、マトリックスLEDに何か表示することが目的となっており他の処理がしづらい状態でした。
表示自体は割り込みを使って、CPUを解放してみました。

// Arduino Pro Miniで手っ取り早くマトリックスLEDを使うスケッチ (Arduino Pro Mini専用)
//   (SZ420788K: 8x8, 0.8inch, カソードコモン)
//   timer2使用
const uint8_t MATRIX_ROW[] = {  2,  7, 17,  5, 10, 16, 11, 14 };  // 行 → デジタルピン番号
const uint8_t MATRIX_COL[] = {  9,  8,  4, 15,  3, 13, 12,  6 };  // 列 → デジタルピン番号 (左からMSB -> LSB)
uint8_t *MATRIX_IMAGE;        // イメージのポインタ

uint8_t face_smile[] = {      // にこにこ
  B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10100101,
  B10011001,
  B01000010,
  B00111100 };

uint8_t face_angry[] = {      // ぷんぷん
  B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10011001,
  B10100101,
  B01000010,
  B00111100 };
  
void setup() {
  for( int i = 2; i <= 17; i++ ) pinMode( i, OUTPUT );
  TCCR2A = B00000000;         // Timer2 (8bit) のオーバーフローで割り込む。ちらつきがない分周比は
  TCCR2B = B00000010;         // dot毎なら010(8分周まで),line毎なら101(128分周まで)くらい。
  TIMSK2 = B00000001;         // TOIE2 (オーバーフロー割り込み許可)
}

void loop() {
  MATRIX_IMAGE = face_smile;
  delay(1000);
  MATRIX_IMAGE = face_angry;
  delay(1000);
}

ISR( TIMER2_OVF_vect ) {
  static uint8_t row, col;
  digitalWrite( MATRIX_COL[ col ], LOW  );
  if( ++col == 8 ) {
    col = 0;
    digitalWrite( MATRIX_ROW[ row ], HIGH );
    row = ( row + 1 ) % 8;
    digitalWrite( MATRIX_ROW[ row ], LOW  );
  }
  digitalWrite( MATRIX_COL[ col ], ( MATRIX_IMAGE[ row ] >> col ) & 1 );
}

交互に顔が変わります。
matrix_angry.jpg
loop() 関数内は、Lチカみたいな感じかな?


Arduino Pro Mini 328 5V 16MHz

Arduino Pro Mini 328 5V 16MHz

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス


手っ取り早くマトリックスLEDを使う [Arduino]

マトリックスLEDを使いたくても、16本の配線がネックになります。
手っ取り早くマトリックスLEDをつかう方法を思いついたのでやってみました。
ArduinonPro Mini (およびその互換機) を使う方法です。
ard_pro_mini.jpg
単色でピンの列の間が600milのものだとぴったりはまります。
今回は以前に aitendo という通販のお店で購入した、SZ420788K というものを使いました。

aitendo
http://www.aitendo.com/

こんな感じでソケットをつけます。
ard_pro_mini_socket.jpg
配線は一切なく、ピンソケットとシリアル&電源のピンをはんだ付けするだけです。
ソケットは普通のピンソケットを使うとゆるゆるなので、丸ピンICソケットを使用しました。

丸ピンICソケット (シングル40P): パーツ一般 秋月電子通商 電子部品 ネット通販
http://akizukidenshi.com/catalog/g/gP-01591/

今回使用したマトリックスLED (SZ420788K) のデータです。
matrix_data.png
だいたいどのマトリックスLEDも同様のピンアサインのようです。
またピンの順番も通常のICと同様の割り振り方です。

とりあえず表示するということでスケッチをかいてみました。
// Arduino Pro Miniで手っ取り早くマトリックスLEDを使うスケッチ (Arduino Pro Mini専用)
//   (SZ420788K: 8x8, 0.8inch, カソードコモン)
const uint8_t MATRIX_ROW[] = {  2,  7, 17,  5, 10, 16, 11, 14 };  // 行 → デジタルピン番号
const uint8_t MATRIX_COL[] = {  9,  8,  4, 15,  3, 13, 12,  6 };  // 列 → デジタルピン番号 (左からMSB -> LSB)

uint8_t smile[] = {      // にこにこ
  B00111100,
  B01000010,
  B10100101,
  B10000001,
  B10100101,
  B10011001,
  B01000010,
  B00111100 };

void setup() {
  for( int i = 2; i <= 17; i++ ) pinMode( i, OUTPUT );  // デジタル2~17まで出力ピン設定
}

void loop() {
  unsigned int i;
    // ドットごと、行ごとでの表示で明るさの比較
  for( i = 0; i < 64000; i++ ) {
    matrix_update_dot( smile );             // ドットごとの書き換え
  }
  for( i = 0; i <  1000; i++ ) {
    matrix_update_line( smile );            // 行ごとの書き換え
    delay(1);                               // delay(1) を入れることで明るくなる
  }
}

void matrix_update_dot( uint8_t *d ) {      // 1ドットずつ更新(暗いが明るさ均一)
  static uint8_t row, col;
  digitalWrite( MATRIX_COL[ col ], LOW  );
  if( ++col == 8 ) {
    col = 0;
    digitalWrite( MATRIX_ROW[ row ], HIGH );
    row = ( row + 1 ) % 8;
    digitalWrite( MATRIX_ROW[ row ], LOW  );
  }
  digitalWrite( MATRIX_COL[ col ], ( *( d + row ) >> col ) & 1 );
}

void matrix_update_line( uint8_t *d ) {     // 1行ずつ更新(明るいが明るさ不均一)
  static uint8_t row, col;
  digitalWrite( MATRIX_ROW[ row ], HIGH );
  row = ( row + 1 ) % 8;
  for( col = 0; col < 8; col++ ) digitalWrite( MATRIX_COL[ col ], ( *( d + row ) >> col ) & 1 );
  digitalWrite( MATRIX_ROW[ row ], LOW  );
}

データシート上は左から列を数えていますが、左を上位ビットにするとそのまま2進表記と一致するので逆としました。
ドットごとの書き換えだと、64回に1回の点灯になるので暗くなりますが、各ドットは明るさ均等のはず。
それに対して、行ごとの書き換えだと、8回に1回の点灯になるので明るくなりますが、おそらく1行全灯した場合にはLOW に流れる電流が多くなるものの引き込める電流に限界があるだろうということで輝度が不均一になることが考えられたり、電流制限抵抗もなにもはさんでいないので点灯時間は短くしたほうがいいということも考えれるのかと思っています。
dot_vs_line.jpg
行ごとで書き換えだけにして表示しつづけた場合ボードが熱くなりました。

アノードコモンのマトリックスLEDを使う場合には、digitalWrite() の出力をすべて逆にすればOK。

Uno / Leonardo用のPWMを使用した赤外線リモコン [Arduino]

以前、ATtiny13Aで作ったもののアレンジです。
delayMicroseconds() を使って疑似的にキャリア周波数を作ることもできるのですが、あまりエレガントな感じがしないので、キャリア周波数(38-40kHz)はPWMで作成し、信号の波形の作成はdelayMicroseconds() を使用することとしました。

uno_ir_pwm.jpg
UnoとLeonardoで動作確認しました。
デジタル10ピンとGNDに赤外線LEDを直結しています。(AVRの駆動力という点と、パルス出力をするという点でたぶん大丈夫?)

// PWMで38kHzをつくる赤外線リモコン (Arduino Uno, Leonardo共通版)
#include "wiring_private.h"          // sbi(), cbi() を使うため
#define F_IR  38000L                 // キャリア周波数 (NEC, AEHAは38kHz, SONYは40kHz)

void setup() {                      // OC1B (Arduino的には10番ピン) を 38kHz PWM 出力にする。 
  pinMode( 10, OUTPUT );             // 出力方向にする
  TCCR1A = (0<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (1<<WGM11) | (1<<WGM10); 
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (0<<CS02) | (1<<CS01) | (0<<CS00);
      // 比較出力選択 COM1B1-0 :   10 で 高速PWM時OC1Bが BOTTOMでHIGH、比較一致でLOW, 00で切断
      // 波形生成種別 WGM13-0  : 1111 で 高速PWM動作
      // クロック選択 CS12-0   :  010 で 8分周 (000 で停止、001で分周なし など)
  OCR1AL = F_CPU / F_IR / 8 - 1;     // (( 16MHz / 38kHz ) / 8(分周) ) - 1 = 51
  OCR1BL = OCR1AL / 3;               // duty比を1/3にする OCR1B / 3 = 17
}

void loop() {
  sendIrNEC( 0xE41BBF40 );      // REGZA: 0x40 0xBF (TOSHIBA), 0x1B (Ch.Up), 0xE4 (~Ch.Up)
  sendIrNEC( 0xE41BBF40 );      // 2回送ってみる。
  delay(5000);                  // 5秒のdelay
}

void sendIrNEC( uint32_t d ) {
      // NEC形式の時間単位(T)は、9/16 msec = 562.5usec
  sbi(TCCR1A, COM1B1);  delayMicroseconds(  9000 );  // リーダ ON  (16T)
  cbi(TCCR1A, COM1B1);  delayMicroseconds(  4500 );  // リーダ OFF (8T)
  for(uint16_t i=0; i<32; i++) {                     // データ 32ビット分処理
    sbi(TCCR1A, COM1B1);  delayMicroseconds(   562 );                    // データ ON  (1T)
    cbi(TCCR1A, COM1B1);  delayMicroseconds( (d>>i) % 2 ? 1687 : 562 );  // データ OFF (0:1T/1:3T)
  }
  sbi(TCCR1A, COM1B1);  delayMicroseconds(   562 );  // トレーラ ON  (1T)
  cbi(TCCR1A, COM1B1);  delayMicroseconds( 39937 );  // トレーラ OFF (71T) (計192T)
}

UnoとLeonardoとのスケッチ共用とするため、Timer/Counter 1 (16bit)を8bitで使用しています。
デジタル9ピンのAnalogWrite()は競合するので使えません。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。