用Visual Studio 2019 开发stm32,cortex-m3, arm

1.下载Visual Studio Community 2019

https://visualstudio.microsoft.com/zh-hans/vs/

2.添加vs上面的Linux工具,cmake工具,IOT开发工具 

3.stm32 工程配置

不推荐使用stm32 cubex 生成的makefile工程,因为我试过好多次编译出来的bin文件都不能运行,不知道为什么...

我这里用的芯片是STM32F103C8T6

所以需要用到stm32F1xx标准库:StdPeriph_Driver/inc, StdPeriph_Driver/src,这两个人文件夹里面的文件是所有外设的头文件和库

还要用到stm32F1系列系统文件 system_stm32f10x.c,system_stm32f10x.h,stm32f10x.h

此外需要用到cmsis内核文件

stm32给gcc用的启动文件 startup_stm32f103xb.s

stm32给gcc用的链接文件STM32F103C8Tx_FLASH.ld

我喜欢把系统文件都放到标准库里面去

新建user文件,把自己的main.c程序放进去,方便管理

4.启动vs2019

通过“打开本地文件夹(F)”来启动项目。

打开上面弄好的文件

4.点了“选择文件夹”后应该能看到,vs2019已经自动包含了里面的全部文件

5.添加CMakelits.txt

添加CMakelists.txt后,vs2019会自动配置cmake工程,同时会自行生成out文件夹,放工程信息

6.CMakelists.txt编写

设置工程名称, “#”相当于C语言里面的“//”,注释的意思

STM32_Templete是此次工程的名字

# Project name
project(STM32_Templete)

设置编译用的工具, arm-none-eabi-gcc是专门给arm开发的编译工具

set(AA BB)有点类似于#define AA BB,把AA 定义为BB,不过有些AA已经被编译器定义过了

# compiler tools
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_SIZE arm-none-eabi-size)

添加版本gcc说明

cmake_minimum_required(VERSION 3.15)

设置编译选项

-mcpu=cortex-m3,表明用cortex-m3内核的芯片

--specs=nano.specs --specs=nosys.specs,使用nano.specs,避免出来xx问题

-Os -g程序优化等级s级,可选-O0不优化,-O1,-O2,O3优化1,2,3

-Wall 全部警告

-ffunction-sections -fdata-sections给每个函数设置单独的空间,链接时不使用的函数不会链接,可以缩小代码体积

# compiler build flags
set(MCU_FLAGS "-mcpu=cortex-m3")
set(CMAKE_C_FLAGS "${MCU_FLAGS} --specs=nano.specs --specs=nosys.specs")
set(CMAKE_C_FLAGS_DEBUG "-Os -g -Wall -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELEASE "-Os")

选用DEBUG的选项

# cmake type
set(CMAKE_BUILD_TYPE "Debug")

添加头文件路径

把所有头文件的路径加进去

${CMAKE_CURRENT_SOURCE_DIR}是指根目录


include_directories(
    CMSIS
    StdPeriph_Driver/inc
    StdPeriph_Driver/src
    user
)

查找*.C文件

std_src存放所有标准库

user_src存放用户程序

# search *.c files
file(GLOB std_src StdPeriph_Driver\src*.c)
file(GLOB user_src user/*.c)

把找到的文件打包成静态库,std,user

# Drivers
add_library(
    std
    ${std_src}
)
# main source file
add_library(
    user
    ${std_src}
)

单独打包启动文件

# startup file
enable_language(ASM)
add_library(startup startup_stm32f103xb.s)
set_property(SOURCE startup_stm32f103xb.s PROPERTY LANGUAGE C)

设置链接文件

# linker script
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/STM32F103C8Tx_FLASH.ld)

设置链接选项

#link flags
#set(link_extraFlag "-u _sbrk -u link -u _close -u _fstat -u _isatty -u _lseek -u _read -u _write -u _exit -u kill -u _getpid ")
set(link_extraFlag "-lc -lm -lgcc -lnosys")
set(CMAKE_EXE_LINKER_FLAGS
"${link_extraFlag} -T${LINKER_SCRIPT} -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map,--cref -Wl,--gc-sections -Wl,--entry=Reset_Handler"
)

 链接时加入“ -Wl,--print-memory-usage ”编译器会输出内存使用情况

  Memory region         Used Size  Region Size  %age Used
             FLASH:      120305 B       252 KB     46.62%
      FLASH_CONFIG:          0 GB         4 KB      0.00%
               RAM:       18396 B        40 KB     44.91%
               CCM:          2 KB         8 KB     25.00%

设置链接查找路径

# link directories
link_directories(
    CMSIS
    StdPeriph_Driver
    StdPeriph_Driver\inc
    StdPeriph_Driver\src
    user
)

设置要链接的库,前面打包好的静态库

#link librarise
link_libraries(
    startup
    std    
    user    
)

添加可执行文件,main函数所在的文件

#generate excutable file
add_executable(${PROJECT_NAME}.elf user/main.c)

设置输出文件,bin,hex,elf, hex输出有bug,咱不要了.(GNU Tools Arm Embedded更新至gcc version 9.2.1 20191025可解决生成hex问题)

#output hex and bin file
set(ELF_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf)
set(HEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.bin)

生成并计算输出文件大小

#build hex and bin file and display size
add_custom_command(TARGET "${PROJECT_NAME}.elf" POST_BUILD
    COMMAND ${CMAKE_OBJCOPY} -Obinary ${ELF_FILE} ${BIN_FILE}
    #COMMAND ${CMAKE_OBJCOPY} -Oihex  ${ELF_FILE} ${HEX_FILE}
    COMMENT "Building ${PROJECT_NAME}.bin and ${PROJECT_NAME}.hex"

    #COMMAND ${CMAKE_COMMAND} -E copy ${HEX_FILE} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.hex"
    COMMAND ${CMAKE_COMMAND} -E copy ${BIN_FILE} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"

    COMMAND ${CMAKE_SIZE} --format=berkeley ${PROJECT_NAME}.elf
    COMMENT "Invoking: Cross ARM GNU Print Size"
)

7.把工程设置为IOT工程

删除不是IOT的是

添加IOT

最后记得“Ctrl + S”保存!!!!!!!!!!!!!!

回到CMakelists.txt

再按一次Ctrl + S,看到这个就配置成功了

下面是CMakelists.txt的所有代码

# Project name
project(STM32_Templete)

cmake_minimum_required(VERSION 3.15)

# compiler tools
set(CMAKE_OBJCOPY arm-none-eabi-objcopy)
set(CMAKE_SIZE arm-none-eabi-size)

# compiler build flags
set(MCU_FLAGS "-mcpu=cortex-m3")
set(CMAKE_C_FLAGS "${MCU_FLAGS} --specs=nano.specs --specs=nosys.specs")
set(CMAKE_C_FLAGS_DEBUG "-Os -g -Wall -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELEASE "-Os")

# cmake type
set(CMAKE_BUILD_TYPE "Debug")

# include path
include_directories(
	CMSIS
	StdPeriph_Driver/inc
	StdPeriph_Driver/src
	user
)

# search *.c files
file(GLOB std_src StdPeriph_Driver/src/*.c)
file(GLOB user_src user/*.c)

# Drivers
add_library(
	std
	${std_src}
)
# main source file
add_library(
	user
	${std_src}
)

# startup file
enable_language(ASM)
add_library(startup startup_stm32f103xb.s)
set_property(SOURCE startup_stm32f103xb.s PROPERTY LANGUAGE C)

# linker script
set(LINKER_SCRIPT ${CMAKE_CURRENT_SOURCE_DIR}/STM32F103C8Tx_FLASH.ld)

#link flags
#set(link_extraFlag "-u _sbrk -u link -u _close -u _fstat -u _isatty -u _lseek -u _read -u _write -u _exit -u kill -u _getpid ")
set(link_extraFlag "-lc -lm -lgcc -lnosys")
set(CMAKE_EXE_LINKER_FLAGS
"${link_extraFlag} -T${LINKER_SCRIPT} -Wl,-Map=${PROJECT_BINARY_DIR}/${PROJECT_NAME}.map,--cref -Wl,--gc-sections -Wl,--entry=Reset_Handler"
)

# link directories
link_directories(
    CMSIS
    StdPeriph_Driver/inc
    StdPeriph_Driver/src
	user
)

#link librarise
link_libraries(
	startup
	std	
	user	
)

#generate excutable file
add_executable(${PROJECT_NAME}.elf user/main.c)

#output hex and bin file
set(ELF_FILE ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf)
set(HEX_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.hex)
set(BIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.bin)

#build hex and bin file and display size
add_custom_command(TARGET "${PROJECT_NAME}.elf" POST_BUILD
    COMMAND ${CMAKE_OBJCOPY} -Obinary ${ELF_FILE} ${BIN_FILE}
    #COMMAND ${CMAKE_OBJCOPY} -Oihex  ${ELF_FILE} ${HEX_FILE}
    COMMENT "Building ${PROJECT_NAME}.bin and ${PROJECT_NAME}.hex"

    #COMMAND ${CMAKE_COMMAND} -E copy ${HEX_FILE} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.hex"
    COMMAND ${CMAKE_COMMAND} -E copy ${BIN_FILE} "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.bin"

    COMMAND ${CMAKE_SIZE} --format=berkeley ${PROJECT_NAME}.elf
    COMMENT "Invoking: Cross ARM GNU Print Size"
)

8.开始编程

按生成

不出意外的话,会有一堆问题,

可以在CMakelists.txt 那时加入声明,对了,忘了stm32的库要加入型号说明的,

#define STM32F10X_MD 

#define USE_STDPERIPH_DRIVER

# mcu definitions
add_definitions(
    -DSTM32F10X_MD
    -DUSE_STDPERIPH_DRIVER
)

头文件里面还要添加RTE_Components.h,stm32f10x_conf.h,添加完成后需要在CMakelists.txt那里再点一次生成,每次添加新文件后都让,CMakelists.txt重新生成一次

再试下生成,就应该没问题了

根目录下也能看到生成的Bin文件

最后写个Printf函数

由于GCC没有提供_write(),和keil里面重定义putchar不一样的是,要重定义_write()

int _write(int fd, char* ptr, int len)
{
    uint16_t count = 0;
    count = len;
    usart_sendNbytes((uint8_t*)ptr, len);
    return count;
}

下面main.c的完整代码

#include "stm32f10x.h"
#include <stdio.h>
int _write(int fd, char* ptr, int len);
void RCC_Configuration(void)//时钟配置,8MHz晶振,72MHz系统时钟
{
	ErrorStatus HSEStartUpStatus;
	/* RCC system reset(for debug purpose) */
	RCC_DeInit();

	/* Enable HSE */
	RCC_HSEConfig(RCC_HSE_ON);


	while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET);
	/* Wait till HSE is ready */
	HSEStartUpStatus = RCC_WaitForHSEStartUp();

	if (HSEStartUpStatus == SUCCESS)
	{
		/* Enable Prefetch Buffer */
		FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

		/* Flash 2 wait state */
		FLASH_SetLatency(FLASH_Latency_2);

		/* HCLK = SYSCLK */
		RCC_HCLKConfig(RCC_SYSCLK_Div1);

		/* PCLK2 = HCLK */
		RCC_PCLK2Config(RCC_HCLK_Div1);

		/* PCLK1 = HCLK/2 */
		RCC_PCLK1Config(RCC_HCLK_Div2);

		/* PLLCLK = 8MHz * 9 = 72 MHz */
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

		/* Enable PLL */
		RCC_PLLCmd(ENABLE);

		/* Wait till PLL is ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
		{
		}

		/* Select PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		/* Wait till PLL is used as system clock source */
		while (RCC_GetSYSCLKSource() != 0x08)
		{
		}
	}
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);// 串口 PORTA时钟
	//RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);// 串口时钟
	//RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
}
void GPIO_Configuration(void)
{
	//USART1
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void USART1_Configuration(uint32_t buadrate)
{
	USART_InitTypeDef USART_InitStructure;
	USART_InitStructure.USART_BaudRate = buadrate;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &USART_InitStructure);
	USART_Cmd(USART1, ENABLE);
}
void usart_sendByte(uint8_t b)
{
	USART_SendData(USART1, b);
	while (USART_GetFlagStatus(USART1, USART_FLAG_TC) != SET);
	USART_ClearFlag(USART1, USART_FLAG_TC);
}
void usart_sendBytes(uint8_t* bs)
{
	while (*bs)
	{
		usart_sendByte(*bs++);
	}
}
uint16_t usart_sendNbytes(uint8_t* bytes, uint16_t len)
{
	while (len--)
	{
		usart_sendByte(*bytes++);
	}
	return len;
}
int _write(int fd, char* ptr, int len)
{
	uint16_t count = 0;
	count = len;
	usart_sendNbytes((uint8_t*)ptr, len);
	return count;
}
void main()
{
	RCC_Configuration();
	GPIO_Configuration();
	USART1_Configuration(115200);
	printf("All system ready!\n\n");
	while (1)
	{
		printf("Hello world\n");
	}
}

实际运行情况

下面是工程例程

http://download.csdn.net/download/u013866683/11998012

lalala

猜你喜欢

转载自blog.csdn.net/u013866683/article/details/103242378