引言
在前面的笔记中,我们都是将所有的源码文件放到工程的根目录下,如果工程文件比较少的话这样做无可厚非,但是如果工程源文件达到几十、甚至数百个的时候,这样一股脑全部放到根目录下就会使工程显得混乱不堪。所以我们必须对工程文件做管理,将不同功能的源码文件放到不同的目录中。另外我们也需要将源码文件中,所有完成同一个功能的代码提取出来放到一个单独的文件中,也就是对程序分功能管理。本章我们就来学习一下如何对一个工程进行整理,使其美观、功能模块清晰、易于阅读。
5.1 工程管理简介
打开我们上一章的工程根目录,如下图所示:
在上图中我们将所有的源码文件都放到工程根目录下,即使这个工程只是完成了一个简单的流水灯的功能,但是其工程根目录下的源码文件就已经不少了。如果在添加一些其他的功能文件,那么文档就会更大,显得很混乱,所以我们需要对这个工程进行整理,将源码文件分模块、分功能整理。我们可以打开一个 STM32 的例程,如下图所示:
上图中的工程目录就很美观、不同的功能模块文件放到不同的文件夹中,比如驱动文件就放到 HARDWARE
文件夹中,
ST
的官方库就放到
STM32F10x_FWLib
文件夹中,编译产生的过程文件放到 OBJ
文件夹中。我们可以参考这个工程目录结构来整理第十二章的例程工程,新建名为“5_ledc_bsp
”的文件夹,在里面新建
bsp
、
imx6ul
、
obj
和
project
这
4
个文件夹,
完成以后如下图
所示:
其中 bsp
用来存放驱动文件;
imx6ul
用来存放跟芯片有关的文件,比如
NXP
官方的
SDK库文件;obj
用来存放编译生成的
.o
文件;
project
存放
start.S
和
main.c
文件,也就是应用文件;将上次实验中的 cc.h
、
fsl_common.h
、
fsl_iomuxc.h
和
MCIMX6Y2.h
这四个文件拷贝到文件夹 imx6ul
中;将
start.S
和
main.c
这两个文件拷贝到文件夹
project
中。我们前面的实验中所有的驱动相关的函数都写到了 main.c
文件中,比如函数
clk_enable
、
led_init
和
delay
,这三个函数可以分为三类:时钟驱动、LED
驱动和延时驱动。因此我们可以在
bsp
文件夹下创建三个子文件夹:clk
、
delay
和
led
,分别用来存放时钟驱动文件、延时驱动文件和
LED 驱动文件,这样main.c 函数就会清爽很多,程序功能模块清晰。工程文件夹都创建好了,接下来就是编写代码了,其实就是将时钟驱动、LED 驱动和延时驱动相关的函数从 main.c 中提取出来做成一个独立的驱动文件。
5.2 硬件原理分析
硬件就是led0前面的文章有说明,在此就不再赘述。
5.3.1 创建 imx6ul.h 文件
新建文件 imx6ul.h
,然后保存到文件夹
imx6ul
中,在
imx6ul.h
中输入如下内容:
示例代码:
1
#ifndef __IMX6UL_H
2
#define __IMX6UL_H
3
/***************************************************************
4
5
文件名
: imx6ul.h
6
作者
: 嘴硬的xiaolaji
7
8
描述
:
包含一些常用的头文件。
9
其他
:
无
10
11
日志
:
2019/1/3
创建
12
***************************************************************/
13
#include
"cc.h"
14
#include
"MCIMX6Y2.h"
15
#include
"fsl_common.h"
16
#include
"fsl_iomuxc.h"
17
18
#endif
文件 imx6ul.h
很简单,就是引用了一些头文件,以后我们就可以在其他文件中需要引用imx6ul.h 就可以了。
5.3.2 编写 led 驱动代码
新建
bsp_led.h
和
bsp_led.c
两个文件,将这两个文件存放到
bsp/led
中,在
bsp_led.h
中输入
输入如下内容:
示例代码 13.3.2.1 bsp_led.h 文件代码
1
#ifndef __BSP_LED_H
2
#define __BSP_LED_H
3
#include
"imx6ul.h"
4
/***************************************************************
5
6
文件名
: bsp_led.h
7
作者
: 嘴硬的xiaolaji
8
版本
: V1.0
9
描述
: LED
驱动头文件。
10
其他
:
无
11
12
日志
:
初版
V1.0 2019/1/4
创建
13
***************************************************************/
14
15
#define LED0
0
16
17
/*
函数声明
*/
18
void
led_init
(
void
);
19
void
led_switch
(
int
led
,
int
status
);
20
#endif
bsp_led.h 的内容很简单,就是一些函数声明,在
bsp_led.c
中输入如下内容:
示例代码:
1
#include
"bsp_led.h"
2
/***************************************************************
3
4
文件名
: bsp_led.c
5
作者
: 嘴硬的xiaolaji
6
版本
: V1.0
7
描述
: LED
驱动文件。
8
其他
:
无
9
10
日志
:
初版
V1.0 2019/1/4
创建
11
***************************************************************/
12
13
/*
14
* @description : 初始化
LED
对应的
GPIO
15
* @param : 无
16
* @return : 无
17
*/
18
void
led_init
(
void
)
19
{
20
/* 1
、初始化
IO
复用
*/
21
IOMUXC_SetPinMux
(
IOMUXC_GPIO1_IO03_GPIO1_IO03
,
0
);
22
23
/* 2
、、配置
GPIO1_IO03
的
IO
属性
*/
24
IOMUXC_SetPinConfig
(
IOMUXC_GPIO1_IO03_GPIO1_IO03
,
0X10B0
);
25
26
/* 3
、初始化
GPIO,GPIO1_IO03
设置为输出
*/
27
GPIO1
->
GDIR
|= (
1
<<
3
);
28
29
/* 4
、设置
GPIO1_IO03
输出低电平,打开
LED0*/
30
GPIO1
->
DR
&= ~(
1
<<
3
);
31
}
32
33
/*
34
* @description : LED 控制函数,控制
LED
打开还是关闭
35
* @param - led :
要控制的
LED
灯编号
36
* @param - status : 0
,关闭
LED0
,
1
打开
LED0
37
* @return :
无
38
*/
39
void
led_switch
(
int
led
,
int
status
)
40
{
41
switch
(
led
)
42
{
43
case
LED0
:
44
if
(
status
==
ON
)
45
GPIO1
->
DR
&= ~(
1
<<
3
);
/*
打开
LED0 */
46
else if
(
status
==
OFF
)
47
GPIO1
->
DR
|= (
1
<<
3
);
/*
关闭
LED0 */
48
break
;
49
}
50
}
bsp_led.c 里面就两个函数
led_init
和
led_switch
,
led_init
函数用来初始化
LED
所使用的
IO
,
led_switch
函数是控制
LED
灯的打开和关闭,这两个函数都很简单。
5.3.3 编写时钟驱动代码
新建 bsp_clk.h
和
bsp_clk.c
两个文件,将这两个文件存放到
bsp/clk
中,在
bsp_clk.h
中输入如下内容:
示例代码:
1
#ifndef __BSP_CLK_H
2
#define __BSP_CLK_H
3
/***************************************************************
4
5
文件名
: bsp_clk.h
6
作者
: 嘴硬的xiaolaji
7
版本
: V1.0
8
描述
:
系统时钟驱动头文件。
9
其他
:
无
10
11
日志
:
初版
V1.0 2019/1/4
创建
12
***************************************************************/
13
14
#include
"imx6ul.h"
15
16
/*
函数声明
*/
17
void
clk_enable
(
void
);
18
19
#endif
bsp_clk.h 很简单,在
bsp_clk.c
中输入内容:
示例代码:
1
#include
"bsp_clk.h"
2
3
/***************************************************************
4
5
文件名
: bsp_clk.c
6
作者
: 嘴硬的xiaolaji
7
版本
: V1.0
8
描述
:
系统时钟驱动。
9
其他
:
无
10
11
日志
:
初版
V1.0 2019/1/4
创建
12
***************************************************************/
13
14
/*
15
* @description :
使能
I.MX6U
所有外设时钟
16
* @param : 无
17
* @return : 无
18
*/
19
void
clk_enable
(
void
)
20
{
21
CCM
->
CCGR0
=
0XFFFFFFFF
;
22
CCM
->
CCGR1
=
0XFFFFFFFF
;
23
CCM
->
CCGR2
=
0XFFFFFFFF
;
24
CCM
->
CCGR3
=
0XFFFFFFFF
;
25
CCM
->
CCGR4
=
0XFFFFFFFF
;
26
CCM
->
CCGR5
=
0XFFFFFFFF
;
27
CCM
->
CCGR6
=
0XFFFFFFFF
;
28
}
bsp_clk.c 只有一个
clk_enable
函数,用来使能所有的外设时钟。
13.3.4
编写延时驱动代码
新建
bsp_delay.h
和
bsp_delay.c
两个文件,将这两个文件存放到
bsp/delay
中,在
bsp_delay.h
中输入输入如下内容:
示例代码:
1
#ifndef __BSP_DELAY_H
2
#define __BSP_DELAY_H
3
/***************************************************************
4
5
文件名
: bsp_delay.h
6
作者
: 嘴硬的xiaolaji
7
版本
: V1.0
8
描述
:
延时头文件。
9
其他
:
无
10
11
日志
:
初版
V1.0 2019/1/4
创建
12
***************************************************************/
13
#include
"imx6ul.h"
14
15
/*
函数声明
*/
16
void
delay
(
volatile unsigned int
n
);
17
18
#endif
在
bsp_delay.c
中输入内容:
示例代码:
/***************************************************************
文件名
: bsp_delay.c
作者
: 嘴硬的xiaolaji
版本
: V1.0
描述
:
延时文件。
其他
:
无
日志
:
初版
V1.0 2019/1/4
创建
***************************************************************/
1
#include
"bsp_delay.h"
2
3
/*
4
* @description :
短时间延时函数
5
* @param - n :
要延时循环次数
(
空操作循环次数,模式延时
)
6
* @return : 无
7
*/
8
void
delay_short
(
volatile unsigned int
n
)
9
{
10
while
(
n
--){}
11
}
12
13
/*
14
* @description : 延时函数
,
在
396Mhz
的主频下
15
*
延时时间大约为
1ms
16
* @param - n :
要延时的
ms
数
17
* @return :
无
18
*/
19
void
delay
(
volatile unsigned int
n
)
20
{
21
while
(
n
--)
22
{
23
delay_short
(
0x7ff
);
24
}
25
}
bsp_delay.c 里面就两个函数,
delay_short
和
delay
,这两个其实就是第十二章中
main.c
里面的函数。