Arduino やっぱり気になる放置ポート
Arduino-UNOに搭載されているマイコンはATmega328P。
あれこれ公開されているArduinoの参考スケッチ、たいていの場合、使うポート以外はみんな放置したままなんです。
それが気になります。
例えば出力にするところは、
pinMode(1, OUTPUT);
などとして、
digitalWrite(1, HIGH);
と、出力をHに。
プルアップ付の入力なら
pinMode(2, INPUT_PULLUP);
として、スイッチなどを対GNDにつなげば
digitalRead(2);
で、スイッチのオン・オフが読み取れます。
ところが・・・スケッチで使わない入出力ポートは、何もしないのが普通になっています。
出力指定、あるいはプルアップ入力指定しないままだと、リセット後のそのポートは裸の入力のまま。
I/Oポートの構成図だとこんなふうになります。
・ATmega328Pのデータシート(日本語訳)より
入力ピンに何もつながず放置しておくと、インピーダンスが非常に高いためH/Lが安定しません。
(オシロスコープで観察しようとしてプローブをつないだら、そのプローブの抵抗(たいてい10MΩ)でLレベルに安定してしまい、真の姿が見えない)
★マークのシュミットトリガ入力がその関門です。
入力ポートのシュミット、そのスレッショルド電圧は電源電圧のおよそ中央。
そしてヒステリシスが0.5Vほど。
つまり、何らかの原因(誘導ノイズなど)で入力レベルが変動してスレッショルド電圧付近に達したら・・・
C-MOSのシュミットゲート回路、入力がスレッショルド電圧付近になると電流が増えるという特性があります。
※昔々、いろんなシュミットIC(4584や4093、HC14、HC132、
シュミット入力になったモノマルチなどその電流の増加を
調べたことがあったんですが、資料行方不明。
プロセッサ誌あたりに投稿した記憶がうっすらと)
ATmega328Pの入力でも同様のことが生じます。
何かの拍子、オープンになった入力ポートの電圧が電源電圧の半分近くになると・・・1つの入力につきざっと0.5mA~1mA電源電流が増加します。
USBから電源が供給されて動くArduino、こんなちょっとの電源電流増加は目立ちません。
Arduinoの環境ではなく、チップ単独で電池運用する時などにこの放置が問題になってくるでしょう。
未使用I/Oポート、その扱いの基本は、
・入力専用ポート
抵抗でプルアップかプルダウン
直接GNDあるいは電源につなぐ
・出力専用ポート
放置
・入出力ポート(たいていのArduinoのポート)
出力に指定して放置
入力指定で(イニシャルせず)プルアップかプルダウン抵抗を付加
入力にして内蔵プルアップ、プルダウン機能を有効に
リセット時の挙動、イニシャルプログラムが走る前のことも考えておかなくてはなりません。
ポートを出力にする。あるいは内蔵のプルアップやプルダウンを有効にする。これらはプログラムが正常に走りはじめてから設定できる機能です。
何らかの異常でリセット状態が続いた時、出力ポートにするはずのポートが入力のままで、これをC-MOSゲートで受けているとH/Lレベルが定まらず思いもよらない出力がオンしてしまうことがあります。
出力にもプルアップ、プルダウン抵抗が必要な場合があるのです。
もうひとつ。
ATmega328Pをスリープさせると入力ポートを外部から切り離してくれる機能があります。
※上の図、シュミットゲートの右側のスイッチ(Lへ落とすFETも)。
このおかげでスリープさせた時に入力が安定し(放置していた入力も)、スレッショルド付近の不安定な状態(シュミット回路の電流が増える)になりません。
未使用ポートの放置が気になって、私の書くプログラムはこんな具合に全ポートを入力か出力に区分けしています。
※例:JIS C8708:2019充放電実験回路のスケッチ (スペースがズレるかな)
// I/Oイニシャル
PORTB = 0b00000000; // data/pull up
DDRB = 0b00111111; // port指定
// |||||+---- PB0 IO8 out -
// ||||+----- PB1 IO9 out OC1A 充電PWM
// |||+------ PB2 IO10 out OC1B 放電PWM
// ||+------- PB3 IO11 out OC2A BZZ
// |+-------- PB4 IO12 out -
// +--------- PB5 IO13 out (LED)
PORTC = 0b00001110; // data/pull up
DDRC = 0b00110000; // port指定
// |||||+---- PC0 AD0 in 電池電圧 A/D入力
// ||||+----- PC1 AD1 in START SW
// |||+------ PC2 AD2 in ↑ TX SW
// ||+------- PC3 AD3 in ↓ MENU SW
// |+-------- PC4 AD4 out 充電オン
// +--------- PC5 AD5 out 放電オン
PORTD = 0b00000011; // data/pull up
DDRD = 0b11111110; // port指定
// |||||||+---- PD0 IO0 in RXD
// ||||||+----- PD1 IO1 out TXD
// |||||+------ PD2 IO2 out LCD RS
// ||||+------- PD3 IO3 out LCD E
// |||+-------- PD4 IO4 out LCD DB4
// ||+--------- PD5 IO5 out LCD DB5
// |+---------- PD6 IO6 out LCD DB6
// +----------- PD7 IO7 out LCD DB7
いっぱい書いてますが、実際の命令コードは6行だけ。
※Arduino-UNO + SDカードでシリアルデータロガー 完成形 ではこんなの。
未使用ポートは出力にしています。
// I/Oイニシャル
PORTB = 0b00011100; // data/pull up
DDRB = 0b00101111; // port指定
// |||||+---- PB0 IO8 out 赤LED (Lでon)
// ||||+----- PB1 IO9 out 緑LED (Lでon)
// |||+------ PB2 IO10 out CS カードアクセス時Lに
// ||+------- PB3 IO11 out MOSI カードDI
// |+-------- PB4 IO12 in MISO カードDO
// +--------- PB5 IO13 out SCLK
PORTC = 0b00000000; // data/pull up
DDRC = 0b00111111; // port指定
// |||||+---- PC0 AD0 out -
// ||||+----- PC1 AD1 out -
// |||+------ PC2 AD2 out -
// ||+------- PC3 AD3 out -
// |+-------- PC4 AD4 out -
// +--------- PC5 AD5 out -
PORTD = 0b10000011; // data/pull up
DDRD = 0b01111110; // port指定
// |||||||+---- PD0 IO0 in RXD
// ||||||+----- PD1 IO1 out TXD
// |||||+------ PD2 IO2 out -
// ||||+------- PD3 IO3 out -
// |||+-------- PD4 IO4 out -
// ||+--------- PD5 IO5 out -
// |+---------- PD6 IO6 out -
// +----------- PD7 IO7 in SW入力 pull up
| 固定リンク
「Arduino」カテゴリの記事
- Arduino UNO R3で±19.9V表示電圧計(2023.10.14)
- 「御詠歌プレーヤー」の製作 (MP3-TF-16Pモジュールの使用例)(2023.08.10)
- Arduino UNO R3のソケット・・思えば違和感がぁ(2023.07.07)
- 初めて買ったArduino UNO・・・今は(2023.05.25)
- 液晶表示コントローラ HD44780で迎撃(2023.05.16)
コメント
基板の絶縁抵抗は10の10乗Ωも無いだろうから、何もしなくてもLow側で安定しているはず、と思っていたのですが、
ちょっと確認してみると、基板(石?)によってはじわじわとVcc側に上がっていくピンがあったりして、あらら、と言う感じでした。もう少し調べてみますが、こりゃちゃんと対策しておいた方が良さそうです。
あと、DC的にはなんとか大丈夫でもラインの誘導には違いなく反応するので、やはり空き端子処理しておいた方がいろいろと安全なんでしょうね。ただプログラムが読み難くなるのが難点です。
投稿: ラジオペンチ | 2020年4月26日 (日) 21時34分
放置したポートの状態を検証。
スケッチ例 01.Basicの中のblink.inoをベースに。
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT); // そのまま
analogWrite(10, 64); // ★1 PWM output Digital10(PB2 16pin)
// pinMode(9, INPUT_PULLUP); // ▲1 D9 pullup
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, digitalRead(9)); // ★2 D9=PB1 15pin input
}
デジタル9(PB1:15pin ATmega328Pの端っこの足)を入力にしたまま、その状態でデジタル13(PB5)のLEDポートを駆動します。
隣の16ピン(PB2)をPWM出力にして480Hzのパルスを出します。
15ピンを指先やピンセットの先で触ったり、近づけたり遠ざけたりしてみてください。
LEDを駆動するPB5ポートをオシロで見ながらごそごそすると状態がよくわかります。
商用電源周波数の誘導を拾っている様子、そして16ピンが出すパルスの誘導を観察できます。
次に▲1のコメントを取ってプルアップを有効にするスケッチを書き込みます。
すると、安定してLEDが点灯。
指で触ったくらいでは大丈夫。
15ピンと16ピンを短絡すると、PWMパルスでLEDが点きます。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年4月27日 (月) 09時37分
はい、やってみました。
UNOだと盛大に誘導していてそのまんまの波形がPB5に出てました。
ちなみに配線が短いArduino NANO で同じことをやると、こっちは大丈夫でした。NANO の Pin9 の引き出しパターン長は5mmくらいです。パッケージの根本で止めて余計なアンテナを付けなければ大丈夫なのかもしれません。まあ対策しておいた方が良いのは間違いないです。
居酒屋ガレージ日記さんは未使用ピンはLOW出力にされてますが、これって出来るだけインピーダンスを下げとこう、という狙いもあるのでしょうか。
投稿: ラジオペンチ | 2020年4月27日 (月) 18時28分
LOW出力での固定、特に意識はしていません。
空きポート、L出力にしているのは「処理タイミングのチェックでHパルスを出す」ということとも関係あるといえばあるかなぁっというところ。
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年4月28日 (火) 21時53分
ラジオペンチさんによる実測 #1
http://radiopench.blog96.fc2.com/blog-entry-999.html
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年4月29日 (水) 22時13分
ラジオペンチさんによる実測 #2
・Arduino よもやま話-15 (未使用ピンの電圧変化の観察)
http://radiopench.blog96.fc2.com/blog-entry-1000.html
以下、私の追実験。
・Arduino 放置したポートが及ぼす電源電流変化
http://igarage.cocolog-nifty.com/blog/2020/05/post-441cf8.html
・Arduino ポートの初期化と通信設定
http://igarage.cocolog-nifty.com/blog/2020/05/post-463930.html
投稿: 居酒屋ガレージ店主(JH3DBO) | 2020年5月 3日 (日) 13時18分