VSCode+GCC开发STM32


前言

目前主流开发STM32的工具有Keil等工具,但个人认为其界面复杂,操作繁琐,导致开发效率低下。故自行寻找STM32提供的交叉编译工具的使用方法,自行搭建交叉编译环境,进行STM32的开发,后续也可沿用此方法进行其他嵌入式的开发,


提示:这一套开发环境使用工具有VSCode,Make,WSL/Centos,arm-none-eabi-gcc。其中前三者的安装过程在这里不再赘述。
提示:WSL/CentOS在本文中统一名称为编译服务器
arm-none-eabi-gcc的安装请点击这里

一、准备好官方提供的库文件

在例程中,本人使用STM32C8T6开发,故下载ST官网提供相关的库函数包。
官网地址为:https://www.st.com/en/embedded-software/stm32-embedded-software.html
打开后选择标准库
在这里插入图片描述
随后找到自己开发板对应的型号
在这里插入图片描述
最后下载并解压,文件夹内容如下
在这里插入图片描述

二、创建工作目录

在编译服务器中,创建好文件夹,并在文件夹中创建user目录和Makefile文件,再把官方库文件的Libraries复制过来,我的目录如下:
在这里插入图片描述

三、编写相关文件

1.在user目录中编写main.c文件,用来进行最终的效果测试

本人使用的是stm32c8t6最小系统板,使用led灯闪烁例程进行测试。
代码如下(示例):

/**
 ******************************************************************************
 * @file    Project/STM32F10x_StdPeriph_Template/main.c
 * @author  MCD Application Team
 * @version V3.6.0
 * @date    20-September-2021
 * @brief   Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2011 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 "stm32f10x_conf.h"
#include "stm32f10x.h"
#include <stdio.h>

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 
#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 
#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 
#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 
#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入
#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入
#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
void GPIO_Configuration(void);
//=============================================================================
//文件名称:Delay
//功能概要:延时
//参数说明:nCount:延时长短
//函数返回:无
//=============================================================================
void Delay(uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}
/**
 * @brief  Main program.
 * @param  None
 * @retval None
 */
int main(void)
{
    GPIO_Configuration();
    while (1)
    {
        PCout(13) = 1;
        Delay(0xfffff);
        Delay(0xfffff);
        PCout(13) = 0;
        Delay(0xfffff);
        Delay(0xfffff);
    }
}
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE); 						 
//=============================================================================
//LED -> PC13
//=============================================================================			 
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
  GPIO_Init(GPIOC, &GPIO_InitStructure);
}

/**
 * @brief  Retargets the C library printf function to the USART.
 * @param  None
 * @retval None
 */

#ifdef USE_FULL_ASSERT

/**
 * @brief  Reports the name of the source file and the source line number
 *         where the assert_param error has occurred.
 * @param  file: pointer to the source file name
 * @param  line: assert_param error line source number
 * @retval None
 */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

    /* Infinite loop */
    while (1)
    {
    }
}
#endif

/**
 * @}
 */

2.stm32f10x_conf.h

把库文件的stm32f10x_conf.h 复制到user目录中。该文件在
STM32F10x_StdPeriph_Lib_V3.6.0\Project\STM32F10x_StdPeriph_Template
目录下。

3.stm32f10x_flash_extsram.ld

在Makefile平级的目录中自行创建该文件,该文件用于交叉编译的链接阶段,规定flash、ram等大小。

若使用的芯片不同,则该文件的内容不同

/* Default linker script for STM32F103C8T6 */
MEMORY
{
  /* STM32F103C8T6 内存区域 */
  RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}

__Stack_Size = 1024;                /* 默认栈大小 */
PROVIDE ( _Stack_Size = __Stack_Size );

__Stack_Init = _estack - __Stack_Size;
PROVIDE ( _Stack_Init = __Stack_Init );
_Minimum_Stack_Size = 0x100;
_estack = 0x20005000;                /* 栈的高地址,接近 RAM 的顶部 */

/* 代码段和数据段的定义 */
SECTIONS
{
    /* 启动代码和中断向量表 */
    .isr_vector :
    {
        . = ALIGN(4);
        KEEP(*(.isr_vector))          /* 中断向量表 */
        . = ALIGN(4);
    } >FLASH

    /* 程序代码段,放在 Flash 中 */
    .text :
    {
        . = ALIGN(4);
        *(.text)                     /* 程序代码 */
        *(.text.*)                   /* 其他代码 */
        *(.rodata)                  /* 只读数据(常量) */
        *(.rodata*)
        . = ALIGN(4);
        _etext = .;
        _sidata = _etext;            /* 用于初始化数据段 */
    } >FLASH

    /* 初始化数据段 */
    .data : AT (_sidata)
    {
        . = ALIGN(4);
        _sdata = .;
        *(.data)                    /* 初始化数据 */
        *(.data.*)
        . = ALIGN(4);
        _edata = .;
    } >RAM

    /* 未初始化的数据段 */
    .bss :
    {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)
        *(COMMON)
        . = ALIGN(4);
        _ebss = .;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );

    /* 用户栈 */
    ._usrstack :
    {
        . = ALIGN(4);
        _susrstack = . ;
        . = . + _Minimum_Stack_Size ;  /* 最小栈大小 */
        . = ALIGN(4);
        _eusrstack = . ;
    } >RAM

    /* 丢弃调试信息 */
    DISCARD :
    {
        libc.a (*)
        libm.a (*)
        libgcc.a (*)
    }

    /* 调试信息(可选) */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
}

4.编写Makefile文件

注意:在这里我把库文件的目录改为stm32f10x_lib
最终目录结构如下:
最终如下
Makefile文件内容如下

# toolchain
TOOLCHAIN    = arm-none-eabi-
CC           = $(TOOLCHAIN)gcc
CP           = $(TOOLCHAIN)objcopy
AS           = $(TOOLCHAIN)gcc -x assembler-with-cpp
# all the files will be generated with this name (main.elf, main.bin, main.hex, etc)
PROJECT_NAME=stm32f10x_project

# define include dir
INCLUDE_DIRS =

# define stm32f10x lib dir
STM32F10x_LIB_DIR      = ./stm32f10x_lib

# define user dir
USER_DIR     = ./user

# link file
LINK_SCRIPT  = ./stm32f10x_flash_extsram.ld

# user specific
SRC       =
ASM_SRC   =
SRC      += $(USER_DIR)/main.c
# user include
INCLUDE_DIRS  = 

# source director
STM32F1_STD_LIB     = $(STM32F10x_LIB_DIR)/STM32F10x_StdPeriph_Driver
STM32F1_CORE_DIR    = $(STM32F10x_LIB_DIR)/CMSIS/CM3/CoreSupport
STM32F1_DEVICE_DIR  = $(STM32F10x_LIB_DIR)/CMSIS/CM3/DeviceSupport/ST/STM32F10x
STM32F1_SRC_DIR     = $(STM32F1_STD_LIB)/src
STM32F1_INC_DIR     = $(STM32F1_STD_LIB)/inc

# startup
ASM_SRC  += $(STM32F1_DEVICE_DIR)/startup/gcc_ride7/startup_stm32f10x_md.s

# CMSIS
SRC  += $(STM32F1_DEVICE_DIR)/system_stm32f10x.c
SRC  += $(STM32F1_CORE_DIR)/core_cm3.c

# use libraries, please add or remove when you use or remove it.
SRC  += $(STM32F1_SRC_DIR)/stm32f10x_rcc.c
SRC  += $(STM32F1_SRC_DIR)/stm32f10x_gpio.c
SRC  += $(STM32F1_SRC_DIR)/stm32f10x_exti.c
SRC  += $(STM32F1_SRC_DIR)/stm32f10x_usart.c
SRC  += $(STM32F1_SRC_DIR)/misc.c

# include directories
INCLUDE_DIRS += $(STM32F1_CORE_DIR)
INCLUDE_DIRS += $(STM32F1_DEVICE_DIR)
INCLUDE_DIRS += $(STM32F1_INC_DIR)
INCLUDE_DIRS += $(STM32F1_STD_LIB)
INCLUDE_DIRS += $(USER_DIR)
INC_DIR  = $(patsubst %, -I%, $(INCLUDE_DIRS))
OBJECTS  = $(ASM_SRC:.s=.o) $(SRC:.c=.o)

# Define optimisation level here
MC_FLAGS = -mcpu=cortex-m3
AS_FLAGS = $(MC_FLAGS) -g -gdwarf-2 -mthumb  -Wa,-amhls=$(<:.s=.lst)
CP_FLAGS = $(MC_FLAGS) -Os -g -gdwarf-2 -mthumb -fomit-frame-pointer -Wall -fverbose-asm -Wa,-ahlms=$(<:.c=.lst) 
LD_FLAGS = $(MC_FLAGS) -g -gdwarf-2 -mthumb -nostartfiles -Xlinker --gc-sections -T$(LINK_SCRIPT) -Wl,-Map=$(PROJECT_NAME).map,--cref,--no-warn-mismatch

# makefile rules
all: $(OBJECTS) $(PROJECT_NAME).elf  $(PROJECT_NAME).hex $(PROJECT_NAME).bin
	$(TOOLCHAIN)size $(PROJECT_NAME).elf

%.o: %.c
	$(CC) -c $(CP_FLAGS) -I . $(INC_DIR) $< -o $@

%.o: %.s
	$(AS) -c $(AS_FLAGS) $< -o $@

%.elf: $(OBJECTS)
	$(CC) $(OBJECTS) $(LD_FLAGS) -o $@

%.hex: %.elf
	$(CP) -O ihex $< $@

%.bin: %.elf
	$(CP) -O binary -S  $< $@

clean:
	rm -f $(OBJECTS) $(PROJECT_NAME).elf $(PROJECT_NAME).bin $(PROJECT_NAME).hex $(PROJECT_NAME).map $(PROJECT_NAME).lst
	rm -f $(STM32F10x_LIB_DIR)/**/*.lst $(USER_DIR)/**/*.lst
# del /Q  $(PROJECT_NAME).elf $(PROJECT_NAME).hex $(PROJECT_NAME).bin


5.相关文件的修改

如果这时候编译会报相关错误。
在stm32f10x_lib/CMSIS/CM3/DeviceSupport/ST/STM32F10x/目录下找到stm32f10x.h文件,找到67行把#define STM32F10X_MD一行注释掉不同的芯片这里解除注释的内容不同
找到该文件104行,解除掉#define USE_STDPERIPH_DRIVER的注释
找到stm32f10x_lib/CMSIS/CM3/CoreSupport下的core_cm3.c文件,736行和753行,改为如下代码

__ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
__ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );

6.最后使用Make编译

成功的结果如下,可以烧录进行测试
在这里插入图片描述


例程模板在https://gitee.com/iFENG-123/template-stm32

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值