UART(rs232c) 08.12.12
UART(rs232c)を使った実験は他所に書いてきましたが、HIDaspxのハードウエア利用のusbRS232がデータ量が少ないときには十分実用になると感じて、これを使った実験をしてみます。UART機能は、AVRでは特定のデバイスを除いてハードウエアで持っていますから、AVRボード間でも簡単に行えます。
1 UART−USBアダプタ HIDaspx
USB-UART変換には FTDI232L や cp210x を使うのが普通でかつ性能がよいのですが、データ量が少ないことからTiny2313で作ることができるHIDaspxハードウエアを使うことにしています。ファームウエアはusbRS232を使います。
HIDaspxハードウエアは原典とほとんど変わりはないのですが、UARTに特化したために、@ライタ機能のコネクタがありません、A電源はデバイスの頻繁なon,offを避けるためにバスパワーにしています、ただしターゲットには送りません、B電源にシリコンダイオードを2個直列に入れて電源電圧を3.6V程度にしています、CD±のZDは入れていません、D中途半端な電圧で、5V/3.3Vのターゲットに共用するつもりです、EインジケーターLEDは電源直結のものだけにしています、といったところを変更しています。
当初はターゲットにバスパワーを送る予定は無かったのですが、簡易周波数カウンタでは消費電流が少ないことと、さらに電源を必要とする回路が付加されることはないのでバスパワーを送ることができるようにコネクタにVccを追加しました。送るかどうかはターゲットのVccの配線をするかどうか(4番ピンを接続するかどうか)で決めることにします。
さらに、記録式簡易電圧計で長時間に亘って充電池の放電特性をしているときに問題が生じました。測定時間が長いことから測定中はPCの電源を切ることになります。再起動時にUSBに認識されなくなり、ファームを書き直すと動作します。HIDaspxハードウエアの電源が切れた状態でターゲットの通信線を通じて電力が供給され、入力保護ダイオードを通じて不安定なVccを与えることになるようです。入力回路(RXD)に10kの抵抗を入れるとフラッシュが書き換えられることは無くなったようですが、PCの再起動時にUSBを差し直さないと認識されない場合が生じました。これを回避するために回路図の赤色部分を変更しました。ダイオードでH入力をカットしてL入力だけを受け入れ、H入力はプルアップ抵抗で得ます。擬似的にオープンコレクタで受けることになります。これで正常に再起動できるようになりました。
UARTコネクタはヘッダピンとヘッダソケットを4Pに切ったものを使っていますが、使うたびに結線が異なって困りましたので、今回は決めることにしました。
2 HIDaspxのファームウエア
ファームはusbRS232を使います。(usbRS232-2009-0914.zip)
windowsでドライバーのinfファイルが必要ですが、AVR-Doperに付属のavrdoper.inf を使用します。
USBロースピード規格と使用コンピュータがUHCIであるために ボーレートは最大の 19200bps を使いますが、このファームはフローがコントロールされていないので通信の脱落を防ぐために1バイト送信する毎に1ms程度のwaitを入れる必要があります。
ここでの実験は一度の通信量が数十バイト程度と考えますのでこのために通信に支障がでることはないと思います。
3 PC側のソフトウエア
簡単な通信テストにはteratermが便利ですが、表示デザインが自由になりません。またキーボードからの送信に限られます(マウスでの選択ができません)。ExcelのVBAで通信したこともありますが、これも私自身がVBAになじみにくいこととexcel画面から抜け出せないために使わないことにしました。
そこで、喘ぎあえぎですがDelphi6を使うことにします。表示画面のデザインが自由になります。(使いこなせれば極めて有用な道具ですが、使い方が難しくて難行苦行の連続です。)ずいぶん前にver3.1を購入していましたが、今はver6のpersona版を使っています。
4 実験1 ターゲットボードからPCにデータを読みとる
通信の第一歩です。ターゲットボードは以前の実験に使った90S2313によるもので、常には受信待ちの状態にあって、"1"を受信すると"one"、"2"で"two"、"3"で"three"、それ以外では"select1,2,3"を返すというものです。いずれも文字列の後に 0X0c、0x0aを付けています。前の実験からプログラムを少し変えて、19200bpsとして、また、文字毎の送信の間に1ms程度のwaitを入れています。
手始めは、確実なteratermで行いました。用いたHIDaspxが"com5"になりましたのでそのポートでアクセスしています。ときどき、はじめて受信するときは最初の一文字が抜けることがありますが、接続後の2回目からはそのようなことはありません。意図したとおりの結果となっています。
久しぶりのDelphiは"他人"になっていました。思い出そうにも、その緒さえ見つかりません。以前に自分で書いたものをみながら、かなりの時間がかかってやっと one、two …… が読めるプログラムができました。
ポートとボーレートを選んで"connect"ボタンを押すと回線がつながればその右に"open comX"と表示されます。続けて、文字"3"を書いて"send"ボタンを押したところです。"three"が受信された状態です。
接続したままUSBを抜くとうまくないので、"close"ボタンを付けました。もちろんこれを押すと"open"が"closed"に変わります。
5 超簡易周波数カウンタ
実験場所にPCがあれば、測定値をPC画面に表示すれば場所も取らないし、装置も簡単になるのではないか、と考えて実験してみました。
装置はTiny2313を使って、実験のために最小限にしています。ファームウエアも珍しいものではありません。とりあえずカウンタからはデータを出しっぱなしにして、Teratermで受信・表示をすることにしました。
ハードウエア:最小限にしましたので、インジケーターのLEDさえ準備していなくて、デバッグ時に不便なため後から追加しています(不格好)。入出力端子には一応の保護抵抗を付けています。クロック源はTCXOがなかったので、遊び心で25MHzの表面実装発振器を使いました。京セラ製で±50ppmのものだそうです。場所によっては\400もするようですが、デジットで5個\100で買ってあったものです。25MHzはオーバースペックですが、これも遊び心です。
ファームウエア:カウントのプログラムは過去に作った90S2313使用のものとほとんど変わりません。CTC動作で、カウンタ設定値になると割り込みが生じるとともにカウンタがリセットされます。25MHzを1024分周で使い、1秒経過したときに割り込みが発生するようにして、その時にT0入力のカウンタ値を読みとるとともにリセットしています。カウント値はタイマ/カウンタ0の8ビットとオーバーフローを16ビット変数で受けて合計32ビットで得ています。
CTC動作時の動作は90S2313と分周時に違いがあるようで、90Sは設定値に達した次のクロックで割り込みが発生するのに対して、Tinyでは設定値が終了した次のクロックで終わるようです。ここでは1024分周していますので、たとえば100に設定すると、100のクロックが1024回続いて次に101のクロックが1024回続く計算になりますが、90Sでは100の第1クロックの次のクロックで終わるのに対して、Tinyでは100の1024回目のクロックの次のクロックで終わります。したがって同じ設定値にしますとTinyは1024クロック分(25MHzで40μs)長くなります。Tinyでは-1の値を設定します。
測定値は十進の各桁に算術分解して、アスキーコードに変換した後送信します。とりあえずTeratermで受けることにしましたから、カンマ区切りと、"Hz"を付けてみました。国際的には小数点にピリオドを使う国とカンマを使う国があることから桁区切りはカンマもピリオドも使わない、としているようですから"空白"が良いのかもしれません。(1,234ドルは1000ドル余りですが、1,234ユーロは1ユーロ余りです。)
横着でリーディングゼロサプレスはしていません。
UART(RS232C)の出力は 文字列にCR、LF記号を付けてフロー制御なしに、流し放しにしています。1秒の測定ごとに送信しています。前回の実験では文字の送出間に1ms程度のディレイが必要だったのですが、今回は入れない方が良かった(理由は不明)ので入れていません。19200bpsで使っています。
動作結果とその他:一応初期の目的は達しました。8MHzを最高に幾種類かの測定をしましたが、京セラの12.8MHzTCXO使用のカウンタと比べるといずれの場合でも 2×10-5 程の違いでした。温度変化は調べていませんが、クロックの測定程度には実用になるかと思います。最高は10MHzくらいは測定できるのではないかと思います。もっとも、測定桁は 9,999,999Hz までですが。
次は受信と表示に特別な窓を書いて見やすくしたいと考えています。また、この程度のものを接続するならバスパワーにしたほうが便利なようです。
Tiny2313と水晶があれば簡単にできますから、簡易カウンタがないときには作ってみるのも良いのではないでしょうか
(追記)前置アンプがないため、Tiny2313を駆動する入力が必要です。できればアンプを付加したいところです。また、2〜4分周するとマイクロコンピュータのクロック関係を調べるのに便利かと思います。
Delphiによる受信プログラム:を作りました。
comポートはとりあえずcom1〜com6を用意しました。ボーレートは 19200bps 固定です。接続ボタンを押すと、回路がつながれば comx open と表示が変わります。
測定ボタンを押すと測定値表示が始まりますが、ターゲットからは1秒に1回しかデータが来ませんのでそれに同期して表示されます。接続後の第1回目は最初の文字が受信できないことがあって、一瞬表示がずれることがあります。継続測定中は表示が同じであれば更新は目に見えません。
実行ファイルをここに置きます。ソースは見るに耐えないものですが、もし必要ならメールをいただければお送りします。
裏話:ほとんどまともには勉強していないDelphiと久しぶりに格闘しました。イベントドリブン型のDelphiはイベントが終了するまで表示しないようです。
今回も、受信、表示のルーチンを whileループで回したかったのですが、このループは同じイベント内にありますから何回回しても最終の結果しか表示されません。したがって、無限ループにすると無限の彼方まで表示が行われないことになるようです。
net情報をいろいろ調べて、タイマーコンポーネントを使うとたとえば1秒に1回のイベントを発生できることを知りました。今回は0.5秒ごとにタイマーによるイベントを発生させて、その中で受信結果を表示しています。(ここに辿りつくまでかなりしんどい思いでした)
「たとえば、3回の演算結果を同じ欄に時間的に順に表示したいときはどうしたらいいのか」については、まだ方法を見つけていません。それでも、窓に表示できる私にとっては唯一の手段ですから、ぼつぼつと考えましょう。
Excel-VBAによる受信プログラム:を作りました。
VBAにはなかなかなじめませんが、数値を後から利用するときに便利ですから、以前のものを参考に作ってみました。
文法も一部しかわからないので例によって暗中模索で進みます。くどくなりますが、その手続きをかきます。
・ RS232Cを使うために、EasyCom モジュールをダウンロードして解凍し、マイドキュメントに置きます(Excelはここを見に行きます)。
・ Excelを起動して、ツール→マクロ→VBエディタを開きます。alt+f11 でも同じです。
・ VBA画面で左上のプロジェクト窓に「Microsoft Excel Object」フォルダがなければ、その上の3つの四角ボタン右端の「フォルダの切替」ボタンで「Microsoft Excel Object」を表示させます。
・ この窓で右クリックして 挿入 → 標準モジュール で標準モジュールを挿入します。
・ 「標準モジュール」フォルダが開いている状態で、窓を右クリックして「ファイルのインポート」を選び、ec.bas をインポートします。
・ 同様に ecDef.bas もインポートします。 これで「標準モジュール」に3つのモジュールがぶら下がることになります。
・ Excel画面に戻って、表示 → ツールバー → visual basicをクリックしてVBメニューを表示します。
・ この窓の 「コントロールツールボックス」をクリックして「コントロールツールボックス」窓を作ります。
・ コントロールツールボックス(またはVBメニュー窓)の「デザインモード」ボタンで画面設計モードに入ります。
・ 3つのボタンを画面の左方に作ります。上から順に、「接続」「測定」「切断」とします。最初のボタンをダブルクリックするとVBエディタ画面となり、左下にボタンのプロパティ窓がありますから、その Caption を 接続 とします。
・ 同様に、2番目には 測定 、3番目には 切断 の表示に変えます。
・ 次はプログラムの記述です。デザインモードで 接続ボタン をダブルクリックするとVBエディタ画面の該当イベントのプログラムクラム欄にカーソルがありますから、そこにこのイベントのプログラムを書きます。
Private Sub CommandButton1_Click()
For j = 1 To 25 'これから表示する欄をクリアしておく
Worksheets("Sheet1").Cells(j, 5).Value = ""
Next
ec.COMn = 5 'ポートは5番
ec.Setting = "19200,n,8,1" 'ボーレイト、パリティ、データビット、ストップビット
ec.Delimiter = ec.DELIMs.CrLf 'デリミタ
n = 1
End Sub
最初と最後の行はすでに書かれているので7行を書きます。
・ 次に、測定ボタンのプログラムを書きます。デザインモードでボタンをダブルクリックしてプログラム欄を呼び出し、
Private Sub CommandButton2_Click()
While (1 = 1) '表示を無限に繰り返す wendまで
ec.InBufferClear '古いデータは捨てて
a$ = ec.AsciiLine 'MCUから受け取り
Worksheets("Sheet1").Cells(n, 5).Value = a$ 'セルに書き込む
n = n + 1 'カラムを一段下げて
If n = 25 Then '25行に達したら測定値を消して最初の行に戻って
For j = 1 To 25 '表示する
Worksheets("Sheet1").Cells(j, 5).Value = ""
Next
n = 1
End If
Wend '繰り返しの終わり
End Sub
・ 3番目の 切断 にはポートのクローズとプログラムの終了を書きます。
Private Sub CommandButton3_Click()
ec.COMn = -1 '通信終了
End 'プログラムの終了
End Sub
・ 使っている i,n の変数宣言をプログラムの最初に書きます。
dim i,n as integer
(プログラムはこの画面からのコピー&ペーストで書くことができます。)
Excelを終了すればポートもクローズされるようですが、クローズしてから終わった方が問題がないと思います。
ExcelのVBA作成画面ではプログラムのための情報が少なくて好きになれませんが、Excelを持っている方は多くおられますから追試いただけるのではないかと思います。得られたデータを利用するときには便利な手段です。excelのワークシートをここに置きます。
6 簡易(記録式)電圧計 計画中 2009.01.19
10年近く前に中古で購入したニッケル水素電池がいくつかあります。たまに使う程度なのですが、思い出してどれくらい容量が残っているのか調べてみようと思ったのがこの項の動機です。豆電球を負荷に時間を測ろうと思うのですが、ついでのことにAVRに電圧を測らせて、rs232cでPCに送るか、EEPROMに蓄えてまとめてPCに送ることを考えました。
とりあえずAD変換を使いたいのでTiny2313ではなく、手持ちのmega48で考えます。EEPROMにデータを書くのが常道ですが、電池駆動にして電源に接続したままならSRAMが簡単です。1バイトデータとすると256バイト使えば5分間隔でサンプリングして21時間記録できます。電池の容量を調べるだけならこの半分もあれば十分です。1バイトで12Vを測ると最小単位は50mVとなりますが今回はこの精度で十分と考えます。
ハードウエアは回路図を書くまでもないほど簡単で、
クロックは12MHzクリスタル+22pF*2
電源回路は 0.1μF パスコンだけ、
AVCC端子は、単にVccに接続
入力は 10k+1k で1/11に分圧してADC7端子へ、
TXDとRXDを usbR232 に接続
ISPコネクタ実装
というものです。
装置を完成する過程は実験の連続ですから、小さな動作を確実にして次のステップへ進むことにしています。まとめて書いてしまってはどこが悪いのかさえ見いだせなくなります。手順を考えます。
@ Teratermとの通信。PCからコマンドの1文字を送ると、既定の文字列を返すルーチンの完成。
A タイマ割り込み。とりあえず1秒ごとにPCに文字列を返す。
B 入力電圧を1/11に分圧して8ビットAD変換する。(1/10より抵抗の設定がらく)
C 電圧の値(MAX12V)をPCに返す。
D 1分または5分間隔でAD変換値を1バイトの数値でSRAM(配列)に書き込む。
E PCからのコマンドによりSRAMを読み出してTeratermに送る。
F 1秒ごとに読み出し=rコマンド、1分ごとにSRAMに記録=mコマンド、5分ごとにSRAMに記録=nコマンド、
SRAMからの読み出し=pコマンド、とする。
似たような作業をしたことがありますが、しばらくするとすべて忘却の彼方です。またまたデータシートと格闘して探し出すことになります。
今後、再利用しやすいようにこれらの対策をメモしてみます。
@Teratermとの通信=UART:AVR側受信は割り込みを使い、送信はバッファの空き+ディレイで行う。
/* USART設定 */
UBRR0 = 38; /* ボーレート設定 19200bsp 12MHz */
UCSR0B = _BV(RXEN0)|_BV(TXEN0)|_BV(RXCIE0); /* 送受信許可 受信割込許可 */
UCSR0C = 6; /* フレーム形式設定(8ビット,1ストップビット) */
/* 受信割込ルーチン */
ISR(USART_RX_vect){
rflg=1; /* フラグを立てて */
rdat=UDR0; /* データを読み出すとクリアされる rdat:char変数 */
while(!(UCSR0A & _BV(UDRE0))); UDR0 = 0x0d; delay_ms1(6); /* 送信バッファの空きを待ってデータをセット CRLF送信*/
while(!(UCSR0A & _BV(UDRE0))); UDR0 = 0x0a; delay_ms1(6); /* 送信バッファの空きを待ってデータをセット */
}
/* 文字列送信ルーチン */
void string_out (char *msg_string){ /* "*"で受けると、呼び出し側の配列の番地を受け取る */
uint8_t i;
i=0;
while (msg_string[i] !='\0'){
while ( !(UCSR0A & _BV(UDRE0)) ); //送信バッファの空きを待って
UDR0 = msg_string[i]; //送信データをセットします
i++;
delay_ms1(6);
}
}
A タイマ割り込み。
/* タイマ1の設定 1秒割り込み */
TCCR1A=0;
TCCR1B=_BV(WGM12)|_BV(CS12)|_BV(CS10); //CTC動作 1024分周
OCR1A=11719; //12MHz/1024のカウント
TIMSK1=_BV(OCIE1A); //compA一致割り込み
/* タイマ1割り込みルーチン フラグを立てるだけ 処理場所でフラッグポーリング */
ISR(TIMER1_COMPA_vect) { //1秒フラグ CTC動作
t1s=1; //処理場所でフラグを倒すこと
}
BAD変換(8ビット) ADC7使用(注釈がわかりやすいようにSFRの設定を複数行に分けてみた)
/* ADコンバータ設定 ADC7使用 割り込み不使用 */
ADMUX= _BV(REFS1)|_BV(REFS0)| /* 内部1.1V */
_BV(ADLAR)| /* 左揃え */
_BV(MUX2)|_BV(MUX1)|_BV(MUX0); /* ADC7選択 */
ADCSRA=_BV(ADEN)| /* 変換許可 */
_BV(ADSC)| /* スタート */
_BV(ADPS2)|_BV(ADPS1); /* 64分周 12MHz/64=187.5kHz */
/* 変換 */
cli();
ADCSRA|=_BV(ADSC); /* スタート */
data=ADCH; /* 変換 8ビットだからHだけ */
sei();
C 電圧の値(MAX12V)をPCに返す。
8ビット値に係数をかけて電圧(数値 小数計算しないために100倍値)に変換し、
10nの剰余を取って各桁毎の数値に分解し、+0x30で文字に変換して
文字列に代入した上で、送信する。
D 1分または5分間隔でAD変換値を1バイトの数値でSRAM(配列)に書き込む。
コマンドを受けると配列を初期化し、
1秒タイマを60回、または300回検出したら配列に格納する。
E PCからのコマンドによりSRAMを読み出してTeratermに送る。
簡単にするために120個のデータ(電圧値)を連続して送る。
現在は、1秒間隔でのサンプリング実験までは成功しています。電池駆動の電源部分は未作成です。
(2009.01.24) 仕様を変更しながら完成へ近づきました。
まず、コマンドの取り扱いでは、PCからの送信文字のコピーだけでは、RS232コネクタの挿抜、接続したままのPCのon/offで雑音により誤動作するようです。
それを避けるために、コマンドでフラグをセットするとともに、コマンドを増やしました。
rコマンド=リアルタイムのデータ転送(PCへ)
mコマンド=配列にデータ記録開始(同時にrコマンドの1秒ごとのリアルデータ送信の禁止)データ保存は5分ごとだけに変更。1分毎は廃止。
pコマンド=配列データから一括してPCへ送信。配列数も180(5分ごとに15時間分)に変更。
これらに加えて、
sコマンド=測定の停止。
iコマンド=配列の0初期化。
を追加しました。
プログラムはこのようになりました。
冗長なところもありますが、改良はあらためて考えることにします。
単4電池4個と中古のPC用電源用Ni-MH4個の放電記録をグラフにしてみました。
単4電池は公称1000mAhですがグラフからは620mAh位です。約0.5Aの豆電球負荷はやや重すぎた感じがあります。
4/3A 4本組はかなり以前に中古で購入したノートPC用を分解したものです。同じ負荷で測定しましたが、公称の3200mAhに比べて1700mAhくらいと読みとれます。
どちらもニッケル水素電池の特長である平坦部が見られます。
7 簡易Lメータ 2009.03.29
スイッチング電源の実験にいくつかインダクタを買いました。ドラム状で値を印刷してあるのは良いのですが、トロイダルコアに巻いたものは表示がありません。したがって購入直後からわからなくなります。精度は必要でないのですがインダクタンスを測るものはないかと検索していましたら比較的簡単にLCが測定できる例がありました。
その中から、手持ちの部品だけでテストしてみたのがこの項です。結果的に十分満足な測定値が得られました。LC並列の共振回路を持った発振器を作り、周波数カウンタで発振周波数を調べ、 f=1/( 2π*√(L*C) ) から未知のLを計算するもののようです。周波数カウンタはこのページで簡単なものを作っていますからそれが利用できます。あと、計算があるのですが装置を簡単にするためにPCでの表示としていますからPCのDelphiで計算と表示をすることにしました。
したがって発振部だけを作れば良いことになります。
手持ちには1000pFのコンデンサが無かったのですが、40年ほど前のジャンクから 3200pFのスチコンが出てきましたので、傾向が見えればよいと付けてみたところが意外に 数μF〜数百μFの範囲の測定ができることがわかりました。また、抵抗値もありあわせで間に合わせてあります。
共振回路は被測定のLと内蔵の56μHが直列となって3200pFと構成されていますから、計算式の3200pFは正確なものとしてLを求め、内蔵の56μH分を差し引いて計算しています。測定端子を短絡したときに0となるようにしました。結果的に53.4uHを差し引いています。計算には他の要因もあるようですが、手持ちの 3.3、56、100uHのものを測定したところ、3.1、55.2、103と 5%以内に納まっているでこれでよし、とします。
PC(Delphi)では適当に位取りして整数計算として、途中は3桁で切り捨てています。答えがμHの10倍値で出るように整数計算をして表示の時に小数点が入るようにしています。
Delphiのプログラムは何とも言えない状態ですから、ここには載せませんが関心をお持ちの方にはお送りします。下記に置きます。読めるかどうかは別ですが。
これで、コイルを一部ほどいたり、巻き足したときのインダクタンスが測定できます。
私の作業場所はコンピュータを置いている机だけですからこの方が場所をとらずに済みます。1000円以下で周波数カウンタとLメータを作ったことになります。
(2009.03.31追記) 日を置いて動かしますと温度変化などでLCの状態が違うためか0点が少しずれます。おおざっぱですが測定端子を短絡したときに 0μH になるようにアジャスト機能を追加しました。 短絡状態で adj. ボタンを押すと内蔵Lを引き算して結果が0になるように内蔵Lの定数を変更します。
これによって実験に使った内蔵Lと異なるインダクタを使ってもプログラムは使えると思いますので、(読みにくさや善し悪しは別にして)プログラムをここに置きます。Delphi6でコンパイルしています。もし、試されるか方がおられましたらご報告をお願いします。
8 テスト用ターゲットボード 2009.05.08
RS232C(COMポート)通信をするPCソフトを作るときに確実な動作をするターゲットボードがあれば落ち着いて開発できる、という考えで作りました。これがないとソフトが悪いのかターゲットが悪いのか不安になるからです。
以前に作った「1」を送ると「one」を返すボードを改造したものです。
構造は回路図を書くまでもなく、
mcu: 90S2313 8MHz Xtal(c=22pF*2)
sw: 1=PD4 2=PD5 3=PD6 (ソフトウエアプルアップ、on=L)
LED: 1=PB3(青) 2=PB2(黄) 3=PB1(赤) (Hで点灯)
です。
機能は、
19.2kbps PC側はTeraTerm使用。
sw1で ボードのLED1が点滅して、文字'12345'cr fl をPCへ送る。0.2sのディレイつき。 PCのrecieveテスト用。
sw2で PCから1,2,3を送るとそれぞれLED1、LED2。LED3が点灯。 PCのsendテスト用。
sw3で PCから1,2,3と送るとそれぞれ one two three を返す。 PCのsend,recieveテスト用。
というものです。