GPIOの使い方を学ぶ
GPIOとはいろんな使い方ができるIO portのことです.
STM8Sのピン配置を見ると、PA0とかPD3とかいう文字が見えます.これらは全てGPIOとして利用可能です.
ただし、OSCIN/PA1のように書かれているピンは、PA1の他に外部水晶発振子の端子としての役割も兼ねているので、水晶発振子を取り付けている場合はPA1をGPIOとして使うことはできません.
STM8S105C6のGPIOは全部でこれだけあります.
PA[6:1]
PB[7:0]
PC[7:1]
PD[7:0]
PE[7:5],PE[3:0]
PG[1:0]
GPIOの使い方の説明
STMicro社のライブラリで知っておくべき関数を以下に解説します.
●GPIOの入力出力の設定
使用例:
GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_LOW_FAST); → PB5を出力にする.ドライブ能力は低い.
GPIO_Init(GPIOD, GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_FAST); → PD6を出力にする.ドライブ能力は高い.
GPIO_Init(GPIOG, GPIO_PIN_0, GPIO_MODE_IN_PU_NO_IT); → PG0を入力にする.プルアップする.
・1つ目の引数の意味は、どのGPIOかの指定です.
GPIOA/GPIOB/GPIOC/GPIOD/GPIOE/GPIOGのどれかです.
・2つ目の引数の意味は、どのbitかの指定です.
つぎのどれかまたはORです.
ORとは、(
GPIO_PIN_2 |
GPIO_PIN_1 |
GPIO_PIN_0 ) とすれば[2:0]を一括設定できるという意味です.
GPIO_PIN_0 bit0
GPIO_PIN_1 bit1
GPIO_PIN_2 bit2
GPIO_PIN_3 bit3
GPIO_PIN_4 bit4
GPIO_PIN_5 bit5
GPIO_PIN_6 bit6
GPIO_PIN_7 bit7
GPIO_PIN_LNIB Low nibble つまり[3:0]のこと
GPIO_PIN_HNIB High nibble つまり[7:4]のこと
GPIO_PIN_ALL ぜんぶ[7:0]
・3つ目の引数はたくさん説明しなくちゃいけませんが、赤字のやつだけ知っておけば当面は足りるでしょう.
GPIO_MODE_IN_FL_NO_IT
Input
floating, no external interrupt
GPIO_MODE_IN_PU_NO_IT Input pull-up, no external interrupt
GPIO_MODE_IN_FL_IT
Input floating, external interrupt
GPIO_MODE_IN_PU_IT
Input pull-up, external interrupt
GPIO_MODE_OUT_OD_LOW_FAST Output open-drain, low level, 10MHz
GPIO_MODE_OUT_PP_LOW_FAST Output push-pull, low level, 10MHz
GPIO_MODE_OUT_OD_LOW_SLOW Output open-drain, low level, 2MHz
GPIO_MODE_OUT_PP_LOW_SLOW Output push-pull, low level, 2MHz
GPIO_MODE_OUT_OD_HIZ_FAST Output open-drain, high-impedance level,10MHz
GPIO_MODE_OUT_PP_HIGH_FAST Output push-pull, high level, 10MHz
GPIO_MODE_OUT_OD_HIZ_SLOW Output open-drain, high-impedance level, 2MHz
GPIO_MODE_OUT_PP_HIGH_SLOW Output push-pull, high level, 2MHz
_IN_/_OUT_は入力にするか出力にするかを設定する意味です.
_FL_/_PU_/_OD_/_PP_はゲートの電気的構造を意味します.
_FL_はFloatingの略です.普通の入力端子です.
_PU_はPull Upの略です.内蔵プルアップ抵抗が付加されます.
STM8Sを普通に使うには、これが適しています.
_OD_はOpen Drainの略です.外付けでプルアップ抵抗をつけないといけません.
電気回路に精通した人なら使っても良いですが、普通にSTM8Sを使う分には使わないでしょう.
(3.3V系から5V系への変換に使うことがあります)
_PP_はPush Pullの略です.出力ポートはまずはこれを使えばいいでしょう.
_NO_IT_/_IT_は、割り込みの無し/有りです.とりあえず割り込み無しの_NO_IT_を憶えておきましょう.
_FAST_/_SLOW_は、高速な出力ゲートか、低速な出力ゲートかの設定です.
低速な出力ゲートの方が消費電力が小さいメリットがあるので、バッテリー駆動する時に_SLOW_を使いたい場面があるかもしれません.
しかし、まずは_FAST_だけ憶えておけばよいでしょう.
多少順番が前後しましたが、_LOW_/_HIGH_/_HIZ_というのもありますね.
これは、出力の初期値がLOWかHIGHかあるいはハイインピーダンスかの設定です.
初期値設定はどんな場面で有用な機能なのでしょうか?
例えば、出力ポートの先にモーターがついていて、HIGHだとモーターが回転する仕様になっているとします.
そのケースでは、初期値がLOWになるようにSTM8Sを設定すれば、STM8Sの起動時にモーターがピクッと動く症状を防止できます.
GPIO_Init()の引数の説明はおしまいです.
●GPIOに値を出力する方法
次の4つの関数を知っておけばOKです.
GPIO_Write ( GPIOB, 0xA2
);
// PB[7:0] = 0xA2
GPIO_Write ( GPIOD, 0b10100010 ); // PD[7:0]=0xA2
GPIO_WriteHigh ( GPIOG, GPIO_PIN_0 ); // PG0=1
GPIO_WriteLow ( GPIOA, GPIO_PIN_7 ); // PA7=0
GPIO_WriteReverse ( GPIOC, GPIO_PIN_2 ); // PC2の値を反転する
●GPIOの値を読む方法
次の2つの関数を知っておけばOKです.
uint8_t in;
in = GPIO_ReadInputData ( GPIOD ); // GPIOD[7:0]を読む
BitStatus in;
in = GPIO_ReadInputPin ( GPIOA, GPIO_PIN_5 ); // PA5を読む
サンプルプログラム
サンプルworkspaceをこちらに置きます.
このworkspaceの中には、projectが4つ入っています.以下では各projectを説明します.
test04
このprojectのソースコードは正味これだけです.
STM8S-DISCOVERYに焼くと、LEDが光ります.
PD0を出力に設定し、_LOW_で初期値=0に設定しているからLEDが光るのです.
#include "stm8s.h"
void main(void)
{
GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_LOW_FAST); // PD0 output
while(1) { } // Main loop
}
test04b
このprojectのソースコードは正味これだけです.
STM8S-DISCOVERYに焼くと、LEDが光りません.
PD0を出力に設定し、_HIGH_で初期値=1に設定しているからLEDが光らないのです.
#include "stm8s.h"
void main(void)
{
GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST); // PD0 output
while(1) { } // Main loop
}
test04c
以前につくったプログラムで、UARTでPCと接続し小文字大文字変換するプログラムがありました.
このプログラムに、CPUの動作中を示すインジケータLED点滅機能を追加しました.
ソースコードの赤いところが追加部分です.
main()では、LEDが接続されているPD0を出力に設定しています.その後、蛇足ながらPD0=1に設定.
main()に、TIM3_xxxx()な関数も追加されていますが、これはLED点滅用のタイマーです.タイマーについては後の章で解説します.
TIM3_UPD_OVF_BRK_IRQHandler()はタイマー割り込みルーチンで、GPIO_WriteReverse()でPD0を反転させることでLEDを点滅させています.
void main(void)
{
CLK_ClockSwitchConfig ( CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE );
GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST);
GPIO_Write(GPIOD, 0b00000001);
TIM3_TimeBaseInit( TIM3_PRESCALER_1, ARR );
TIM3_ITConfig(TIM3_IT_UPDATE, ENABLE);
TIM3_Cmd(ENABLE);
// PC setting = 115200bps 8bit ODD-parity stop=1bit
UART2_DeInit();
UART2_Init((u32)115200,
UART2_WORDLENGTH_9D, UART2_STOPBITS_1, UART2_PARITY_ODD,
UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TXRX_ENABLE);
UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);
UART2_Cmd(ENABLE);
enableInterrupts();
SerialPutString("This is a converter small words to capital words.\r\n");
SerialPutString("key in any words.\r\n");
while(1) // Main loop
{
UART_Menu();
}
}
u16 cnt;
void TIM3_UPD_OVF_BRK_IRQHandler(void) interrupt 15
{
TIM3_ClearFlag(TIM3_FLAG_UPDATE);
cnt++;
if(cnt==(INTF/2-1)){
GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
cnt=0;
}
return;
}
test04d
せっかくGPIOを学んだのですから、外部ピンをLOW/HIGHにすることでLEDの点滅速度を変えられるようにしましょう.
PB6がCN3の4ピンに出ています.また、GNDがCN3の2ピンにあります.
そこで、CN3の2ピンと4ピンをジャンパーピンでショート(下図の赤の箇所)すれば、PB6=0にできます.
ジャンパーピンを外せばPB6=1にできます.
これで、プログラムを制御します.
プログラムは、main()の冒頭で、PB6をプルアップ抵抗つきの入力に設定しています.
タイマ割り込みルーチンのTIM3_UPD_OVF_BRK_IRQHandler()の中では、if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_6))のところでPB6の値を読んで点滅周期を変更しています.
このプログラムを焼いて動かすと、PB6にジャンパーピンをつけたとき点滅が速くなります.ジャンパーピンを外すと点滅がゆっくりになります.
void main(void)
{
CLK_ClockSwitchConfig ( CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE );
GPIO_Init(GPIOB, GPIO_PIN_6, GPIO_MODE_IN_PU_NO_IT ); // PB6 input
GPIO_Init(GPIOD, GPIO_PIN_0, GPIO_MODE_OUT_PP_HIGH_FAST); // PD0 output
GPIO_Write(GPIOD, 0b00000001);
TIM3_TimeBaseInit( TIM3_PRESCALER_1, ARR );
TIM3_ITConfig(TIM3_IT_UPDATE, ENABLE);
TIM3_Cmd(ENABLE);
// PC setting = 115200bps 8bit ODD-parity stop=1bit
UART2_DeInit();
UART2_Init((u32)115200, UART2_WORDLENGTH_9D,
UART2_STOPBITS_1, UART2_PARITY_ODD, UART2_SYNCMODE_CLOCK_DISABLE,
UART2_MODE_TXRX_ENABLE);
UART2_ITConfig(UART2_IT_RXNE_OR, ENABLE);
UART2_Cmd(ENABLE);
enableInterrupts();
SerialPutString("This is a converter small words to capital words.\r\n");
SerialPutString("key in any words.\r\n");
while(1) // Main loop
{
UART_Menu();
}
}
void TIM3_UPD_OVF_BRK_IRQHandler(void) interrupt 15
{
u16 max;
TIM3_ClearFlag(TIM3_FLAG_UPDATE);
if(GPIO_ReadInputPin(GPIOB, GPIO_PIN_6)) max=INTF/2-1;
else max=INTF/8-1;
cnt++;
if(cnt>=max){
GPIO_WriteReverse(GPIOD, GPIO_PIN_0);
cnt=0;
}
return;
}