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_Cloc
kSwitchConfig ( 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;
}

inserted by FC2 system