VSCode和STM32CubeMX的最简单步骤教程,实现STM32优雅开发

配置安装环境

  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 #新增这个选项

    物联沃分享整理
    物联沃-IOTWORD物联网 » VSCode和STM32CubeMX的最简单步骤教程,实现STM32优雅开发

    发表评论