PICでデバッグしたい時にいちいち定数を書き換えてコンパイルしなおして焼き直すというのは面倒ですよね
毎回上手に焼けましたぁってなるまで待つのもめんどくさいし
ってことで PICでscanfが使えれば便利
どうやって使うか
シリアルポートの場合
char getche(void) { while(!RCIF); return RCREG; }
と
void putch(unsigned char ch) { while(!TRMT); TXREG = ch; }
の2行を追加すればおk
STDOUTはputch
STDINはgetcheです
出力がchだからといって入力もchとは限らない
紛らわしい...
で 実際に使うには
普通にC言語のコンソールアプリと同じです
scanf("%d", &num);
でnumに整数を読み込んで
printf("%d\r\n", num);
でnumを文字列にして書きだす
ただまぁscanfとかの問題もそのまま残ってるはずなので
製品には使用しないほうがいいよなぁ
もっとも使う用途も思いつかないけど
↑のget/putはとにかく簡単に済ます方法なので
速度とかを優先するならこのコードではダメです
例えば9600bpsで通信した場合1バイト送/受信するのに1mS位かかります
これはかなりのロス
バッファとか割り込みとかを活用すれば
100バイトでもメインのコードは1mSかからずに処理できるので
ただそうすると割り込みやら色々めんどくさいんだよなぁ
とりあえず PICで数値とか読み取る方法
覚書でした
2012年3月16日金曜日
2012年3月15日木曜日
PIC18のスペック
PIC18だとUSB内蔵があります
で その簡単な見分け方
クロックの最高が48MHzだとUSB対応
楽ですね
でもまぁ僕はUSBとか使わないので意味無いですが…
PIC18FのDIPでも64MHz(16MIPS)っつー恐ろしいマイコンがあるみたい
28pinの300milなので缶サットにいいんじゃないかと 思ってるんですが
シリアルも2本あるのでXBee用とGPS用 みたいな
どうせ手元にないと調べる気も起こさないダメ人間なので
2個位買っちゃえばとりあえず使うかな
で 何がしたいかというと
PIC18F2550って値段高くね?
ってことなんですよ
で プログラムメモリとSRAMとEEPROMが2550の倍でクロックが1.3倍くらいでタイマも倍近いのに値段が半分の石 ってのが目の前におかれたら飛びつくしか無いじゃないですか
まぁまだ買ってないんで目の前には無いんですけど
でもなんか裏が有りそうだよなぁ…
クレイモアでも仕掛けて有りそうな感じの
でもそういうのがなければ結構よさそうな石です
-追記-
PIC18F2550が350円で売ってる
あれー? 前は500円くらいじゃなかったっけ?
2010年11月に買った時の納品書には400円って書いてあるから
50円値下げしたのかもしれないけど 前はもっと高かった気がするんだよなぁ…
で その簡単な見分け方
クロックの最高が48MHzだとUSB対応
楽ですね
でもまぁ僕はUSBとか使わないので意味無いですが…
PIC18FのDIPでも64MHz(16MIPS)っつー恐ろしいマイコンがあるみたい
28pinの300milなので缶サットにいいんじゃないかと 思ってるんですが
シリアルも2本あるのでXBee用とGPS用 みたいな
どうせ手元にないと調べる気も起こさないダメ人間なので
2個位買っちゃえばとりあえず使うかな
で 何がしたいかというと
PIC18F2550って値段高くね?
ってことなんですよ
で プログラムメモリとSRAMとEEPROMが2550の倍でクロックが1.3倍くらいでタイマも倍近いのに値段が半分の石 ってのが目の前におかれたら飛びつくしか無いじゃないですか
まぁまだ買ってないんで目の前には無いんですけど
でもなんか裏が有りそうだよなぁ…
クレイモアでも仕掛けて有りそうな感じの
でもそういうのがなければ結構よさそうな石です
-追記-
PIC18F2550が350円で売ってる
あれー? 前は500円くらいじゃなかったっけ?
2010年11月に買った時の納品書には400円って書いてあるから
50円値下げしたのかもしれないけど 前はもっと高かった気がするんだよなぁ…
2012年3月11日日曜日
1でdisなフラグの謎
PIC18F2550でRB0を入力として使ってた時にハマったおかしな点
ADON = 0; ADCON1 = 0;
としていて デジタル出力として正常に使えていたのでそのまま使っていた
そして入力として使おうとした時 なぜか常に0になる
んで データシート見て気がついた
ADCON1 = 0;ってアナログ入力じゃん
ええ 初期設定がアナログだから0にしてアナログをオミットかと思ったら
デジタルを有効にするために1を設定
なのね
PICって時々「1で無効にする」ってのがあるよね...
多分これ前も引っかかったよなぁ…
ということで PIC18F2550ですべてデジタルポートとして使う場合
ADCONbits.ADON = 0; ADCON1 = 0x0F;
というのが正解
ADCON1の下位4bitが0でアナログ 1でデジタルになる
上位2bitは無効 上位3-4がVREFで これは0で
なのでADCON1 = 0x0F;
詳しくは データシート265ページあたりの
"10-BIT ANALOG-TO-DIGITAL CONVERTER (A/D) MODULE"
を参照してくだされ
16Fのアナログ入力に慣れてると
18Fのアナログ入力は意外と厄介なので
使う場合はまずデータシートを見てください
16のように「好きなポートをアナログに」っていう設定ができないので
では
PICで前にもやらかしたバグを再発させたという恥さらし覚書でした
ADON = 0; ADCON1 = 0;
としていて デジタル出力として正常に使えていたのでそのまま使っていた
そして入力として使おうとした時 なぜか常に0になる
んで データシート見て気がついた
ADCON1 = 0;ってアナログ入力じゃん
ええ 初期設定がアナログだから0にしてアナログをオミットかと思ったら
デジタルを有効にするために1を設定
なのね
PICって時々「1で無効にする」ってのがあるよね...
多分これ前も引っかかったよなぁ…
ということで PIC18F2550ですべてデジタルポートとして使う場合
ADCONbits.ADON = 0; ADCON1 = 0x0F;
というのが正解
ADCON1の下位4bitが0でアナログ 1でデジタルになる
上位2bitは無効 上位3-4がVREFで これは0で
なのでADCON1 = 0x0F;
詳しくは データシート265ページあたりの
"10-BIT ANALOG-TO-DIGITAL CONVERTER (A/D) MODULE"
を参照してくだされ
16Fのアナログ入力に慣れてると
18Fのアナログ入力は意外と厄介なので
使う場合はまずデータシートを見てください
16のように「好きなポートをアナログに」っていう設定ができないので
では
PICで前にもやらかしたバグを再発させたという
2012年2月26日日曜日
HI-TECHで再帰
どうやらHI-TECHでは再帰ができないらしい
まぁ組み込み用コンパイラならそれが妥当か
しかし
printf関数で%sはポインタ渡してなすがまま
という仕様で作ってたから
作りなおしだーよ
それにポインタを関数で渡しちゃったら
char text[] = "hello %d";
みたいなのが渡された時に困るからな
今回はforで\0まで出力
んで 現状10進での出力しか対応してないけど
やっぱ組み込みで使うなら2進も必要だよなぁ
ちなみにオリジナルのprintf関数で九九を出力させるコードは
ROM1399/RAM119くらい消費してる
結構重いよなぁ
そして いろいろいじってて気がついたのだけど
htc.hをインクルードするとstdio.hもインクルードされるのね
めんどくせぇよorz
つーことで
自分でprintf作っちゃうよぉ というお話でした
うーん 他に色々やることあるのに
優先順位低い方ばっかりやってるなぁ
まぁ組み込み用コンパイラならそれが妥当か
しかし
printf関数で%sはポインタ渡してなすがまま
という仕様で作ってたから
作りなおしだーよ
それにポインタを関数で渡しちゃったら
char text[] = "hello %d";
みたいなのが渡された時に困るからな
今回はforで\0まで出力
んで 現状10進での出力しか対応してないけど
やっぱ組み込みで使うなら2進も必要だよなぁ
ちなみにオリジナルのprintf関数で九九を出力させるコードは
ROM1399/RAM119くらい消費してる
結構重いよなぁ
そして いろいろいじってて気がついたのだけど
htc.hをインクルードするとstdio.hもインクルードされるのね
めんどくせぇよorz
つーことで
自分でprintf作っちゃうよぉ というお話でした
うーん 他に色々やることあるのに
優先順位低い方ばっかりやってるなぁ
2012年2月17日金曜日
C18
C18の最適化ってどれくらいなのかなぁと
今作りたい関数の変数値は
動作中に変わることは無いので
コンパイル時に渡して計算してくれればいいな と
思ってるわけですよ
例えば
i = sum(50 + 100, 20 + 50);
みたいに呼び出したら
50+100と20+50は
150と70に置き換えられるわけじゃなく
プログラムの実行時に計算されるわけですが
中で多少複雑な計算をしているので
それだけで40usくらいの時間がかかります
(18F2550@48MHz動作)
だけど その処理はしたくないわけですよ
で 計算する値はコンパイル時には決まっているので
コンパイラが書き換えてくれるとありがたいわけです
(言い換えると 最悪の場合コンパイル毎に変化するので式は必須)
HI-TECHだと
for (i = 0; i < 10; i++) {
__delay_ms(i);
}
みたいなコードはエラーになってしまうので
強制的にコンパイル時に計算 ってことは可能なのかもしれませんが
方法がわからない
HI-TECH独自の機能なのか
そうでなければC18でも可能なのか
まぁプログラミングは初心者とたいして変わらないくらいのレベルなので
僕が知らないだけという説が最有力なわけですが
インライン展開とか 興味あるんだけど
詳しく解説してるところが無いんだよなぁ
ま,いろいろ 探してみます
1個頼まれごと(?)があるんだけど
デバッグ環境がないとか 夏までは使う予定ないとか
色々な理由を作って放置してるんだよなぁ…
バグ修正でデバッグ環境が無い+原因不明 となるとやる気でないよなぁ…
せめてソフトウェアかハードウェアかだけでも切り分けられればいいんだけど
デバッグ環境が手元にないからそれもできないわけで...
おもって Standardを試してみたいんですが
確かインストール時にStandardかLiteか選べるようになってたはずなんだけど
選べない
でも ダウンロードリンクのアドレスが StandardとLite 同じ行き先なので
多分どっかで選択できるはずなんだけどなぁ…
(落ちてくるファイルの名前が微妙に違うんだけど 容量は同じ)
(落ちてくるファイルの名前が微妙に違うんだけど 容量は同じ)
んで 実験環境がVirtualPCなんですけど
なんか変わった気がするなぁと思ったら
バージョン上がってるのね
8.83だそうです
Win7でいつも使ってるのは8.70
微妙にメニューが増えてる気がするから
バグ抜きとかだけじゃなくて機能追加もされてるんだろうな
そーいや MPLAB Xとかどうなったんだろう
PICKIT3に対応したら とか思ってたけど
べつにWinでも苦労してないのよねぇ
だって外出先でプログラムの変更とかしないし
(昨年2日連続で呼び出されてやったりしたけど その2回だけだし その時はBoot Campで対応)
で Standard版
どうやったら使えるんだろう
今作りたい関数の変数値は
動作中に変わることは無いので
コンパイル時に渡して計算してくれればいいな と
思ってるわけですよ
例えば
i = sum(50 + 100, 20 + 50);
みたいに呼び出したら
50+100と20+50は
150と70に置き換えられるわけじゃなく
プログラムの実行時に計算されるわけですが
中で多少複雑な計算をしているので
それだけで40usくらいの時間がかかります
(18F2550@48MHz動作)
だけど その処理はしたくないわけですよ
で 計算する値はコンパイル時には決まっているので
コンパイラが書き換えてくれるとありがたいわけです
(言い換えると 最悪の場合コンパイル毎に変化するので式は必須)
HI-TECHだと
for (i = 0; i < 10; i++) {
__delay_ms(i);
}
みたいなコードはエラーになってしまうので
強制的にコンパイル時に計算 ってことは可能なのかもしれませんが
方法がわからない
HI-TECH独自の機能なのか
そうでなければC18でも可能なのか
まぁプログラミングは初心者とたいして変わらないくらいのレベルなので
僕が知らないだけという説が最有力なわけですが
インライン展開とか 興味あるんだけど
詳しく解説してるところが無いんだよなぁ
ま,いろいろ 探してみます
1個頼まれごと(?)があるんだけど
デバッグ環境がないとか 夏までは使う予定ないとか
色々な理由を作って放置してるんだよなぁ…
バグ修正でデバッグ環境が無い+原因不明 となるとやる気でないよなぁ…
せめてソフトウェアかハードウェアかだけでも切り分けられればいいんだけど
デバッグ環境が手元にないからそれもできないわけで...
2012年2月15日水曜日
メモリが120バイトしか使えない
PIC18Fって 大体のコードがC18を使っています
でも 僕はHI-TECHを使っていました
だけど そろそろC18使いたいなと思って
使い始めたんですが
なんと 変数が120バイト以上宣言できない
18F2550ですが
例えば
char c, d, buf[118];
は大丈夫で
char c, d, buf[119];
はダメです
また
int i;
char buf[118];
は大丈夫で
int i;
char buf[119];
はダメです
変数120個 じゃなくて メモリ120バイト が上限らしい
んで それを超えると
Error [1300] stack frame too large
んで ぐぐってみると まぁ 結構同症状が出てるらしい
なんかマニュアルに書いてあるっぽかったので
見てみたら
こんなことが書いてあった
E.1 ソースコード互換性
E.1.1 スタックフレームサイズ
コンパイラーは拡張モードで動作する時、ローカル変数の合計サイズは関数当り、
96 バイトに制限されています。非拡張モードの場合は 120 バイトです
なるほど
どうやら1個の関数で使えるのは最大でも120バイトらしい
うーん…
文字列からデコードさせたいとかだと
受信用に100バイト位確保して いろいろカウンタつけると
ギリギリ って感じだよなぁ
ま グローバル変数はいくらでも宣言し放題らしいので
最悪それを使うとして
ところで
#include <p18f2550.h>
void main(void) {
for ( ; ; ) ;
}
っていうコードだけでメモリを270バイト近くも使うというのはどういうことなんじゃ?
C語ってそんなに重いコードなの?
んな訳ないよなぁ
いくら2550のメモリが広大だからといって2048バイトしか無い内の300バイトは痛いよ
つーことで
C18で120バイト以上メモリを確保できない><
という問題でした
1個の関数の中では最大120個しか使えないらしい
ま、それ以上使う方法もあるっぽいんだけど
でも 僕はHI-TECHを使っていました
だけど そろそろC18使いたいなと思って
使い始めたんですが
なんと 変数が120バイト以上宣言できない
18F2550ですが
例えば
char c, d, buf[118];
は大丈夫で
char c, d, buf[119];
はダメです
また
int i;
char buf[118];
は大丈夫で
int i;
char buf[119];
はダメです
変数120個 じゃなくて メモリ120バイト が上限らしい
んで それを超えると
Error [1300] stack frame too large
っていうエラーが出てくる
んで ぐぐってみると まぁ 結構同症状が出てるらしい
なんかマニュアルに書いてあるっぽかったので
見てみたら
こんなことが書いてあった
E.1 ソースコード互換性
E.1.1 スタックフレームサイズ
コンパイラーは拡張モードで動作する時、ローカル変数の合計サイズは関数当り、
96 バイトに制限されています。非拡張モードの場合は 120 バイトです
なるほど
どうやら1個の関数で使えるのは最大でも120バイトらしい
うーん…
文字列からデコードさせたいとかだと
受信用に100バイト位確保して いろいろカウンタつけると
ギリギリ って感じだよなぁ
ま グローバル変数はいくらでも宣言し放題らしいので
最悪それを使うとして
ところで
#include <p18f2550.h>
void main(void) {
for ( ; ; ) ;
}
っていうコードだけでメモリを270バイト近くも使うというのはどういうことなんじゃ?
C語ってそんなに重いコードなの?
んな訳ないよなぁ
いくら2550のメモリが広大だからといって2048バイトしか無い内の300バイトは痛いよ
つーことで
C18で120バイト以上メモリを確保できない><
という問題でした
1個の関数の中では最大120個しか使えないらしい
ま、それ以上使う方法もあるっぽいんだけど
2012年1月13日金曜日
PICで温度計 を作りたかった
PICで温度計を作りたかった
要するに作れなかった
PIC16F88を使って温度計をつくろうとしたんだが!が!
Q. なぜ作れないのか
A. HI-TECH Litteだから
HI-TECHのLiteって printf("%f", f);って書き方ができないんですよ
浮動小数点数の出力ができない
なので温度の計算ができない
↑の写真の149というのはADCから得られた数字です
0〜1023の間の149
大体室温は150±1くらいで安定してます
1は誤差のうちですね
んで ADCの結果からどういう計算をするのか
((((5/(2^10))*値)*1000)-500)/10
となります
暗算? 無理ッス
むしろファーレンハイト的な発想でいいじゃないかと
150なら室温 それ以下なら寒いかな それ以上なら暑いかな
ダメすか...
とりあえず USBシリアル変換をつないで
アナログ値をそのまま送り出そうかなとか思ってます
そしたら PC側で計算して
記録するなり
グラフにするなり グラフをFacebookに投稿するなり
いろいろできるはずなんですよ
とりあえず 温度センサをライターで炙ったらあっという間に300を超えるので
一応温度計としては動作しています
ちなみに 今回使ったセンサは以前にこのブログで紹介したものと同じなので
詳しくはそちらをどうぞ
↑↑↑の方の検索枠から「温度計」とか入れて探せばすぐ出るはず
その時はNetduino使ったんだよね
ふつーに浮動小数点数が扱えるし
しかし 浮動小数点数使えないとなるとどうするかなぁ…
まぁ 方法はいくつかあるのですけどね
やっぱめんどくさいのですよ
要するに作れなかった
PIC16F88を使って温度計をつくろうとしたんだが!が!
Q. なぜ作れないのか
A. HI-TECH Litteだから
HI-TECHのLiteって printf("%f", f);って書き方ができないんですよ
浮動小数点数の出力ができない
なので温度の計算ができない
↑の写真の149というのはADCから得られた数字です
0〜1023の間の149
大体室温は150±1くらいで安定してます
1は誤差のうちですね
んで ADCの結果からどういう計算をするのか
((((5/(2^10))*値)*1000)-500)/10
となります
暗算? 無理ッス
むしろファーレンハイト的な発想でいいじゃないかと
150なら室温 それ以下なら寒いかな それ以上なら暑いかな
ダメすか...
とりあえず USBシリアル変換をつないで
アナログ値をそのまま送り出そうかなとか思ってます
そしたら PC側で計算して
記録するなり
グラフにするなり グラフをFacebookに投稿するなり
いろいろできるはずなんですよ
とりあえず 温度センサをライターで炙ったらあっという間に300を超えるので
一応温度計としては動作しています
ちなみに 今回使ったセンサは以前にこのブログで紹介したものと同じなので
詳しくはそちらをどうぞ
↑↑↑の方の検索枠から「温度計」とか入れて探せばすぐ出るはず
その時はNetduino使ったんだよね
ふつーに浮動小数点数が扱えるし
しかし 浮動小数点数使えないとなるとどうするかなぁ…
まぁ 方法はいくつかあるのですけどね
やっぱめんどくさいのですよ
実験用の基板
このPIC↓ 16F88なんですけど 仕事で急に必要になってRSで買ったんですよ
すげぇなおいこんな梱包始めてみたぞ
プラスチックケースに入ってます
1/10インチ間隔でデコボコになってるのでピンが曲がる心配も少ない というもの
無駄にたけーと思ったら...
んで 作ったのが↓
液晶と ADCを実装する予定
ADCは内臓のを使うけど
んで 一番アレなのがここ↓
まんなかにチップ抵抗があるでしょ
これ3個積んであるんですよ…
LEDの丁度良い制限抵抗がなかったので 4.7kを3個重ねました
1.5kΩ 3/10Wの抵抗となりますw
今回は12V入力にしました
いつもは5Vの電源を使うんですけどね
なんとなく 気分で
レギュは定番7805 3本の足の間にチップコンデンサが2個入ってたりしますが
まぁ「とりあえずつないどきゃ大丈夫でしょ」で作ってるので
本当はどういうふうに作るべきか知らないのですよ
あっ 電解コンデンサも47uFが1個ずつついてますよ
とりあえずまずは液晶の配線をつないで
そのあとでADCの実験
ADCなんて2回くらいしか使ったこと無いorz
ちなみに
缶サットは 電源用にPIC16F88を1個乗っけようかと思ってます
電源の電圧監視とか その他もろもろで
でも PICのADCって1024段階じゃないですか
電池はNi-MH4セルなんですけど 充電時には12V近くかかるので
1/3くらいに分圧したいわけですよ と言うことは分解能も1/3になるわけです
分解能14.64mVくらい?
-ΔVが1セルあたり5〜10mVくらいらしいので
全然分解能足りないのですよ
どうしたらいいんですかねぇ...
mbedの分解能は恐ろしい物がありますけど 実際にその分解能があるのかな…
例えば 12bitADCというのがあるんですよ マイコンっていうか半導体
6pinパケで2ch入って600円くらい
12bitだと 0〜5V 分圧1/3としたばあい
分解能3.66mVくらいになるんですよ これならまぁなんとかなるか というくらい
ギリギリですけどね
で 外部にADCを使うなら 16F88を使う理由が無いんですよ
なるべく小型化したいので8pinPICでいいじゃないですか
実際は追加機能とか考えると8pinじゃ無理な気もしますが
ADC2個とFET2個あればいいのでね
ADCのIF次第では 8pinのPCIでもいいかもしれません
(ただ普通の8pinだとIOが5本しか無いので かなりキツイ)
ということで 今回はココらへんで
2011年10月25日火曜日
PICで高速にシリアル通信
PICでpurintfを使う場合
普通は
void sputch(const char ch) {
while(!TXSTAbits.TRMT);
TXREG = ch;
}
っていう関数を使うことになる
これはシリアルで文字列を送信するためのものなんだけど
9600bpsだと1bitあたり
1/9600*1000000で104uSかかる
それが8bit+2(スタートストップ)で
1バイト送信するのに1mSくらい
ということは30文字送信するのに30mSかかる
これは無視できない時間
ということで
割り込みで送信できるようにしてみた
char text[50];
char textSize;
char textCnt = 0;
static void interrupt intr(void) {
if (TXIF) {
if (textSize > textCnt) {
TXREG = text[textCnt];
textCnt++;
} else {
textCnt = 0;
TXIE = 0;
}
}
}
これで
void main(void) {
init();
textSize = sprintf(text,"hello world ... serial TEST\r\n");
TXIE = 1;
for ( ; ; ) {
}
}
とかだと 300uS程度で処理が完了する
あとは割り込みで勝手に送信してくれる
ただ 当たり前だけどこれはハードウェアシリアルが有るPICに限られます
普通は
void sputch(const char ch) {
while(!TXSTAbits.TRMT);
TXREG = ch;
}
っていう関数を使うことになる
これはシリアルで文字列を送信するためのものなんだけど
9600bpsだと1bitあたり
1/9600*1000000で104uSかかる
それが8bit+2(スタートストップ)で
1バイト送信するのに1mSくらい
ということは30文字送信するのに30mSかかる
これは無視できない時間
ということで
割り込みで送信できるようにしてみた
char text[50];
char textSize;
char textCnt = 0;
static void interrupt intr(void) {
if (TXIF) {
if (textSize > textCnt) {
TXREG = text[textCnt];
textCnt++;
} else {
textCnt = 0;
TXIE = 0;
}
}
}
これで
void main(void) {
init();
textSize = sprintf(text,"hello world ... serial TEST\r\n");
TXIE = 1;
for ( ; ; ) {
}
}
とかだと 300uS程度で処理が完了する
あとは割り込みで勝手に送信してくれる
ただ 当たり前だけどこれはハードウェアシリアルが有るPICに限られます
2011年10月11日火曜日
みろ!電子部品がゴミのようだ!
「摂氏−30℃でも動作可能なシステム」に液晶使うわけにもいかないので
とりあえずLED作ってみた
意外と暗い
抵抗値は20Ω程度でもいいみたいだけど47Ωにしておいた
まぁ極端に言っちゃえば抵抗なんてなくてもいいんだけど
(2mS程度で切り替えてるから デューティ比は12%程しか無い)
裏↓
みろ!基板がゴミのようだ!
チップ抵抗は9個使用
LEDの制限用に47Ωが8個
プルアップ抵抗に47kΩが1個
本当はもう一箇所プルアップしたかったけどやめた
LED側↓
これは4桁程度なら仕事で4個前後作ってるから
いつもどおりって感じ
さすがに8桁は初めてだけどw
配線は70本超えてるはず
まぁ… 二度と作りたくないっすね
制御には18F2550を使ってる
一応チップコンデンサならGNDに入れられるからUSB接続もできるw
まぁUSARTっすけどね…
かなり余裕ある と言うかこの程度であのROMがキツキツになるならいったいどんな処理してるのか気になる
もうちょっと機能追加してみて だな
ICSPコネクタが無いからデバッグは大変
2011年9月20日火曜日
【追記】LCDモジュールに外字登録
追記
このコードとんでもないバグを抱えてるらしい
壊れはしないと思うけど なんか怪しい
ということで↓のコードは使用禁止
できれば今日中に修正コード書きます
が 明日朝早いので無理だったら来週まで更新できませんorz
(水曜日~土曜の4日連続で早朝出発のイベントが...)
******************************************************
マイコンで制御できる液晶モジュール(*)に外字登録を試してみたよ
今回作った関数はこれ↓
/* *** */
void LCD_Cset(char addr, char ca[]) {
LCD_8set(0x40 + addr, 0);
putch(ca[0]);
putch(ca[1]);
putch(ca[2]);
putch(ca[3]);
putch(ca[4]);
putch(ca[5]);
putch(ca[6]);
putch(ca[7]);
LCD_clear();
}
/* *** */
使い方は
/* *** */
const char data[] = {
0b00000000,
0b00000100,
0b00000100,
0b00011111,
0b00000100,
0b00000100,
0b00011111,
0b00000000 };
LCD_Cset(0, data);
/* *** */
みたいな感じで
でも配列を使うと結構コストが高いから
配列を使わないようにしてもいいかも
putchはHI-TECHでprintf関数を使えるようにするためのもの
簡単に言うとRSを1にして1byte送信
表示する場合はaddrで指定したアドレスをRSを1にして送信すればいいです
外字登録って結構便利で
ゲームを作ってる人とかカレンダーを作ってる人もいるみたい
あとおっきな文字を表示することもできるらしい
注意点としては外字は8文字までしか登録できないみたい
8文字を超えて登録しようとした時の処理とかは書いてないから各自注意してください
ということで 覚えておくとちょっと便利な小ネタでした
*これとかこれで動作確認をしたよ
このコードとんでもないバグを抱えてるらしい
壊れはしないと思うけど なんか怪しい
ということで↓のコードは使用禁止
できれば今日中に修正コード書きます
が 明日朝早いので無理だったら来週まで更新できませんorz
(水曜日~土曜の4日連続で早朝出発のイベントが...)
******************************************************
マイコンで制御できる液晶モジュール(*)に外字登録を試してみたよ
今回作った関数はこれ↓
/* *** */
/* *** */
使い方は
/* *** */
/* *** */
みたいな感じで
でも配列を使うと結構コストが高いから
配列を使わないようにしてもいいかも
putchはHI-TECHでprintf関数を使えるようにするためのもの
簡単に言うとRSを1にして1byte送信
表示する場合はaddrで指定したアドレスをRSを1にして送信すればいいです
外字登録って結構便利で
ゲームを作ってる人とかカレンダーを作ってる人もいるみたい
あとおっきな文字を表示することもできるらしい
注意点としては外字は8文字までしか登録できないみたい
8文字を超えて登録しようとした時の処理とかは書いてないから各自注意してください
ということで 覚えておくとちょっと便利な小ネタでした
*これとかこれで動作確認をしたよ
2011年9月15日木曜日
DIPスイッチを使うよ
今回はDIPスイッチの基本的な使い方を解説するよ
回路は↓これ
どっか間違ってる気もするので参考程度に
DIPSWの左側がプルアップ抵抗 今回は470Ωを使ったけど本来はV+に直結するべき
DIPSWの右側はプルダウン抵抗 4.7kΩを使ったよ
基本的にこれだけで使える
スイッチがOFFだとPICはLになりスイッチがONだとPICはHになる
一般的にはプルアップしてスイッチを押すとLになるけど
今回はわかりやすいように(+後々簡単なように)アクティブHにした
そしてコードは↓これ
/* *** */
一応
5ms毎にスイッチを監視し変更があればASCII16進に変換してバックスペースと共に送信
という感じ
これはぼくが作ったLCDモジュールの仕様によるもので
バックスペース(0x08)→1行目1文字目に移動
ENTER(0x13)→2行目1文字目に移動
ESC(0x1B)→表示クリア
になってるから
今回はこれ以外に機能を付けなかったから通常のポート使用量だけど
気が向いたらもうちょっと少ないポート数で使えるような工夫も紹介するかも
回路は↓これ
どっか間違ってる気もするので参考程度に
DIPSWの左側がプルアップ抵抗 今回は470Ωを使ったけど本来はV+に直結するべき
DIPSWの右側はプルダウン抵抗 4.7kΩを使ったよ
基本的にこれだけで使える
スイッチがOFFだとPICはLになりスイッチがONだとPICはHになる
一般的にはプルアップしてスイッチを押すとLになるけど
今回はわかりやすいように(+後々簡単なように)アクティブHにした
そしてコードは↓これ
/* *** */
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#define _XTAL_FREQ 20000000
#define TXP RC6
void send(char);
void main(void) {
TRISC = 0x0F;
PORTC = 0;
TXP = 1;
char data = 0;
while(1) {
if (data != (PORTC & 0x0F)) {
send(0x08);
data = (PORTC & 0x0F);
send(data + (data > 9 ? (0x37) : ('0')));
}
__delay_ms(5);
}
}
void send(char ca) {
TXP = 0; __delay_us(100);
TXP = ((ca >> 0) & 1); __delay_us(100);
TXP = ((ca >> 1) & 1); __delay_us(100);
TXP = ((ca >> 2) & 1); __delay_us(100);
TXP = ((ca >> 3) & 1); __delay_us(100);
TXP = ((ca >> 4) & 1); __delay_us(100);
TXP = ((ca >> 5) & 1); __delay_us(100);
TXP = ((ca >> 6) & 1); __delay_us(100);
TXP = ((ca >> 7) & 1); __delay_us(100);
TXP = 1; __delay_us(100);
}
/* *** */
一応
5ms毎にスイッチを監視し変更があればASCII16進に変換してバックスペースと共に送信
という感じ
これはぼくが作ったLCDモジュールの仕様によるもので
バックスペース(0x08)→1行目1文字目に移動
ENTER(0x13)→2行目1文字目に移動
ESC(0x1B)→表示クリア
になってるから
今回はこれ以外に機能を付けなかったから通常のポート使用量だけど
気が向いたらもうちょっと少ないポート数で使えるような工夫も紹介するかも
2011年9月9日金曜日
PICでLチカ【改】
#include <htc.h>
#include <config.h>
#define _XTAL_FREQ 20000000
#define LED RB5
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
PORTA = 0;
PORTB = 0;
PORTC = 0;
while(1) {
LED = !LED;
__delay_s(1);
}
}
コンフィグをヘッダにすることで移植を楽にした
自分は現状88と873Aしか使ってないから
#if defined(PIC16F88)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif
#if defined(PIC16F873A)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif
みたいな感じになってる
これでプロジェクトを作るときに選択した石のコンフィグが作られる
まぁ「典型的なコンフィグ」しか設定できないけどね
ちょっと動作確認したいだけならこれでも大丈夫だと思う
#include <config.h>
#define _XTAL_FREQ 20000000
#define LED RB5
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
TRISC = 0b00000000;
PORTA = 0;
PORTB = 0;
PORTC = 0;
while(1) {
LED = !LED;
__delay_s(1);
}
}
コンフィグをヘッダにすることで移植を楽にした
自分は現状88と873Aしか使ってないから
#if defined(PIC16F88)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif
#if defined(PIC16F873A)
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#endif
みたいな感じになってる
これでプロジェクトを作るときに選択した石のコンフィグが作られる
まぁ「典型的なコンフィグ」しか設定できないけどね
ちょっと動作確認したいだけならこれでも大丈夫だと思う
2011年9月5日月曜日
PICで液晶
/* *** */
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#define _XTAL_FREQ 20000000
#define E RB0
#define RS RB1
#define RW RB2
#define D4 RA3
#define D5 RA2
#define D6 RA1
#define D7 RA0
void LCD_init(void);
void LCD_clear(void);
char LCD_printf(char text[]);
void LCD_8set(unsigned char, char, char);
void LCD_4set(unsigned char, char, char);
static void interrupt intr(void) {
if (RCIF) {
RCIF = 0;
char c = RCREG;
if (c == 0x1B) { LCD_clear(); return; }
if (c == 0x08) { LCD_8set(0x80, 0, 0); return; }
if (c == 0x0D) { LCD_8set(0xC0, 0, 0); return; }
LCD_8set(c, 1, 0);
}
}
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;
LCD_init();
LCD_printf("LCD init ok...");
__delay_s(1);
LCD_clear();
for(;;) {
LCD_printf("hello");
__delay_s(1);
LCD_clear();
__delay_ms(1);
LCD_printf("world");
__delay_s(1);
LCD_clear();
__delay_ms(1);
}
}
void LCD_init(void) {
__delay_ms(15);
LCD_4set(0x30, 0, 0);
__delay_ms(5);
LCD_4set(0x30, 0, 0);
__delay_ms(1);
LCD_4set(0x30, 0, 0);
LCD_4set(0x20, 0, 0);
LCD_4set(0x20, 0, 0);
LCD_4set(0x80, 0, 0);
LCD_4set(0x00, 0, 0);
LCD_4set(0x80, 0, 0);
LCD_4set(0x00, 0, 0);
LCD_4set(0x01, 0, 0);
__delay_ms(2);
LCD_8set(0x06, 0, 0);
LCD_8set(0x80, 0, 0);
LCD_8set(0x0C, 0, 0);
}
void LCD_clear(void) {
LCD_8set(0x01, 0, 0);
__delay_ms(1);
LCD_8set(0x0C, 0, 0);
}
char LCD_printf(char text[]) {
char c;
for (c = 0; text[c] != '\0';c++)
{ LCD_8set(text[c], 1, 0); }
return c;
}
void LCD_8set(unsigned char data, char RSb, char RWb) {
LCD_4set(((data << 0) & 0xF0), RSb, RWb);
LCD_4set(((data << 4) & 0xF0), RSb, RWb);
}
void LCD_4set(unsigned char data, char RSb, char RWb) {
RS = RSb;
RW = RWb;
D4 = ((data >> 4) & 1);
D5 = ((data >> 5) & 1);
D6 = ((data >> 6) & 1);
D7 = ((data >> 7) & 1);
__delay_us(500);
E = 1;
__delay_us(1000);
E = 0;
}
/* *** */
PIC16F88 @ 20MHz
液晶との接続はコード最初のほうで確認してください
あと__delay_s()の追加をしてない人は
__delay_msに修正するなり
#define __delay_s(sec) { __delay_ms(sec * 1000); }
とか書き足すなり(動作確認はしてないけど)
適当に対応してください
実はこれARMチャレンジャーの液晶の動作確認に作ったコード
なぜかARMからだと動作してくれなかったので
PICで動作確認
んでこのコードをARMに移植しても動かないんだよね…
LCDの電源が5VでARMが3.3Vだからとかいうくだらない理由でも無いと思うんだけど…
何なんだろう
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_ON & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#define _XTAL_FREQ 20000000
#define E RB0
#define RS RB1
#define RW RB2
#define D4 RA3
#define D5 RA2
#define D6 RA1
#define D7 RA0
void LCD_init(void);
void LCD_clear(void);
char LCD_printf(char text[]);
void LCD_8set(unsigned char, char, char);
void LCD_4set(unsigned char, char, char);
static void interrupt intr(void) {
if (RCIF) {
RCIF = 0;
char c = RCREG;
if (c == 0x1B) { LCD_clear(); return; }
if (c == 0x08) { LCD_8set(0x80, 0, 0); return; }
if (c == 0x0D) { LCD_8set(0xC0, 0, 0); return; }
LCD_8set(c, 1, 0);
}
}
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;
LCD_init();
LCD_printf("LCD init ok...");
__delay_s(1);
LCD_clear();
for(;;) {
LCD_printf("hello");
__delay_s(1);
LCD_clear();
__delay_ms(1);
LCD_printf("world");
__delay_s(1);
LCD_clear();
__delay_ms(1);
}
}
void LCD_init(void) {
__delay_ms(15);
LCD_4set(0x30, 0, 0);
__delay_ms(5);
LCD_4set(0x30, 0, 0);
__delay_ms(1);
LCD_4set(0x30, 0, 0);
LCD_4set(0x20, 0, 0);
LCD_4set(0x20, 0, 0);
LCD_4set(0x80, 0, 0);
LCD_4set(0x00, 0, 0);
LCD_4set(0x80, 0, 0);
LCD_4set(0x00, 0, 0);
LCD_4set(0x01, 0, 0);
__delay_ms(2);
LCD_8set(0x06, 0, 0);
LCD_8set(0x80, 0, 0);
LCD_8set(0x0C, 0, 0);
}
void LCD_clear(void) {
LCD_8set(0x01, 0, 0);
__delay_ms(1);
LCD_8set(0x0C, 0, 0);
}
char LCD_printf(char text[]) {
char c;
for (c = 0; text[c] != '\0';c++)
{ LCD_8set(text[c], 1, 0); }
return c;
}
void LCD_8set(unsigned char data, char RSb, char RWb) {
LCD_4set(((data << 0) & 0xF0), RSb, RWb);
LCD_4set(((data << 4) & 0xF0), RSb, RWb);
}
void LCD_4set(unsigned char data, char RSb, char RWb) {
RS = RSb;
RW = RWb;
D4 = ((data >> 4) & 1);
D5 = ((data >> 5) & 1);
D6 = ((data >> 6) & 1);
D7 = ((data >> 7) & 1);
__delay_us(500);
E = 1;
__delay_us(1000);
E = 0;
}
/* *** */
PIC16F88 @ 20MHz
液晶との接続はコード最初のほうで確認してください
あと__delay_s()の追加をしてない人は
__delay_msに修正するなり
#define __delay_s(sec) { __delay_ms(sec * 1000); }
とか書き足すなり(動作確認はしてないけど)
適当に対応してください
実はこれARMチャレンジャーの液晶の動作確認に作ったコード
なぜかARMからだと動作してくれなかったので
PICで動作確認
んでこのコードをARMに移植しても動かないんだよね…
LCDの電源が5VでARMが3.3Vだからとかいうくだらない理由でも無いと思うんだけど…
何なんだろう
2011年9月4日日曜日
手っ取り早くPICでデバッグするためのUSART
/* *** */
void send(unsigned char data) {
TXP = 0;
__delay_us(100);
TXP = ((data >> 0) & 1);
__delay_us(100);
TXP = ((data >> 1) & 1);
__delay_us(100);
TXP = ((data >> 2) & 1);
__delay_us(100);
TXP = ((data >> 3) & 1);
__delay_us(100);
TXP = ((data >> 4) & 1);
__delay_us(100);
TXP = ((data >> 5) & 1);
__delay_us(100);
TXP = ((data >> 6) & 1);
__delay_us(100);
TXP = ((data >> 7) & 1);
__delay_us(100);
TXP = 1;
}
/* *** */
出力するポートを予め
#define TXP RA4
みたいに定義しておく必要があります
あと__delay_usを使うためにhtc.hもインクルードする必要があります
それと↓みたいにコンパイラに動作クロックを指定する必要があります
#define _XTAL_FREQ 20000000 // 動作クロック20MHz
ということで内部クロックを使って動作周波数が可変とかだと無理です
そういう時はdelay関数自分で作ってください
とりあえずこれだけで9600bpsで一文字送信はできます
void send(unsigned char data) {
TXP = 0;
__delay_us(100);
TXP = ((data >> 0) & 1);
__delay_us(100);
TXP = ((data >> 1) & 1);
__delay_us(100);
TXP = ((data >> 2) & 1);
__delay_us(100);
TXP = ((data >> 3) & 1);
__delay_us(100);
TXP = ((data >> 4) & 1);
__delay_us(100);
TXP = ((data >> 5) & 1);
__delay_us(100);
TXP = ((data >> 6) & 1);
__delay_us(100);
TXP = ((data >> 7) & 1);
__delay_us(100);
TXP = 1;
}
/* *** */
出力するポートを予め
#define TXP RA4
みたいに定義しておく必要があります
あと__delay_usを使うためにhtc.hもインクルードする必要があります
それと↓みたいにコンパイラに動作クロックを指定する必要があります
#define _XTAL_FREQ 20000000 // 動作クロック20MHz
ということで内部クロックを使って動作周波数が可変とかだと無理です
そういう時はdelay関数自分で作ってください
とりあえずこれだけで9600bpsで一文字送信はできます
2011年8月19日金曜日
C語高速化のコツ
ちょっと気になったのでメモ
たとえば
byte data[8,8];
っていうのがあったとして そこにデータを入れたい場合 一番手っ取り早いのは
char x, y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
data[x, y] = ((関数の引数[x] >> y) ? 1 : 0);
}
}
みたいなかんじのコードが楽
だけど PICの場合かなり高コストになっちゃう
ということで 実行速度をなるべく早くしたいなら
char x;
for (x = 0; x < 8; x++) {
data[x, 0] = ((関数の引数[x] >> 0) ? 1 : 0);
data[x, 1] = ((関数の引数[x] >> 1) ? 1 : 0);
data[x, 2] = ((関数の引数[x] >> 2) ? 1 : 0);
data[x, 3] = ((関数の引数[x] >> 3) ? 1 : 0);
data[x, 4] = ((関数の引数[x] >> 4) ? 1 : 0);
data[x, 5] = ((関数の引数[x] >> 5) ? 1 : 0);
data[x, 6] = ((関数の引数[x] >> 6) ? 1 : 0);
data[x, 7] = ((関数の引数[x] >> 7) ? 1 : 0);
}
たとえば
byte data[8,8];
っていうのがあったとして そこにデータを入れたい場合 一番手っ取り早いのは
char x, y;
for (x = 0; x < 8; x++) {
for (y = 0; y < 8; y++) {
data[x, y] = ((関数の引数[x] >> y) ? 1 : 0);
}
}
みたいなかんじのコードが楽
だけど PICの場合かなり高コストになっちゃう
ということで 実行速度をなるべく早くしたいなら
char x;
for (x = 0; x < 8; x++) {
data[x, 0] = ((関数の引数[x] >> 0) ? 1 : 0);
data[x, 1] = ((関数の引数[x] >> 1) ? 1 : 0);
data[x, 2] = ((関数の引数[x] >> 2) ? 1 : 0);
data[x, 3] = ((関数の引数[x] >> 3) ? 1 : 0);
data[x, 4] = ((関数の引数[x] >> 4) ? 1 : 0);
data[x, 5] = ((関数の引数[x] >> 5) ? 1 : 0);
data[x, 6] = ((関数の引数[x] >> 6) ? 1 : 0);
data[x, 7] = ((関数の引数[x] >> 7) ? 1 : 0);
}
とかのほうが 早くなると思う
まぁ場合によって多少違うだろうけど
forをネストすると実効速度がどんどん遅くなる っていう感じらしい
ということらしいので
やっぱなるべくネストはしないほうがいいらしい
16F88でLチカ
/* ** */
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#define _XTAL_FREQ 20000000
#define LED RB4
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;
while(1) {
LED = !LED;
__delay_s(1);
}
}
/* ** */
はい
↓のポストのコードを実際に使うためのコード
このコードでは外部20MHzクロックで
RB4に接続したLEDを点滅させる
だけ
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
#define _XTAL_FREQ 20000000
#define LED RB4
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000000;
ANSEL = 0;
PORTA = 0;
PORTB = 0;
while(1) {
LED = !LED;
__delay_s(1);
}
}
/* ** */
はい
↓のポストのコードを実際に使うためのコード
このコードでは外部20MHzクロックで
RB4に接続したLEDを点滅させる
だけ
【メモ】HI-TECHでウエイト処理
htc.hをインクルードして
#define _XTAL_FREQ 20000000
をコードに追加
20000000はクロック この場合20MHzね
そしてコードで
__delay_ms(10);
ってやったら10mS待ってくれる
__delay_us
ならマイクロ秒で
そしてついでだから
pic.hに
#define __delay_s(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4.0)))
を追加してみた
これだと秒単位でウエイトができる
20MHzだとして最大で800秒分ちょっと
たぶんusでもmsでもsでもおなじはず
あとWin6.x(Vistaとか7)の場合普通はUACでpic.hを書き換えはできない はず
とりあえず自分はVisualC++を使ってるから 右クリックから 管理者として実行 で起動しておいた
とりあえず
メモ
#define _XTAL_FREQ 20000000
をコードに追加
20000000はクロック この場合20MHzね
そしてコードで
__delay_ms(10);
ってやったら10mS待ってくれる
__delay_us
ならマイクロ秒で
そしてついでだから
pic.hに
#define __delay_s(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4.0)))
を追加してみた
これだと秒単位でウエイトができる
20MHzだとして最大で800秒分ちょっと
たぶんusでもmsでもsでもおなじはず
あとWin6.x(Vistaとか7)の場合普通はUACでpic.hを書き換えはできない はず
とりあえず自分はVisualC++を使ってるから 右クリックから 管理者として実行 で起動しておいた
とりあえず
メモ
2011年8月18日木曜日
【メモ】PIC16F88でUSART(受信割り込み)
/* *** */
#include <htc.h>
__CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & MCLRE_OFF & BOREN_OFF & LVP_OFF & DEBUG_OFF);
static void interrupt intr(void) {
if (RCIF) {
char t;
RCIF = 0;
TXREG = 'R';
t = RCREG;
RB4 = (t == '0' ? 0 : 1);
}
}
void main(void) {
TRISA = 0b000000;
TRISB = 0b00000100;
ANSEL = 0;
PORTA = 0;
PORTB = 0;
RCIE = 1;
PEIE = 1;
GIE = 1;
TXSTA = 0x20;
RCSTA = 0x90;
SPBRG = 32;
TXREG = 'S';
while(1) {
}
}
/* *** */
とりあえず動作確認だけだから無駄なコードとかあるかも
ハードUSARTなので回路図は省略
とりあえずTXとRXを間違えずに接続してください
あとRB4にLEDを1kΩくらいの抵抗を介してGNDに接続すると
数字の0(アスキーコード49だったかな?)で消灯
それ以外で点灯します
シリアル受信割り込みで処理してるから他の命令を実行中でも動作すると思う
とりあえずメモ程度なので変なバグあっても怒らないでorz
(バグ見っけたらコメント等で教えていただけると)
追記:動作クロックは20MHzです
(includeのあとが表示されない問題を修正 HTMLタグと間違われてたらしい バックスラッシュとかで"<"とかを無効化できたはずなんだけどどうやるんだっけ… 2011/08/19)
登録:
投稿 (Atom)





