vscode stm32cubemx 优雅开发stm32,最简单步骤教程

本文详细介绍了如何配置STM32的开发环境,包括STM32cubeMX、VSCode、arm-none-eabi-gcc、MinGW-w64和OpenOCD的下载与安装。通过STM32cubeMX创建工程,配置SWD调试、外部晶振、LED和串口。然后在VSCode中安装C/C++Cortex-Debug和STM32-for-VSCode插件,实现编译、烧录和调试功能。最后,文章提到了如何处理C++中的printf和iostream问题,以及解决_exit报错的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

配置安装环境

  1. 下载STM32cubeMX,这个大家可以自己在stm的官网下载到
  2. 下载VSCode
  3. 下载arm-none-eabi-gcc
  4. 下载MinGW-w64,为了实现里面的makefile 等功能
  5. 下载OpenOCD这里用来调试stm32,支持jlink stlink daplink

上述安装步骤1、安装步骤2在这里比较简单,就不赘述了

安装arm-none-eabi-gcc:

 此处我们下载zip包,方便安装。

以我为例,我们解压到 E:\Tools\ 目录下

安装MinGW-w64

此处我们同样下载zip包,安装比较方便,注意一定要安装上述划线的版本

 以我为例,我们解压到 E:\Tools\ 目录下

安装openocd

 此处我们下载最新的版本

以我为例,我们解压到 E:\Tools\ 目录下

通过stm32cubemx新建一个例程

这里以我的开发板为例,使用的是stm32f407vgt6,我们创建一个工程

配置一下SWD调试

 配置外部8mhz晶振

 配置PA1,用作测试LED

 配置usart1作为串口输出测试

 

 配置时钟,完成最后一步工作

 这里我们选择makefile,即可,点击generate code

通过vscode 生成刚刚用stm32cubemx 创建的工程

 在这里,我们在扩展中找到插件并安装

  • C/C++
  • Cortex-Debug
  • stm32-for-vscode

 刚刚下载的工具我都放在这个目录了,如图所示

 

 为了使用方便,我稍微改下名字

这样就舒服多了

 安装好stm32-for-vscode以后,我们会发现侧边栏增加了一个图标:

 按照上述提示,我们导入相应的工具

这里已经配置成我的路径了

重新打开vscode,即可看到变化

几个选项分别为

  • 编译
  • 全编译
  • 烧录到stm32
  • 调试stm32
  • 修改下载工具

 我简单演示一下,首先我们选择自己的编译工具,例如我这边使用的是dap-link

 我们看到这里已经选择成功了,那么我们先点击build

 已经生成成功了,我们看到编译速度是keil的指数级的提升

我们点击flash stm32,即可看到已经下载成功了!

最基本的操作已经可以了,编译下载一条龙,那么接下来我们试试调试功能。

 使用vscode调试

我们在代码里简单添加一些代码,作为调试的现象

不出意外的话,我们可以在debug中观察到i的变化

那么我们来试一下吧,点击build,再点击 debug在 printf 处添加断电

可以看到我们已经进入到调试的模式了,那么我们新增一个监视来监视i

 

 此时i的值为0,我们在全速运行两次次试试

 

可以看到,我们已经有i的值的变化,也在串口输出了值,符合我们的预期

这种开发方式已经可以替代keil了 

最后小结

那么我们知道,在keil中调用printf 只需要在前面增加putc函数即可,那在这种开发方式中,我们如何添加函数,使得可以printf。

很简单,只需要将下述代码复制到头,并且包含stdio.h即可

int _write(int fd, char *ch, int len)
{
  HAL_UART_Transmit(&huart1, (uint8_t*)ch, len, 0xFFFF);
  return len;
}

进一步更新使用C++

如果使用C++来编写工程的话,我们发现本来的printf不行了,怎么回事呢

很简单,这里借鉴可以新增两个文件 target.h,插入一下内容

#ifndef _RETARGET_H__
#define _RETARGET_H__
#include "stm32f4xx_hal.h"
#include <sys/stat.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C" {
#endif

void RetargetInit(UART_HandleTypeDef *huart);
int _isatty(int fd);
int _write(int fd, char *ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char *ptr, int len);
int _fstat(int fd, struct stat *st);

#ifdef __cplusplus
}
#endif

#endif //#ifndef _RETARGET_H__

再新增一个target.c

#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <retarget.h>
#include <stdint.h>
#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

UART_HandleTypeDef *gHuart;

void RetargetInit(UART_HandleTypeDef *huart)
{
    gHuart = huart;
    /* Disable I/O buffering for STDOUT stream, so that
     * chars are sent out as soon as they are printed. */
    setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd)
{
    if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
        return 1;
    errno = EBADF;
    return 0;
}
int _write(int fd, char *ptr, int len)
{
    HAL_StatusTypeDef hstatus;
    if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
    {
        hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
        if (hstatus == HAL_OK)
            return len;
        else
            return EIO;
    }
    errno = EBADF;
    return -1;
}
int _close(int fd)
{
    if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
        return 0;
    errno = EBADF;
    return -1;
}
int _lseek(int fd, int ptr, int dir)
{
    (void) fd;
    (void) ptr;
    (void) dir;
    errno = EBADF;
    return -1;
}
int _read(int fd, char *ptr, int len)
{
    HAL_StatusTypeDef hstatus;
    if (fd == STDIN_FILENO)
    {
        hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
        if (hstatus == HAL_OK)
            return 1;
        else
            return EIO;
    }
    errno = EBADF;
    return -1;
}
int _fstat(int fd, struct stat *st)
{
    if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    {
        st->st_mode = S_IFCHR;
        return 0;
    }
    errno = EBADF;
    return 0;
}
#endif //#if !defined(OS_USE_SEMIHOSTING)

就可以继续使用print了,甚至是cout也完全没有问题

  while (1)
  {
    /* USER CODE END WHILE */
    printf("test i = %d \n", i++);
    std::cout << 123 << std::endl;
    HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
    HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }

面对_exit等报错,我们这里需要在STM32-for-VSCode.config.yaml这个文件中新增选项,就可以没有报错了

# Compiler flags
cFlags: []
cxxFlags: []
assemblyFlags: []
linkerFlags: 
  - -specs=nano.specs
  - -Wl,--gc-sections
  - -ffreestanding -flto
  - -specs=nosys.specs #新增这个选项

### 使用 VSCode 和 Keil 进行 STM32 开发 #### 安装 Keil 工具 Keil 是一款广泛应用于嵌入式系统的集成开发环境 (IDE),尤其适合 ARM 架构微控制器的开发。为了使用 Keil 编译 STM32 项目,在安装过程中需注意选择合适的版本并完成注册激活过程[^1]。 #### 下载与安装 Visual Studio Code Visual Studio Code (简称 VSCode) 是由微软开发的一款轻量级源代码编辑器,支持多种编程语言及其扩展功能。对于 STM32开发而言,VSCode 提供了一个灵活且高效的编码平台。用户可以从官方网站获取最新版的应用程序,并按照提示逐步完成安装操作。 #### 配置 VSCode 插件 为了让 VSCode 能够更好地支持 STM32 开发工作流,建议安装一些必要的插件来增强其功能: - **C/C++ 扩展包**: 提供语法高亮显示、智能感知等功能; - **STM32CubeMX Integration**: 方便导入通过 STMCubeMX 创建好的工程文件; 这些插件可以通过访问 Extensions Marketplace 来查找并一键安装。 #### 在 VSCode 中配置 Keil 支持 要使 VSCode 能识别来自 Keil 的编译命令,则需要做如下设置: - 设置 `PATH` 环境变量指向 Keil 的安装目录下的 `\ARM\bin` 文件夹路径; - 修改 `.vscode/settings.json` 文件加入以下内容以指定 CMakeLists.txt 或 Makefile 的位置: ```json { "cmake.configureSettings": { "generator": "MinGW Makefiles", "buildType": "Debug" } } ``` 此外还需确保已正确设置了交叉编译器的相关参数以便于后续链接库文件时不会出现问题[^2]。 ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值