基于 VsCode + GCC + STM32 环境下的串口输入输出重定向

文章讲述了在GCC编译环境下,如何将printf函数的输出重定向到STM32的串口,以实现嵌入式产品的调试。通过定义int_write函数并使用HAL_UART_Transmit进行串口传输来实现这一功能。同时,文章也提到了其他IDE如Keil、IAR的重定向方法以及MicroLib的使用。
摘要由CSDN通过智能技术生成

串口是 MCU 最重要的一个通信端口,几乎所有的嵌入式产品都会用到串口,产品预研时的调试、与外设之间的通信、产品固件升级。虽然直接使用串口输入输出字符也可以,但是考虑到不定长的字符发送代码编写的便携性,固然会运用到 printfvsprintf 等重定向。

打印调试最常用的方法是printf,所以要解决的问题是将printf的输出重定向到串口,然后通过串口将数据发送出去。

本文探讨的是 GCC 编译环境下的输入输出重定向,关于 Keil、IAR等IDE的输入输出网上一大堆,不再赘述。

串口初始化配置

首先要配置串口,串口的配置包括:

  1. 开启串口和GPIO时钟
  2. GPIO引脚模式配置
  3. 串口波特率、数据位、停止位、校验位的配置
  4. 列表项目
  5. 使能串口

不同编译环境下的输入/输出重定向

在 gcc环境下,printf重定向跟以往的在 IDE上的重定向有点不同。

  • Keil、IAR等 IDE上面,都是用以下方式重定向的:
int fputc(int ch, FILE *f)
int fgetc(FILE *f)
  • gcc环境下,使用的是如下方式:
int _write(int file, char *ptr, int len)
int _read(int file, char *ptr, int len)

因此,重新定义上述相关函数即可。

解决方式

均为阻塞式,超时无限等待标志位置位。

/**
 * @brief 阻塞式重定向 C 标准库 printf 函数到串口 huart1
 * 适用于 GCC
 * @author Suroy
 * @param ptr 
 * @param fd 
 * @return int 
 * 
 * @usage printf("USART1_Target:\r\n");
 */
int _write(int fd, char *ptr, int len)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)ptr, len, 0xFFFF); //huart是对应串口
    return len;
}

以下未测试:

/* 输出重定向 printf */
int __io_putchar(int ch){
    uint8_t temp[1]={ch};
    HAL_UART_Transmit(&huart1,temp,1,0xff);
    return (ch);
}

通用版 syscall.c [已移植]

直接调用即可,推荐使用;**未测试 Keil 环境!**理论通用
修改之 STMCubeMX 生成的 CubeIDE 串口工程,在 MacOS 下基于 VsCode + EmbededIDE + GCC 去编译冲突,重定向printf、scanf。

/**
 ******************************************************************************
 * @file      syscalls.c
 * @author    Suroy Wrote with Auto-generated by STM32CubeIDE 
 * @url       https://suroy.cn
 * @brief     STM32CubeIDE Minimal System calls file
 *
 *            For more information about which c-functions
 *            need which of these lowlevel functions
 *            please consult the Newlib libc-manual
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2020-2022 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */

/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
#include "usart.h"


/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));



/* Functions */

__attribute__((weak)) int _read(int file, char *ptr, int len)
{
  (void)file;
  int DataIdx;

  for (DataIdx = 0; DataIdx < len; DataIdx++)
  {
    *ptr++ = __io_getchar();
  }

  return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
  (void)file;
  int DataIdx;

  for (DataIdx = 0; DataIdx < len; DataIdx++)
  {
    __io_putchar(*ptr++);
  }
  return len;
}



// 条件编译
#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 fgetc(FILE *f)
#endif /* __GNUC__ */


/**
  * 函数功能: 重定向 c库函数 printf到 DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); //阻塞式无限等待
  return ch;
}


/**
  * 函数功能: 重定向 c库函数 getchar,scanf到 DEBUG_USARTx
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明:无
  */
GETCHAR_PROTOTYPE
{
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xFFFF);
    
  return ch;
}



/* 非GCC模式才允许编译使用即 Keil、IAR 等 */
#ifndef __GNUC__

/**
 * @brief 重定向 C 标准库 printf 函数到串口 huart1
 * 适用于 Keil、IAR 等IDE;不适用 GCC
 * @author Suroy
 * @param ch 
 * @param f 
 * @return int 
 * 
 * @usage printf("USART1_Target:\r\n");
 */
int fputc(int ch, FILE *f)
{
    //采用轮询方式发送1字节数据,超时时间为无限等待
    HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY); //huart1是串口的句柄 
    return ch;
}

/**
 * @brief fgets 重定向
 * 重定向 C 标准库 scanf 函数到串口 huart1
 * 注意以 空格 为结束
 * @param f 
 * @return int 
 * 
 * @usage scanf("%c", &RecData);
 */
int fgetc(FILE *f)
{
  uint8_t ch;
  HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); //huart1是串口的句柄 
  return ch;
}

#endif /* __GNUC__ */


注意:阻塞式收发会出现程序卡顿问题,建议采用中断运行;若的确需要此模式,建议更改最大超时时间。

Keil、IDE 下的重定向

记得勾选魔术棒处 MicroLib

/**
 * @brief 重定向 C 标准库 printf 函数到串口 huart1
 * 适用于 Keil、IAR 等IDE;不适用 GCC
 * @author Suroy
 * @param ch 
 * @param f 
 * @return int 
 * 
 * @usage printf("USART1_Target:\r\n");
 */
int fputc(int ch, FILE *f)
{
    //采用轮询方式发送1字节数据,超时时间为无限等待
    HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,HAL_MAX_DELAY); //huart1是串口的句柄 
    return ch;
}

/**
 * @brief fgets 重定向
 * 重定向 C 标准库 scanf 函数到串口 huart1
 * 注意以 空格 为结束
 * @param f 
 * @return int 
 * 
 * @usage scanf("%c", &RecData);
 */
int fgetc(FILE *f)
{
  uint8_t ch;
  HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY); //huart1是串口的句柄 
  return ch;
}

博客原文: https://suroy.cn/embeded/serial-port-inputoutput-redirection-based-on-vscode-gcc-stm32-environment.html

参考资料:

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zsuroy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值