提示

  文章中操作基于Keil MDK5.23、STM32F1和标准库V3.5,建议读者阅读前确保自己已经安装好Keil和STM32F1系列的Pack。

  同时,如果希望照着本文操作的话,请准备好标准库的库文件,可在官网下载,地址:链接,下载需要注册,嫌麻烦也可以找别人分享的资源。

(这里也给出一份:链接

  另外,本教程是为校科协电子部的Birch系列开发板准备的配套文档之一,所以,使用STM32F103C8T6这颗芯片进行演示。

写在前面

  在网上搜索STM32新建工程模板的方法的话,大部分教程都比较繁琐,主要原因在于大部分人只是照抄官方的指南、原子或者野火的教程什么的,甚至不明白自己在搬运一些什么文件,自然不会去想着简化步骤。

  但是已经0202年了嘛,各种开发工具越来越强大,开发者在实现想法时需要面对的困难应该越来越少才是(合理使用工具的话)。所以呢,在这里我准备分享一下这段时间总结的一个快速建立工程模板的方法。

步骤

一、新建文件夹

  • 首先,新建一个文件夹来存放我们的工程模板。起个描述用途的名字,比如“F103_Template”什么的。
  • 然后,打开新建的文件夹,在里面新建“Doc”“Lib”“Project”“User”四个文件夹分别用于存放用户添加的文档、库文件、工程文件、用户代码等等

P1.jpg

二、新建工程

  • 打开Keil,依次选择“Project -> New uVision Project”
  • 然后呢,会弹出一个窗口,用于指定工程文件的所在目录和名称,选择我们之前建立的“Project”文件夹,然后,给工程文件起个“容易从名称上明白含义含义”的名字,比如“F103_Template”什么的,保存。
  • 然后你会看到这样的界面,在这里,应当选择一个芯片型号,以便IDE为你准备芯片需要的启动文件等等。

P2.jpg

显然,为了方便,应该在Search后面的框内输入信息以搜索自己需要的型号而不是点加号展开列表慢慢找。

P3.jpg

选中后点击OK确认。

  • 然后会来到配置运行时环境的界面,在一般的新建工程教程中,大部分藏得很深的、要在文件夹里翻找半天才能看见的文件基本都是和芯片的内核、启动、各项配置等相关的,合理配置运行时环境可以大大简化这一步骤。

    (如图勾选然后确认即可,作用是添加内核相关的文件和启动相关的文件)

P4.jpg

(其实在这个界面下可以直接勾选需要的组件来配置标准外设库,但是由于库文件不会被复制到工程中,有时会出一些问题。而选择Core和Startup时,Keil软件会在工程文件所在文件夹(我们之前建立的“Project”)下新建一个“RTE”文件夹并复制相关资源到这里,所以工程移动到其他安装合适版本的Keil的PC上之后这部分也能正常编译)

三、分组、添加文件

  • 之前建立文件夹的时候是给文件分了类的,但是,刚刚建立的工程里面可没有我们规整的划分,打开一看,孤零零一个“Target_1”,(点加号)展开是下面这样的:

P5.jpg

嗯,不对劲,得改。

  • 所以,在"Target_1"那里单击右键,然后选择“Manage Project Items”

P6.jpg

  • 弹出一个这样的界面,在这里管理不同文件所属的分组。

P7.jpg

很明显,点击叉叉可以删除当前选中的组。不过,点叉叉左边的符号(然后输入名字)可以新建分组,这一点倒是不太明显。

  • 删掉默认的分组,新建分组“App”“Hardware_Driver”"Lib""Doc"四个分组,分别用于存放用户的应用层级代码文件、硬件驱动相关的代码文件、库文件、文档(然后,记得点OK来确认修改)。

    然后就要准备添加文件到相应分组。不过,咱们的“模板”里面还没有库文件呢,所以我们得来添加一下。

  • 解压之前下载的STM32F1的标准外设库压缩包,按照“STM32F10x_StdPeriph_Lib_V3.5.0 -> Libraries”的顺序打开文件夹,然后复制“Libraries”目录下的“STM32F10x_StdPeriph_Driver”文件夹到我们准备的工程模板的“Lib”文件夹里。这样,工程模板的文件目录下就有需要的库文件了。
  • 之后回到Keil软件,在左边工程结构里的“Lib”上单击右键,选择“Add Exsiting File ····”来添加文件(进入之前的“Manage Project Items”然后选中对应的组来添加文件也是一样的)。

P8.jpg

添加文件的时候,进入我们工程模板的Lib文件夹下,打开“STM32F10x_StdPeriph_Driver”这个我们添加的文件夹,你会看到两个分别叫“src”和“inc”的文件夹,“src”表示“source”,用于存放代码文件,点开会发现一堆“xxx.c”,这些文件需要添加到工程;“inc”表示“include”,即程序应该包含的头文件,打开会发现一堆“xxx.h”,这些文件不需要添加到工程,但需要在软件中添加他们的路径让编译器能够顺利找到这些文件。

  • 所以,在打开了“STM32F10x_StdPeriph_Driver”之后,你需要做的就是,打开”src”文件夹,全选里面的文件,点击“Add”然后退出(没有确认给你点)。之后你就能看到“lib”这一项的左边多出一个加号,展开后就是添加的一堆文件。
  • 搞定src之后,还得处理inc,这次不需要添加文件,而是需要添加路径。

    在“Target_1”处右键,然后选择“Options for Target···”

P9.jpg

  • 在弹出的菜单中选择“C/C++”选项卡,然后,在添加路径之前(既然都到这来了),先来添加一个宏定义,

    在Define后边的文本框中输入一串字符“STM32F10X_MD,USE_STDPERIPH_DRIVER”,如下图:

P10.jpg

在Define文本框中输入的内容会被作为全局的宏,不同的宏之间应该以英文逗号分隔(虽然看起来像句号,但那是个逗号)。

为嘛要用宏呢,我们知道,C语言里面宏定义重要作用是用来进行添加编译,写一个

#ifdef  XXX //如果定义了叫"XXX"的宏
    //do something here.
#elif defined XXXX
    //do something here.
#endif

这样的结构就可以根据不同条件编译不同内容。

我们这里有两个宏,第一个是XXX_MD是“中容量产品”的意思,我们使用的芯片STM32F103C8T6的Flash存储器(作为芯片的ROM)容量为64KB(8 -> 64K),属于ST划分的F1系列下的“中容量产品”,如果是STM32F103ZET6这样的“大容量产品”的话(E -> 512K),M就得改成H(High)了。另一个宏就很好理解了,使用标准库的意思。

  • 然后,点击“Include Paths”右侧的“···”(如图)

P11.jpg

  • 在弹出的界面中,嗯,你应该知道点哪个东西来添加条目,选择inc目录并添加,效果如下图,退出时记得点OK。

P12.jpg

敲黑板

  到这里,虽然模板还不完善,但是你已经了解过所有的步骤,并且大致知道为什么要这么做了,之后的讲解中如遇类似操作,细节不再赘述。

添加用户代码等等

  我们的用户文件夹“User”现在还是空空的,之前分组的时候我们试图用分组让文件的存储更有条理,添加库文件和路径的时候我们发现库文件分了src和inc两个文件夹分别存储.c和.h文件,仔细一想这样好像挺不错的,所以我们的User文件夹里的内容也可以如此放置。

  • 在工程模板的User文件夹下新建“Application”"BSP""Hardware_Driver"三个文件夹(BSP,即板级支持包,通常用于提供一些与特定开发板相关的接口函数),并分别在每个文件夹下新建src文件夹和inc文件夹。

    (温馨提示:win下新建文件夹的快捷键为Ctrl + Alt + N)

  • 回到Keil软件界面,从顶部菜单依次选择“File -> New”新建一个空白文件,然后保存为“main.c”,保存的地方选择"User -> Application -> src"(类型选择默认的allfile即可,".c"不要省去)。
  • 然后,把main文件添加到“App”这个分组下(现在你应该会这个操作)。
  • 对了,到这还有个补充的操作,需要你回到之前解压出来的外设标准库文件夹下找点东西,请依次打开“STM32F10x_StdPeriph_Lib_V3.5.0 -> Project -> STM32F10x_StdPeriph_Template”,看名字就知道这是一个官方提供的工程模板,不过结构不是很适合我们,所以我们拿点东西就走。
  • 把该文件夹下的“stm32f10x_it.c”复制到"User -> Application -> src"下;“stm32f10x_it.h”复制到"User -> Application -> inc",然后C文件添加到Keil工程里的App分组下,inc的路径记得添加一下,这个操作你会的(笑)。
  • 还是获取“stm32f10x_it.c”的那个文件夹,把“stm32f10x_conf.h”复制到"User -> Application -> inc"下,添加过的路径不同重复添加(既然在同一文件夹下)。

    OK,这个教程里面我们就搬这几次东西。

测试与完善

  做完之前的步骤后,我们建立了一个简单但有序的空白工程,但是还不知道是否能用、好用,而且也缺乏一些平时经常使用到的内容,接下来我们就对这个工程进行一些测试和完善。

  首先,在main.c文件中输入如下代码:

#include "stm32f10x.h"
#include "stm32f10x_conf.h"

int main()
{
    return 0;
}

  (这部分代码什么也没有执行)

  使用快捷键F7可以进行编译(无效的话按Fn + Esc可以切换热键的状态),或者点击顶部菜单里的"Build"也行,如下图:

P13.jpg

  编译完成后工作区域的底部应有类似下图的提示:

P14.jpg

  可能会有一些warning(s),但是没有Error的话就说明之前新建的空白工程基本没问题。

  接下来就可以编写程序测试这个工程模板是否真的能用了。

  当然我们会为还在学习怎么建立工程模板的童鞋提供代码的,复制下面内容到main.c就可以了(覆盖原来的)。

#include "stm32f10x.h"
#include "stm32f10x_conf.h"

void delay_ms_test(uint32_t delay_time);

void Board_LED_Init(void);
void Board_LED_ON(void);
void Board_LED_OFF(void);

int main()
{
    Board_LED_Init();
    
    while(1)
    {
        Board_LED_ON();
        
        delay_ms_test(200);
        
        Board_LED_OFF();
        
        delay_ms_test(200);
    }
    return 0;//程序不会运行到这里
}

void delay_ms_test(uint32_t delay_time)
{
    for(int i=0;i<delay_time;i++) 
    {
        for(int j=0;j<11450;j++) 
        {
            __nop();//do nothing
        }
    }
}

void Board_LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    
}

void Board_LED_ON(void)
{
    GPIO_WriteBit(GPIOC,GPIO_Pin_13,0);
}

void Board_LED_OFF(void)
{
    GPIO_WriteBit(GPIOC,GPIO_Pin_13,1);
}

  这部分程序实现的功能是让核心板上PC13引脚连接的LED进行闪烁,通常STM32核心板都会有至少一个的板载LED,而且默认烧录一个闪灯的代码来测试,我们用的“BluePill”也是这样,为了与原本的程序相区别,我把闪烁的频率调快了一些。

  F7之后,编译没问题的话就可以准备下载了,工程默认的下载器是ulink,不常用。这里我们使用STlink进行下载。当然,ISP下载也是可以的,不过这里不做讲解。

  • 打开下图界面,进入“debug”选项卡,在图示下拉列表中选择ST-Link,然后点击右侧的“Settings”。

P15.jpg

  • 然后在弹出的菜单中选择“Flash Download”选项卡,在该界面下勾选“Reset and Run”。很明显,这个设置是让下载器完成下载后帮你复位芯片以运行新下载的程序,省去手动复位的麻烦。

P16.jpg

  • 然后,F8下载,或者点击顶部菜单里的“Load”,如下图:

P17.jpg

  如果没有意外的话,核心板上的与“PC13”字样相邻的LED将会以一定频率闪烁,我们的工程模板实现了“能用”的阶段性目标,不过,如果没有顺利实现预期效果也不要放弃,这里提供一份做好的工程模板以供不顺利的童鞋查对,地址:链接

  当然了,目前这个工程模板极不完善,缺少很多常用的功能,比如准确的延时函数什么的,要让它变得“好用”,还需要继续完善,不过,那是应该是下一篇文章的内容了。

(PS:现在可以试着基于已有的工程模板让LED发送“SOS”求救信号,并把操作封装成一个函数)


ngHackerX86
22 声望24 粉丝

000000