2014年、今年も無事に過ごせました
2014年もあと残りわずかとなりました。
うーん、時間の経過が早く感じる今日この頃です。
まあ、私の家族・猫たちとも平和で平穏な1年でした。2014年はまあ良い年でした。
こたつの住人タマちゃん
膝の上が大好きルミちゃん(しかし、ちょっと鬱陶しい)
寒いのでちょっと席を外すと、椅子(保温クッション付き)が占領される
本ブログ、来年はもう少し猫成分を多めにしよう。
guremikeさんのようなお洒落なブログを狙ってみようか・・
« 2014年11月 | トップページ | 2015年1月 »
2014年もあと残りわずかとなりました。
うーん、時間の経過が早く感じる今日この頃です。
まあ、私の家族・猫たちとも平和で平穏な1年でした。2014年はまあ良い年でした。
こたつの住人タマちゃん
膝の上が大好きルミちゃん(しかし、ちょっと鬱陶しい)
寒いのでちょっと席を外すと、椅子(保温クッション付き)が占領される
本ブログ、来年はもう少し猫成分を多めにしよう。
guremikeさんのようなお洒落なブログを狙ってみようか・・
作業メモです。
肥大化する C:\Windows\WinSxSフォルダのお掃除のメモです。
多分、大がかりなアップデート後等、何回か行うことになるでしょう。
参考にしたサイト
1)マイクロソフト WinSxS フォルダーのクリーンアップ
2)@IT 山市良のうぃんどうず日記(15):あのころ、君はもっとスリムだったはず
最初は1)の情報のみで作業をしたところ、エラーが発生しました。
C:\Windows\WinSxSフォルダのお掃除
1)StartComponentCleanup タスク同等の処理の実行
管理者権限でコマンドプロンプトを実行して、次のコマンドを実行する。
Dism.exe /online /Cleanup-Image /StartComponentCleanup
この処理は、タスク スケジューラからも定期的に呼ばれる処理なので、
危険性は少ないです。 処理が完了するまで1時間以上かかりました。
処理後、使用領域は20.9Gバイトとなりました。1Gバイト弱領域が広がりました。
2)コンポーネントのすべての古いバージョンを削除する
これを行うとサービスパック・更新プログラムのアンインストールができなくなるので
要注意。問題のあった更新プログラムも削除できなくなると思われる。
まあ、最悪再インストールで構わないのでやっちゃいます。
管理者権限でコマンドプロンプトを実行して、次のコマンドを実行する。
Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase
「エラー:1726 リモート プロシージャ コールに失敗しました。」で異常終了しました。
この対策は、参考にしたサイト2)にて解説されています。
タスクマネージャーにて"Windows Search"を停止後、再度実行するとうまくいきました。
処理後、再起動してCドライブの利用状況を確かめると使用領域は18.7Gとなりました。
使用領域は18.7Gバイトになりました。
処置前は21.8Gバイトなので3.1Gバイトのダイエットが出来ました。
最近、格安 $100以下の Windows8.1タブレットがAliexpressで売られているのですが、
SDDの容量は16Gバイトです。流石に16Gバイトだと使いものにならない気がします。
Lenovo Miix 2 8の環境設定の作業メモです。
OneDriveに写真や動画を詰めていると、Cドライブの領域を圧迫するので
SDカードに移動させました。
手順
1)SDカードをNTFSフォーマットする
FAT形式の場合、OneDriveのフォルダをSDカード上に変更しようとすると
エラーとなり設定出来ません。
(フォーマットすると当然、データは消えるので要バックアップ)
2)SDカード上にOneDriveフォルダを作成する
2)フォルダの移動
OneDriveのフォルダのプロパティ画面の[場所]タブにて移動先のフォルダを
指定して移動する。
前回の続きです。赤外線リモコンでモーターを制御出来るようにしました。
さらに、単3電池1本で強引に駆動させてみました。
リモコンによる操作機能
電源ボタン 低速前進 or 停止
+ボタン 速度をUP
-ボタン 速度をDOWN
速度は27段階(-13 〜 0 〜 13)で変化でき、
0は停止、正の場合前進、負の場合は後進する。+、-ボタンで操作できる。
回路図
主な部品
・8ピン8ビットマイコン ATtiny13A
・赤外線受信モジュール PL-IRM2161-XD1
・モータードライバモジュール DRV8830(秋月電子)
・DC-DCコンバータ(in 1〜5V out 5V 500mA)
・M1 DCモーター (FA-130RA相当) ダイソー プチ電車に搭載
・C1,C2 0.1μF セラミックコンデンサ
・C3 1000pF セラミックコンデンサ
・R1,R2 2.2kΩ 1/4W 炭素被膜抵抗
・R3 0.2Ω 1W 炭素被膜抵抗
DC-DCコンバータはAliexpressで購入したものです。
1Vから5Vの電圧を生成出来ます。
スケッチ(プログラムソース)
前回のスケッチに赤外線リモコンの受信処理を追加しました。
スケッチのサイズはジャスト 1024バイトです。何とか実装出来ました。
#include <tinyI2C.h> // I2Cアドレス #define DRV_ADR 0xC8 // DRV8830のI2Cアドレス #define CTR_ADR 0x00 // CONTROLレジスタのサブアドレス #define FLT_ADR 0x01 // FAULTレジスタのアドレス // ブリッジ制御 #define M_STANBY B00 // スタンバイ #define M_REVERSE B01 // 逆転 #define M_NORMAL B10 // 正転 #define M_BRAKE B11 // ブレーキ // 電圧定義 #define MAX_VSET 0x15 // 1.69V #define MIN_VSET 0x09 // 0.72V // for I/O Port #define IR 0 #define IR_DDR DDRB #define IR_PORT PORTB #define IR_PININ PINB #define IRbitRead() (IR_PININ&_BV(IR)) #define RC_RDH_TS 9000 // リーダコードOFF間隔 9ms判定用 #define RC_RDL_TS 3800 // リーダコードON間隔 4.5ms判定用 #define RC_BITLOW_TS 1000 // ビットデータON間隔 1.69ms判定用 #define RC_TMOVER 8000 // タイムオバー // リモコンコマンド #define RC_CMD_SW 0xA2 // ON/OFF スイッチ #define RC_CMD_UP 0x90 // 速度UP #define RC_CMD_DOWN 0xA8 // 速度DOWN // // 赤外線リモコンコード取得 // 4バイトのデータを返す // CCCCDDdd // CCCC カスタムコード // DD データコード // dd データコードのビット反転(データチェック用) // ただし、 // リピートコードの場合 0 // エラーの場合 0xFFFFFFFF // を返す. // uint32_t Read_IR() { uint8_t repeat = 0; // リピートコード検出フラグ uint32_t dt = 0; // 赤外線リモコン読み取りデータ unsigned long t ; // 信号長計測用 // リード部の取得 // 受信データはH/L反転で読まれる while(1) { while(IRbitRead()); // OFF検出受信待ち t = micros(); // OFF検出時刻取得 while(!IRbitRead()); // ON受信検出待ち t = micros() -t; // OFF->ONの時間間隔取得 if (t > RC_RDH_TS) { // 9ms以上ならリーダコードとみなす t = micros(); // ON検出時刻取得 while(IRbitRead());// OFF検出待ち t = micros() -t; // ON->OFF時間間隔取得 break; } } // データ部取得 if (t < RC_RDL_TS) { // 0N->OFF がリピートコードの場合、データ取得はスキップ repeat = 1; } else { // 0N->OFF がリダーコードの場合、データを取得 for (uint8_t i = 0; i <32; i++) { //32ビット分取得ループ // ビット開始待ち while(!IRbitRead()); // ON待ち t = micros(); while(IRbitRead()); // OFF待ち t = micros() -t; if (t>RC_TMOVER) return 0xFFFFFFFF; // エラー dt<<=1; dt |= (t>RC_BITLOW_TS) ? 1:0; } } // ストップビットの待ち while(IRbitRead()); // OFF待ち if (repeat) return 0; return dt; } // 制御コマンド送信 void write_vset(byte vs, byte ctr) { tinyI2C_Start(); tinyI2C_Write(DRV_ADR); tinyI2C_ReadBit(); tinyI2C_Write(CTR_ADR); tinyI2C_ReadBit(); tinyI2C_Write( ctr + (vs<<2) ); tinyI2C_ReadBit(); tinyI2C_Stop(); } //uint8_t dct = 0; // 方向 0:前 1:後ろ short spd = 0; // 速度 (0:停止 ,走行:1-13) byte hbg = M_STANBY; byte vout; void setup() { IR_DDR &= ~_BV(IR); // IRピンのみ入力設定する tinyI2C_Init(); // スタンバイ write_vset(MIN_VSET, M_STANBY); } void loop() { uint8_t rc = (uint8_t)(Read_IR()>>8 & 0xFF); // IR受信 switch(rc) { case RC_CMD_SW: // スイッチON/OFF if (spd == 0) { spd =1; } else { spd = 0; } break; case RC_CMD_UP: if (spd < 13) spd ++; break; case RC_CMD_DOWN: if (spd > -13) spd --; break; } if (spd == 0) { hbg = M_BRAKE; vout = MIN_VSET; } else if (spd > 0) { hbg = M_NORMAL; vout = MIN_VSET+spd-1; } else { hbg = M_REVERSE; vout = MIN_VSET-spd-1; } write_vset(vout,hbg); }
あとは、基板実装してなんとかケース内に収めてみます。
「ATtiny13Aでダイソー プチ電車を赤外線リモコン操作してみた」に続きます。
この前、arduino Unoにて試したDCモーター制御を
ATtiny13A(arduino IDE環境利用)に置き換えました。問題なく動作しました。
I2C接続は「ATtiny13AでI2C接続キャラクタLCDを利用する(3)」で作成したライブラリを
利用しました。
スケッチのサイズは728バイトです。
最終的に以前試した赤外線リモコンで操作したいのですが、
プログラムサイズを1024バイトにおさめるのに苦労しそうです。
スケッチ
#include <tinyI2C.h> // I2Cアドレス #define DRV_ADR 0xC8 // DRV8830のI2Cアドレス #define CTR_ADR 0x00 // CONTROLレジスタのサブアドレス #define FLT_ADR 0x01 // FAULTレジスタのアドレス // ブリッジ制御 #define M_STANBY B00 // スタンバイ #define M_REVERSE B01 // 逆転 #define M_NORMAL B10 // 正転 #define M_BRAKE B11 // ブレーキ // 電圧定義 #define MAX_VSET 0x15 // 1.69V #define MIN_VSET 0x09 // 0.72V // 制御コマンド送信 void write_vset(byte vs, byte ctr) { tinyI2C_Start(); tinyI2C_Write(DRV_ADR); tinyI2C_ReadBit(); tinyI2C_Write(CTR_ADR); tinyI2C_ReadBit(); tinyI2C_Write( ctr + (vs<<2) ); tinyI2C_ReadBit(); tinyI2C_Stop(); } void setup() { tinyI2C_Init(); } void loop() { // スタンバイ write_vset(MIN_VSET, M_STANBY); delay(1000); // 順方向 徐々にスピードを上げる for (byte i = MIN_VSET; i <= MAX_VSET; i++) { write_vset(i, M_NORMAL); delay(1000); } // 5秒間最大電圧 delay(5000); // 順方向 徐々にスピードを下げる for (byte i = MAX_VSET; i >= MIN_VSET; i--) { write_vset(i, M_NORMAL); delay(1000); } // 5秒間最小電圧 delay(5000); // ブレーキ write_vset(MIN_VSET, M_BRAKE); delay(5000); // 逆方向 徐々にスピードを上げる for (byte i = MIN_VSET; i <= MAX_VSET; i++) { write_vset(i, M_REVERSE); delay(1000); } // 5秒間最大電圧 delay(5000); // 逆方向 徐々にスピードを下げる for (byte i = MAX_VSET; i >= MIN_VSET; i--) { write_vset(i, M_REVERSE); delay(1000); } // 5秒間最小電圧 delay(5000); // ブレーキ write_vset(MIN_VSET, M_BRAKE); delay(5000); }
この前買った秋月電子の「お楽しみ袋」にPICマイコン(PIC16F84A)が入っていました。
このマイコンは古いけど割と人気のあるもの見たいです。
捨てるのも勿体無い。これを機会にPICマイコンを使ってみようと、
プログラマー pickit3 PIC programmerを購入し、試してみました。
手持ちのセラミック発振子 12Mhzを使ってクロックを供給しています。
pickit3の接続は、
nanoblog PICkit3を使ってMPLABからプログラムを焼く方法
PICkit™3インサーキット デバッガの使い方
を参考にしました。
4)プログラムの作成
C言語のプロジェクトの作成手順は
技術系のど根性 PICマイコンで遊ぶ 超入門編(C言語)
を参照して作成しました。
#include <stdio.h> #include <stdlib.h> #include <xc.h> #pragma config CP = OFF, PWRTE = ON, WDTE = OFF, FOSC = HS #define _XTAL_FREQ 12000000 int main(int argc, char** argv) { TRISA0 = 0x00; while(1){ RA0 ^= 1; __delay_ms(500); } return (EXIT_SUCCESS); }まず、最初にハマったのは、#pragma configでPICマイコンに設定する方法です。
一日がかりで、1ビットのLEDピコピコが出来ました。
内部クロック(CR発振)での動作も試してみましたがちゃんと動きました。
たかが Lチカですが、多くことを学べました。
OCN モバイル ONEの月額900円 でSIMカードを追加して利用していました。
1枚はスマートフォン(ARROWA ME F-11D)、もう一枚は7インチタブレットです。
別途通話&メール用にガラパゴス携帯(au)を使っています。
暫くこの形態(3台)で使っていると、スマートフォンの利用機会が徐々になくなりました。
移動時や外出時での情報検索は、タブレットの大きさでも全く問題無しです。
最近の7インチタブレットって重さも軽量ですし..
電話や、プッシュ型のメール着信はガラパゴス携帯を利用します。
結論
ガラパゴス携帯 と
タブレット(データ通信専用NVMO SIM利用)併用が最強!
ガラパゴス携帯の携帯性と電池の持ちの良さと(3週間はOK)、丈夫なところと
情報端末であるタブレットの組み合わせが一番です。
データの閲覧にはやはり、7インチくらいのサイズは必要ですね。
電子書籍や動画の閲覧は、スマートフォンだと閲覧微妙ですし。
ということで、スマートフォン用のSIMカードは解約しました。
私の職場では同様の結論に達した方が何人かいます。
私の所有している Lenovo Miix 2 8 はスリープモードになった場合に
電源ボタンを押しても復帰出来ないことがありました。
ロットが古い機器だけに発生するといううわさがあり、BIOSをアップデートしてみました。
まず、現在のBIOSのバージョンを確認してみます。
シャットダウン後、電源ボタン+音量UPボタンでBIOSを起動させます。
確認すると、V1.03でした。
一方、最新のBIOSは、サポートページを見るとV1.07が公開されています。
Readme(英語)ファイルを読んだ限りでは、具体的な変更内容が書かれていません。
取りあえず、早速ダウンロードしてアップデートしてみました。
BIOSのアップデートは、ダウンロードした90cn24ww.exeをLenovo Miix 2 8で動かす
だけで行えます。
アップデート中の画面はこんな感じです。
BIOSアップデート完了後、当然ですがWindows 8.1は問題なく起動しました。
見た感じでは何が改善されたのかさっぱり分かりません。
取りあえず、暫く使って見て改善点を探ってみます。
arduinoでDCモーターを制御したいと思い、I2C接続で制御できるDRV8830を試してみました。
秋月電子のDRV8830モータードライバモジュールを使いました。
税込170円と安いです。
モーター制御の知識はあまりないので徐々に勉強していきます。
モジュールはこんな感じ。思ったよりもも小さいです。
こんな小さいICでDCモーター駆動出来るんですねぇ。
最終的にATtiny13Aを使って赤外線リモコンでダイソーのプチ電車を動かすのが目標です。
ダイソーのプチ電車(100円)
100円でDCモータ付きです。
DRV8830を使ったモジュールは他にいくつかあるようです。
秋月電子 DRV8830使用DCモータードライブキット
秋月電子 フルブリッジドライバ DRV8830DGQR(2個入)
ストロベリー・リナックス I2Cモータードライバ・モジュール DRV8830
データーシート等の資料はストロベリー・リナックスの製品のものが大変参考になります。
それでは実験です。
回路図
次のような配線を行いArduino Unoに接続します。データシートおよび
上記製品のモジュールの回路を参考にしました。
部品
C1,C2 0.1μF セラミックコンデンサ
C3 1000pF セラミックコンデンサ
R1,R2 2.2kΩ 1/4W 炭素被膜抵抗
R3 0.2Ω 1W 炭素被膜抵抗(1Wなのはこれしか入手出来なかったためです)
M1 ダイソーのプチ電車のDCモーター(多分 秋月FA-130RA-2270相当)
実装
プチ電車は、電池ボックス部を切除しました。
スケッチ
動作は加速正回転、減速正逆転、停止、加速逆回転、減速逆回転、停止を繰返します。
徐々に電圧の上げ、下げをしています。
DRV8830によるモーター制御は、関数 int write_vset(byte vs, byte ctr) で行っています。
vs で電圧を指定、ctrでブリッジ制御(正転、逆転、スタンバイ、ブレーキ)を指定します。
vs(VSET)の設定値(5V電源利用時)
出力電圧の実測値を測定すると0.1Vほど低いです。
VSET 0x08h 以下はモーターが回転しませんでした。
テストでは、0x09h〜 0x15h (0.72V〜 1.69V)の範囲で電圧を指定しています。
ctrの設定値(2進数)
00 スタンバイ
01 逆転
10 正転
11 ブレーキ
スタンバイ、ブレーキともモーターの回転は停止となります。
DRV8830がほとんどやってくれるので、スケッチはシンプルです。
今回のテストでは、ピン8に接続しているFAULTの処理は作りこんでいません。
今後、ピンの変化を割り込みで処理しエラーの対応を行いたいと思います。
#include <Wire.h> // I2Cアドレス #define DRV_ADR 0x64 // DRV8830のI2Cアドレス #define CTR_ADR 0x00 // CONTROLレジスタのサブアドレス #define FLT_ADR 0x01 // FAULTレジスタのアドレス // ブリッジ制御 #define M_STANBY B00 // スタンバイ #define M_REVERSE B01 // 逆転 #define M_NORMAL B10 // 正転 #define M_BRAKE B11 // ブレーキ // 電圧定義 #define MAX_VSET 0x15 // 1.69V #define MIN_VSET 0x09 // 0.72V // 制御コマンド送信 int write_vset(byte vs, byte ctr) { Wire.beginTransmission(DRV_ADR); Wire.write(CTR_ADR); Wire.write( ctr + (vs<<2) ); return Wire.endTransmission(); } void setup() { Wire.begin(); } void loop() { // スタンバイ write_vset(MIN_VSET, M_STANBY); delay(1000); // 順方向 徐々にスピードを上げる for (byte i = MIN_VSET; i <= MAX_VSET; i++) { write_vset(i, M_NORMAL); delay(1000); } // 5秒間最大電圧 delay(5000); // 順方向 徐々にスピードを下げる for (byte i = MAX_VSET; i >= MIN_VSET; i--) { write_vset(i, M_NORMAL); delay(1000); } // 5秒間最小電圧 delay(5000); // ブレーキ write_vset(MIN_VSET, M_BRAKE); delay(5000); // 逆方向 徐々にスピードを上げる for (byte i = MIN_VSET; i <= MAX_VSET; i++) { write_vset(i, M_REVERSE); delay(1000); } // 5秒間最大電圧 delay(5000); // 逆方向 徐々にスピードを下げる for (byte i = MAX_VSET; i >= MIN_VSET; i--) { write_vset(i, M_REVERSE); delay(1000); } // 5秒間最小電圧 delay(5000); // ブレーキ write_vset(MIN_VSET, M_BRAKE); delay(5000); }
実際の動き
ちょっと分かりにくいですが、雰囲気を感じてください。
意外と簡単にモーターを制御出来ました。発熱等もないです。
ただしこのモジュール、「1Aの最大連続駆動電流」をうたっていますが、
いろいろ調べてみると、実際は200mAの連続駆動が実用レベルのようです。
使い方が分かったので、今度はATtiny13Aに置き換えてみます。
「DRV8830を使ったDCモーターの制御(2)」に続きます。
ちっちゃいArduinoでUSB接続でHID(Human Interface Device)として動くデバイスです。
なんか面白そうことが出来そうなので買ってみました。
まあ、本物のDigisparkではなくクローン製品だと思いますが...
到着した製品は、こんな感じです。ほぼ2㎝の正方形です。
思っていた以上に小さいです。
ATtiny85が乗っているデバイスです。microUSBケーブル接続で利用できます。
一応、三端子レギュレータが乗っていてVIN端子から7〜35Vの電源が利用できます。
ドライバおよびDigispark専用arduino IDEは、次のサイトからダウンロードできます。
http://digistump.com/wiki/digispark
< 2015/02/06 追記 、2016/02/11 修正
現時点では、開発環境は arduino IDE 1.6.x 系に移行したようです。
純正arduino IDE のボードマネージャにてボードの追加にて対応出来ます。
http://digistump.com/wiki/digispark/tutorials/connecting
>
開発環境はarduino IDE 1.04をDigispark対応させた感じです。
メニュー - ツール - マイコンボードの一覧にDigisparkが登録されています。
またいくつかの専用ライブラリやスケッチの例(サンプル)が組み込まれていて
利用できます。
早速サンプルのKeybordを試してみました。次のスケッチです。
#include "DigiKeyboard.h" void setup() { // don't need to set anything up to use DigiKeyboard } void loop() { // this is generally not necessary but with some older systems it seems to // prevent missing the first character after a delay: DigiKeyboard.sendKeyStroke(0); // Type out this string letter by letter on the computer (assumes US-style // keyboard) DigiKeyboard.println("Hello Digispark!"); // It's better to use DigiKeyboard.delay() over the regular Arduino delay() // if doing keyboard stuff because it keeps talking to the computer to make // sure the computer knows the keyboard is alive and connected DigiKeyboard.delay(5000); }
キーボード入力デバイスとして動作し、5秒間隔で"Hello Digispark!"と
キー入力した振る舞いをするプログラムです。
若干、書き込み方法がArduino Unoと異なります。
書込みを実行すると、コンパイル後60秒内に抜!き差しすると書き込みが開始されます。
Running Digispark Uploader...
Plig in device now... (will timeout in 60 seconds)
と表示されると、抜き差しして書き込みが開始されます。
書込み速度はちょっと遅いですね。
書込み完了後、メモ帳を開くとご覧と通り。
5秒間隔で勝手に"Hello Digispark!"と入力されます。
ATmega32u4を搭載したArduino Leonardo、Arduino Microみたいなことが出来ます。
これはちょっと面白いかも。
(この後、IDEでプログラム修正をしようとすると"Hello Digispark!"と書き込まれるので
ちょっとうざい)
さて、搭載されているマイコンがATtiny85なのでピン数や機能、記憶容量等の
制約があるかと思います。
専用IDEのメニューに登録されているライブラリをみると次のような感じです。
シリアル通信、I2C、SPI、PWM等が使えそうなので色々と出来そうです。
ちなみに、利用できるフラッシュメモリはブートローダが2kバイト使っているので、
は6Kバイトです。
ちょっと、面白そうな入力デバイスが作れそう。
やっとタマちゃんが落ち着きを取り戻してきました。
頭や右耳を触っても嫌がらなくなりました。取りあえず、一安心です。
でも、右耳の中がぐじゅぐじゅして耳垂れ(?)が付着している状態です。
また来週病院に連れて行く予定です。
一方ルミちゃんは、相変わらずの甘えん坊さん状態。
ただ、今日は一日中寝込んでいる状況です。
こんな状態は初めてでとても心配。速く元気になってほしい。
仕事から帰ってくると、タマの様子が何となくおかしい。
ぐったりとして、頭を撫でると唸り声をたてて怒る。
何処か怪我でもしているのか身体を触ろうとすると嫌がって隠れてしまう。
挙動もなんか、変だ。怯えているよう状態。
見た感じ、出血も外傷もない用なんだけれど…
母に聞いてみると、玄関全開にしたまま友人と長時間バカ話をしていた間、
外に出てしまったとのこと。戻ってくると挙動がおかしい状態だだったそうだ。
またかぁ、何回も母に注意しても同じことを繰りている。
前は顎の骨を骨折して、血だらけになって私の蒲団の上でうずくまっていて、
母に確認すると、外に出られてしまったとのこと。
足を怪我して、帰ってきたこともある。
さっき、ご飯を上げると食べたので危機的な状態ではないようだ(と思いたい)。
明日は、朝一で動物病院に連れていく予定。
Arduino Unoでウォッチドックタイマを使ったインターバール割り込みが
実用的であるか試してみました。8x8ドットマトリックス表示で試してみました。
この前調べたtiny13A用のソースを流用しています。
作成したスケッチと回路はテストのためちょっとてんこ盛りとなりました。
特に問題なく動作しています。
ウォッチドックタイマ、今後は積極的に利用していきたいと思います。
解説等
8x8ドットマトリックスの表示はダイナミック点灯(駆動)方式で行っています。
ウォッチドックタイマ割り込みで16ms間隔で点灯処理を行います(ISR(WDT_vect))。
点灯処理内では1行分(横8個のLED)を順次点灯し、人間の目の残像を利用して
8x8のすべてが表示しているように見せています。
回路では8x8ドットマトリックスを直接Arduino Unoで駆動しています。
1ピン当たり最大40mAの制限があるため若干暗くなっちゃいますが実用レベルでしょう。
表示パターンの漢字を表示するためI2C接続EEPROM(AT24C1024B)を利用しています。
利用部品
・Arduino Uno 互換機
・I2C接続 シリアルEEPROM AT24C1024B
・赤色8x8ドットマトリクスLED MNA20SR092G
・抵抗器 2.2kΩ x 2
・抵抗器 220Ω x 8
ドットマトリックスのLEDに流す電流を決める抵抗は厳密に計算すると
ROW1-POW8の各ピンにそれぞれ40mAしか流せないので、
COL1-COL8の各ピンは40mA ÷8 = 5mAしか流せません。
したがって、COL1-COK8の電流制御用の抵抗Rは
R= (5V-Vf) / 5mA = (5V - 1.8V) / 5mA = 640Ω
となります。Vfはデータシートの数値を利用。
ただ、640Ωだとちょっと暗く、Vf=1.8VはIf=20mA時の値なので
色々試してみて220Ω当たりが良さそうと判断しました。
スケッチ(プログラムソース) ダウンロード(matrix.zip)
ちょっと長いですが、掲載します。
// // 8x8ドットマトリックスLED直接駆動デモ // 2014/11/29 たま吉さん #include <avr/interrupt.h> #include <Wire.h> //***************************** // 出力ピンの定義 //***************************** // 横 #define COL1 2 #define COL2 3 #define COL3 4 #define COL4 5 #define COL5 6 #define COL6 7 #define COL7 8 #define COL8 9 // 縦 #define ROW1 10 #define ROW2 11 #define ROW3 12 #define ROW4 13 #define ROW5 14 #define ROW6 15 #define ROW7 16 #define ROW8 17 //**************************** // WDT利用のための定義 //**************************** #define WDT_reset() __asm__ __volatile__ ("wdr") #define sleep() __asm__ __volatile__ ("sleep") #define WDT_16MS B000000 #define WDT_32MS B000001 #define WDT_64MS B000010 #define WDT_125MS B000011 #define WDT_250MS B000100 #define WDT_500MS B000101 #define WDT_1S B000110 #define WDT_2S B000111 #define WDT_4S B100000 #define WDT_8S B100001 //***************************** // フォントROM参照用 //***************************** #define DEVICE_ADDRESS 0x50 // AT24C1024B I2Cデバイスアドレス #define FONT_DATA_SIZE 56960 // フォントデータサイズ(バイト) #define FTABLESIZE 7120 // フォントテーブルデータサイズ #define FTABLE_ADDR 0x10000 // フォントテーブル先頭アドレス #define FONT_LEN 8 // 1フォントのバイト数 //***************************** // グローバル変数 //***************************** // COL,ROWのピン割り付けテーブル uint8_t col[8] = {COL1,COL2,COL3,COL4,COL5,COL6,COL7,COL8}; uint8_t row[8] = {ROW1,ROW2,ROW3,ROW4,ROW5,ROW6,ROW7,ROW8}; // 表示用バッファ(8x8ドット分) uint8_t pdata[8]; //********************************* // ウォッチドッグタイマー関連関数 //********************************* // WDTタイマー開始 void WDT_start(uint8_t t) { cli(); // 全割り込み禁止 WDT_reset(); // ウォッチドッグタイマーリセット WDTCSR |= _BV(WDCE)|_BV(WDIE); // WDCE:ウォッチドッグ変更許可、WDTIE:動作種別=割り込み WDTCSR |= t; // 割り込み間隔設定 sei(); // 全割り込み許可 } // WDTタイマー停止 void WDT_stop() { cli(); // 全割り込み停止 WDT_reset(); // ウォッチドッグタイマリセット MCUSR &= ~_BV(WDRF); // ウォッチドッグリセットフラグ解除 WDTCSR |= _BV(WDCE)|_BV(WDE); // WDCEとEDEに1をセット WDTCSR = 0; // ウォッチドッグ禁止 sei(); // 全割り込み許可 } // タイマー割り込みで呼び出される関数 // この割り込みでドットマトリックスLEDを表示 ISR(WDT_vect) { matrix_out(); matrix_off(); } //********************************* //I2C接続 EEPROM AT24C1024B制御用 //********************************* // 1バイト読込 // address: アドレス(19ビット 0x00000 - 0x7FFFF) // [A2][A1][P0] + 16ビットメモリ空間 byte read(unsigned long address) { uint8_t devaddr = (uint8_t)DEVICE_ADDRESS | (uint8_t)(address>>16); // DEVICE_ADDRESS + [A2][A1][P0] uint16_t addr = address & 0xFFFF; byte data = 0xFF; int rc; Wire.beginTransmission(devaddr); Wire.write((byte)(addr >> 8)); // アドレス上位 Wire.write((byte)(addr & 0xFF)); // アドレス下位 rc = Wire.endTransmission(); rc = Wire.requestFrom(devaddr,(uint8_t)1); data = Wire.read(); return data; } // nバイト読込 // address: アドレス(19ビット 0x00000 - 0x7FFFF) // [A2][A1][P0] + 16ビットメモリ空間 // rcvdata: 読込データ格納アドレス // n : 読込みデータ数 // 戻り値 : 読み込んだバイト数 byte Sequential_read(unsigned long address, byte* rcvdata, byte n) { uint8_t devaddr = (uint8_t)DEVICE_ADDRESS | (uint8_t)(address>>16); // DEVICE_ADDRESS + [A2][A1][P0] uint16_t addr = address & 0xFFFF; byte data = 0xFF; int rc; Wire.beginTransmission(devaddr); Wire.write((byte)(addr >> 8)); // アドレス上位 Wire.write((byte)(addr & 0xFF)); // アドレス下位 rc = Wire.endTransmission(false); rc = Wire.requestFrom(devaddr,(byte)n,(byte)false); byte c = 0; for (int i=0; i < n; i++) { rcvdata[c++] = Wire.read(); } rc = Wire.endTransmission(true); return rc; } // 1ワード読込 // address: アドレス(19ビット 0x00000 - 0x7FFFF) // [A2][A1][P0] + 16ビットメモリ空間 // 戻り値: 取得したデータ uint16_t read_word(unsigned long address) { uint16_t rcv[2]; uint16_t rc; address<<=1; rcv[0] = read(FTABLE_ADDR+address); rcv[1] = read(FTABLE_ADDR+address+1); rc= rcv[0]+(rcv[1]<<8); return rc; } //********************************* // 美咲フォントデータ用関数 //********************************* // フォントコード検索(バイナリーサーチ方式) // (コードでROM上のテーブルを参照し、フォントコードを取得する) // ucode(in) UTF-16 コード // 戻り値 該当フォントがある場合 フォントコード(0-FTABLESIZE) // 該当フォントが無い場合 -1 int findcode(uint16_t ucode) { int t_p = 0; // 検索範囲上限 int e_p = FTABLESIZE-1; // 検索範囲下限 int pos; uint16_t d = 0; int flg_stop = -1; while(true) { pos = t_p + (e_p - t_p+1)/2; d = read_word (pos); if (d == ucode) { // 等しい? flg_stop = 1; break; } else if (ucode > d) { // 大きい? t_p = pos + 1; if (t_p > e_p) break; } else { // 小さい? e_p = pos -1; if (e_p < t_p) break; } } if (!flg_stop) return -1; return pos; } // UTF8文字(1~3バイト)をUTF16に変換する // pUTF8(in): UTF8文字列格納アドレス // pUTF16(out): UTF16文字列格納アドレス // 戻り値: 変換処理したUTF8文字バイト数 byte charUFT8toUTF16(char *pUTF8, wchar_t *pUTF16) { byte bytes[3]; wchar_t unicode16; bytes[0] = *pUTF8++; if( bytes[0] < 0x80 ) { *pUTF16 = bytes[0]; return(1); } bytes[1] = *pUTF8++; if( bytes[0] >= 0xC0 && bytes[0] < 0xE0 ) { unicode16 = 0x1f&bytes[0]; *pUTF16 = (unicode16<<6)+(0x3f&bytes[1]); return(2); } bytes[2] = *pUTF8++; if( bytes[0] >= 0xE0 && bytes[0] < 0xF0 ) { unicode16 = 0x0f&bytes[0]; unicode16 = (unicode16<<6)+(0x3f&bytes[1]); *pUTF16 = (unicode16<<6)+(0x3f&bytes[2]); return(3); } else return(0); } // UTF8文字列をUTF16文字列に変換する // pUTF16(out): UFT16文字列 // pUTF8(in): UTF8文字列 // 戻り値: UFT16文字長さ (変換失敗時は-1を返す) byte Utf8ToUtf16(wchar_t* pUTF16, char *pUTF8) { int len = 0; int n; wchar_t wstr; while (*pUTF8) { n = charUFT8toUTF16(pUTF8, pUTF16); if (n == 0) return -1; *pUTF16 = utf16_HantoZen(*pUTF16); // 半角を全角補正 pUTF8 += n; len++; pUTF16++; } return len; } // UTF16に対応する美咲フォントデータ8バイトを取得する // utf16(in): UTF16コード // data(out): フォントデータ格納アドレス // 戻り値: true 正常終了1, false 異常終了 boolean getFontDataByUTF16(wchar_t utf16, byte* fontdata) { int code; unsigned long addr; byte n; if ( 0 > (code = findcode(utf16))) { // 該当するフォントが存在しない return false; } addr = code; addr<<=3; n = Sequential_read(addr, fontdata, (byte)FONT_LEN); if (n!=8) return false; return true; } // UTF16半角コードをUTF16全角コードに変換する // (変換できない場合は元のコードを返す) // utf16(in): UTF16文字コード // 戻り値: 変換コード wchar_t utf16_HantoZen(wchar_t utf16) { if (utf16 > 0xff || utf16 < 0x2f ) return utf16; switch(utf16) { case 0x005C: case 0x00A2: case 0x00A3: case 0x00A7: case 0x00A8: case 0x00AC: case 0x00B0: case 0x00B1: case 0x00B4: case 0x00B6: case 0x00D7: case 0x00F7: return utf16; case 0x00A5: return 0xFFE5; case 0x0021: return 0xFF01; case 0x0022: return 0x201D; case 0x0023: return 0xFF03; case 0x0024: return 0xFF04; case 0x0025: return 0xFF05; case 0x0026: return 0xFF06; case 0x0027: return 0x2019; case 0x0028: return 0xFF08; case 0x0029: return 0xFF09; case 0x002A: return 0xFF0A; case 0x002B: return 0xFF0B; case 0x002C: return 0xFF0C; case 0x002D: return 0x2212; case 0x002E: return 0xFF0E; } return utf16 - 0x2F + 0xFF0F; } //********************************* // ドットマトリックス表示用関数 //********************************* // 点灯する行の選択 // y: 行(0〜7) void selectRow(uint8_t y) { for(uint8_t i=0; i <8; i++) digitalWrite(row[i], HIGH); digitalWrite(row[y], LOW); } // 1行分データの出力 void setData(uint8_t d) { uint8_t msk = B10000000; for (uint8_t i = 0; i<8; i++) { if (msk & d) { digitalWrite(col[i], HIGH); } else { digitalWrite(col[i], LOW); } msk>>=1; } } // バッファの内容をドットマトリックスに出力する void matrix_out() { for (uint8_t i=0; i <8; i++) { setData(0); selectRow(i); setData(pdata[i]); } } // ドットマトリックスの表示OFF void matrix_off() { for (uint8_t i = 0; i < 8; i++) digitalWrite(row[i], HIGH); } // バッファクリア void clrar_buf() { for (uint8_t i=0; i <8; i++) pdata[i]=0; } // バッファへの書き込み // 8x8フォントパターンを表示用バッファに書き込む void write_buf(uint8_t* dat) { for (uint8_t i=0; i<8; i++) pdata[i]= dat[i]; } // 指定座標にフォントパターンをセット void write_bufat(uint8_t* fptr, uint8_t x, uint8_t y) { uint8_t w; if (x>7 || y >7) return; for (byte j=y,i=0; j < 8; j++,i++) pdata[j] = (pdata[j]>>(8-x))<<(8-x) | fptr[i]>>x; } // バッファーデータのスクロール // h_mode : 0 なし,1 左 ,2 右 // v_mode : 0 なし,1 上, 2 下 void scroll(uint8_t h_mode, uint8_t v_mode) { if (h_mode ==1) for (byte i = 0; i < 8; i++) pdata[i] = pdata[i]<<1; if (h_mode ==2) for (byte i = 0; i < 8; i++) pdata[i] = pdata[i]>>1; if (v_mode ==1) { for (byte i = 0; i < 7; i++) pdata[i]= pdata[i+1]; pdata[15]=0; } if (v_mode == 2) { for (byte i = 7; i >0; i--) pdata[i]= pdata[i-1]; pdata[0] = 0; } } // スクロールしながらパターンを表示 void scrollout(uint8_t* fptr, uint16_t dly) { for (byte i=0; i<8; i++) { scroll(1, 0); write_bufat(fptr, 7-i, 0) ; delay(dly); } } //********************************* // メイン処理 //********************************* void setup() { WDT_stop(); // 起動直後に念のためにWDTを停止 for (uint8_t i=0; i <8; i++) { // ピンモードの設定 pinMode(col[i], OUTPUT); pinMode(row[i], OUTPUT); } Serial.begin(9600); Wire.begin(); clrar_buf(); WDT_start(WDT_16MS); } char *str="こんにちは さいたま県♪ 今、さいたまがアツい!"; char buf[129]; wchar_t wstr[128]; uint8_t fnt[8]; uint8_t len; void loop() { len = Utf8ToUtf16(wstr, str); // utf8からutf16に変換 while(1) { for (uint8_t i=0; i <len; i++) { getFontDataByUTF16(wstr[i], fnt); // 文字のフォントデータ取得 scrollout(fnt, 75); // スクロールしながら文字を表示 } clrar_buf(); if (Serial.available() > 0) { // シリアルデータの着信があった break; } delay(1000); } // シリアルデータ受信 uint8_t n=0; while (Serial.available() > 0) { buf[n] = Serial.read(); n++; if (n>128) { break; } } buf[n] = 0; str = buf; Serial.println("OK"); Serial.flush(); }
漢字フォントについて
漢字フォントデータはLittle Limitさんが公開している美咲フォントを利用しています。
公開しているX11 BDF 形式を加工してEEPROMに格納しています。
フォントは半角・全角合わせて7120文字です。ただし8x8ドットのため、
複雑な漢字は可読出来ないものもあります。
ご存じの通り、Arduinoで使用する文字コードはUTF-8が採用されています。
そのためフォントデータをUTF16コード順ソートしています。
文字表示時、文字のUTF-8コード(=可変長)をUTF16(2バイト固定)に変換し、
EEPROM上のインデックス(UTF16コード2バイトをソートして格納)をバイナリーサーチで
検索し、該当フォントデータを取得しています。
半角文字のフォントデータも格納していますが見栄えとバランス悪いため
今回のデモでは全角に変換しています。
表示する1文字毎に、I2Cバス上のEEPROMの7120件のデータをバイナリーサーチで
検索しているので、時間がかかるのではと思ったのですが、問題ないようです。
これなら、EEPROM上に簡単なデータベースを作っても実用になるかも。
EEPROMへのフォントデータの書き込み
書込み用ツールを用意しました(Windows用)。
あまり良い作りではなく、送信速度遅いです。書込み完了に8分かかります。
(以前ブログに書いたCH341A programmerだと1分で完了します)
次のフォントデータとツールをダウンロード後解凍し、
手順に従って書き込みを行って下さい。他の書き込み手段がある場合、
解凍フォルダ内の美咲フォント(misaki_gothic.bin)のみをお使い下さい。
EEPROM書き込みツール&スケッチ(download2.zip)のダウンロード
2016/08/05 訂正
上記ファイルを差し換えました。
添付しているフォントファイルがフォントテーブルが無いファイルでした。
動作確認で同じ既にテーブルが書かれているEEPROMを使用していたため、
たまたま動作したようです。 大変申し訳ございません。
フォントファイルのサイズは 79,776バイトとなります。
手順
1)上記のリンクからdownload2.zipをダウンロードして解凍します。
解凍したフォルダdownload2には次の3つのファイルが入っています。
・download2.ino Arduino Uno用スケッチ
・EEPROMWrite.exe Windows用書き込みツール
・misaki_gothic.bin 美咲フォント
インターネットからダウンロードした実行モジュールは実行のブロックが
されている場合があります。
プロパティを開いて「ブロックの解除」を押して解除してください。
2)Arduino Unoで回路図の配線を行い、
Arduino IDEでdownload.inoを開きArduino Unoにスケッチを書込みます。
書き込みだけを行うのであれば、EEPROM回りの配線のみでもOKです。
3)EEPROMWrite.exe を実行します。
EEPROMWrite.exeの実行には .NET Framework 3.5以上が必要です。
必要に応じて、インストールしてください。
(Windows XP SP3, Windows 8.1での動作は確認しています)
実行すると次の画面が表示されます。
Arduino Unoと接続可能なシリアルポートを選択し、[参照]ボタンで
フォントデータ misaki_gothic.bin を指定します。
[書込み]ボタンを押すと、書き込みが開始されます。
書き込みの進捗状況が画面に表示されます。
書込みが完了するまで8分くらいかかります。正常終了すると、
次のような画面になります。
中断する場合は、[中止]ボタンを押してください。
正常終了すると、次のような画面になります。
稀に、途中で止まってチェックサム処理まで行かない場合があります。
その場合はArduino Unoをリセットし、ツールを再実行してやり直して下さい。
ツールのプロトコルの出来が今一悪く、低速です。
(arduinoのシリアル通信(Serial)の受信部の実装が今一良くないんですよね)
最近のコメント