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
最近のコメント