サンプルプログラム G431KB_UART2 の説明
マスコット   UART(非同期シリアル通信)の
 サンプルプログラムです。

  STMicroelectronics社製の
 評価用基板、NUCLEO-G431KB と
 freeの開発ツール、STM32CubeIDE
 使用しています。

  NUCLEO-G431KB基板のST-LINK部分は
 VCP(仮想COMポート)の機能も有しています。

  NUCLEO-G431KB基板とPCとをUSBケーブルで接続すると
 ST-LINKとCOMポートの二つを認識します

  COMポートは、STM32G431KBの
 PA2(USART2_TX) と PA3(USART2_RX) に接続されていて
 PC と CPU との UART(非同期シリアル通信)接続が可能です。


目次

UART(非同期シリアル通信)について

サンプルプログラム G431KB_UART2 のソース

サンプルプログラム G431KB_UART2 の説明
 G431KB_UART2 の構成
 G431KB_UART2 の動作パラメータの定義
 ユーザープログラムの実行開始位置
 G431KB_UART2 の main() の説明
  1) 初期化の部分
  2) LED点滅 と UART2通信処理 の部分

 UART2通信処理 Commu_UART2 の説明

 コマンド送信について

 モジュール Execute_Command_LED について



UART(非同期シリアル通信)について
 以下のページでUARTについて簡単に説明しています。
 UART(非同期シリアル通信) の説明 をご覧ください。


サンプルプログラム G431KB_UART2 のソース
 STM32CubeIDE 1.12.1 を使用して作成しました。
 ここからサンプルプログラム W_G431KB_UART2.zip をダウンロードしてください。

  プロジェクト W_G431KB_UART2 は、
 フォルダ C:\Work_CubeIDE\W_G431KB\W_G431KB_UART2 のように配置して作成しました。

  フォルダ C:\Work_CubeIDE\W_G431KB を作成して、
 そのフォルダに W_G431KB_UART2.zip を貼り付けて解凍し、
 プロジェクト作成時と同一に C:\Work_CubeIDE\W_G431KB\W_G431KB_UART2 と
 配置した場合は、普通にプロジェクトを開くことができます。

  サンプルプログラムのプロジェクトを任意のフォルダに配置した場合に、
 STM32CubeIDEにより、そのプロジェクトを開く方法については
既存のプロジェクトを開く方法 をご覧ください。



サンプルプログラム G431KB_UART2 の説明
  STM32G431KBのUART2の通信を行うプログラムです。
  PCが送信したコマンドを受信して、コマンドに応じてLEDの点滅間隔を変化させます。

 プロジェクト最初にを開いた画面は以下のようになります。

UART2_Scrn_First

 以下、サンプルプログラム G431KB_UART2 について説明していきます。



 G431KB_UART2 の構成
  STM32CubeIDEの画面左側、Project Explorerの
 G431KB_UART2を展開した画面は以下のようになります。

UART2_Tree

  サンプルプログラム G431KB_UART2 の構成を以下に示します。
G431KB_UART2
  |- Includes
  |
  |- C_Lib
  |    |- User_IF_Lib
  |    |    |- Blink_LED_Status : Status LED点滅処理
  |    |         |- Blink_LED_Status.c
  |    |         |- Blink_LED_Status.h
  |    |
  |    |- Wait_Interval : 時間待ち処理
  |         |- Wait_Interval.c
  |         |- Wait_Interval.h
  |
  |- Core
  |    |- Inc
  |    |    |- main.h
  |    |    |- stm32g4xx_hal_conf.h
  |    |    |- stm32g4xx_it.h
  |    |
  |    |- Src
  |    |    |- main.c
  |    |    |- stm32g4xx_hal_msp.c
  |    |    |- stm32g4xx_it.c : 割り込み処理
  |    |    |- syscalls.c
  |    |    |- system.c
  |    |    |- system_stm32g4xx.c
  |    |
  |    |- Startup
  |
  |- Drivers
  |
  |- Periph_Lib
  |    |- Handle_G4 : 周辺インターフェースのハンドラ
  |         |- H_G4_UART2 : UART2ハンドラ
  |              |- H_G4_UART2.c
  |              |- H_G4_UART2.h
  |
  |-UART2_Ope
  |    |- Commu_UART2 : UART2通信処理
  |    |    |-Commu_UART2.c
  |    |    |-Commu_UART2.h
  |    |
  |    |- Execute_Command_LED : LED点滅コマンド処理
  |    |    |- Execute_Command_LED.c
  |    |    |- Execute_Command_LED.h
  |    |
  |    |- G431KB_Config : 動作パラメータの定義
  |         |- Dev_Conf.h
  |
  |- G431KB_UART2.launch
  |- STM32G431KBTX_FLASH.ld



 G431KB_UART2 の動作パラメータの定義
  サンプルプログラム G431KB_UART2 の動作パラメータの定義を
  UART2_Ope/G431KB_Config/Dev_Conf.h に記述しています。

  使用する CPU の定義、ヘッダ名の定義、GPIO のポートとピンの定義、
 などを記述しています。



 ユーザープログラムの実行開始位置
  プログラムは、int main(void) から実行開始します。

  int main(void) は、フォルダ Core/Src/main.c にあります。

UART2_main

  STM32CubeIDEでビルドされたプログラムは、自動的にCPUの初期化を
 行った後、int main(void) を呼び出します。

  ユーザーコード(記述したプログラム)は、
 int main(void) の先頭から実行されます。



 G431KB_UART2 の main() の説明
  サンプルプログラム G431KB_UART2 の main() の記述は、
 以下のとおりです。


/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  uint8_t uint8_JobNum_LED = 0;   // LED点滅処理番号
  uint8_t uint8_JobNum_UART = 0;  // UART処理番号

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //------------------------------------------------------
    // Status LED点滅
    //------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // uint16_t uint16_Time_ON  : 点灯時間
    // uint16_t uint16_Time_OFF : 消灯時間

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //------------------------------------------------------
    Blink_LED_Status(&uint8_JobNum_LED,
                     GLB_uint16_Time_LED_Status_ON,
                     GLB_uint16_Time_LED_Status_OFF);


    //------------------------------------------------------------
    // UART2通信処理
    //------------------------------------------------------------
    // 処理内容 :

    //  1. UART2の初期化がされていない場合、初期化します。
    //  2. 受信が発生するのを待ち、受信データを取得します。
    //  3. 受信データを判定して、内容に従い処理を行います。
    //  4. 受信データによる処理の結果、送信データがセットされた場合、送信処理を行います。
    //------------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG終了
    //------------------------------------------------------------
    Commu_UART2(&uint8_JobNum_UART);
  }
  /* USER CODE END 3 */
}


 1) 初期化の部分

  a) CPUのPeripheral初期化
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
   により、CPUのPeripheralなどの基本的な初期化を行います。
  PeripheralとはCPUの周辺インターフェースなどのことを言います。

   プロジェクト構築時に自動的に組み込まれる、
  HAL Drivers(フォルダ Drivers/STM32G4xx_HAL_Drivers) 内に記述されています。


  b) CPU動作クロックの設定
  /* Configure the system clock */
  SystemClock_Config();

   CPUの動作クロックとPeripheralの動作クロックを設定します。

   SystemClock_Config(); の設定内容は、

int main(void)
{
         .
         .
         .
}
 の、すぐ下に記述されています。



 2) LED点滅 と UART2通信処理 の部分
   永久ループ部分の記述を以下に示します。


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //------------------------------------------------------
    // Status LED点滅
    //------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // uint16_t uint16_Time_ON  : 点灯時間
    // uint16_t uint16_Time_OFF : 消灯時間

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //------------------------------------------------------
    Blink_LED_Status(&uint8_JobNum_LED,
                     GLB_uint16_Time_LED_Status_ON,
                     GLB_uint16_Time_LED_Status_OFF);


    //------------------------------------------------------------
    // UART2通信処理
    //------------------------------------------------------------
    // 処理内容 :

    //  1. UART2の初期化がされていない場合、初期化します。
    //  2. 受信が発生するのを待ち、受信データを取得します。
    //  3. 受信データを判定して、内容に従い処理を行います。
    //  4. 受信データによる処理の結果、送信データがセットされた場合、送信処理を行います。
    //------------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG終了
    //------------------------------------------------------------
    Commu_UART2(&uint8_JobNum_UART);
  }
  /* USER CODE END 3 */

  Status LED点滅処理 Blink_LED_Status と
  UART2通信処理 Commu_UART2 を
 呼び出しています。

  Commu_UART2 では、コマンドを受信して、コマンドの内容に応じて
 LEDの点滅時間変更を行います。

  Blink_LED_Status と Commu_UART2 は並列に実行されます。



 UART2通信処理 Commu_UART2 の説明
  データを受信して、LED点滅コマンドの場合、コマンドの内容に応じて、LEDの点滅間隔を変更します。
  受信したデータはエコーバックされます。

  LED点滅コマンドは以下の通りです。
LED1 B0\r\n : 1000mSec 点灯 / 2000mSec 消灯
LED1 B1\r\n : 100mSec 点灯 / 100mSec 消灯
LED1 B2\r\n : 200mSec 点灯 / 200mSec 消灯
LED1 B3\r\n : 300mSec 点灯 / 300mSec 消灯
LED1 B4\r\n : 400mSec 点灯 / 400mSec 消灯
LED1 B5\r\n : 500mSec 点灯 / 500mSec 消灯
  \r : CR : 0x0D
  \n : LF : 0x0A
 です。



  Commu_UART2 は
 UART2_Ope/Commu_UART2/Commu_UART2.c 内にあります。

  以下に、Commu_UART2 のコードを示します。
//------------------------------------------------------------
// UART2通信処理
//------------------------------------------------------------
// 処理内容 :

//  1. UART2の初期化がされていない場合、初期化します。
//  2. 受信が発生するのを待ち、受信データを取得します。
//  3. 受信データを判定して、内容に従い処理を行います。
//  4. 受信データによる処理の結果、送信データがセットされた場合、送信処理を行います。
//------------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ

// 戻り値:
//    -1 : 処理中
//    0 : OK終了
//    1 : NG終了
//------------------------------------------------------------
int16_t Commu_UART2(uint8_t *puint8_JobNum)
{
  static uint8_t STC_uint8_JobNum_UART;

  int16_t int16_ReceiveLength;

  int16_t int16_Return;


  switch(*puint8_JobNum)
  {
  case 0:
    if(GLB_int16_vUART2_ReceiveIRQ == 0){
      //-----------------------------------------------------------
      // UART2通信パラメータ初期化
      //-----------------------------------------------------------
      // 引数:
      // uint32_t uint32_BaudRate : 通信速度

      // 戻り値:
      //    0 : OK
      //    1 : NG
      //-----------------------------------------------------------
      int16_Return = Init_Commu_UART2((uint32_t)115200);
      if(int16_Return != 0){
        // NG
        break;  // NG終了
      }
    }


    STC_uint8_JobNum_UART = 0;  // UART処理番号初期化


    (*puint8_JobNum)++;  // 次の処理番号に移行する。: case 1:
    int16_Return = -1;   // 処理継続
    break;

  case 1:
    //--------------------------------------------------
    // UART2 受信処理
    //--------------------------------------------------
    // 戻り値:
    //    -2 : エラー発生
    //    -1 : 受信なし
    //     0 : 受信なし
    // 1以上 : 受信byte数
    //--------------------------------------------------
    int16_ReceiveLength = Receive_UART2(&STC_uint8_JobNum_UART,
                      GLB_uint8_ReceiveData_UART2);
    if(int16_ReceiveLength <= 0){
      if(int16_ReceiveLength ==  -2){
        //--------------------------
        // エラー発生
        //--------------------------
        *puint8_JobNum = 0;  // 処理番号初期化 : case 0: に移行する。
        int16_Return = -2;   // エラー発生
        break;  // エラー終了
      }

      //-------------------
      // 受信なし
      //-------------------
      int16_Return = -1;  // 処理継続 : case 1: をループ
      break;  // 処理番号維持
    }


    //-----------------------------------------------------------------
    // 受信コマンド実行
    //-----------------------------------------------------------------
    GLB_uint16_vTx2_Transfer = Execute_Command_LED((uint16_t)int16_ReceiveLength,
                                                   GLB_uint8_ReceiveData_UART2,
                                                   GLB_uint8_Tx2_Buffer);


    (*puint8_JobNum)++;  // 次の処理番号に移行する。: case 2:
    int16_Return = -1;   // 処理継続
    break;

  case 2:
    // 応答データ送信
    //------------------------------------------------------------------
    // UART2 送信処理
    //------------------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号が格納される変数のポインタ

    // 戻り値:
    //   -1 : 処理中
    //    0 : 送信終了
    //    1 : エラー
    //------------------------------------------------------------------
    int16_Return = Send_UART2(&STC_uint8_JobNum_UART);
    if(int16_Return == -1){
      // 処理中
      break;  // 処理番号維持 : 処理継続 : case 2: をループ
    }

    *puint8_JobNum = 0;  // 処理番号初期化
    // int16_Return : 結果
    break;

  default:
    *puint8_JobNum = 0;  // 処理番号初期化
    int16_Return = 1;    // NG
    break;
  }

  return(int16_Return);
}

 1) case 0:
   初期化 および エラー発生 の判定フラグ GLB_int16_vUART2_ReceiveIRQ を判定して
  0 の場合、UART2 の初期化を行います。

 2) case 1:
   UART2 の受信処理を行います。
   受信が発生して、1回の受信が終了するまで、case 1: をループします。

  a) エラーが発生した場合は、処理番号を 0 にして、エラー終了します。
   Commu_UART2 は、case 0: から処理を実行します。

  b) 1回の受信が終了した場合、受信データは GLB_uint8_ReceiveData_UART2 にセットされています。

  c) 受信コマンド実行 Execute_Command_LED に GLB_uint8_ReceiveData_UART2 を渡して実行します。
   受信コマンド実行結果に伴う送信データは GLB_uint8_Tx2_Buffer にセットされます。

  d) 処理番号をインクリメントします。
    処理は、case 2: に移行します。

 3) case 2:
   UART2 送信処理 Send_UART2 を実行して、GLB_uint8_Tx2_Buffer のデータを送信します。

  a) 送信が終了するまで、case 2: をループします。

  b) 送信が終了すると、処理番号を 0 に初期化して終了します。

  Commu_UART2 は再び、処理番号 0 : case 0: から実行されます。



 コマンド送信について
  PCからBase-N431KB基板に搭載されているNUCLEO-G431KB基板にコマンド送信を
 行うために、Tera Termを使用しました。

  Tera Termのファイル送信により、コマンドを送信します。

  例えば、Textファイルに LED1 B1<改行> を記述し、
 Tera Termの端末の設定で、改行コードの送信に CR+LF を指定して、
 ファイル送信します。



 モジュール Execute_Command_LED について
  モジュール Execute_Command_LED は、
 UART2_Ope/Commu_UART2/Commu_UART2.c 内にあるモジュール、
 Commu_UART2 から呼び出されています。

  以下に、モジュール Execute_Command_LED のコードを示します。


//----------------------------------------------------------------------
// 受信コマンドを実行する。 : LED点滅
//----------------------------------------------------------------------
// 引数:
// uint16_t uint16_ReceiveLength : 受信データ数
// uint8_t *puint8_ReceiveData : 受信データが格納されているBufferのポインタ
// uint8_t *puint8_SendData : 応答送信データを格納するBufferのポインタ

// 戻り値:応答送信データ数
//----------------------------------------------------------------------
uint16_t Execute_Command_LED(uint16_t uint16_ReceiveLength,
                             uint8_t *puint8_ReceiveData,
                             uint8_t *puint8_SendData)
{
  uint16_t uint16_I;
  uint16_t uint16_SendLength = 0;


  //----------------------------------------------------------------------
  // Command処理
  //----------------------------------------------------------------------

  //------------------------------------------------------------------
  // LED1(緑) 点滅間隔切り替え
  //------------------------------------------------------------------
  if(memcmp(puint8_ReceiveData, "LED1 B0\r\n", 9) == 0){
    // LED1(緑) : 点灯1000mSec / 消灯2000mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)1000;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)2000;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }
  else if(memcmp(puint8_ReceiveData, "LED1 B1\r\n", 9) == 0){
    // LED1(緑) : 点灯100mSec / 消灯100mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)100;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)100;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }
  else if(memcmp(puint8_ReceiveData, "LED1 B2\r\n", 9) == 0){
    // LED1(緑) : 点灯200mSec / 消灯200mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)200;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)200;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }
  else if(memcmp(puint8_ReceiveData, "LED1 B3\r\n", 9) == 0){
    // LED1(緑) : 点灯300mSec / 消灯300mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)300;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)300;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }
  else if(memcmp(puint8_ReceiveData, "LED1 B4\r\n", 9) == 0){
    // LED1(緑) : 点灯400mSec / 消灯400mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)400;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)400;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }
  else if(memcmp(puint8_ReceiveData, "LED1 B5\r\n", 9) == 0){
    // LED1(緑) : 点灯500mSec / 消灯500mSec
    GLB_uint16_Time_LED_Stat_ON = (uint16_t)500;
    GLB_uint16_Time_LED_Stat_OFF = (uint16_t)500;

    GLB_int16_Restart_LED_Stat = 1;  // Status LED再起動フラグON
  }


  // エコーバック
  for(uint16_I = 0; uint16_I < uint16_ReceiveLength; uint16_I++){
    puint8_SendData[uint16_I] = puint8_ReceiveData[uint16_I];
  }

  uint16_SendLength = uint16_ReceiveLength;

  return(uint16_SendLength);
}

  受信データを判定して、LED点滅コマンドだった場合、
 コマンドの内容に応じて、LEDの点滅時間を設定します。

  また、受診データをエコーバックします。


A+-2C (ええ加減にC) のページに戻る




 メールアドレス: apm2c.sumi@gmail.com

 なんでも、気軽に ご相談ください。
 担当:おの

マスコット
  えがおのでんし 案内