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