今回からは、実際にマイコンを使って特定の動作を行うプログラミングのお話を行っていきたいと思います。ここでは、レジスタの設定情報はもちろん、サンプルのプログラムも合わせて紹介していきたいと思います。
今回はマイコンの基本中の基本であるデジタル入出力のお話を行いたいと思います。
入出力設定
マイコンを使うときには初めにマイコンにピンを入力として使うか、出力として使うかを設定しなければなりません。
ピンを入力モードとして設定すると、インピーダンスは高くなります。逆に出力モードとして設定を行うと、ピンのインピーダンスは低くなります。そのため、回路上入力になる端子を出力設定すると、場合によっては過電流が流れマイコンが破損する場合があります。逆に回路上出力の個所を入力設定にすると出力先をドライブできなくなりますが、マイコンが破損する心配はほぼありません。(出力の条件次第(出力先の入力部をプルダウンやプルアップしていないなど)で出力先の回路が壊れる危険性はありますが…)この理由からAVRマイコンでは初期設定では、ピンは入力モードになっています。
レジスタ設定
入出力の設定を行うレジスタはAtmega328のデータシート(https://avr.jp/user/DS/PDF/mega328P.pdf
)の65ページから67ページにかけて書かれています。これより、PORTB,C,Dそれぞれの入出力を設定するレジスタはDDRB,C,Dであることがわかります。
例としてPORTBの入出力の設定レジスタであるDDRBのリストを引用します。
「DDRB」レジスタの0ビット目から7ビット目までそれぞれPB0~PB7までの入出力の設定を行うレジスタビットになっています。それぞれのピンに対応するビットを0にすると入力、1にすると出力になります。初期設定は上の図の「リセット値」になるのですべて0、つまりすべて入力モードになっています。
また、PORTBの場合以下のようにPB6,7(下図赤□)が水晶端子と重なっていることがわかります。
このように特定の機能を持ったピンがある場合は、そのピンの持つ機能に合わせて入出力を設定します。今回のPB6,7は水晶入力なので、入力の設定にしておきます。(ピンの特殊機能を使う場合は基本的にここでの入出力設定は無視されて、正しい設定になるはずですが、一応保険のためにこのように設定しておきます。)
また、青で囲った部分は通常のピンとして利用できるピンです。このピンの中から使用するピンの入出力の設定を行います。(この中にはSPI通信の機能を持ったピンもあるので必要に応じて使い分けてください)
例として、PB1,3を出力、PB0,2,4,5を入力とする場合のレジスタ設定を紹介します。
上位の2ビットは使用不可なので0(入力)とし、ほかは出力ピンを1、入力ピンを0としてビットを並べて2進数としたものを、16進数に変換を行い桁数の削減を行います。
デジタル出力(出力状態設定)/内部プルアップ設定
入出力の設定が終われば次は、マイコンのデジタル出力の設定を行います。これは、マイコンのピンからHレベルの信号を出力するかLレベルの信号を出力するかの設定です。また、ピンを入力モードとしたときに、ピンをマイコン内部でプルアップするかしないかの設定も同じレジスタで行います。
レジスタ設定
ピンの出力状態の設定を行うレジスタはデータシートの65~67ページより、PORTB,C,Dそれぞれ、PORTB,C,Dであることがわかります。また、データシートの55ページの以下の情報から、プルアップが可能なことがわかります。
図の青で囲った、「PUD(MCUR第4bit)」(プルアップ禁止)レジスタは初期設定で0、つまりプルアップ許可(禁止でない)となっています。そのため、入力状態(DDRB,C,Dの対応ビットが0)である時に、PORTB,C,Dの対応ビットを1にすると、そのピンがプルアップされた入力になるというわけです。
次に例としてPORTBを紹介します。今回もリストを引用します。
入出力の設定と同じく、「PORTB」レジスタの0ビット目から7ビット目までそれぞれ、PB0からPB7までのピンの出力状態の設定を行うレジスタとなっております。それぞれのピンに対応するビットを0にするとLが出力され、1にするとHが出力されるようになっています。また、初期時(リセット時)はすべてLが出力されます。
例として、PB2,3をH出力、PB4,5をL出力、PB1をプルアップ入力、PB0をハイインピーダンス入力とした場合のレジスタ設定を紹介します。
まずは入出力の設定
DDRB = 0b00111100
↓
DDRB = 0x3C
入出力設定は、上位2ビットが使用不可、下位2ビットが入力で、ほかは出力なので、その通りにビットを並べ、入出力の設定を行います。そして、出力状態の設定はPB2,3がH出力、つまり第2,3ビットが1、またPB1がプルアップなので第1ビットが1になり、ほかはLまたはHZ(ハイインピーダンス)なので0となります。こちらも、最終的には桁数削減のために16進数表記にしています。
デジタル入力(ピン状態読み込み)
先ほどの設定でピンの出力状態の設定はできました。ですが、出力のレジスタでは入力モードの時にピンの状態を読み込むことができません。そのため、入力状態を取得するときには「入力レジスタ」と言われる別のレジスタを使用します。
レジスタ設定
ピンの入力状態を読み込むレジスタは、先ほどと同じくデータシートの65~67ページより、PORTB,C,Dのそれぞれに対して、PINB,C,Dであることがわかります。例として、PORTBの入力レジスタである、PINBについて紹介します。
このレジスタも、0ビット目から7ビット目までそれぞれPB0~PB7に対応しており、1を読み込んだ時はピンの状態がHレベル、0を読み込んだ時はピンの状態がLレベルとなっております。
また、このレジスタは種別としては読み書きの両対応のレジスタになっていますが、基本的には読み込みとして使用します。(PINBに書き込みを行うと、対応するPORTBの状態がトグルしますが、使うことはないと思います)
特定のピンのみの状態を読み込む場合はAND演算を使って、読み込みたいビットのみを取り出します。(ほかのピンの状態は無視する必要があるため)また、必要に応じてビットシフトを行って、ビットをずらします。
以上で今回の(デジタル)入出力のお話は終了です。
サンプルプログラム
今回紹介したデジタル入出力を使った、サンプルプログラムの紹介を行いたいと思います。今回は、PD7にアクティブLOWのスイッチを接続し、内部プルアップを設定します。また、PB5端子にアクティブHIGHのLEDを接続し、スイッチが押されている間点灯するプログラムとします。
List1 DigitalInOut
#include <avr/io.h>
int main(void)
{
DDRB = 0x20;//PBを出力
DDRD = 0x00;//PD7は入力
PORTD = 0x80;//PD7をプルアップ
/*
Replace with your application code */
while (1)
{
if(PIND & 0x80){//H状態=ボタンが押されていないとき
PORTB &= ~0x20;//PB5をL出力
}else{//L状態=ボタンが押されているとき
PORTB |= 0x20; //PB5をH出力
}
}
}
プログラムの構成としては、初めに初期設定として、入出力の設定とプルアップの設定を行います。その後の無限ループ内で、PD7の状態を読み込み、Hの場合はPB5をL状態、Lの場合はPB5をH状態にしています。また、if文は0か非0かの判定であるので、状態判別時のビットシフトは省略できます。
また、今回の条件の場合は別の書き方として、while(1)の中を下のようにもすることができます。
while (1)
{
PORTB = ~((PIND & 0x80) >> 2);
}
こちらの書き方の考え方は、入力信号をANDとビットシフト、反転を行い、if文などを使わずに、そのまま出力しています。
この2つの書き方は場合により使い分ければよいと思いますが、後者は比較的使う場面は少ないと思います。(マイコン的な考え方ではありますが…)まあ、考え方として知っておけば損はしないと思います。
今回はマイコンの入出力の方法を紹介しました。次回はマイコンで音楽を奏でるミソであるPWMの出力のお話をしていきたいと思います。