【STM32(nucleo)】標準入出力(printf、scanf)の設定方法【PlatformIO】

標準入出力コマンドprintfとscanfのSTM32での使用方法です

開発環境はPlatforIO+STM32CubeMXとなります

STM32(nucleo)開発環境構築(PlatformIO+STM32CubeMX)

まずはシリアル通信を設定する

マイコンボードにはPCのような入出力装置がないため入出力はシリアル通信にて構成します

PCなどに接続しtera termのようなターミナルソフトで表示/入力を行うといった感じです

シリアル通信の設定は以下記事で解説してますが、printfとscanfはそれら自体がブロッキング処理となりますのでシリアル通信も最も基本的なブロッキング処理での構成とします

【STM32(nucleo)】シリアル通信の使い方【PlatformIO】

syscalls.cをプロジェクトに追加する

printfとscanfの関数はSTM32のフレームワーク内に備わっているのでそれらの処理とシリアル通信の関連付けを行う必要があります

syscalls.cというソースファイルで1byteの入出力関数(__io_putchar、__io_getchar)が外部定義されているのでそれらの関数をシリアル通信の送受信処理として記述してやればOKです

しかし、IDEで作成したプロジェクトにはsyscalls.cが含まれるらしいのですが、STM32CubeMXで生成したファイルにはなぜか含まれません

PlatformIOのパッケージフォルダにも含まれていないので、仕方なく下記よりソースを拝借しました

syscalls.cはプロジェクトフォルダ内のCore/Srcフォルダ内に保存しました

__io_putchar関数と__io_getchar関数の作成

標準入出力処理を構成する1byteの入出力関数を作成します

今回はmain.cに作成しましたが、ファイルは分けた方が良いかもしれません

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int f getc(FILE* f)
#endif

void __io_putchar(uint8_t ch)
{
  HAL_UART_Transmit(&hlpuart1, &ch, 1, 0xFFFFFFFF);
}

int __io_getchar(void)
{
  uint8_t rxBuf;
  while(HAL_UART_Receive(&hlpuart1, &rxBuf, 1, 0xFFFFFFFF) != HAL_OK);
  return(rxBuf); 
}

printfとscanfをfloat型に対応させる

初期状態ではprintfとscanfの型指定にfloatを選ぶと正常に動作しないためオプションを変更する必要があります

以前下記記事で作成したextera_script.pyに設定を追記します(-u_printf_float、-u_scanf_float)

【STM32(nucleo)】PlatformIOでFPUを有効化する方法
Import("env")

#
# Dump build environment (for debug)
# print(env.Dump())
#

flags = [
    "-mfloat-abi=hard",
    "-mfpu=fpv4-sp-d16",
    "-u_printf_float",
    "-u_scanf_float"
]

env.Append(CCFLAGS=flags, LINKFLAGS=flags)

なお、extera_script.pyを編集してもPlatformIO側が再読み込みしてくれないことがある(というかほとんどそう)ため、platformio.iniを適当に上書き保存したりして読み込ませる必要があります

テスト用コードの作成、動作確認

テスト用にfloatの値の入出力を試してみました

初期設定としてsetbuf関数を実行する必要があります

なお、stdio.hのインクルードを忘れないようにしましょう

#include <stdio.h>

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* 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 */
  MX_GPIO_Init();
  MX_LPUART1_UART_Init();
  /* USER CODE BEGIN 2 */
  setbuf( stdout, NULL );
  setbuf( stdin, NULL );
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
    float fNum;
    while(1)
    {
      printf("\ninput float value = ");
      scanf("%f", &fNum);
      printf("your input value: %f\n", fNum);
    }
      
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

tera termにて正常に動作していることを確認しました

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA