田舎の組み込みプログラマーがわざわざ趣味でも色々開発してみようとあがく様を綴るブログです。
DMM.makeのクリエイターズマーケットに出品しています。
ラジコン用のコーナーウエイトゲージを作ろう ― 2018年11月07日
またもや随分更新をサボってしまいました。
忙しかったと言えばそれまでですが、やはり具体的なビジョンがなければ頓挫しやすいということだと思います。
ということですので
ラジコン用のコーナーウエイトゲージを作ってみることにしました。
元々電子工作を始めようと思ったのはラジコン用の何かを作りたいというのが一番の理由で、コーナーウエイトゲージもずっと以前から作りたいと思っていた物です。
ぐずぐずしているうちに市販品が出てしまったわけですが、ロードセルとかロードセル用ADコンバータとかが簡単に手に入るようになったので、今更ながらやってみます。
で、これが試作品。
ロードセルは2kg、ADコンバータは定番のHX711、マイコンはいつものようにR8C/32Mです。
20MHzで不足とは・・・
HX711の使い方はあちこちで解説されていますが、マイコンからパルスを送ると同期してデータが出てくるという、クロック同期シリアルインターフェイス的なやつですね。
「的な」と言っているのはちょっと独自仕様が入っているからで、おかげでマイコンのシリアル通信機能が使えないわけですが、今回のように4つの物を使うとなるとクロック同期シリアルが4つも使えるマイコンなんて見当たらないので結局は自力でなんとかするしかないわけですね。
具体的には、転送クロックをタイマー機能で生成し、立ち下がりで割り込みをかけてシフトするわけですが、クロックパルスの幅は標準1μsecとかなり高速です。
この速度だと、1周期は2μsecですので20MHzだと40サイクルしかなく、この時間で4つ分のデータのシフトは無理そうというか実際無理でした。
ゆっくりしていってみる
標準はあくまでも標準ですので、ゆっくりやれば別に問題はないわけです。
が、一つ注意が必要なのはパルスがHIGHになっている時間が60μsecを超えるとHX711がパワーダウンモードに入ってしまうということです。
で、通常は50μsecまでにしろとのことですので、そこは守らないといけないわけですね。
ということで、実際の波形がこちら。
クロック周期を10μsec、HIGH時間を0.5μsecにしてみました。
具体的には、タイマRC機能でTRCIOAに出力、TRCGRAで10μsec周期を作りつつパルスの立ち下げと割り込み処理を、TRCGRCで9.5μsecの時点でパルスを立ち上げています。
どうやら10μsecもあればHX711の4個分のシフト処理は間に合うようです。
あとはメインループでHX711のデータ出力を監視し、4個全部の出力がLOWになったらタイマRCをスタート、タイマRCは1回分の入力処理が終わったら停止するように作り込んでいます。
といったところで、今回はこの辺で。
シリアル カンタービレ ― 2018年05月12日
とても昔からあって、今でも便利に使い続けられている技術。
それは俗にシリアルとかターミナルとか呼ばれているやつです。
以前少しだけarduinoをいじってみたんですが、標準でターミナルが実装されいて、コマンドを送ったりデータを表示させたりといったことが簡単にできるのが印象的でした。
そんなわけで
随分以前に写真だけ公開した基板をようやく動かす時が来ました。
実は通電するのも初めてだったりします。
そして、まずはシリアル送信を試してみます。
$LOOP
; タイミング処理
btstc SYSTEM_CYCLE ; 1msec毎にONされる
if C
DIVIDING$_ regular_10, 10 ; 10分周
PROC$_CALL$_B S0T$_PUT, 30h
PROC$_CALL$_B S0T$_PUT, 31h
PROC$_CALL$_B S0T$_PUT, 32h
_$
endif
$END
; シリアル送信処理
S0T$ 1
QUEUE$_B$_ALLOC send_queue, 20 ; 送信キュー確保
_ITP ; 送信終了割り込み(レジスタバンク切り替え)
QUEUE$_GET send_queue, R0L
if C
WRITE$_B R0L
endif
_PUT
if [ ti_u0c1 ] ; 送信バッファ空
WRITE$_B [PARAMETER].b
else ; 送信中
; 送信データをキューに入れる(満杯の場合は空くまで待つ)
QUEUE$_PUT$_WAIT send_queue, [PARAMETER].b
endif
_INIT
QUEUE$_INIT send_queue
_END
10msec周期で3バイトのデータを送り続けるだけの簡単なお仕事です。
簡単と言いつつ、送信バッファが空なら直に送信し、そうでなければキューに入れるという小技も使っています。
そして、キューにいれておけば、送信終了割り込みで勝手に持って行ってくれるという寸法です。
結果はこんな感じ。
狙い通り、10msec周期できっちり送信されていますね。
ちなみに、通信速度設定は9600bpsです。
気分のほうが乗ってきたので
受信もやってみます。
パソコンのターミナルソフトから送ってみて・・・・・・・・・・・・・・・・・・・・・・・・・・受信できません。
一応、受信割り込みは1回かかるのですが、2回目以降は反応なし。
よく見るとフレームエラーが出ていましたが、速度・ストップビット・パリティの設定は間違っていないし、何故?
で、信号をよく見てみると・・・
信号は問題無さそうですが、電圧が3V少々ですね。
実は、使っているUSB-シリアル変換モジュールの出力(マイコン側では入力)が3.3V系なんですが、入力は5V対応なので5V電源のマイコンともそのまま接続できるということだったので気にしていませんでした。
しかし、R8C/xMの5V電源時のH入力閾値には届かないようですね。
受信割り込みはかかったので、オーバーシュート分が微妙に届いている感じなんだと思います。
そこでレベル変換です。
変換ICを乗せる程のことでもないので、トランジスタを使いました。
改めて信号を確認してみると、ちゃんと5V付近まで上がっています。
ソフトの動作はこちらです。
これでようやく準備が整い、あとはパソコンからコマンドを送って・・・と行きたいのですが、字句解析とかやったことがないので、どうなりますやら。
いきなりつまづいてみたり ― 2016年11月24日
さて、システムを一から再構築すると決めた(ゼロからではないのが味噌です)ので、色々スッキリハッキリ分離させておこうと分析中です。
マイコン機能に極力依存しないシステムというのが王道なんでしょうけど、構造化アセンブラにどっぷり浸っている身としてはもうR8C以外に考えられませんので無理な相談というヤツだったりします。
とは言え
R8Cにも色々グループがあって周辺機能も様々なので、その辺は分離して簡単に使い分けられるようにするために当面使いそうな物をピックアップしてみました。
- R8C/3xM
- 会社で使っているのがこれなので、基本はこれになります。
20PINの32Mと、32PINの33Mを個人的に持っています。2029年1月までは生産してくれるとのことですが、本当でしょうね?ルネサスさん。 - R8C/M12A
- DIP20PINの使いやすいパッケージでお値段100円と超リーズナブルでありながら、20MHzの内蔵オシレータと2Kバイトのデータフラッシュも
ついているというスーパーなマイコンです。
ただ、E1エミュレータが使えないのでわざわざ旧型のE8aエミュレータを追加で買うハメに orz
プログラムメモリ2Kバイト、RAMは256バイトと一見制限は厳しいのですが、これを拡張する方法を公開してくれている方がいます。
しかし、この制限内でも十分電子工作を楽しめるようなシステムを目指そうと思っています。 - R8C/3xW
- 元々は80PINのR8C/38WとCANトランシーバーを搭載したボードを買ったのが最初でした。
続いて64PINの36W(48PINの34Wだったかもしれません)を載せたボード+CANトランシーバーボードを買いました。
当面CANの開発はこれで行こうと思いますが、移り気なもので・・・ - R8C/5xE
- 単品で購入可能なCAN内蔵R8Cを探していて見つけたのがこれです。
R8C/3系の周辺機能を踏襲しつつ動作周波数が高いのが魅力ですが、今のところそこまでの必要は感じていません。 - R8C/23
- 同じく単品購入可能なCAN内蔵R8Cです。
動作温度範囲の広いKバージョンが手に入るのが車載を考えると魅力ですが、他の使用部品の動作可能温度が低かったら意味がないので保留中です。
今のところこんな感じですが、まずは手元にある上3つを使えるようにするのが先決ですね。
もちろん、必要になれば下の2つにも対応できるような仕組みにしつつです。
都合のいいことに
R8Cの統合開発環境では、マイコンの品種を指定してプロジェクトを作成するとレジスタを網羅したインクルードファイルを作ってくれます。
今では当たり前の事なのかもしれませんが、その辺りも自作していた身としてはかなり感動物です。
というわけで、早速プロジェクトを一通り作ってみました。
一番上の"gestimotor"というのは先日ご紹介した基板に搭載した機能をPPAP的に並べたものです。
続いてCAN関連の比較です。
ピックアップした中ではCANがつかえる物が3つありますが、まずは38Wと56Eの割り込み部分から。
右側の56EはCAN割り込みが3つしかありませんが、38Wの方はこの先も続いています。
次は56Eと23の比較です。
これは明らかに別物ですね。
ということで3グループ共にCAN機能は別物だと分かりました。見比べてみると56Eが一番シンプルな感じで、もしかすると洗練されていて使いやすいのかも。
でも、まずは38WのCANを使えるようになるのが先決です。
ここまではグループが違えば周辺機能が違っていても仕方がないと納得できるのですが、驚いたのはこれ。
M12Aは割り込み関係の処理が全く違っているようです。
割り込み処理はコア機能だと漠然と考えていましたが、周辺機能から割り込みがかかるわけですからやはり周辺機能ということになるんでしょうね。
ここさえクリアできればちょっとした工作にどんどん使えそうなのですが・・・。
ということで
先はまだまだ長そうですが、地道にやっていこうと思います。
実践!ロータリーエンコーダ ― 2015年09月17日
このところ
ずっとロータリーエンコーダ関連の処理に取り組んでいて、先日ようやくR8Cのタイマ機能を使って取り込むところまで進みました。
今回はいよいよアプリケーションの中でどう使うかを追求します。
その前に
先日は入力のCRフィルターが効き過ぎていたのを放置していましたが、やはりそれでは勉強にならないと考えて調整してみました。
と言っても、コンデンサを0.1uFから0.033uFに変更しただけですが。
その結果がこちら。
昨日とほぼ同じ速さですが連続検出中もほぼ5Vまで戻っています。
わずか60msec足らずの間に15カウントした結果ですので十分だと思います。
そして、指先一つで速度自在なロータリーエンコーダはやはり便利なデバイスですね。
システム化
まず、R8Cの位相計数モードの設定はこんな風にしてみました。
;-----------------------------------
; タイマRG
;-----------------------------------
TRG$_MDF_MODE 00010001b ; 位相計数モード[ 加算/減算条件 ]
TRG$_START ; カウント開始
マクロの中身は公開できませんが、先日ご紹介した位相計数モードの使用準備がこれだけでできるようにしてあります。
そして、いきなりですがロータリーエンコーダの処理部分がこちら。
;-----------------------------------
; メモリ定義部
;-----------------------------------
DIFFERENCE$_ALLOC rotary
char_num: .blkb 1
;-----------------------------------
; 初期化部
;-----------------------------------
DIFFERENCE$_INIT rotary, [trg].w
[ char_num ] = 'A'
LCD$_POS 0, 0
LCD$_WRITE [char_num]
;-----------------------------------
; メインループ
;-----------------------------------
MAIN_LOOP$
DIFFERENCE$_EXEC$_ rotary, [trg].w
[ char_num ] = R0L + [ char_num ]
LCD$_POS 0, 0
LCD$_WRITE [char_num]
_$
_END
本当にいきなりですが、LCDに1文字表示していて、その文字をロータリーエンコーダで切り換えていると書けば何となくお分かりいただけるのではないでしょうか。
"DIFFERENCE"は変化分を抽出するオブジェクトで、今回新設しました。
"[trg].w"はタイマRGのカウント値が入っているレジスタで、これを直に指定するのは隠蔽が不十分な感じですが、位相計数モードのためだけにこの手の処理を作るのも特化しすぎな気もするのでこれでよしとしておきます。
"DIFFERENCE$_EXEC$_"〜"_$"はメインループの中にありますので最短周期で実行されていて、"[trg].w"が変化した時だけブロックの中まで入っていくようになっています。
この時、R0には変化分がワードサイズで入っていますが、ブロック中ではR0Lで下位バイトだけ使っています。
このフリーダムさもアセンブラの魅力ですね。
とまあ、こんな風に構造化アセンブラにどっぷり浸っていますので他のマイコンが使えなくて困っていたりもします。
ちなみに、上記のソースは構造化アセンブラを使って筆者がこう書いているだけで、構造化アセンブラ自体に"MAIN_LOOP$"とかがあるわけではありません。
割り込みを使わなかったわけ
色々考えてみましたが、R8CのタイマRGの割り込みは位相計数モードでは実質アウトプットコンペアだけで、1カウント毎に割り込みをかけたかったら現在のカウント値の+1と-1の値で割り込みがかかるようにその都度セットする必要があり現実的ではありません。
それに、ロータリーエンコーダの処理はカウント毎に実行しないといけないわけでもなく、例えば100msec周期でチェックしてその間に30カウント増えていたとしたら30カウント分増えた処理をしてやればいいだけです。
カウントはタイマRGがキッチリやってくれていますので、周期はもっと長くても平気です。
とは言え、さすがにそれでは操作に違和感があるでしょうから、実際は10msecくらいが妥当でしょうか。
オシロで見たところ、相当速く回しても10msecだと4カウントまでいかないくらいでしたし。
というわけで、やっとロータリーエンコーダを使いこなすことができたと思います。
位相計数モードで楽々カウント ― 2015年09月16日
あると便利
ロータリーエンコーダはとても優れた操作性を持つ一方、プログラミングは面倒臭そうです。
しかし、マイコンが「位相計数」という機能を持っていれば簡単に処理できる模様。
幸いR8Cにもこの機能がありますのでその恩恵に預かれます。
ただし、少ピンの品種ではこの機能が省かれていたりしますので、ロータリーエンコーダを使う場合はタイマRG機能のある物を選ぶといいでしょう。
楽々設定
位相計数機能を使うにはロータリーエンコーダの信号をTRGCLKA端子とTRGCLCB端子に入れてやる必要があります。
そして、タイマ端子選択レジスタ(timsr)のb6とb7をONにしてこれらの端子機能を有効にします。
タイマモードを位相計数モードにしただけでは端子機能は有効にならないので注意が必要です。また、端子機能の設定はタイマを動作させる前に済ませておきましょう。
次にカウントアップ/ダウンの条件を設定します。
タイマRGカウント制御レジスタ(trgcntc)の上位4bitがカウントアップ条件、下位4bitがカウントダウン条件となっていますが、単純なロータリーエンコーダの場合はそれぞれどれか1bitをONしておけばいいようです。
これらをうまく設定することでもっと複雑なエンコードをするエンコーダにも対応できるということだと思います(たぶん)。
あとはタイマRGモードレジスタ(trgmr)でタイマモードを「位相計数モード」にし、カウントを開始すればロータリーエンコーダの操作に呼応してタイマRGカウンタ(trg)の値をアップ/ダウンしてくれます。
かなりお手軽ですね。
ただし
これだけだと単純にカウンタのアップダウンをしてくれるだけで、割り込みをかけたいとかいう場合にはあれこれ設定が必要なようです。
その辺りのことはデータシートの位相計数モードの項には書かれていないのでちょっと面倒臭そう。
と言っても、タイマRGカウンタをポーリングするだけでも当面は大丈夫だと思いますのでその辺りの追求は後回しにするかもしれません。
あと、エンコーダからの入力パターンに対してカウントのアップダウン方向を変えることはできませんので、希望した方向と違う場合にはハード側で対応する必要があります。
接続を入れ替えてもいいのですが、入力の安定性を考えて反転付きのシュミットトリガやフリップフロップを入れる方がいいかもしれません。
ハードは堅実に
ハードは今絶賛学習中ということもあり、まずはロータリーエンコーダをマイコンに直結してみました。
あ、もちろんプルアップはしてあります。
オシロで見ると存外きれいな波形です。
巷のロータリーエンコーダの解説では分からなかったんですが、クリック感のあるタイプでは停止位置だと両方オープンになっているようですね。
これならそのままでもいけるかもと思ったんですが、マイコンのカウント値を確認すると操作感と全く一致せず・・・。
で、さらに波形の観察をしているとこんな状態になることも。
そこでウェブの情報を頼りにCRフィルタの値を決めてみました。
ロータリーエンコーダをゆっくり操作した時はきちんとカウントできたので喜んだのも束の間、が〜〜〜〜っと回すと全然だめでした。
オシロで見ると一目瞭然。
参考にしたのは押しボタンスイッチに対するフィルタですので、ロータリーエンコーダに使うには時定数が大きすぎました。
フィルタの要素をあれこれ試すのは面倒そうだったので、とりあえずプルアップ抵抗を替えてみた結果がこちら。
まだ効き過ぎてはいますが、取りこぼしはなかったので当面はこれで行こうと思います。
そう言えば、今使っているカーオーディオのヘッドユニットはロータリーエンコーダの取りこぼしが酷いんですが、こういうことなのかもしれないと思ってみたり。
これまではソフトの処理がまずいんじゃないかと考えていたんですけどね。
職場では何でもソフトのせいにされると嘆いていたんですが、自分でも同じ事をしていたとは・・・。
そんなばなな ― 2015年09月06日
CANのレジスタ関連処理をアセンブラでごりごりと書いていたんですが、アセンブルしてみると謎のエラーが・・・。
どうもCAN関連のレジスタに対してビット処理をするとエラーが出るようですが一見おかしいところはなく、アセンブラマニュアルを見てもビット定義のアドレスは0ffffhまでとなっていて問題なし。
そこでR8Cのソフトウェアマニュアルを見てみると、絶対ビット命令アドレッシングではベースアドレスは1fffhまでしか使えないという衝撃の記述が。
CANのレジスタは軒並みこの範囲を外れているので、どうしてもビットで処理したければアドレスレジスタかベースレジスタ相対でやるしかなさそうですが、こんな場合SB相対を使うのかFB相対を使うのかも分からなかったりしますので、まだまだ先は長そうです。
R8CのCANモジュールを読み解く(1) ― 2015年09月04日
記憶が追いつかない
マイコンのデータシートを読み解こうとしても読んだ端から忘れてしまってとても理解できません。
当たり前のようにビット名を列挙したりしていますが、一つの解説文に複数のレジスタのビットがあったりして理解よりも想起のように意識が向きがちです。
そんなわけで、R8CのCANモジュールについてもちょっとまとめてみました。
このメールボックスの構成がデータシートの書き方では頭に入らなかったんですが、これなら分かりやすいと思います。
怒濤のメッセージから必要なものだけキャッチ
CANバスには大量のメッセージが流れていて、これをアプリケーションの処理だけで抜き出すのは大変そうですが、幸いR8CのCANモジュールにはメッセージフィルタがあってソフトの負担を軽減してくれます。
が、やはりデータシートが難解で自分の頭の負担が大きかったので図示してみました。
R8C/3xWのCANモジュールには16個のメールボックスがあり、受信したいCANメッセージのIDをメールボックスにセットしておくとそのメッセージがバス上に流れた時に取り込んでくれるのが基本です。
しかし、それだけだと1つのメールボックスで1種類のメッセージしか取り込めませんので、範囲指定できるようにする仕組みがアクセプタンスフィルタです。
マスクレジスタに受信IDとメールボックスにセットしたIDとの一致させるビット/違っていてもかまわないビットの情報をセットすることで範囲指定ができるようになっています。
メールボックスが16個あるのに対してマスクレジスタが4つしかないので使い方がなかなか理解できませんでしたが、試しにOBDメッセージの受信について考えてみたら分かったような気がします。
といっても、R8CのCANモジュールのメッセージ選択方法は他にもあり、それはこれから勉強するところです。
最近のコメント