2014/11/24

Arduino - ロータリスイッチの状態をA/D変換で取得する

前置きが長いので,すぐに回路図とスケッチを確認したい場合は,最初の2項目を読み飛ばしてください.

しろくま氏のPWMパワーパックの改良

しろくま氏ジオタウンドットコムで公開している,PWMパワーパックを製作してみることにしました. プログラムをPICに移植して製作しようと思っていたのですが,Arduinoの使用経験がなかったこともあり,私の技術不足で一筋縄では行きそうにありません. そこで,Arduinoの開発環境を用意して,ひとまずArduinoで製作してみることにしました.

しろくま氏が記事を投稿してから3年以上経過しているため,既に多くの方が,しろくま氏のPWMパワーパックを製作したようです. ジオタウンドットコムのコメント欄を見ると,誤動作するという方も散見されます. どうやら,マスコンとして使用している,ロータリスイッチ周辺回路やプログラムに問題が1つあるようです. 今回は,このロータリスイッチ周辺回路とプログラムの改良について考えてみました.

誤動作の原因は回路にあると推測

誤動作の原因や対応策についてコメント欄でさまざまな議論がされていますが,私は回路に原因があると考えました. 記事の添付写真から推測すると,しろくま氏が使用しているロータリスイッチは,秋月電子通商で発売されているノンショーティングタイプの1回路12接点のものです. ノンショーティングタイプのロータリスイッチは,スイッチを回転させて選択接点を切り換える際,一時的に共通接点がどの選択接点にも接触していない状態になります.

ここで,しろくま氏の回路図を確認します. ロータリスイッチ RSW_12の共通接点aは,アナログ入力ピンに接続されています. つまり,ロータリスイッチを回転させた際に,一時的にアナログ入力ピンがどこにも接続されていない状態(ハイインピーダンス)になります. このとき,Arduinoがロータリスイッチの状態を取得できなくなりますので,誤動作が発生します. ただし,これは回路図から読み取った推測です. 実際には,見当違いであったり,複合的な原因である可能性もありますのでご注意ください. ご指摘があれば,コメントをいただければ幸いです.

次項から,改良した回路について紹介します.

回路
回路図

PDFファイルにて公開します. 回路図中の「ユーザ回路」部分を製作し,Arduinoのアナログ入力ピンに接続してください.

ロータリスイッチ SW1の共通接点Aは,グランドに接続されています. 一方,Arduinoのアナログ入力ピンは,常にSW1の選択接点1に接続されています. スイッチを回転させると,合成抵抗の分圧比が変化し,アナログ入力ピンに印加される電圧が変化します. この変化を読み取ることで,SW1の状態を取得できます.

仮に共通接点Aがいずれの選択端子にも接続されていない状態になっても,アナログ入力ピンは抵抗 R1でプルアップされている状態となり,ハイインピーダンスにはなりません.

回路部品

下表は,回路図中の「ユーザ回路」部分の使用部品表です. 参考単価をクリックすると,秋月電子通商のページに飛びます. 「互換品」と記載されているリンクについては,互換性があると考えられる部品のページに飛びます. ただし,私が互換性および動作を確認したわけではありませんので,ご注意ください.

番号 部品名 型番 数量 参考単価
SW1 ロータリスイッチ 1回路12接点
ノンショーティングタイプ
1 150円
(互換品)
R1, R10 炭素皮膜抵抗 各社 1/4W 4.7kΩ 2 1円
(互換品)
R2 炭素皮膜抵抗 各社 1/4W 470Ω 1 1円
(互換品)
R3 炭素皮膜抵抗 各社 1/4W 680Ω 1 1円
(互換品)
R4 炭素皮膜抵抗 各社 1/4W 820Ω 1 1円
(互換品)
R5 炭素皮膜抵抗 各社 1/4W 1kΩ 1 1円
(互換品)
R6 炭素皮膜抵抗 各社 1/4W 1.2kΩ 1 1円
(互換品)
R7 炭素皮膜抵抗 各社 1/4W 1.5kΩ 1 1円
(互換品)
R8 炭素皮膜抵抗 各社 1/4W 2.2kΩ 1 1円
(互換品)
R9 炭素皮膜抵抗 各社 1/4W 3kΩ 1 1円
(互換品)
R11 炭素皮膜抵抗 各社 1/4W 8.2kΩ 1 1円
(互換品)
R12 炭素皮膜抵抗 各社 1/4W 15kΩ 1 1円
(互換品)
その他 リード線など 適量
回路製作例

私が製作した回路の写真です. 炭素皮膜抵抗R2R12は1/4Wの小型品を使用し,ロータリスイッチの接点間に直接ハンダ付けしました.


回路製作例
スケッチ
A/D変換値からロータリスイッチの状態を取得する方法

まず,ロータリスイッチの各状態における,アナログ入力ピンへの印加電圧を計算してみましょう. 計算結果を下表に示します. 下表から,例えば選択接点2の場合は,アナログ入力ピンへの印加電圧が0.455Vになることがわかります. ArduinoのA/D変換の分解能は10bit(0~1023)ですから,A/D変換値は93になると考えられます. ただし,電源電圧や抵抗値の公差により,各値は多少変動します.

これらの計算結果を基に,A/D変換値と閾値を比較することで,ロータリスイッチの状態を割り出します. 例えば,選択接点が3以下か4以上かを調べるためには,各状態におけるA/D変換値(201と302)の中間値(252)を閾値にします. このような比較処理を繰り返すことで.選択接点が特定できます.

ロータリスイッチの選択接点とアナログ入力ピンへの印加電圧の関係
選択接点 印加電圧 [V] A/D変換値(10bit)
1 0.000 0
2 0.455 93
3 0.983 201
4 1.477 302
5 1.936 396
6 2.351 481
7 2.734 560
8 3.130 641
9 3.491 715
10 3.841 787
11 4.175 855
12 4.459 910
スケッチ例

下記は,スケッチ例 rotary_sw.inoです. A/D変換値からロータリスイッチの状態を取得する,getRotarySwStatus()関数を作成しました. 復帰値1~12でロータリスイッチの状態を,復帰値0で取得エラーを示します.

getRotarySwStatus()関数内の条件分岐処理がif文の入れ子構造になっているのは,ロータリスイッチの状態によって関数内の処理時間が変動しないようにしたかったためです. この関数では,ロータリスイッチがいずれの状態であっても条件分岐処理が3回以内になっています. よりスマートなやり方があるのだとは思いますが….

製品紹介
2014/11/23

16F88 XC8開発例 - 可変抵抗でLEDの輝度を制御する

概要

PIC16F88とMPLAB XC8 C Compilerを使用した開発例として,可変抵抗でLEDの輝度を制御するプログラムを紹介します. この開発例では,PIC16F88のA/D変換モジュールとCCPモジュールのPWMモードを使用しています. 開発環境は下記のとおりです.

PIC PIC16F88-I/P
MPLAB X IDE MPLAB X IDE v2.15
MPLAB XC8 MPLAB XC8 C Compiler v1.32
PICkit 2 MPLAB X IDEを使用して書込み
回路
回路図

PICkit 2を使用してICSP (In Circuit Serial Programming)と電源供給を行うことを前提とした回路です. 今回は,これをブレッドボード上に組んで動作を確認しました.

電源はPICkit 2から5.0Vを供給しています. 内蔵クロックを使用するため,外部発振子は不要です. AN0に可変抵抗を接続し,RB3に電流制限用抵抗 330Ωを経由してLEDを接続しています.


回路図
回路部品

下表は使用部品表です.

番号 部品名 型番 数量 参考単価
U1 PICマイコン Microchip PIC16F88-I/P 1 200円
LED1 LED 各社 各色 1 10円
VR1 可変抵抗 各社 30kΩ B 1 40円
R1 炭素皮膜抵抗 各社 1/4W 10kΩ 1 1円
R2 炭素皮膜抵抗 各社 1/4W 330Ω 1 1円
その他 リード線など 適量
プログラム
main.c

下記はソースファイル「main.c」です.参考になれば幸いです.

2014/11/18

Arduino - ソースコードを複数ファイルに分割して記述する(2)

.inoファイルは外部エディタで編集しづらい

前回の投稿で,スケッチを複数のファイル(タブ)に分割して記述する方法を紹介しました. 前回紹介した方法でも,コンパイルに問題はありません. しかし,できれば.inoファイルは作成せず,.cppと.hファイルのみでコーディングしたいと考えました. Arduino IDEのエディタは使いづらいのでサクラエディタを使用しているのですが,デフォルト設定のサクラエディタでは,.inoファイルは.cppファイルのように色分け表示や自動インデントが行われないからです. そこで,.cppと.hファイルのみでスケッチを構成する方法について調べてみました.

スケッチには最低1つの.inoファイルが必要

Intel Galileo Arduino IDEのユーザですが,調査された方を発見しました.

上記Webページによると,各スケッチには,スケッチフォルダ名と同名の.inoファイルが必要であるとのことです. ただし,.inoファイルには何も記述されていなくても良いようです(ブランクのダミーファイル.) 上記Webページを例に,適当なスケッチをダミーの.inoファイル,.cppファイルおよび.hファイルの組み合わせに変更してみました.

.cppと.hファイルのみで記述する方法
概要

.inoファイルのみで記述されたサンプルスケッチを,ダミーの.inoファイル,.cppファイルおよび.hファイルの組み合わせによる記述に変更します. ソースコードは.cppファイルと.hファイルに記述するため,外部エディタを使用しても色分け表示や自動インデントの機能が使用できます. また,別の開発環境やマイコンへの移植性の改善も期待できます.

サンプルスケッチ

LED点滅回路用のサンプルスケッチ,led_test2.inoです.

サンプルスケッチの記述変更例

6つのファイルに分割して記述しました. まずはダミーファイル,led_test3.inoです.

ヘッダファイル,stdafx.hです.

setup()関数およびloop()関数を記述した,led_test3.cppです.

ヘッダファイル,led_test3.hです.

led_toggle()関数を記述した,led_toggle.cppです.

ヘッダファイル,led_toggle.hです.

製品紹介
2014/11/17

Arduino - Arduino IDEのエディタのタブ幅を変更する

Arduino IDEの設定ファイル

Arduino IDEの環境設定は,「ファイル」-「環境設定」をクリックして表示されるウィンドウで変更できます. しかし,このウィンドウ上で変更できる項目は限られているため,より詳細な環境設定を行うためには,設定ファイルを直接編集しなければいけません. 設定ファイルのファイル名はpreferences.txtで,この設定ファイルのパスは環境設定のウィンドウで確認できます. パスをクリックすると,エクスプローラで設定ファイルが格納されているフォルダが表示されます.


Arduino
エディタのタブ幅を変更する

設定項目については,下記Webサイトにまとめが掲載されています.

デフォルトのタブ幅は2ですが,下記のようにタブ幅を4に変更しました.

Arduino IDEのエディタは貧弱…

行番号表示もできませんし,インデントにタブ文字が使用できないようです. 私は,外部エディタとしてサクラエディタを使用し,Arduino IDEはコンパイルにのみ使用しています. 今後のバージョンアップで機能増強が図られるのでしょうか….

製品紹介

Arduino - typedef宣言を使用する際の注意

C/C++のようで違う,Arduino

前回の記事でも書きましたが,関数のプロトタイプ宣言をユーザが記述する必要がないなど,Arduino IDEで使用するプログラミング言語はC/C++とは若干異なります.

実際には,スケッチ内のタブのうち.inoファイルと拡張子のないファイルは,コンパイル前に1つの.cppファイルに統合されるようです. 一方,.cファイルと.cppファイルは個別にコンパイルされ,最後にリンクが実行されます.

これらの処理は,ユーザのコーディングを簡略化することを目的としているのだと思います. しかしながら,ここに罠が隠れており,私はその罠にかかってしまいました.

typedef宣言が無視されてしまう
コンパイルエラーとなるプログラム

一見すると問題のないソースコードのようですが,コンパイルエラーが発生します. メッセージは「led_test2:12: error: 'STATUS_LED' does not name a type」でした.

問題の原因

この問題の原因は,Arduino IDEがプロトタイプ宣言を自動挿入する位置がプリプロセッサ(#include#defineのこと)の直後であることです. つまり,プロトタイプ宣言はプリプロセッサとtypedef宣言の間,8行目に自動挿入されることになります. したがって,typedef宣言でデータ型を定義する前にそのデータ型を使用したプロトタイプ宣言があることになり,コンパイルエラーとなってしまうのです.

問題の回避方法
方法(1) typedef宣言をヘッダファイルに移行する

Arduino Build Processでも紹介されている問題回避方法です. 自動挿入されるプロトタイプ宣言はプリプロセッサの直後なので,プリプロセッサでインクルードされるヘッダファイルでtypedef宣言を行えば良い,というものです.

方法(1)を適用したプログラムを示します. 下記は既存タブのled_test2.inoです. 新規作成するヘッダファイル,led_test2.hをインクルードしています.

下記は新規タブのled_test2.hです. typedef宣言を記述しています.

方法(2) プロトタイプ宣言を自分で記述する

プロトタイプ宣言が既に存在する場合は,自動挿入が実行されません. したがって,typedef宣言の後方に自分でプロトタイプ宣言を書いておくことでも,この問題を回避できます.

製品紹介
2014/11/16

Arduino - ソースコードを複数ファイルに分割して記述する

Arduino,はじめました

かなり今更ですが,最近になってArduinoを触り始めました. Arduinoと言っても,基板は買わずにATmega328Pを買ってきて,ブートローダと開発環境だけを使用しています. 参考書なども買っていないため,インターネットで調べつつ試行錯誤しています.

最初に躓いたのは,ソースコードを複数ファイルに分割して記述する方法についてです. Arduino Build Processでも説明されていますが,備忘録として記述しておこうと思います.

ソースコードを複数ファイルに分割して記述する
サンプルプログラム

説明に使用するサンプルプログラム,led_test.inoです. PIN_LEDで指定したデジタル入出力ピンのLEDを点滅させるプログラムです. LEDを接続する際は,電流制限用抵抗を忘れずに挿入してください.

今回は,loop()関数内の32~35行目の処理を関数化し,別ファイルに記述します.

新規タブを作成する

Arduinoでは,1つのスケッチで複数ファイルを扱うとき,各々を「タブ」と呼ぶようです. 新規タブは,ウィンドウ右側のアイコンをクリックすると表示されるメニューから作成できます. 私は最初これを知りませんでした….


Arduino

ウィンドウ下部に表示されるテキストボックスで,新規タブ名を指定します. Arduino Build Processによれば,タブとして扱うことができるファイルは,拡張子なし,.c,.cppまたは.hのいずれかのようです. しかし,私の使用しているArduino 1.0.5-r2では,このテキストボックスで拡張子を指定しなかった場合,拡張子は.inoになります. 1つのスケッチで,複数の.inoファイルが扱えるようです.

関数を記述するのであれば,C++言語ライクではなくC言語ライクに書くのであっても,個人的には拡張子は.cppを指定すれば良いと思います. 今回は拡張子を指定しませんでしたので,led_func.inoというファイルがスケッチフォルダに新規作成されました.


Arduino
ソースコードを編集する

上記のサンプルプログラムを分割して記述した例を示します. loop()関数内の32~35行目の処理を,led_func()関数として関数化しています. このように関数化やファイル分割を行うことで,ソースコードの再利用性が向上します.

下記は既存タブのled_test.inoです.

下記は新規タブのled_func.inoです.

なお,関数のプロトタイプ宣言は,Arduinoにおいてはコンパイル時に自動挿入されるため,必要ありません. また,作成したタブが拡張子.hのヘッダファイルでない限り,#includeの記述も必要ありません. しかし,これらにも例外があります. 詳細については,別記事「Arduino - typedef宣言を使用する際の注意」をご覧ください.

追加情報

よりC/C++言語ライクに記述したい場合は,Arduino - ソースコードを複数ファイルに分割して記述する(2)をご覧ください.

製品紹介
2014/11/14

16F88 アセンブリ言語開発例 - LED点滅回路

概要

PIC16F88とMPASM (アセンブリ言語)を使用した開発例として,LED点滅回路のプログラムを紹介します. 開発環境は下記のとおりです.

PIC PIC16F88-I/P
MPLAB X IDE MPLAB X IDE v2.15
MPASM MPASMWIN v5.57
PICkit 2 MPLAB X IDEを使用して書込み
回路
回路図

電源はPICkit 2から5.0Vを供給しています. 内蔵クロック 8MHzで動作させています. RB0には,電流制限用抵抗 330Ωを経由してLEDが接続されています.


回路図
回路部品

下表は使用部品表です.

番号 部品名 型番 数量 参考単価
U1 PICマイコン Microchip PIC16F88-I/P 1 200円
LED1 LED 各社 各色 1 10円
R1 炭素皮膜抵抗 各社 1/4W 10kΩ 1 1円
R2 炭素皮膜抵抗 各社 1/4W 330Ω 1 1円
その他 リード線など 適量
プログラム
main.asm

下記はソースファイル「main.asm」です.参考になれば幸いです.

更新履歴
2014/11/15 プログラムを修正(動作にほぼ影響なし)
  • サブルーチンTIMER2内のNOP命令を削除
  • サブルーチンTIMER3内のNOP命令を削除
2014/11/14 公開開始