気ままに備忘録

電子工作・人力飛行機についてのメモ

海外出張についての駄文

この記事は
WMMC Advent Calendar 2022 - Adventar
の21日目の記事です.なんか数日更新止まっているようですが….まあそんなこともありますよね().自分も次の人より後に書いたことは黙っておきましょう().
 毎年Advent Calendarの時にしかブログを書いてないですね.ブログをまめに書くこと,そもそも進捗を出していないこと,最近は就活が忙しいことが原因ですが….まあ細かいことは置いておきましょう().
 というわけで本題に入りましょうか.今回はもはや技術系の話でもない駄文なので適当に読み飛ばしてください.

0. 本日のお題

 さて,この記事を読んでいるような方はおそらく理系の大学生当たりの方が多いのかなと思います(分析したことがないので適当).そのような方だと,多くの方はB3かB4で研究室に所属し,研究をすることになるかと思います.すると,時々「学会」に行って発表してこいとボスから指令が入ることがあります.国内ならいいのですが,国外に行くとさあ大変!いろいろ準備が増えます.自分も今年の夏に学会に参加してきて,だいぶ大変だったことを覚えています.そんな海外出張の準備についてのお話を,自分の体験談を交えながら雑にお話していきましょう.

1. Abstract, Draftの提出

 学会によって申し込みの手順や時期は異なり,出すものも変わります.私の場合だと,夏開催の学会でしたが,年あけごろにAbstractの提出締め切り,2月ごろにDraftの提出締め切りがありました.Abstractは論文の冒頭についている内容要約みたいなやつで,Draftは普通の論文みたく,10Pほど書きました.2月だったので卒論とかぶり,だいぶ大変でしたが….学会によってはAbstractが実質Draftで2Pだったり,AbstractなしでDraftのみだったりと,いろいろありますので自分で参加する学会については確認しましょう.
 ここでのポイントは「まず図のリストを作る」ことですかね.分野にもよりますが,僕の分野では大体10Pの論文だと5P分くらいは図で埋まります.本文も図の説明をする流れになるので,図を作りこむことが割と大切だったりします.最悪これができていれば文章は一気に書けるのでここに時間をかけましょう.
 あと英文校正はお金払ってやるのがいいのではないでしょうか.帰ってくる期間によって料金が変わるので,上司と相談の上,英文校正にかかる時間を逆算して締め切りを設定しましょう.あと会計処理を忘れないように.
 私の場合ですが,10PのDraftの本文は大体2週間弱で完成させた感じです.図のリストはほぼ出来上がっていたこと(多少修正は加えましたが),内容もほぼ出来上がっていたこと,過去に自分の研究班で書かれたDraftが多数残っており,実験装置や数値計算法など,内容が参考にしやすかったこともあるので,初めて書く英弱勢ではこれが最速ラインなのではないでしょうか(うぬぼれ).個人的にはもう少し余裕を持ちたかった記憶があります.この2週間の間に研究室内でOKをもらい,その後英文校正に出しました.英文校正もだいぶ赤入りましたが,致命的ではなかったので1日で直し,提出にこぎつけています.
 以上を考えると,Draft作成には英文校正込みで3~4週間は確保できるとそこそこ余裕を持てる気がします.また,学会発表を考えている方は,必ず使う図(実験装置とか)については平時から用意しておくとよいのではないでしょうか.慣れてくればもっと短くできるんでしょうけどね….慣れてなくても短期間でやる人は割といますが,だいたい死にかかっている印象があります().
 この後学会のほうでの内容確認(査読というほどでもないのか…?)があり,何点か修正事項を求められます.反映させるとともに,回答書を作成する必要があります.量が多い学会から少ない学会までまちまちですが,きたら速攻処理するのが吉です.大体期限短いので…(確か1,2週間だった気がする).

2. 動画撮影

 パンデミックのせいもあり,ここ数年オンライン学会が普及しました.だいぶ対面に戻ってきましたが,それでもオンライン学会の名残なのか,動画提出を求められることがしばしばあります.僕の場合もそのパターンで,事前動画提出をしました.これが割と大変だったのでコメントしておきます.
 まず,最初にやるべきことは「動画提出を求められていないか,逐次確認すること」です.後述しますが,英弱勢が他の業務と並走しながら準備をすると1か月あっても足りません.冷静に日本語発表でも,時間制限ありのちゃんとした発表を,1週間で準備から本番までやり切ることは,学生には大変ではないかと思います.間違っても期限前日に気づくことがないよう,毎日確認してください.僕の場合はある日突然連絡があり,1か月後が提出期限でした.すぐに気づいたのでそこそこ準備期間はありましたが結構大変でしたね….
 さて,実際の動画作成についてもコメントしましょう.とはいえこういうのはいい資料がたくさんネットにあるので,自分の経験から何点かコメント.例外はだいぶあります.
 スライド作成は,すでに図のリストがあると思うのでそこまで大きく時間はかからないはずです.Gif動画に差し替えるため作り直した部分もありましたが,とはいえ全体像をざっと作るのは大変ではないです.ただ,後述する理由で2点ほど注意しておいてください.「説明に使う大切な図はスライド下側に置くことは避ける」「Draftに使った図はすべて使おうとは思わない」これだけ注意してください.
 次に台本です.私としてはあまり作りたくないですが,初の英語学会で,時間制限があるのに台本無しはさすがに厳しかったです.話すペースとかはいろいろ調べたり自分でも測定したりして調整してください.ここで先ほどの「Draftに使った図はすべて使おうとは思わない」が絡みます.英語がペラペラな方は読み飛ばしてください.一般的な英弱勢だと,言いたいこと全部は言い切れないです.下手すると日本語で言えることの半分くらいしか言えません.なので,一般的なスライド目安枚数よりも少なめにスライドを作成し,話す内容も絞って,ほんとうに話のコアだけを話しましょう.それでも最初時間オーバーすると思います.
 最後に練習です.が,これが曲者….研究室生活でスライド作成などは割とやってきていると思うので,早い人はここまではさっくり終わってしまうと思います.しかし,実際にスライドを使って発表練習をすると,全然読み終わらなかったり,台本が覚えられなかったり,スライドにぼろが見つかったりします.動画撮影の場合だと台本読めますが,割と棒読みになりやすいので,後々のことも考え,ある程度は覚えたほうが便利です.しかも録音できるので自分の発音の下手さも耳につく….撮り直しの無限ループに入ります.対策としては,もう「余裕を持っておく」ことにつきます.練習時間を確保しましょう.個人的には台本修正込みで2週間練習しましたが,うまくならなかったです().練習方法としては,読み上げアプリを使用するといい感じに発音練習ができるので個人的にはおすすめです.
 動画撮影は様々な方法がありますが,スライドごとに撮り直しができる「Power Pointの録画機能」がおすすめです.ただ,自分が使いやすいものを使ってください.新しいソフトを勉強している時間があったら練習したほうがいいです.

3. 航空券手配,その他事務作業

 学会の日程が決まったら航空券の手配をしましょう.なんか僕の学会はサイレントで日程が変更されたことがあったので,会場ホテルが確定してからと,割と迫ってきてからとりましたが,近くなればなるほどお値段が上がり,便も限られます.なるべくはやくとりましょう
 安い方がいいのは大学からの補助などの関係があります.私の大学は補助が比較的手厚く,また事務の方の尽力により相当額を出していただけましたが,ちょうど円高に,どっかの独裁者のせいで燃料サーチャージが上がったりして,だいぶ予算面で苦労しました.学校によってはオーバーすると自腹になったり,研究費を削るのを嫌がって出張自体が流れたりします.もったいないので,できるだけ安いうちにとりましょう.
 事務関係は大学や行先によってかなり違うので割愛.帰ってきてからもあるので大変なんですが….ただ,コメントしておくと,「保険関連は確認を忘れずに」「飛行機を利用する際は航空券をなくさないように」ということですかね.
 航空券の取り方は価格もありますが,他には「ロストバッゲージをしない」というのもファクターに入れるといいのではないでしょうか.遅延などやむを得ない理由でロストバッゲージは発生しますが,なぜか発生率の高いエアライン,あるいは経由空港というものが存在します.慣れている方は別として,初海外出張でこれはパニックになります.できるだけ避けるためにも,「可能な限り直行便を選択」「ない場合は日系はじめ,サービスのよいエアラインを選ぶ」をお勧めしたいですね.何より,乗り継ぎ時間には余裕を(やはり2時間~2時間30分あると安心…かなあ…).
なんでこんな話をするかって?次読むとわかります().

4. 荷物

 そろそろ直前の話をしましょう.ここで一番重要なことは「大切なものは絶対に預入にしないこと」です.飛行機の乗換がある場合,「ロストバッゲージ」という脅威があります.私は帰りの飛行機でやられました.帰りだった上,翌々日には届いたのでよかったのですが,それでもPCの充電ケーブルや洋服など地味になくて困るものが出ました.(なんとなく嫌な予感がして普段着用のベルトだけ手荷物に入れておいたから帰ってきた後普段着が普通にきれたっていうのは別の話).これが,もし大体の荷物を預入,適当にTシャツ短パンで飛行機に乗って,ロストバッゲージをすると…?あまり想像したくないことになると思います.なので,最低限以下の点には気を付けましょう.

  • 服装はスーツ,あるいはビジネスカジュアルなど,そのまま発表して恥ずかしくない格好で飛行機に乗る
  • PCの他,USBメモリクラウドサービスなどに発表資料を置く.すべて機内持ち込みに.

 あとは機内での暇つぶしの一環で,印刷した発表資料を持ち込んで練習できるようにするといいかもしれません.

5. 現地情報収集

 調べるべきことは多岐にわたります.空港からホテル,会場までのアクセス,会場から推測される部屋のサイズなど….ただ,今一番調べるべきは,検疫関連でしょう.最近はだいぶ制限がゆるくなりましたが,パンデミックのせいで入国がめんどい国は割とまだありそうですね.また,制限がないように見えても,入ってから抽選で検査しろとか言われたりする可能性もあります.可能性レベルまで入国についても情報を集めましょう.これは国や時期によって違うので,私の場合の体験談を.

  • 事前に入国目的やワクチンの接種証明等を渡航先の国公式アプリで登録,登録料も支払う(これをやらないと飛行機にすら乗れない)
  • 入国直後に無作為抽出検査に引っかかる→学会の合間を縫って検査に
  • 日本に帰るための検疫アプリに登録,帰国用検査を受ける(自費)→アプリに障害が起きたため時間をおいて登録

 だいたいおきた出来事はこんな感じですが,事前調査をしておくと楽だったなあ,というのが感想です.1点目は問題なかったのですが,2点目では検査できる場所がわからなくて空港での乗り継ぎ時間に慌てて調べたのを覚えています.事前に調べられもしたんですがね….3点目も直前になって検査を受けたのでだいぶ焦りました.時間には余裕をお持ちください.
 あと,学会の合間に観光をしたいときも多少は調べとくと現地での時間を有効に使えますね.ガイドブックとか適当に買って,飛行機内で見ておくといいのではないでしょうか.
 少しだけ振れた会場の部屋サイズに関連して,当日の発表の注意ポイントも軽く触れておきます.ここについてはほかに有力な情報はググればいくらでも出てくるので,自分の最大の反省点から.
 先述しましたが,「スライドの下のほうには重要な図を入れないほうがいい」ということがあります.大きい会場なら特に問題ないんですが,小さい会場だと,スクリーンの位置が低いことがしばしばあります.この時,下のほうに重要な情報を含む図があっても,見えないので理解してもらえないです.図の下側には,カラーバーや図の注釈など,見えなくても何とかなる情報に抑えたほうがいいです.この点,リモートのほうがそういう配慮が必要なくて楽でしたね….
 もう一点は「スライド記載の説明や注釈は細かく丁寧に」ということです.特に自分はややマイナー分野だったので,背景説明にだいぶ時間を割かないとわかってもらいにくい,ということは強く感じました.また,スライドに注が多く,背景から丁寧に説明をしておくと,聞き手がわかりやすく感じてくれます.自分が聞いていても,英語が聞き取れなくてわからん!というときに,注がおおいスライドは,スライドを見るだけで理解できるのでだいぶ楽でした.このあたりも配慮できるといいかもしれません.

6. まとめ

 内容のない駄文でしたがいかがでしょうか.今回の内容をまとめると

  • Draft執筆,動画作成ともに時間がかかるので,初めての方は1か月程度の余裕を持ったスケジュールを.
  • 航空券はできるだけお早めに.事務処理もしっかりやりましょう.
  • ロストバッゲージを想定した荷物づくりを
  • パンデミックは終わっていないので情報収集はしっかりと

といった感じですね.正直一番効率的な学費回収方法()ですし,他の人の話を聞くのは勉強にもなるので一度海外発表をやってみてもよいのではないでしょうか.行かれる方のご参考になればと思います.
明日(すでに出てますが)の記事は,たなぽーと君の
自己紹介&自作クラシックマウス迷路について - たなぽーとの気まぐれブログ
です.…?迷路作ってる?すごいなあ….ぜひお読みください.

Excelでシリアルモニタ

この記事は
WMMC Advent Calendar 2020 - Adventar
の3日目の記事です.きのうはしまじゃきさんによる
【WMMC ADC 2020】コロナ禍でハマったこと
でした.マイコン原理主義者だけでない,しまじゃきさんの素顔がうかがえる記事でしたね.半年以上お会いしていませんが平常運転で安心しました.しかし私はWMMCではジャッジーsophiaさんほど変人ではないと思うし,むしろ常識人だと思うのですが….なぜでしょう.

 さて,またまた投稿間隔があいてしまいました.どうも私にはこのブログというものは向いていないらしいです.というかほんとに何もしてなかっただけなんですけどね(-_-;).
 言い訳がてら近況報告をすると,4月に更新した後,ぼちぼち夏休みはHPA(人力飛行機)の電装をArduino系列からSTM32系への移行を目指した開発(というかお遊び)やってたり,マウス設計したりしてました.が,どれもこれもあまり進まず….もっぱら一番進んだのがミシンとか言うよくわからないことしてました.その後秋学期では研究室の見学とレポートに振り回され,今日に至ったわけです.いやあ,驚くほどの堕落っぷり….Perfumeやら某艦隊娘ゲームにハマったりしたのもあり,最近は全然ダメです().

 言い訳はこの辺までにして,本題に入りましょう.今回はここまでの記事(実質2本しかないですが)とはちょっと違うお話をしたいと思います.

0.本日のテーマ

 この記事を読んでいる人はいつも何かしらのマイコンを使っていると思います.そして,マイコンを使うときには,だいたいセンサを使って何かを測定していると思います(例外はあると思いますが).その時,「データのログがとりたい!」っていうことがないでしょうか.ところが,ちゃんとデータのログをとるのって結構大変で,シリアルモニタに出力させたはいいけどその場では何言っているかわからなかったり,それが嫌だからちゃんとしたものを作ろうとすると新たにツールを入れなきゃいけなかったりします.マウサーの方だったらそのままコマンドラインやシリアルモニタに出力させていたり,MATLABつかったりしているかもしれません.が,初心者には割と難易度高かったり,あるいは結果を整理して制御の補正係数を…なんてやろうとするときにはコマンドラインは不便だったりします.あるいは,それだけで計測機器として使いたいとき,特にほかの人(しかも素人)が見るときなんかには,もっと見やすくないときついこともあります.そうするとUI作る必要が出てきて…沼にハマるわけです.
 こんな悩みをなくしてくれる機能が実はExcelにはついています.最近実装されて,一時期Twitterでも話題になりました.今回はこれを使ってみようというのが主題になります.

1. Microsoft Data Streamer for Excelとは

今回使うのは「Microsoft Data Streamer for Excel」というアドオンです.このアドオンを使うことで,USARTで送られてくるデータの記録や確認,さらにはUSARTで信号を送ることができるようになります.いわば,Arduino IDEにおけるシリアルモニタと同じことができるわけです.ここまでは例えばArduino使いの方にはあんまり利点がないかもしれないですが,すごいのはここから先.「すでにデータがエクセルに入っている」ということです.つまり,グラフだったり,演算だったり,エクセル上でできる機能がリアルタイムにできるのです.リアルタイムでデータを監視しながらログをとりたい!っていうときにとてもおすすめです.最もマイクロマウスの界隈ではあまり需要がないかもしれませんが….
 欠点としては基本的にカンマ区切りのデータしか扱えないことがあります.これは基本的にマイコンしか扱えないことを意味しています.無線機器(Xbeeなど)から直接データを受信する場合については,基本的に想定していないようです.ただ今回検証はしていませんが,データの中にカンマを入れて送れば問題はないと考えられます(送信可能データは減ってしまいますが…).もう一つ致命的な欠点は「Windowsしか使えない」ことです.Macでは使えない(らしい,確認はできていません)ので,MacユーザーにはWindowsを買えということなのでしょうか.
 それでは実際に使ってみましょう.参考にしたのはMicrosoftの公式ページです.ここをいろいろ探しているとArduinoのサンプルコードやらサンプルのエクセルシートやら出てきます.あれ?このページいらなくね?

2.Excelの準備

 まず,Excelにアドオンを入れます.シートを開き,ファイル>オプションを選択,「Excelのオプション」ウインドウを立ち上げます.左の列から「アドイン」を選択.そこからMicrosoft Data Streamer for Excelを選択し,アクティベートします.すると,シートのタブの列にData Streamerというタブが増えます.詳しくは公式のページ->
Data Streamer アドインを有効にする - Excel
やっぱりこの記事いらない気がしてきた().

3.マイコンの準備

 Arduino使ってもいいのですが,せっかくなのでSTM32を使いましょう.今回はSTM32F303K8 Nucleoを使います.開発環境はSTM32 CubeIDEです.センサ使ってデータを実際にとろうとしたのですが,たまたま手元にデータを気軽にとれるセンサがなかったので,今回は単純にデータを送るところだけやります.
 まずはcubeMXの設定から,新しいプロジェクトを起動します.Target Project TypeはSTM32Cubeで設定します.意図的に忘れた方はこのページを閉じてマイコンとの対話を優先されることをお勧めします.画面がDevice configuration Toolになったら,左側のペリフェラルが一覧になっているリストの中から,Connectivity->USART2を選択します.すると,USART2 Mode and Configurationという画面が,リストの横に出てきます.上の段のModeの中から,Asynchronousを選択します.そのほかの設定は何もいじる必要はないですが,Configuration>Parameter Setting>Basic Parametersの数字はよく覚えておいて下さい.主にBaud RateとWord Lengthですね.今回はそれぞれ38400Bits/s, 8bitとなっています.設定が終わると,図3.1のようになるはずです.ただ,図3.1ではADC等ほかのペリフェラルも動いているので,そこは無視してください.右上のVCP_RXと左下のVCP_TXが緑ならOKです.設定ができたらProject>Geterate Codeとします.このあたり,詳しくは前回の記事を参照ください.

f:id:tomo_amber:20201213020345p:plain
図3.1 CubeMXの設定

 続いてコードを書きます.シリアル通信をprintfでできるようにしたかったので,そんなコードを書きました.書き足した部分だけ書きます.複数データを送るときには,カンマ区切りで送信し,最後のデータの後に\nを追加します.CSVと同じですね.

printfを使えるようにする部分

USER CODE BEGIN 0の後
int __io_putchar(int c) {
  if( c == '\n' ) {
    int _c = '\r';
    HAL_UART_Transmit(&huart2, &_c, 1, 1);
  }
  HAL_UART_Transmit(&huart2, &c, 1, 1);
  return 0;
}
USER CODE BEGIN 2の後
  setbuf(stdout, NULL);

データ送信部分

USER CODE BEGIN 2の後
  int i = 0;		        //送信データ1
  int j = 100;		//送信データ2
USER CODE BEGIN WHILEの後
  printf("%d, %d\n", i, j);//データ送信
  i++;
  j--;
  HAL_Delay(50);

4. 実行してみた

 実行してみます.マイコンをPCと接続し,書き込みをします.エクセルのData Streamerタブを選択,一番左のデバイスの接続を選択します.すると接続したマイコンが候補として表示されるので,これを選択します.これで接続が成立します.うまくいくと「入力データ」「出力データ」「設定」のシートが新たに発生します(図4.1参照).この時点では,まだデータの受信は開始しません.

f:id:tomo_amber:20201213023939p:plain
図4.1 通信が成功した様子

 次に通信の設定を変更します.「詳細」を選択し,詳細ウインドウ(図4.2)を開きます.設定を選択します.ここでUIについていじれますがここでは省略.重要なのはその下のCOMポートです.データビット,ボーレートを先ほど設定したように,8bit, 28400bpsに設定します.これを忘れるとほかのシリアルモニタ同様データが読めません.Excelでは読めないデータは表示されないので,何が死んでいるかわからないのでお気を付けください.適用を押して,OKで終了.そうしたら「データの開始」を選択すると受信・記録が始まります.データはこれで受信が開始でき,すると自動的に図4.1のようにデータが受信できます.「設定」シートからいろいろいじれます.詳しくは下表4.1参照.

f:id:tomo_amber:20201213024241p:plain
図4.2 詳細設定


表4.1 設定シートで変更できる定数

項目 用途 値の範囲
データの間隔 Excelの更新間隔を変更.これに関わらず受信はすべて行われる. 10~1000ms
データ行 表示される過去のデータの行数を変更.ここにある分だけタイムスタンプ込みで保存できる 1~500行
データチャンネル 受信するデータの種類. 1~100
データの並び順 過去のデータ並びを古いものを先頭にするか,新しいものを先頭にするかを選択 古い順or新しい

 「データの記録」を選択すると,押した時点から記録の終了を押すまでデータが保存され,のちにCSVファイルとして保存されます.CSVファイルに保存するとタイムスタンプは省略されてしまいます.したがって,データを時間と合わせて保存したい場合には,保存したい時間分だけ表示データ行数を増やしておく必要があります.しかし時間も含めて記録できるのは500行まで….10Hzの計測機器だと50秒しか持ちません.HPAの電装に使用する場合,TFでも運用はぎりぎりです.このため,長時間にわたり時刻も合わせて記録する場合,GPSモジュール等から得られる時刻情報も併せて送信する必要があります.あるいは,VBAを利用してデータを蓄積保存するようなシステムを用意する必要がありそうです.ここが少し欠点ですね.ある程度の時刻は周波数から逆算できますから,ザックリでいいというときによいのではないでしょうか

f:id:tomo_amber:20201213024905p:plain
図4.3 CSVファイルを出力するとき

5. 終わりに~これは使えるのか~

 工夫しないと限られた時間の間しかタイムスタンプを含めたデータロガーとしては使えない欠点はありますが,「データロガーのために今更時間をかけていられない!」という人には適しているかもしれません.また,保存は二の次として,多数のデータの様子をリアルタイムで観測したい!という人にもおすすめです.時間をそれほど気にしなければ,CSVファイルを直接得ることができ,記録したデータからグラフ化まで持ち込むことができます.今回は試していませんが,ここからマイコンにデータを送ることもでき,運用の幅が広がりますね.
 計測機器を作ったはいいけど,表示まで気にしていなかった….しかももう実戦投入まで時間がない…どうしよう…?って時がありましたらぜひともお使いください.

…ちょっとほかのものと比較してみますか?表にできるほどいろんなものを使ったわけではないのですが….
 実はここに書いた機能,ほとんどProcessingで再現可能です().グラフ化はProcessingの十八番ですし,csv出力機能も付いています.さらに言うと,ProcessingとArduinoとの連携は本にもなるほど有名で,この機能を流用すると今回と同じことがSTM32でも容易にできてしまうと思われます(未実証ですが…自明でしょう).
 さらにMATLABも同様の機能を持っています.アドインを入れることなく,標準機能からデータ列を読み込むことができ,これを整理・グラフ化・保存する機能はもともとMATLABも持っています.
 これらに対して優位な面は,はっきり言ってほとんどないかと考えられます.唯一あるのは,「MATLAB/Processingなどは使うまでに勉強が必要だが,Excelはそれが不要」というところでしょうか.ですので,他のツールを十分使いこなせているという人は,あまり必要性は高くないと思われます.ただ,Excel VBAを使いこなせる人にとっては,タイムスタンプまで一括で保存できる(と思われる)ので,こちらのほうが便利かもしれません.また,こういったツールを勉強して実装する余裕がなくなってしまったときには,助け舟になると思います.機能面での差は大したことはないので,冒頭にも書いたように,PCのスペック上の制約で,あまりいろいろなソフトを入れたくないという場合には筆頭候補となりうるでしょう.そういえばマイクロマウスではMATLABが誰でも利用可能…ということは…

 さて,最後に不穏な流れになってまいりましたが,私の担当分はここまでとします.期限ぎりぎりの中適当に書いたので短いうえに読みづらく挙句内容も…と思いますがご容赦ください.
 明日のWMMC Advent Calendar 2020 - Adventarはジャッジー君二本目の記事です.前回登板ではUSBについて書いてくれましたが今回はどんな記事になるのでしょう.大変楽しみです.

<訂正>

明日の担当はジャッジーではなく,yoka様でした.偉大なる同志ジャッジーのあまりのインパクトの大きさとと私の不注意のために誤りをしてしまいました.お詫びして訂正いたします.

STM32で外付けADC ADS1015をうごかしてみた

  久しぶりの更新です.本当は鳥人間が終わったあと,夏くらいから更新再開しようかな(というかそれくらいに更新できる進捗出せるかな)と思っていたのですが,コロナのおかげで鳥コンが消し飛び,しかも自宅待機で時間ができてしまったので,進捗を出してみました.まあ,鳥コンなくなったのは残念なのですが,逆にこれを利用して一つチームの電装の技術レベルを上げられたらなあと思います.今回はその一環としての記事です.ついでに自分がマイクロマウスを作るときの練習としてもやっています.

  今回のテーマは「STM32でI2C通信をしてみる」です.マイクロマウスはともかく,鳥人間ではセンサーにI2C通信が採用されているものが多く,またそこそこの距離の有線通信が可能という特徴から,鳥電装界隈では基本の通信方式だと思います.今回はそれをADS1015というADCで使用して見ました.ADCも鳥人間ではしょっちゅう使う道具ですね.長いケーブルにアナログ信号流すのはさすがにまずいですから.ということでやっていきましょう.

0.IDEについて

  更新をしていなかった間にIDEが変わるという大事件がおきました.これまではSystemWorkbenchForSTM32(SW4STM32)を使っていましたが,これは現在新規導入非推奨になっています.変わって,現在公式が推しているIDEはSTM32CubeIDEというIDEです.これは初期化コード自動生成ツールのCubeMXと,もう一つの公式IDEであるTrueStudioとを統合したものになっています.使用する感覚はCubeMXとSW4STM32を使っていたころとほとんど変わらず,ソフトの重さや不具合も少なくなったように感じます(最もSW4STM32でトラブルが頻発したのは私の固有の問題な気はしますが…).特に絶対にこれは残そう!というコードもなかったので,今後はこちらで開発を行っていきます.導入や具体的な使用方法はググればいくらでも出てきますし,「STM32を始める本~CubeIDE対応版~」(ゆーくりっど著,技術書展7にて配布)にわかりやすくまとまっています.Boothにて販売されているようです.細かい使用方法についても多少は説明を挟みます.

 

1.準備するもの

  今回使用したものは以下のようになっています.

電子部品
開発環境
  • IDE:STM32CubeIDE 1.3.0

  電子部品はすべて秋月電子通商にて調達しました.ADCはADS1015を使用します.表面実装部品ですが,秋月電子にはDIP化キットのみが販売されています.Texas Instruments製で,シリーズのADCがたくさんあります.分解能や変換できるチャンネル数,PGA機能の有無や通信方式などの違いがあります.レジスタマップがよく似ているので,それらを使用する際にも参考になると思います.ADS1015は分解能が12bit,サンプリングレートが3300SPSのもので,4chの変換が可能です.PGA(平たく言うと読み取れる電圧範囲を変える機能)も搭載しています.I2C通信で操作できます.もっとも,使用するのは1chだけなのですが….一番手軽に手に入ったのでしょうがないですね.

  最後に適当な可変抵抗を用意します.私はジョイスティックを使いましたが,これは何でもいいです.動作確認ができれば問題なし!です.

2.配線

  配線の対応は表2.1のようになります.特に何も考えることはありません.今回使用したのは秋月で売っているADS1015のDIPモジュールなので,1kΩのプルアップ抵抗が最初からついています.販売時は接続されていませんが,はんだ付けをしてプルアップすることができます.今回はこれを利用しているので,I2C通信に必須なプルアップ抵抗を省略しています.

  なお,図2.1ではADS1015のADR(4)に+3V3を入力しています.これによってADS1015のI2Cアドレスを0x49に変えています.そのほかのアドレスにしたい場合は,表2.1にあるように,GNDやSDA,SCLを入力してください.

          表2.1 配線の対応

Nucleo-F303K8 ADS1015
PB7(D4) 4(SDA)
PB6(D5) 3(SCL)
+3V3 1(VIN)
GND 2(GND)
GND(0x48)/+3V3(0x49)/PB7(0x4a)/PB6(0x4b) ADR

3.プログラム作成

  本題中の本題です.英語のブログも探しましたが,ADS1015を使っている記事は確認できませんでした.ただ,似た製品のADS1115を使用している記事はありました.ADS1115はADS1015とは違い,分解能を16bitにした代わりにサンプリングレートを860SPSまで落としている製品で,レジスタマップはそっくりです.また,ADS1015を使用するArduinoライブラリも存在します.今回はこれらを参考にしてコードを作成しました.

  参考文献はこちら

ADS1115 with STM32 CubeMx - Thecodeprogram https://thecodeprogram.com/ads1115-with-stm32-cubemx

adafruit/Adafruit_ADS1X15-GitHub https://github.com/adafruit/Adafruit_ADS1X15

3.1.初期設定

  まずはcubeMXの設定(GUI)から.新しいプロジェクトを用意します.このときTargeted Project TypeをSTM32Cubeで設定することを忘れないように.意図的に忘れた人はブラウザバックをお勧めします.画面がDevice configuration Toolになったら,左側のペリフェラルが一覧になっているリストの中から,Connectivity->I2C1を選択します.すると,I2C1 Mode and Configurationという画面が,リストの横に出てきます.上の段のModeの中から,I2Cを選択します.下側のI2CのConfigurationですが,ひとまずデフォルトの設定のままで大丈夫です.一応,設定一覧(表3.1)を書いておきます.
  このうち,人によって変えることがあるのはI2C Speed Modeくらいでしょうか.基本的にはStandard(100kbps)を使うと思いますが,ほかにFast Mode(400kbps),Fast Mode Plus(1Mbps)がF303K8では選択できます.コアを変えれば,さらにHigh Speed Mode(3.4Mbps)も選択できます.ADS1015はStandardとFast Modeはそのまま使え,High Speed Modeは最初にactivateすれば利用できます.今回使用するF303K8ではFast Modeまで使え,特に仕様変更は必要ないことがわかります.High Speed Modeが使いたい人はそこはデータシートから頑張って作ってください.

               表3.1 I2C1設定

Timing configuration Slave Features
I2C Speed Mode Standard Mode Clock No Strech Mode Disabled
I2C Speed Frezuency(kHz) 100 General Call Address Detection Disabled
Rise Time(ns9) 0 Primary Address length selection 7-bit
Fall Time(ns) 0 Dual Address Acknowledged Disnabled
Coefficient of Digital Filter 0 Primary slave address 0
Analog Filter Enabled    
Timing 0x2000090E

  設定ができれば,図3.1のようにPB7とPB6が緑色になります.PB7がI2C1-SDA,PB6がI2C1-SCLとなります.今回はADCしか使わないので他のペリフェラルはすべて起動しませんが,ほかの素子と併用する際は,この2つのピン以外のピンを使ってください.

f:id:tomo_amber:20200427195031j:plain
図3.1 I2C1の設定
  …実はここに落とし穴があります.実は,PB7,PB6以外にもI2C1を使う際に使ってはいけないピンが存在します.私と同じ,Nucleo-F303K8ボードを買ったままの状態で使う際,PA11とPB5に設定を入れてはいけません.「STM32 Nucleo-32 boards User manual」によると,工場出荷の状態ではPA5とPB7が,PA6とPB6とがはんだブリッジ

で接続されているためです.搭載されているSTM32F303K8T6のI2CはPB6,7に設定されているのですが,Arduino Nanoと互換性を持たせるため,こんな配線をしたのだと思われますが….とんでもなく使いづらくしてくれました.これによりPA5,6を使用するSPI通信はcubeIDEでは不可能になります(Arduinoとして使う分には,使うピンが違うらしく問題なさそうです).これは面倒な制約だ….一応,解決策もあります.ここのはんだジャンパーを切断してしまえばいいのです.ユーザーマニュアル添付の回路図を見ると,対応するのはSB16,SB18という二つのジャンパー.これは裏面についている,2つの0Ω抵抗のことです(図3.2内の赤枠).こいつを外せば,SPI通信も同時にできるようになるはずです(実証はしていません).当初,私はここにLEDを付けるためGPIOを設定していて,これが原因でI2C通信が正常に動かず,1週間近くとかしました.マイコンを触るときには,必ずデータシートを読みましょう….あと,これを疑ったのはSTの英語版FAQに記載があったためです.同じようなトラブルは必ず発生しているので,海外のFAQ等も確認したほうがよいでしょう.

f:id:tomo_amber:20200427195330j:plain
図3.2 Nucleo-F303K8の裏面
  設定できたらCode Generateをしましょう.今回は分割コンパイルもやってみたかったので,Project Manager->Code Generator->Generated files->General peripheral initialization as a pair of '.c/.h' files per peripheralにチェックを入れました.これで分割コンパイルもできるようになります.

3.2.ADCを動かす関数

  Code Generateすると,プロジェクトの中のCodeの中にある,IncとSrcにたくさんの.c/.hファイルが入っています.これらのファイルには設定したペリフェラルに関する初期設定がすべて書き込まれており,すでにincludeまで書いてあります.今回はmain.cをのぞいてコードを書き足すことはありません.その代わりに,ADCの機能を設定するファイルを追加したいと思います.Srcの中に"myadc.c",Incの中に"myadc.h"を作成してください.Src/Incを右クリックして,New->sourse file/header fileを選択すると作成できます.細かい文法は,C言語の書き方そのままなので説明は省略.ほかのヘッダファイルを参考にしつつ書きました.

  というわけで,myadc.hとmyadc.cの中身はこちら.

myadc.h

#ifndef INC_MYADC_H_
#define INC_MYADC_H_

#include "main.h"
#include "i2c.h"

typedef struct{
	uint8_t m_i2caddress;
	uint8_t m_conversionDelay;
	uint8_t m_bitShift;
	uint16_t m_gain;
}MYADC;

#define ADC_ZER 0x48 // ADR should be GND
#define ADC_ONE 0x49 // ADR should be VDD
#define ADC_TWO 0x4a // ADC should be SDA
#define ADC_THR 0x4b // ADC should be SCL

//conversion delay
#define ADC_CONVERSIONDELAY 20

//pointer register
#define ADC_REG_P_MASK 0x03 //point mask
#define ADC_REG_P_CONVERT 0x00 //conversion
#define ADC_REG_P_CONFIG 0x01 //configuration
#define ADC_REG_P_LOWTHRESH 0x02 //low threshold
#define ADC_REG_P_HITHRESH 0x03 // high threshold

//config register
#define ADC_REG_CONFIG_OS_MASK (0x8000) ///< OS Mask
#define ADC_REG_CONFIG_OS_SINGLE (0x8000) ///< Write: Set to start a single-conversion
#define ADC_REG_CONFIG_OS_BUSY (0x0000) ///< Read: Bit = 0 when conversion is in progress
#define ADC_REG_CONFIG_OS_NOTBUSY (0x8000) ///< Read: Bit = 1 when device is not performing a conversion

#define ADC_REG_CONFIG_MUX_MASK (0x7000) ///< Mux Mask
#define ADC_REG_CONFIG_MUX_DIFF_0_1 (0x0000) ///< Differential P = AIN0, N = AIN1 (default)
#define ADC_REG_CONFIG_MUX_DIFF_0_3 (0x1000) ///< Differential P = AIN0, N = AIN3
#define ADC_REG_CONFIG_MUX_DIFF_1_3 (0x2000) ///< Differential P = AIN1, N = AIN3
#define ADC_REG_CONFIG_MUX_DIFF_2_3 (0x3000) ///< Differential P = AIN2, N = AIN3
#define ADC_REG_CONFIG_MUX_SINGLE_0 (0x4000) ///< Single-ended AIN0
#define ADC_REG_CONFIG_MUX_SINGLE_1 (0x5000) ///< Single-ended AIN1
#define ADC_REG_CONFIG_MUX_SINGLE_2 (0x6000) ///< Single-ended AIN2
#define ADC_REG_CONFIG_MUX_SINGLE_3 (0x7000) ///< Single-ended AIN3

#define ADC_REG_CONFIG_PGA_MASK (0x0E00)   ///< PGA Mask
#define ADC_REG_CONFIG_PGA_6_144V (0x0000) ///< +/-6.144V range = Gain 2/3
#define ADC_REG_CONFIG_PGA_4_096V (0x0200) ///< +/-4.096V range = Gain 1
#define ADC_REG_CONFIG_PGA_2_048V (0x0400) ///< +/-2.048V range = Gain 2 (default)
#define ADC_REG_CONFIG_PGA_1_024V (0x0600) ///< +/-1.024V range = Gain 4
#define ADC_REG_CONFIG_PGA_0_512V (0x0800) ///< +/-0.512V range = Gain 8
#define ADC_REG_CONFIG_PGA_0_256V (0x0A00) ///< +/-0.256V range = Gain 16

#define ADC_REG_CONFIG_MODE_MASK (0x0100)   ///< Mode Mask
#define ADC_REG_CONFIG_MODE_CONTIN (0x0000) ///< Continuous conversion mode
#define ADC_REG_CONFIG_MODE_SINGLE (0x0100) ///< Power-down single-shot mode (default)

#define ADC_REG_CONFIG_DR_MASK (0x00E0)   ///< Data Rate Mask
#define ADC_REG_CONFIG_DR_128SPS (0x0000) ///< 128 samples per second
#define ADC_REG_CONFIG_DR_250SPS (0x0020) ///< 250 samples per second
#define ADC_REG_CONFIG_DR_490SPS (0x0040) ///< 490 samples per second
#define ADC_REG_CONFIG_DR_920SPS (0x0060) ///< 920 samples per second
#define ADC_REG_CONFIG_DR_1600SPS (0x0080) ///< 1600 samples per second (default)
#define ADC_REG_CONFIG_DR_2400SPS (0x00A0) ///< 2400 samples per second
#define ADC_REG_CONFIG_DR_3300SPS (0x00C0) ///< 3300 samples per second

#define ADC_REG_CONFIG_CMODE_MASK (0x0010) ///< CMode Mask
#define ADC_REG_CONFIG_CMODE_TRAD (0x0000) ///< Traditional comparator with hysteresis (default)
#define ADC_REG_CONFIG_CMODE_WINDOW (0x0010) ///< Window comparator

#define ADC_REG_CONFIG_CPOL_MASK (0x0008) ///< CPol Mask
#define ADC_REG_CONFIG_CPOL_ACTVLOW (0x0000) ///< ALERT/RDY pin is low when active (default)
#define ADC_REG_CONFIG_CPOL_ACTVHI (0x0008) ///< ALERT/RDY pin is high when active

#define ADC_REG_CONFIG_CLAT_MASK (0x0004) ///< Determines if ALERT/RDY pin latches once asserted
#define ADC_REG_CONFIG_CLAT_NONLAT (0x0000) ///< Non-latching comparator (default)
#define ADC_REG_CONFIG_CLAT_LATCH (0x0004) ///< Latching comparator

#define ADC_REG_CONFIG_CQUE_MASK (0x0003) ///< CQue Mask
#define ADC_REG_CONFIG_CQUE_1CONV (0x0000) ///< Assert ALERT/RDY after one conversions
#define ADC_REG_CONFIG_CQUE_2CONV (0x0001) ///< Assert ALERT/RDY after two conversions
#define ADC_REG_CONFIG_CQUE_4CONV (0x0002) ///< Assert ALERT/RDY after four conversions
#define ADC_REG_CONFIG_CQUE_NONE (0x0003) ///< Disable the comparator and put ALERT/RDY in high state (default)

#define ADC_REG_BITSHIFT 4

MYADC AdcInit(uint8_t, uint8_t, uint8_t, uint16_t);
void AdcSetContinuous(MYADC, uint8_t);
void AdcSetSingleShot(MYADC, uint8_t);
uint16_t AdcReadSingle(MYADC adcSet);
#endif /* INC_MYADC_H_ */

myadc.c

#include "myadc.h"

static uint8_t ADSwrite[6];
static uint16_t sendReg;

/*
 * Set ADC setting
 */
MYADC AdcInit(uint8_t address, uint8_t conversionDelay, uint8_t bitShift, uint16_t gain){
	MYADC adcSet;
	adcSet.m_i2caddress = address;
	adcSet.m_conversionDelay = conversionDelay;
	adcSet.m_bitShift = bitShift;
	adcSet.m_gain = gain;
	return adcSet;
}

/*
 * Config ADC by singlemode, and continuous reading
 */
void AdcSetContinuous(MYADC adcSet, uint8_t ch){
	sendReg = ADC_REG_CONFIG_CQUE_NONE |    // Disable the comparator (default val)
		      ADC_REG_CONFIG_CLAT_NONLAT |  // Non-latching (default val)
		      ADC_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low   (default val)
		      ADC_REG_CONFIG_CMODE_TRAD |   // Traditional comparator (default val)
		      ADC_REG_CONFIG_DR_1600SPS |   // 1600 samples per second (default)
		      ADC_REG_CONFIG_MODE_CONTIN;   // Continuous mode

	sendReg |= adcSet.m_gain;
	switch(ch){
		case(0):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_0;
		break;
		case(1):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_1;
		break;
		case(2):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_2;
		break;
		case(3):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_3;
		break;
		}
	ADSwrite[0] = ADC_REG_P_CONFIG;
	ADSwrite[1] = (sendReg & 0xFF00) >> 8;
	ADSwrite[2] = (sendReg & 0x00FF);
	HAL_I2C_Master_Transmit(&hi2c1, adcSet.m_i2caddress << 1, ADSwrite, 3, 100);

	ADSwrite[0] = 0x00;
	HAL_I2C_Master_Transmit(&hi2c1, adcSet.m_i2caddress << 1 , ADSwrite, 1 ,100);
	HAL_Delay(adcSet.m_conversionDelay);
}

/*
 * Config ADC by singlemode, and single shot reading
 */
void AdcSetSingleShot(MYADC adcSet, uint8_t ch){
	sendReg = ADC_REG_CONFIG_CQUE_NONE |    // Disable the comparator (default val)
		      ADC_REG_CONFIG_CLAT_NONLAT |  // Non-latching (default val)
		      ADC_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low   (default val)
		      ADC_REG_CONFIG_CMODE_TRAD |   // Traditional comparator (default val)
		      ADC_REG_CONFIG_DR_1600SPS |   // 1600 samples per second (default)
		      ADC_REG_CONFIG_MODE_SINGLE;   // Single-shot mode(default)

	sendReg |= adcSet.m_gain;
	switch(ch){
		case(0):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_0;
		break;
		case(1):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_1;
		break;
		case(2):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_2;
		break;
		case(3):
			sendReg |= ADC_REG_CONFIG_MUX_SINGLE_3;
		break;
		}
	ADSwrite[0] = ADC_REG_P_CONFIG;
	ADSwrite[1] = (sendReg & 0xFF00) >> 8;
	ADSwrite[2] = (sendReg & 0x00FF);
	HAL_I2C_Master_Transmit(&hi2c1, adcSet.m_i2caddress << 1, ADSwrite, 3, 100);

	ADSwrite[0] = 0x00;
	HAL_I2C_Master_Transmit(&hi2c1, adcSet.m_i2caddress << 1 , ADSwrite, 1 ,100);
	HAL_Delay(adcSet.m_conversionDelay);
}

/*
 * AD convert to 12bit(int)
 */
uint16_t AdcReadSingle(MYADC adcSet){
	int16_t reading = 0;

	ADSwrite[0] = ADC_REG_P_CONVERT;
	HAL_I2C_Master_Transmit(&hi2c1, adcSet.m_i2caddress << 1 , ADSwrite, 1 ,100);
	HAL_Delay(adcSet.m_conversionDelay);

	HAL_I2C_Master_Receive(&hi2c1, adcSet.m_i2caddress <<1, ADSwrite, 2, 100);
	reading = (ADSwrite[0] << 8 | ADSwrite[1] ) >> adcSet.m_bitShift;

	return reading;
}

  myadc.hにたくさん宣言されているマクロは,主要な設定項目です.今回は単に1chについてAD変換できれば充分としてプログラムは書いていませんが,ほかの用途で使用する場合に備え,マクロはすべて定義してあります.実はこの部分はArduinoのコードからの流用で,C++で書かれているArduinoライブラリの名残がMYADC構造体です.ここにADCのアドレスや通信待ち時間,AD変換されたデータの空きビットの大きさ,PGAのゲインなど,おおよそそのADCを使う間は変更しなさそうなことを設定しています.myadc.cで定義されている関数は,そのMYADC構造体に設定を書き込む関数,連続変換を設定する関数,いちいち変換したらリセットされる関数,そしてAD変換を行い値を読み取る関数からなっています.そのため,AdcInit関数とAdcSetContinuous関数は一回,AdcSetSingleShot関数とAdcReadSingle関数は読み取りのたびに使用すればよいようになっています.AdcSetContinuous関数は連続で一つのチャンネルを変換するときに使うことを想定していて,このADCに一つしか測定対象をつなげない場合に使います.一方,AdcSetSingleShot関数は毎回リセットするので動作は遅くなりますが,複数チャンネルの変換が可能になります.複数チャンネル使用の時にはAdcSetSingleShot関数,一つしか使わないならAdcSetContinuous関数を使ってください.

3.3 main.cに書く内容

  main.cには,myadc.c/.hを利用してコードを作成することができます.#include "myadc.h"を忘れないこと.今回は連続変換の場合を書いていますが,いちいちリセットする場合もコメントアウトした状態で書いてあります.なお,
今回のサンプルプログラムはmain関数までのみ掲載しており,そのあとの変更を加えない自動生成部分は省略しています.

main.c

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "myadc.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
MYADC ad1;
float voltage;
const float voltageConv = 4.096 / 2047.0;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  /* USER CODE BEGIN 2 */
  ad1 = AdcInit(0x49, ADC_CONVERSIONDELAY, ADC_REG_BITSHIFT, ADC_REG_CONFIG_PGA_4_096V);
  AdcSetContinuous(ad1, 0);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  //AdcSetSingleShot(ad1, 0);
	  voltage = AdcReadSingle(ad1) * voltageConv;

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

  ちなみに,ADS1115(16bitADC)を使用するときには,bitshiftの設定を0にすればいけます.また,今回は0V~3.3Vまでの範囲のAD変換を行いたいので,ゲインのモードは4.096Vに設定しています.ADS1015はADRピンに入力する信号を変えることでI2Cアドレスの変更ができます.今回はVCCを入力し,0x49としました.

  動作の様子は…省略させてください….というかどうやって映したらいいんですかね().何しろ,ADCに接続したジョイスティックを動かして,読み取った値をcubeIDE内蔵のデバッガ機能で監視しただけなので….デバッガ機能についてもググっていただければたくさん記事が出てくるのでそちらを参考にしてください.

  ちなみにですが,このADCが送ってくるデータは「intの範囲で12bit」です.符号付きです.というのも,負の範囲まで電圧の測定ができる子だからです.だから,今回の使用方法だと,設定範囲の半分も測定に生かせていないという….本当だったら,レギュレータ使って1.7Vくらいの電圧を出して,測定対象との差分を,ゲイン2.048V設定で測定するのがよい気がします.そのためには比較測定をする関数を用意しないといけませんが….

4.終わりに

  ザックリと説明してきました.いろいろ用意していない機能もたくさんありますが,これをベースにいろいろ作れそうです.とりあえず,ほかにもいろいろ行き当たりばったりやっていきたいと思います.

デジタル風向計開発物語 ①LCDつかう

「そうだ、風向計を作ろう」
ということでここからは風向計に関する記事を書いていきます。

何を言っているかわからないと思うので説明します。現在私は風向計を作っています。目的は、テストフライトの時に風速・風向を観測する必要があり、現在の吹き流しよりも、リアルタイムに、かつ正確に風向・風速を計測できるようにするためです。

そういうわけで、この風速・風向計には次のようなものを搭載します。
風速・風向を読む…ロータリーエンコーダ―
PCに結果を送信する…Xbee
手元でも見れるように…LCD
さらに、オプションとして、さらにいろいろなものを搭載していく予定です。

では、さっそくその風速・風向計の開発の様子を書いていきます。

[本題]LCDを使用する

というわけで今回はLCDを使っていきます。ちょうどそのころ、マイクロマウスサークルで「こんなものを使っている人がいる」ということで、それを参考にLCDを買ってきました。
「I2C接続小型LCDモジュール(8×2行)ピッチ変換モジュール[AE-AQM0802]」(秋月電子通商
http://akizukidenshi.com/catalog/g/gM-09109/
LCD本体のみ、DIP化基板付き、組み立て済みが売られています。今回は組み立て済みのモジュールを使用しました。DIP化基板にはプルアップ抵抗までついているので、こちらをまずは使うことがおすすめです。

では、やっていきましょう。

[準備]開発用意

・用意するもの

マイコン:STM32F303K8 Nucleo(STmicroelectronics製)
LCD:AE-AQM0802
抵抗:10kΩ×1

マイコンにはSTM32を使用しました。このNucleoボードなら、電源回りなどの回路を作る必要がないので、試作が簡単にできます。
LCDは先に述べた通り。
最後に、RESETピンをプルアップするため、10kΩの抵抗を用意しました。

・開発環境

STM32の開発環境を明記しておきます。
ライブラリ:HAL
HAL初期設定:CubeMX
IDE:System Workbench for STM32(SW4STM32)

[回路]

回路の組み方は次の図のようになります。
今回はLCDのみのRESETはかけないことにするので、RESETピンは3.3Vに直結します。
I2Cペリフェラルを用いることができるピンは決まっているので、図のように配線します。

f:id:tomo_amber:20190309010953p:plain
LCD_配線図

[設定]

まずはCubeMXの設定。左側のタブの中から、「Connectivity > I2C1」を選択し、その横に現れるボックスの一番上を「Disable」を「I2C」に変更すればOKです。
下の画像では、他にもいろいろ設定していますが、特に必要はないです。

f:id:tomo_amber:20190309005540p:plain
LCD用CubeMXの設定

[プログラム]

これが一番難しい…。要はI2C接続で必要なデータを送り込めばいいのだが…。いかんせん知識不足でどう書けばいいのかわからない。Arduino用のライブラリはたくさんありますが、これをSTM32化するのも一苦労。やってみて、結局失敗。手詰まりか…と思っていると光明が。ある日、「STM32用のライブラリあるよ」と聞きつけ、目にしたのが下のサイト。
https://lawn-tech.jp/aqm0802a.html
これをベースに、アレンジや、風向・風速表示を見越した改造を施した結果のプログラムが下の通り。最終的に読み込んだ風速・風向を出力できるような関数を用意しています。

定義したグローバル関数・マクロ

#define LCDADD 0x7c
uint32_t LastCount2 = 0;
float velocity = 0.0;

初期化(先のブログリンク参照)

//send Instruction for LCD
int LCD_WriteInstraction(uint8_t data)
{
    uint8_t buf[] = { 0x00, data };
    int status = HAL_I2C_Master_Transmit(&hi2c1, LCDADD, buf, 2, 1000);
    HAL_Delay(1);
    return status == HAL_OK;
}
//initialize LCD
void LCD_Init()
{
    LCD_WriteInstraction(0x38);     // Function set
    LCD_WriteInstraction(0x39);     // Function set
    LCD_WriteInstraction(0x14);     // Internal OSC frequency
    LCD_WriteInstraction(0x70);     // Contrast set
    LCD_WriteInstraction(0x56);     // Power/ICON/Contrast set
    LCD_WriteInstraction(0x6c);     // Follower control
    HAL_Delay(200);
    LCD_WriteInstraction(0x38);     // Function set
    LCD_WriteInstraction(0x0c);     // Display ON/OFF control
    LCD_WriteInstraction(0x01);     // Clear Display
    HAL_Delay(1);
}

文字の表示(先のブログリンク参照)

//write data on DDRAM
int LCD_WriteData(uint8_t data)
{
    uint8_t buf[] = { 0x40, data };
    int status = HAL_I2C_Master_Transmit(&hi2c1, LCDADD, buf, 2, 1000);
    HAL_Delay(1);
    return status == HAL_OK;
}
//print characters on LCD
void Puts(const char *p)
{
    for ( ; *p ; p++)
    {
        LCD_WriteData(*p);
    }
}
//print start signals on LCD
void HelloWorld()
{
    LCD_Init();
    Puts("Hello,");
    LCD_WriteInstraction(0x80 + 0x40);  // 2 行目の先頭に移動
    Puts("world!");
    HAL_Delay(1000);
    LCD_WriteInstraction(0x80 + 0x00);
    Puts("2019WASA");
    LCD_WriteInstraction(0x80 + 0x40);
    Puts("Birdman");
    HAL_Delay(2000);
}

風速・風向の表示

//send Speed data for LCD
void speedview(float speed){
	char value[8] = {"00.0 m/s"};

	if(speed < 0) return;

	speed = (speed * 10);

	value[0] = (char)speed / 100;
	value[1] = (char)(speed - 100 * value[0]) / 10;
	value[3] = (char)(speed - 100 * (float)value[0] - 10 * (float)value[1]);

	for(int i=0; i<4; i++){
		value[i] += '0';
	}
	value[2] = '.';

    LCD_WriteInstraction(0x80 + 0x00);
	Puts(value);
    LCD_WriteInstraction(0x80 + 0x40);
}
//send Direct data for LCD
void directview(uint16_t direct){
	char dir[8] = {"000 deg "};

	dir[0] = (char)(direct / 100);
	dir[1] = (char)((direct - 100 * dir[0]) / 10);
	dir[2] = (char)(direct - 100 * dir[0] - 10 * dir[1]);

	for(int i=0; i<3; i++){
		dir[i] += '0';
	}

    LCD_WriteInstraction(0x80 + 0x40);
	Puts(dir);
    LCD_WriteInstraction(0x80 + 0x00);
}

メイン文

user code 2に書いたもの
  HelloWorld();
  HAL_Delay(1000);
user code whileに書いたもの
	  velocity += 0.5;
	  degree ++;
	  speedview(velocity);
	  directview(degree);
	  HAL_Delay(250);
<備考>

CubeMXから吐き出したコードには、HALを用いた設定部分などがすでに記されています。ここに自分で書くプログラムを加えればよいのです。この時、各部分に仕込まれている「//user code 〇〇 bigin」と「//user code 〇〇 end」の間に書けば、幸せになれます。のちにCubeMXで機能追加などの調整を行い、再度コードをはきなおさせても、この間にあるコードは消えません(逆にそのほかの部分はすべて消えてしまいます)。上のプログラムはすべてそういった部分に書き込むとよいでしょう。

[動作]

実際に組んで動かしてみた結果がこちら

[解説]

プログラムではテストとして風速を0.5m/sずつ、風向を1 degずつインクリメントさせています。途中で風速が急に小さい数字を表示するようになったことがわかると思います。確証はありませんが、恐らくは風速を示す変数がfloat型で定義されていることが原因と思われます。数字は
25.0→25.5→0.4→0.9
というように変化していることから、「25.6」という数がキーになっていることがわかります。したがって、STM32のfloat型が2byteの範囲内でしか数を格納できないのではないか、と考えています。確証は持てないので、詳しい方いらっしゃいましたら教えてください…。

あと、上記のプログラムではchar型の数をそのままLCDに送っていますが、データシートを見る限り、LCDで表示される文字データは「char型ではない」と考えられます。数字、アルファベットのみ表示すればよいという方はこのままで問題ないですが、「→」など、他のデータシート記載の文字を使用したい方はそちらをお使いください。

終わりに

はじめはLCDについてやってみました。とりあえず使えるようにはなりましたが、まだまだ味が出そうです。また面白いことを見つけたら書きたいと思います。

なんとなくブログを作ってみた

はじめましての人ははじめまして。閲覧いただき、ありがとうございます。ここは、アマチュアレベルの技術系ブログです。

 

はじめに、このブログの趣旨を説明させていただきます。このブログは、某大学の理工系学生の筆者が、所属するモノづくりサークルでの活動を通し、得た知見を忘れないように保存しておくために作りました。ですので、内容等に微妙な部分があるかもしれません。ご了承ください。

 

意外と調べて出てこなかったところ・調べた通りにやってもうまくいかなかったところを中心に書いていきたいと思います。

主なトピックは次のようになると思います。

マイコン(STM32シリーズが中心)

・上から派生して、マイクロマウス

・ガラッと変わって、飛行機関連(主に人力飛行機

 

今後とも、よろしくお願いします。