这次,我们来看看工程文件的建立。以寄存器为例。【后边还有库函数的函数模型建立,跟这个原理相同,只是要动的文件不太一样】
MDK5 的安装,请参考光盘“ 6 ,软件资料 → 1 ,软件 → MDK5 → 安装过程 .txt ”即可,里面详细介绍了 MDK5 的安装方法,本节我们将教大家如何新建一个 STM32 的 MDK5 工程。为了方便大家参考,我们将本节最终新建好的工程模板存放在光盘:4 、程序源码 \1 ,标准例程 -寄存器版本\ 实验 0 新建工程实验,如遇新建工程问题,请打开该实验对比。
安装完成之后,我们按照图示要求选择器件。注意MINI板选择RC,战舰版或精英版选择ZE。
下半部分的内容看看就行,咱们直接点x关闭即可。(点ok的话会出现奇怪的内容,所以不建议点ok,叉掉就好)
ST 公司提供了 3 个启动文件给我们,分别用于不同容量的 STM32 芯片,这三个文件是:startup_stm32f10x_ld.sstartup_stm32f10x_md.sstartup_stm32f10x_hd.s其中, ld.s 适用于小容量 产品; md.s 适用于中等容量产品; hd 适用于大容量产品;这里的容量是指 FLASH 的大小 . 判断方法如下:小容量: FLASH ≤ 32K中容量: 64K ≤ FLASH ≤ 128K大容量: 256K ≤ FLASH我们开发板使用的是 STM32F103RCT6 , FLASH 容量为 256KB ,属于大容量产品,所以我们选择 startup_stm32f10x_hd.s 作为我们的启动文件。这三个启动文件在开发板光盘 → 4 ,程序源码 → STM32 启动文件 文件夹里面(也可以从我们 的论坛 下载到, 下载地 址: http://www.openedv.com/posts/list/313.htm ), 这里我 们把startup_stm32f10x_hd.s 拷贝到刚刚新建的 USER 文件夹里面。
建立之后,我们按照这样的要求来插入文件。【库函数这个东西在后期编译的时候非常方便,都是,最大的毛病就是 建立巨麻烦!!强烈建议保存源文件,以后直接复制,不用重新建立,不然太累,创建就弄几十分钟。留着以后直接用即可】
这个时候还不能直接编译。它会因为一些小小的问题报错,我们需要继续解决报错事项。
打开user文件夹,我们可以看到三个新文件夹:DebugConfig、Listings 和 Objects,
在 USER 文件夹下, startup_stm32f10x_hd.s (启动文件)和 test.uvprojx ( MDK5 工程文件)是我们必须用到的 2 个文件,然后 DebugConfig 、 Listings 和 Objects 文件夹是 MDK5 自动生成的, DebugConfig 文件夹用于存储一些调试配置文件, Listings 和 Objects 文件夹用来存储 MDK编译过程的一些中间文件。MDK5.21A 已经默认将这些文件生成在了 Listings 和 Objects 文件夹里面,但是 MDK5.11A及之前版本是不会自动生成这两个文件夹的,所有中间文件都是生成在工程同面目录下,也就是 USER 文件夹下,这样会显得比较混乱。这里,我们不用 MDK5 自己生成的 Listings 和 Objects 文件夹来存放中间文件,而是在 TEST目录下新建一个新的 OBJ 文件夹来存放这些中间文件。这样, USER 文件夹专门用来存放启动文件( startup_stm32f10x_hd.s )、工程文件( test.uvprojx )等不可缺少的文件,而 OBJ 则用来存放这些编译过程中产生的中间文件 ( 包括 .hex 文件也将存放在这个文件夹里面 ) 。然后把 Listings和 Objects 文件夹里面的东西全部移到 OBJ 文件夹下(当然要先关闭 MDK 软件),并删除这两个文件夹(DebugConfig 文件夹不用删除)。
还是那个问题,别拷贝错!库函数和寄存器不一样!!不一样!拷贝错了整个都不能用!
之后我们像51单片机那样,添加system文件,并在system文件下添加三个重要文件
user底下再添加test.c文件
接下来我们进行编译环境设置
还有这一步设置
这里特别提醒大家: 图中 1 处,我们必须根据所用 STM32F1 型号的容量,来输入相关宏定义,对于 STM32F103 系列芯片,设置原则如下:16KB ≤ FLASH ≤ 32KB 选择: STM32F10X_LD64KB ≤ FLASH ≤ 128KB 选择: STM32F10X_MD256KB ≤ FLASH ≤ 512KB 选择: STM32F10X_HD因为 MniSTM32 使用的是 STM32F103RCT6 , FLASH 容量为 256KB ,所以,这个位置我们 设置为: STM32F10X_HD 。
后边我们像51单片机那样,构建hex文件,然后随便导入一个工程文件样板进行编译 。这个时候,我们才算是正式完成基础框架的构建。
接下来,咱们顺势看看走马灯设计。
这个是引脚结构。
我们打开样本文件,建立一个叫hardware的文件夹,里面再建立一个叫key的文件夹。之后以同样的方式,在key中建立一个key.c的文件。
#include "key.h"
#include "delay.h"
//按键初始化函数
//PA0.15 和 PC5 设置成输入
void KEY_Init(void)
{
RCC->APB2ENR|=1<<2; //使能 PORTA 时钟
RCC->APB2ENR|=1<<4; //使能 PORTC 时钟
JTAG_Set(SWD_ENABLE); //关闭 JTAG,开启 SWD
GPIOA->CRL&=0XFFFFFFF0; //PA0 设置成输入
GPIOA->CRL|=0X00000008;
GPIOA->CRH&=0X0FFFFFFF; //PA15 设置成输入
GPIOA->CRH|=0X80000000;
GPIOA->ODR|=1<<15; //PA15 上拉,PA0 默认下拉
GPIOC->CRL&=0XFF0FFFFF; //PC5 设置成输入
GPIOC->CRL|=0X00800000;
GPIOC->ODR|=1<<5; //PC5 上拉
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY0_PRES(1),KEY0 按下
//KEY1_PRES(2),KEY1 按下
//WKUP_PRES(3),WK_UP 按下
//注意此函数有响应优先级,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;//按键按松开标志
if(mode)key_up=1; //支持连按
if(key_up&&(KEY0==0||KEY1==0||WK_UP==1))
{
delay_ms(10);//去抖动
key_up=0;
if(KEY0==0)return KEY0_PRES;
else if(KEY1==0)return KEY1_PRES;
else if(WK_UP==1)return WKUP_PRES;
}else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;
return 0;// 无按键按下
}
先看看程序设计,我们大概浏览一下。
以下内容比较专业,于是我直接从手册当中引用了
这段代码包含 2 个函数, void KEY_Init(void) 和 u8 KEY_Scan(u8 mode) , KEY_Init 是用来初始化按键输入的 IO 口的。实现 PA0 、 PA15 和 PC5 的输入设置,注意这调用了: JTAG_Set这个函数,用于禁止 JTAG ,开启 SWD ,因为 PA15 占用了 JTAG 的一个 IO ,所以要禁止 JTAG ,从而让 PA15 用作普通 IO 输入。KEY_Scan 函数,则是用来扫描这 3 个 IO 口是否有按键按下。 KEY_Scan 函数,支持两种扫描方式,通过 mode 参数来设置。当 mode 为 0 的时候, KEY_Scan 函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候就不合适了。当 mode 为 1 的时候, KEY_Scan 函数将支持连续按,如果某个按键一直按下,则会一直返回这个按键的键值,这样可以方便的实现长按检测。有了 mode 这个参数,大家就可以根据自己的需要,选择不同的方式。这里要提醒大家,因为该函数里面有 static 变量,所以该函数不是一个可重入函数,在有 OS 的情况下,这个大家要留意下。同时还有一点要注意的就是,该函数的按键扫描是有优先级的,最优先的是 KEY0 ,第二优先的是 KEY1 ,最后是 WK_UP 按键。该函数有返回值,如果有按键按下,则返回非 0值,如果没有或者按键不正确,则返回 0 。保存 key.c 代码,然后我们按同样的方法,新建一个 key.h 文件,也保存在 KEY 文件夹下面。在 key.h 中输入如下代码:
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#define KEY0_PRES 1 //KEY0 按下
#define KEY1_PRES 2 //KEY1 按下
#define WKUP_PRES 3 //WK_UP 按下
#define KEY0 PCin(5) //PC5
#define KEY1 PAin(15) //PA15
#define WK_UP PAin(0) //PA0 WK_UP
void KEY_Init(void); //IO 初始化
u8 KEY_Scan(u8 mode); //按键扫描函数
#endif
这是头文件代码的输入。【记得把key.h也加到hardware里面】
回到主界面,在test.c当中再写一段代码:
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
int main(void)
{
u8 t;
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //初始化与 LED 连接的硬件接口
KEY_Init(); //初始化与按键连接的硬件接口
LED0=0; //点亮 LED0
while(1)
{
t=KEY_Scan(0); //得到键值
switch(t)
{
case KEY0_PRES:
LED0=!LED0;
break;
case KEY1_PRES:
LED1=!LED1;
break;
case WKUP_PRES:
LED0=!LED0;
LED1=!LED1;
break;
default:
delay_ms(10);
}
}
}
编译之后发现没有报错,也没有警告。我们按照上次笔记所写,通过 daplink下载器把程序内容运行一下。结果确实亮了(忘了录视频了,我截一段别人的视频也不太合适x)
本次的学习内容就到这里