✖
✖
「コレクタ接地ってボルテージフォロワ? エミッタフォロワー? あれ?」って思ったのでちゃんとしとく……
ボルテージフォロワは普通オペアンプに対して使うようだ。エミッタフォロワーはバイポーラトランジスタを使ったボルテージフォロワ、でいいのかな。
ボルテージフォロワは FET も同じようにドレイン接地 (ソースフォロワ) で作れる。
オペアンプをヴォルテージフォロワとして使う場合、中身 (バイポーラトランジスタやらFETやらの集合) のことを無視して考えると、中身がエミッタフォロワーだろうがソースフォロワだろうが、挙動としてはヴォルテージフォロワということっぽい。
- ボルテージフォロワー
- エミッタフォロワー
- ソースフォロワー
ATTiny13A を使った小型エレキー
まとめを後日書きました ボタン電池で動く小型・低消費電力 AVR エレキー (50円 ワンチップマイコン ATTiny13A) | tech | avr | arduino - 氾濫原
前に書いたのの続き。
せっかくメインのICが小さいので、できるだけ小さく作るならどうするのがいいだろう?と考えてる。
まず、乾電池1本で動いたらいいなと思ったので、1.4Vを3.3Vに昇圧する回路を組んで駆動させてみたら、昇圧回路がどうもうまくいかなくて、やたら電気食う感じだった。昇圧回路の調整を別途やれば乾電池1本でもいい感じになるかもしれないけど、実際ブレッドボードで組んでみたら結構体積も食う感じになってしまったので、そもそもこの方法を諦めた。
じゃあリチウムコイン電池を使うことを考えよう、と思った。リチウムコイン電池なら1個で3V出せる。ただ、あまり電流を流すことができなくて、標準で 0.2mA 程度に抑える必要がある。消費電力を減らす工夫はしてるつもりだけど、スピード調節をADCにしたのでボリュームに常に電流が流れるとか (10kΩなのでこれだけで0.3mA流れる)、もうちょっと頑張る必要がありそうだった。
まず、ADC は1秒ごとに行うようにコードを変えて、そもそも頻度を減らした。また、ボリュームに電圧をかけるのも、ADCが行われるときだけにした。これはピン1個を出力にして、VCC の代わりにそこに繋いでる。VCC とピンの出力電圧は厳密には違うので、ADCの精度は落ちるけど、そもそも安定してない電池駆動だし、相対値だけがとれればいいのでまぁいいかな、という気がする。
それでだいたいアイドル時に0.3mA程度まで下がった。しかしこれ以上思いつかないので、とりあえずクロックを下げてみて挙動に問題がないか試すことにした。ATTiny13A の場合、内蔵クロックは 9.6MHz, 4.8MHz, 128kHz とそれらを8分周したものが選べる。なので 4.8MHz を8分周した600kHzで動かしてみると、思ったより変なことにならなかった。これでアイドル中はほぼ0.2mA未満に。
じゃあ 128kHz だとどうだろう、ということでやってみたら、
bad AVRISPmkII connection status: Unknown status 0x00
とかでるように…… たぶんクロックを下げすぎたせいで ISP の書きこみのクロックを読めてないのかな……
うーん困ったと思っていたら avrdude に転送スピードを下げるオプション (-B) があったので、-B 100 ぐらいにしてやったらいけた。しかし書きこみ速度がだいぶ遅い。
コードを全体的に書きなおさないと 128kHz でバグってて動かない感じだけど、軽く試した感じだと、アイドル中で0.09mAぐらい。キーイング中で0.19mA。パワーダウンは変わらず0.6uA程度。コーディングが面倒になった割にはそんなに減らない。ベースの消費が無視できないほどクロックの支配率が低くなってるせいかな。
仕様から
- VCC=3V, f=128kHz
- idle: 0.01mA
- active: 0.04mA
- power down: 0.00015mA
- ADC: 0.225mA
- Timer0: 0.002mA
- pull-up: 0.08mA
- キーイング中は pull-up + active + timer0 + FET GS接地抵抗(440k)電流 = 0.122mA が最低でも必ずかかる
- アイドル中は idle + timer0 = 0.012mA
- ADC中は active + ADC + timer0 = ボリューム電流 = 0.567mA
- パワーダウン中はクロックに関係なく固定で 0.15uA
- 比較すると実測値が結構高いけどなんでだろう
- 瞬間最大電流
- キー同時押し pull-up * 2 + active + timer0 + FET GS接地抵抗(440k)電流 + ADC
- 0.7338mA
パワーダウン中の消費は AVR ISP Mark II と繋っていたからで、RESET をはずせば 0uA になった
- パワーダウンモード 0.0uA未満
- アイドル中 90uA -> 0.09mA
- キーイング中 198uA -> 0.198mA with FET
✖
✖
マイコンプログラミングとか、黙って Arduino やっとけハゲという感じではあるんだけど、Arduino の言語がどうも好きになれなくて使ってない。CっぽいけどCじゃない、でもC、みたいなのがなんとなく嫌だなと感じてる。それは置いておいても Arduino は素晴しいと思います。
Arduino も AVR を使っているし、結局 Arduino 頑張ろうとすると AVR のスペックを理解する必要があるので、じゃあ AVR でいいか、という感じになる (安いし)。
Arduino は、開発環境も含めたエコシステムが魅力で、そこがすごくいいと思うけど、自分みたいに CUI で vim で書いて Makefile でコンパイルして書きこんで gdb でデバッグするみたいのが好きな人間だと、少し魅力が薄れてしまうように思う。
IDE はあればあるで便利で良いんだけど、Makefile と gdb を使ってやっていれば、マイコンプログラミング以外のときにもその知識が生かせて嬉しいと思う (IDEの操作の知識はほかに生かせない)
✖
トトト・トトトト・トトトトト
S (トトト) H (トトトト) 5 (トトトトト) の区別がつくように全然ならない。20wpm 程度でも結構間違える。全部とれない場合、ミスのほとんどがこれ。25wpm になると、1分間やっている中の 5 を全部 H、H を S と書く、あるいは逆、みたいにズレて聞きとったりする。クソすぎてイライラする。
S H 5 だけランダムで聞きとろうとすると、今度は全部聞きとれない。ランダムではなく SHE, HIS とかはパターンで覚えてるからある程度聞きとれるけど、ランダムだと全く意味わかんない。なので、比較して聞きとれるようにするということもできない。というか単体ならまず間違えないんだよ……
E (ト) と I (トト) と S (トトト) の区別は容易にできるけど、それ以上の短点は「いっぱい」としか認識されない。「ちょっと長いから5だろう」「5ほどじゃないからHかな」ぐらいの曖昧な感じ。本当にイライラする。
もう初めて3ヶ月ほど経つのにこのありさまなのでやる気なくす。あまりにもこれらを間違えるので 26wpm から 20wpm 程度までスピードを落としてゆっくりやってる。多少マシになったかもしれないけど。あいかわらず間違える。聞きとれない文字がいくつかあると、それらで考えてしまって止まるので、速度があげられない。一度聞きとれないと、その単語は完全に落とすので、そういう文字があってはならない。
次に J と 1 も、S H 5 ほどではないけど区別がつかない。こっちはコールサインの文脈でよく使うので比較的頭に長さのイメージができているけど、それでも間違える。どうすれば解決するのか全くわからない。3ヶ月やってダメなら一生ダメなんじゃないか。
以上の符号以外にも、2、3、7、Z、X はそれ以外に比べてよく間違える。
AVR 浮動小数点 (float) 演算
浮動小数点演算を使ったとき、-lm を付けないとバイナリサイズが巨大化する問題がある。-lm をつけない場合、デフォルトの (libgccの?) 浮動小数点関数がリンクされるけど、avr 用には高効率なものが libm に実装されている。libgcc だと 3k -> libm だと 1k ぐらいのインパクトがあるので必ず libm を使うようにしたい。
とはいえ、ちゃんと理解してないと libm にリンクされない……
結論からいうと以下じゃないとだめだった。
$(COMPILE) -o main.elf $(OBJECTS) -lm
以下のようだとうまくいかない。
$(COMPILE) -lm -o main.elf $(OBJECTS) $(COMPILE) -o main.elf -lm $(OBJECTS)
というのも、リンカは、引数を順番に読みこんで、読み込み中のファイルに今までで未定義のシンボルがあったとき、それを解決する、という挙動をするらしい (なんとなく逆に、先に定義して解決していくもんだと思ってた)。
なので、先に -lm を指定しても、その時点では未定義のシンボルが何もないので何の意味もない。
gcc のオプションに -v (verbose) を渡すと、最終的に ld (collect2) に渡される引数がわかる。
うまくいく場合は main.o -lm -lgcc -lc -lgcc というふうになってる。main.o で使ってるシンボルが -lm で解決されて、あとまだ足りないのは -lgcc とかで解決される。-lgcc が2回出てくるのは、-lc が -lgcc を使ってるからかな。よくわかんない。
AVR、なぜかリセットされまくるとき
割込みかけるように設定しているにも関わらず、それに対する処理を書いていないと、sei() を呼んだあと、割込みが発生するときに落ちてリセットがかかる。
sei() が呼ばれるまでは問題ないので、コメントアウトでデバッグしていると超ハマる。
AVR シリアルでPCと接続してデバッグ
USB-シリアルポートアダプタ (RS-232C) は前に買っていたけど、RS-232C は正負 -12~+12 で1/0を表現うるので、マイコンのロジックレベル(0 or VCC)とは違っていて、そのままではマイコンと接続できない。
調べてみると、RS232トランシーバー (ドライバ) ICというのがあって、それを使えば簡単にレベル変換できることがわかった。有名なのは MAX232 というやつみたいだけど、ほぼ同じインターフェイス(ピンアサイン)でビットレートや電源電圧が違うやつがいろいろとあるみたいだ。
今回は ICL3232CPZ という 3.3V〜5V で動いて、なおかつ外付け部品が 0.1uF 5個だけというのを選んで作った。
繋いで以下のような、ボーレート 19200 で吐き出すコードを書いてみた (チップは ATTiny2313、レジスタ名がチップによって違うので、チップ変えるとそのままでは動かない)
#include <avr/io.h>
#include <string.h>
#include <util/delay.h>
#define clear_bit(v, bit) v &= ~(1 << bit)
#define set_bit(v, bit) v |= (1 << bit)
static inline void uart_putchar(char c) {
loop_until_bit_is_set(UCSRA, UDRE);
UDR = c;
}
static inline void uart_puts(char* string) {
unsigned int len = strlen(string);
unsigned int i;
for (i = 0; i < len; i++) {
uart_putchar(string[i]);
}
uart_putchar('\r');
uart_putchar('\n');
}
void usart_init(unsigned short baudrate) {
unsigned int d = ((F_CPU + (baudrate * 8L)) / (baudrate * 16L) - 1);
UBRRL = d;
UBRRH = d >> 8;
UCSRB =
(1<<RXCIE) | // RX Complete Interrupt Enable
(1<<TXCIE) | // TX Complete Interrupt Enable
(0<<UDRIE) | // USART Data Register Empty Interrupt Enable
(1<<RXEN) | // Receiver Enable
(1<<TXEN) | // Transmitter Enable
(0<<UCSZ2) | // Character Size
(0<<RXB8) | // Receive Data Bit 8
(0<<TXB8) ; // Transmit Data Bit 8
UCSRC =
(0<<UMSEL) | // USART Mode Select: 0=Asynchronous Operation, 1=Synchronous Operation
(0<<UPM1)|(0<<UPM0) | // Parity Mode
(0<<USBS) | // Stop Bit Select
(1<<UCSZ1)|(1<<UCSZ0) | // Character Size (with UCSRB)
(0<<UCPOL) ; // Clock Polarity
}
static inline void setup_io () {
usart_init(19200);
}
int main(void) {
setup_io();
for (;;) {
uart_puts("Hello, World");
_delay_ms(1000);
}
} PC 側では、この USB シリアルポートアダプタの場合、/dev/tty.usbserial-FTB3L9UG というようなファイルができるので、これを指定して GNU screen の window を1つ作ってる。変なことしてないのでボーレートを指定するだけでいける。
screen /dev/tty.usbserial-FTB3L9UG 19200
これで RX/TX があるチップならかなりデバッグが捗りそう。
ATTiny13A
いろいろパーツを注文するついでに ATTiny13A というチップも買ってみた。
見ての通り8ピンしかないチップだけど、以下のような特徴がある
- 1個50円と激安。
- ADC がついてる
- プログラムに使えるのは1KBしかない
- SRAM が 64B だけある (のでCで書ける)
- 外付け水晶を使うのは面倒 (使わないつもりで書いたほうが良い)
- ISPを殺せば最大6ピンIOに使えるけど、基本5ピンしかIOに使えないと考えたほうがいい
かなり制約があって楽しい。サイズ的に浮動小数点は使えないので工夫する必要がある。メモリ(SRAM)も64Bしかないのでついうっかりするとオーバーしそう。でもCで開発できるのでいいバランス。
とりあえずエレキー作るのがいいかと思って作ってみた。
まとめを後日書きました ボタン電池で動く小型・低消費電力 AVR エレキー (50円 ワンチップマイコン ATTiny13A) | tech | avr | arduino - 氾濫原
ただ、ピン数が少ないせいで大きな問題がある。というのも、必然的に ISP で使うピンとアプリケーションのピンを共有することになるので、回路によっては、繋いだままの ISP というのができないっぽい。「SCK fail」とか「MOSI fail」とか出て意味不明だったけど、このせいみたいだ。うまくやらないと In-System Programming という感じでなくなる。なんか簡単ないい方法ないのかな。
ADC の端子がいくつかあるので、スイッチをたくさん繋いでいくというのは割とできそう。ただ出力はそうもいかない。ソフトウェアに使えるメモリ量も少ないので「ハードにないからソフトで実現」というのも難しいことが多そう。
それにしても「50円で買えるコンピュータ」というのはグっとくる。
Bose QuietComfort 15 のイヤーパッドを交換
使いはじめて2年ぐらい経ったところで、イヤーパッドの縫い目が割けてきしまったので、交換したくなった。とりあえず純正が高いので安いのを買ってみた。
Bose QuietComfort 15 対応交換用パッド◆QC15, QC2, AE2, AE2i 対応(univarcオリジナル) 安心安全保証付き U1355 cho45
さすがに本体とサイズが合わないということはなく、普通に使える感じ。ただ、純正と比べるとちょっと硬い。しばらく使ってみる。
Bose QuietComfort 15 Acoustic Noise Cancelling headphones ノイズキャンセリングヘッドホン QuietComfort15-S cho45
やっぱりほぼ毎日使っていると痛んでくる。どのぐらい長く使えるかな。もうこれ無しの生活とか考えられないんだけど
ピーラーは100均やIKEAのものを買ってはいけない。
IKEA で買ったピーラーの切れ味がよくなくて、うちで不評だったので以下を買った。知り合いの家にあって、便利だったので、検索してみたらすぐ見つかった。
スピードサラダ 19639 cho45
千切り機能とか使わねーだろと思ったけど、使ってみたら便利だった。刃物系はあんまり安いとよくないですね。
爪切りも少しだけ良いものを買ったほう確実に生活が向上していいです。
木屋 はがねの爪切り 大 BK-T02 cho45
↑ これほしい。
万年筆 PILOT カクノ (kakuno)
普段仕事でもなんでも殆ど、筆記用具を使わないので、筆記用具とかもはやどうでもいいやって感じだったけれど、最近になって筆記で勉強しはじめたので、捗る筆記用具について思いを馳せた。
最初は普通に今まで持っていたゴミみたいなシャープペンシルを使っていた。しかし、最近何かのアレで万年筆 (LAMYというメーカーのやつ) をもらったので、せっかくだからと使ってみたら、すごく書きやすかった。気に入った点は大したことではないんだけど、
- インクなのでシャープペンシルと比べて色が圧倒的に濃い
- 筆圧かけずにすらすら書ける
あたりで、それからはずっと万年筆を使って勉強してる。書くのが楽しいので、問題を解くモチベーションに繋る。
しかし、いただいた万年筆は線がちょっと太めな感じだったので、細いのが欲しくなった。と、いうタイミングで、ちょうどよくパイロットのカクノ という子供向け1000円の万年筆が発売されたので、買ってみた。(アマゾンにまだなかったので普通に文具店で買った。今はあるみたい)
買ったのは色はライトグリーンで、ペン先が F のもの。F のものが日本語筆記だとスタンダードっぽくて、ちょっと細めみたいだ。デザインはまぁ……悪くはないけどって感じだけど、使ってみた感じだと、先が細いぶんちょっとひっかかるかなというぐらいで十分良かったので、今はこっちをメインに使ってる。
と、いうのはいいんだけど、最初についてるインクが2週間経たないぐらいでなくなってしまって「えっ!」となった。実はインクがなくなるまで使えたら買おうと思っていたかっこいいインクがあったので、さっそく注文した。
↑ これ、どっかで見かけて、すごいかっこいいなー欲しいなーけど俺使わないなーと思っていたけど、案外インク使うことがわかったのでウキウキしながら買ってみた。
インクを入れるコンバーターというのも買った。(カクノには最初インクカートリッジがついてるけど、コンバーターも普通に使えるようだ)
一回ペンを洗ってから入れかえた。初めて入れかえをやったので結構楽しい。実際書いてみると色がすごく自分に好みだったので大変満足した。嬉しい買いものだった。色はかなりたくさんあって、悩んだけど、これ (月夜) にしてよかった。少しだけ緑が入っている夜空の青。
ペンを変えたら、ペンを使いたくなるので、勉強のモチベーションがちょっとあがる。簡単にモチベーションが上がるようなことは全部やったらいいと思うし、コストの割には結構いい感じに上がるので、たいへんいいなと思った。
しかし、もうすこしいいのも欲しくなるのが困る
カクノ以外は結構なお値段ですね!! カクノは使い捨てというわけではないし、コンバーターも使えるのでコストパフォーマンスは高そう。もうちょっとだけかっこいいのがあればなあ。
✖
Kindle がきた
新しい Kindle Paperwhite を買った (予約してたのを忘れてて、きづいたらきた)
Kindle を所有するのははじめてなので (すこし他人のを触らせてもらったことはある) あんまり比較はできない。とりあえず、持った感じはよくて結構嬉しい感じ。表示の切替えはあんまり早くない (これでも早くなったらしいけど)
とりあえず手元にある PDF を入れみたり、既に購入済みのやつを読んでみたりした。PDF はそのままだとコントラストを最高にしないと読みにくい。
あとウェブページを送信する用に
- Send to Kindle for Mac http://www.amazon.com/gp/sendtokindle/mac
をダウンロードしておいた。プリント先として表示されるようになって便利
持ち歩きで使うならカバーが必須な気がするなー と思っているけど、結構高いので買ってない。
Amazon Kindle Paperwhite用レザーカバー、オニックスブラック【Kindle Paperwhite(第5世代、第6世代、第7世代、マンガモデル)専用】 cho45
✖
テスターを新調した
今まで kaise の SK-6201 というテスターを使っていたけど、中学生ぐらいから使っていて、電流計の表示にオフセットがあったり、測定レンジが狭かったりで不便だったのでこの際に新調した。
電流のレンジが大幅に増えてすごく便利になった。ただ、前のテスターだと値に大きな変化があったときに音が鳴る機能があって気に入っていたんだけど、これにはなくて残念。
サンワは測定器メーカーとして有名なようです。
AVR で USB 接続の PC キーヤーを作る
PC からモールス符号を発生させて無線機に入力するものが欲しいと思っていた。当然既にそういうのはあるんだけど、どうも気に入るのがないので、必要な機能だけ自分で実装する。
基本の要件としては
- クロスプラットフォームであること
- というか Mac で動くこと
- USB バスパワーで動くこと
なので、簡単そうでいろいろ教材としても楽そう。
クロスプラットフォームで面倒なドライバを書かなくてすむ方法は HID デバイスとして作ることだと思うので、そのように作ることにした。また、USB 用の外部チップとか用意したくないので V-USB (AVR マイコン上で USB を処理できるライブラリ) を使うことにした。
いろいろやってなんとか2日ぐらいで最低限の機能の実装ができたのでいろいろメモしておく。
回路図とコード
コード: https://github.com/cho45/AVR-USB-CW
現状制作途中のものなので、実際使う際に必要なリレー部分とかは書いてない。
現状だとダイオード2本で約1.4V程度電圧降下させて 3.3V〜3.6V 程度を作りだす方法を使ってる。V-USB の Wikiに書いてある方法の1つ。
左下のはそのうち試してみたい回路で、AVR自体には5Vをそのまま供給して、信号ラインだけ 3.6V にツェナーダイオードで電圧降下させる。電源電圧を3.3V程度にしてしまうと、動作周波数が 12MHz 程度までしか保証されないので、16MHz や 20MHz で動かすならこちらのほうが安定しそう。
V-USB
まず examples/hid-{data,mouse} を動かして、ふむふむと思いながらやってみたけど、なかなかハマった…… HID デバイスを作ろうとするとデフォルトの usbconfig.h から結構書きかえないといけないんだけど、それを知っていないとだめなのでつらかった。
usbconfig-prototype.h から作るのではなく、example/hid-* のをコピってくるほうが確実に動くと思う。
まだコントロール転送しかできてない。少なくともインタラプト転送はやることになりそうだけどデバッグがだいぶ大変 (追記:インタラプト転送は Mac + libusb だとできなかった)。
あと、自分で設定している割込みの頻度が高すぎると STALL しやすい…… クロック周波数にしても、こういった処理にしても結構シビアなので気を使わざるを得ない……
HID のレポートデスクリプタ定義は、大本の仕様書がどこにあるのかわからないのでコピペと感で書いて試した。
V-USB を妨げない delay_ms
_delay_ms は定数しかスリープできないのと、ビジーループなのでその間割込み以外何も走らなくなってしまう。V-USB は usbPoll() を少なくとも50msecに一回は呼ばないといけないとかなので、これは使えない。
なので、まず割込みで時間を測るタイマー変数を作る。
必要な精度以上のタイマー(あまり短くないほうがいい)を用意 (この例だと1ms) して、グローバルな timer という変数をインクリメントするようにする。(F_CPU / 分周設定 / OCR0A) CTC のほうが自由に時間を設定できて楽
/** * timer interrupt * CTC 16MHz / 64 / 250 = 1kHz = 1msec */ TCCR0A = 0b00000010; TCCR0B = 0b00000011; OCR0A = 250; TIMSK0 = 0b00000010;
unsigned long timer;
ISR(TIMER0_OVF_vect) {
timer += 100;
} 以下のようなマクロを用意して DURATION(msec) で、引数に与えた時間が timer 換算でいくつになるかを出す。浮動小数点演算を使った瞬間、出てくるバイナリサイズが長大になるのでそうならないようにしてる。
#define DURATION(msec) (unsigned int)(msec * 100)
delay_ms を実装する。_delay_ms におけるビジーループ部分が任意に書けるので、ここで usbPoll() をする。
void delay_ms(unsigned int t) {
unsigned long end;
cli();
timer = 0;
end = timer + DURATION(t);
sei();
while (timer <= end) {
wdt_reset();
usbPoll();
}
} これでナイーブに delay_ms() を使ったコードでも可読性と効率をそこそこ両立できそう。しかし、なんかもっといい感じにコード書けそう。。普通どうやるものなのかよくわからない。
I2C 液晶
デバッグするとき、何かしら文字を表示できるインターフェイスがないとつらいため導入。シリアルポートに出力してデバッグするのがたぶん一番楽なんだと思うけど、レベル変換が必要で手元にあるものではできなかった。
I2C を使うにあたって、原理を理解していないのと、なおかつそれを AVR で実現する方法がわからないのと、さらには「デファクトスタンダード」な通信プロトコルも存じあげないため、全ての箇所でハマりにハマった。チップは ATmega168P なのでそこまで細かい原理を知っていて実装できる必要はないけど、だいぶハマった。
やり終わってみれば、別に難しくはないんだけど、どこに問題の原因があるのかが、見える現象が少なすぎて大変だった。面倒でもいちいちLEDチカチカさせて動作確認をすべき。
以下に I2C 液晶 (アドレス 0x7c) を操作するコード。何をするにせよ、とにかくデータシートをよく読んで理解するのが大変に重要だと実感した。
#include <string.h>
#define START 0x08
#define ReSTART 0x10
#define MT_SLA_ACK 0x18
#define MT_DATA_ACK 0x28
#define MR_SLA_ACK 0x40
#define MR_DATA_ACK 0x50
#define MR_DATA_NACK 0x58
#define SLA_W 0xA0
#define SLA_R 0xA1
#define ADDRESS 0x00
#define DATA 0x55
void Error () {
// unsigned i = 0;
// for (i = 0; i < 3; i++) {
// set_bit(PINB, 0);
// _delay_ms(500);
// clear_bit(PINB, 0);
// _delay_ms(500);
// }
// clear_bit(PINB, 0);
}
void i2c_start () {
// start
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != START) return Error();
}
void i2c_stop () {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
}
unsigned char i2c_write (unsigned char data) {
TWDR = data;
TWCR = (1<<TWINT) | (1<<TWEN);
while (!(TWCR & (1<<TWINT)));
switch (TWSR & 0xF8) {
case MT_SLA_ACK:
case MR_SLA_ACK:
case MT_DATA_ACK:
return 1;
default:
Error();
return 0;
}
}
void display_write_instruction (unsigned char address, unsigned char data) {
i2c_start();
i2c_write(address);
i2c_write(0b10000000);
i2c_write(data);
i2c_stop();
_delay_ms(1);
}
void display_write_data (char* string) {
unsigned int i = 0;
unsigned int len = strlen(string);
display_write_instruction(0x7c, 0b00000001);
i2c_start();
i2c_write(0x7c);
i2c_write(0b01000000); // Co=0 RS=1
for (i = 0; i < len && i < 8; i++) {
i2c_write(string[i]);
}
i2c_stop();
_delay_ms(1);
i2c_start();
i2c_write(0x7c);
i2c_write(0b10000000); // Co=1 RS=0
i2c_write(0b11000000); // set ddram address to line 2
i2c_write(0b01000000); // Co=0 RS=1
for (; i < len && i < 16; i++) {
i2c_write(string[i]);
}
i2c_stop();
}
void display_init () {
TWBR = 0x24;
TWSR = 0b00000001;
TWCR = 1<<TWEN;
display_write_instruction(0x7c, 0b00111000); // function set to 0 (default)
display_write_instruction(0x7c, 0b00111001); // function set to 1 (extended)
display_write_instruction(0x7c, 0b00010100); // internal osc frequency
display_write_instruction(0x7c, 0b01110000); // contrast set
display_write_instruction(0x7c, 0b01010110); // power/icon/contrast control
display_write_instruction(0x7c, 0b01101100); // follower control
_delay_ms(300);
display_write_instruction(0x7c, 0b00111000); // function seto to 0
display_write_instruction(0x7c, 0b00001101); // display on/off control
display_write_instruction(0x7c, 0b00000001); // clear all
_delay_ms(10);
} ハマり
ハードウェアが絡むコーディングは、一度ハマると
- 配線ミス
- コーディングのミス
のどちらで発生しているかの見極めができないとかなりつらい…… 配線ミスはあってはならないので、最初の段階でよくよく確認しておかないとあとあとつらい。どんなに確認しても確認したりないぐらい確認する必要がある。あと配線後は必ずテスターをあてたほうがいい……
USB コネクタのピンの半田付けを適当にしすぎたせいで、試している最中に1本がはずれて通信できなくなるということがあった。こういうアホみたいなことでもコーディングミスを疑ったりすると時間を食ってしまう。
PORTB, PINB
出力を操作したいときは PORTB なのに、PINB と書いていてしばらく気付かなかった。この場合、微妙に出力されたりされなかったり、みたいな不安定な挙動になって、全く動かないわけでもないのでなかなかコーディングミスであることに気付けない。
Mac 環境で Ruby + libusb を使って HID デバイスを操作する
最初は feature レポートだけでごにょごにょしていたのでよかったけど、インタラプト転送をしようとしたところで、claim_interface が ERROR_ACCESS エラーを出して止まることがわかった。ググった感じだと、HID デバイスの場合、そのへんの処理を OS のドライバが握っているため、ユーザレベルだと直接扱えないらしい。
とりあえずどうしようもないっぽいので、feature レポートだけで情報をやりとりするように変えた。現状のプログラムだとそれでも問題がないっぽい。
✖
AVR は思ったより難しくなくて結構拍子抜けするぐらいだけど、今までやったことがない分野なので適度に難しい問題がたくさんころがっていてめちゃくちゃ楽しい。久しぶりに深夜3時ぐらいまでひたすらコーディングするとかしてしまった。
USB デバイスとか「作れない」という状態だとほんと全然アイデアが沸いてこないんだけど、やってみると結構「ああ、あれもできそう」「あれができたら楽しそう」みたいなのがでてきていい。
ウェブアプリのように誰かにすぐ使ってもらえるものを作るという感じではないのがもったいない感じだけど、なんか別に、自分そういうのなくてもいいなって感じなので良いです。
僕みたいな普段ウェブアプリみたいなかなりレイヤーが上のほうのことやってる人間でも、最近だとアセンブリとか全く書かなくてもよくていい。
ちょっと考えてみた感じ、何も持っていない状態からの AVR におけるとりあえずの開発に必要なのは以下あたりかなあと思った。
- プログラムの一般的な知識 (ウェブとか関係なく普通の)
- AVR ライター (純正 AVR ISP Mark II も別に高くないので純正のを買うのがよさそう)
- ブレッドボード・ブレッドボード用のジャンパピン集
- ピンヘッダ・オス・メス
- ミノムシクリップコネクタ
- レインボーフラットケーブル (裂いて使えるし、複数の線が纏められるし超便利)
- マイコンチップ (ATTiny2312=150円ぐらい, ATmega168P=200円ぐらい)
- 抵抗E12系一通り10本ずつぐらい
- コンデンサE6系一通り10本ずつぐらい (デジタルだと100uF以下ぐらいでよさそう)
- LED数個 (デバッグその他に必ず必要)
- 電源
- 安定化電源、なければ電池ケース (エネループなら4本直列=4.8V程度のもの)
- あるいはUSBから5Vとってもいいかもしれないけど、ポリスイッチ(何度も使えるヒューズ)を入れたほうがいい
- テスター (必須)
そんなに必要なものない気がしたけど、何もなしからだと結構ある。1万ぐらいあればぎりぎり集められるかな。
AVR エレキー、リグの接続を判定して内蔵ブザーを切り替え
ダイオードだけ入れて対処したのがどうもひっかかっていて、やはりまずい気がするので、やめた。リグ側から電圧がかかっていないとき、こちら側から電圧がかかってしまうのが気持ちわるい。
リグ側からかかっている電圧を使ってFETをスイッチし、接続されているときだけ、特定のプルアップしているピンをグラウンドに落とすような感じにした。スイッチを使わず、実際に接続されているかどうかを見れるようになったので、ジャックは挿しこまれているけど、リグの電源がついていない場合なんかには機能的にも前より便利になった。
素直にこうしとけばよかった。これでそんなにまずいことはない、と思う……
懸念していた点が解消されたので、ブレッドボートをやめてユニバーサル基板に実装した。
今まで、回路図からユニバーサル基板に落とすときはいきあたりばったりでやっていたけど、今回はプリント基板作成ツールを使って事前に実装を考えてみた。
いろいろ、プリント基板を作れるソフトウェアはあるんだけど、どれも微妙に使いづらくて難しい。自分だけの最高の部品ライブラリを作ってからじゃないと基板作成ができないとか、そういうアレがある……
今回はいくつか試した結果、Fritzing という OSS の、プリント基板ビューを使ってやってみた。ビューがいくつかあって楽しいソフトウェアなんだけど、やはりこれも回路図やブレッドボートビューを使う場合、ライブラリを作るあげるのが面倒くさい。ただ、配線を試行錯誤やる程度なら、別の部品を代用して使っても問題ない。
しかし配線を試行錯誤するのも結構つらくて、選択したくないものが選択されてしまうことがものすごく多い。そのためのロック機能がある、と思いきや、ロックをかけても選択できてしまうので意味がない。結果、一切あたり判定が存在しなくて動かすことができない部品とかが存在する (一度かぶっているのをとれば移動できるけど)。かなり辛い。

























