-
如何使用
STM32F4
的
DSP
库
我们平常所使用的
p>
CPU
为定点
CPU
,意思是进行整点数值运算的
CPU
。当遇到形如
1.1+1.1
的浮点数
运算时,定点
CPU
就遇到大难题了。对于
32
位单片机,利用
Q
化处理能发挥他本身的性能,但是精
度和速度仍然不会提高很多。
现在设计出了一个新的
CPU
,叫做
FPU
,这个芯片专门处理浮点数的运算,这样处理器就将整点
数和浮点数分开来处理,整点数
交由定点
CPU
处理而浮点数交由
FP
U
处理。我们见到过
TI
的
DSP
,
还有
STM32
F4
系列的带有
DSP
功能的微控制器
。前者笔者没有用过,不作评论,而后者如果需要用
到
FPU<
/p>
的浮点运算功能,必须要进行一些必要的设置。
首
先,
由于浮点运算在
FPU
中进行,所
以首先应该使能
FPU
运行。在
sys
tem_init()
中,定义
__FPU_PRESENT<
/p>
和
__FPU_USED
/* FPU settings------------------------
------------------------------------*/
#if (__FPU_PRESENT == 1)&&
(__FPU_USED == 1)
SCB->CPACR |= ((3UL<< 10*2)|(3UL <<
11*2));
/*set CP10 and CP11 Full
Access */
#endif
这样就使能了
FPU
。
对于上述改变,当程序中出现
这种简单的加减乘除运算
FPU
就起作用了。但是对于复杂的如
三角
运算、开方运算等,我们就需要加入
math.h
头文件。但是如果单纯的加入他,那么
Keil
会自动调用
内部的
math.h
,该头
文件是针对
ARM
处理器的,专门用于定点
CPU
和标准算法(
IEEE-754
)
。对于使
用了
FPU
的
STM32F4
是没有任何作用的。所以,需要
将
math.h
换成
ST
的库,即
arm_math.h
。在该
头文件中,涉及到另一个文件
core_cmx.h
(
x=0
、
3
、
4
)
,当然了,如同
STM32F1
系列一样,在工程中
加入
core_cm4.h
即可。
到
这里,算是全部设置完毕,之差最后一步,调用!但是别小看了这一步,因为如果调用的不正
确,前面的设置就白费了。在使用三角函数如
sin()
、
cos()
时不要直接写如上形式,因为他们函数的名
字来自于
math.h
,
所以你调用的仍旧是
Keil
库中的标准
math.h
。
要使用
arm_m
ath.h
中的
arm_sin_f32()
< br>函数(见
Line.5780
,原函数见
DSP_LibSourceFastMathFunctions
)
,可以看到他利用的是三次样条插
值法快速求值(见
Line.263 /* Cubic interpolation process */
)
。
注意一下例外函数,
sqrt()
,在
arm_math.h
中为
arm_s
qrt_f32()
。
使用他的时候需要同时开启
#if(__FPU_USED == 1) && defined ( __CC_ARM
)
才行,切记!
C
语言中编程注意事项
要理解
static
,就必须要先理解另一个与之相
对的关键字,很多人可能都还不知道有这个关键字,
那就是
au
to
,其实我们通常声明的不用
static
< br>修饰的变量,都是
auto
的,因为它是默认的,就象<
/p>
short
和
long
< br>总是默认为
int
一样;我们通常声明一个变量:
int a;
string s;
其实就是:
auto
int a;
auto string s;
而
static
变量的声明是:
static int a;
static string s;
这样似乎可以更
有利于理解
auto
和
static<
/p>
是一对成对的关键字吧,
就像
priva
te
,
protected
,
public
一样;
对于
static
的不理解,
其实就是对于
auto
的不理解,
因为它是更一般的;
有的东西你天天在用,
但未必就
代表你真正了解它;
auto
的含义是由程序自动控制变量的生
存周期,通常指的就是变量在
进入其作用域的时候被分配,离开其作用域的时候被释放;
而
static
就是不
auto
,变量在程序初始
化时被分配,直到程序退出前才被释放;也就是
p>
static
是按照程序的生命周期来分配释放变量的,
而不是变量自己的生命周期;所以,像这样的例子:
void func()
{
int a;
static int b;
}
每一次调用该函数,变量
a
都是新的,因为它是
在进入函数体的时候被分配,退出函数体的时候
被释放,所以多个线程调用该函数,都会
拥有各自独立的变量
a
,因为它总是要被重新分配的;而变
p>
量
b
不管你是否使用该函数,
在程序初始化时就被分配的了,
或者在第一次执行到它的声明的时候分
配(不同的编译器可能不同),所以多个线程调用该函数的时候,总是访问同一个变量
b
,这也是在
多线程编程中必须注意的!
static
的全部用法:
1
.类的静态成员:
class A
{
private:
static int
s_value;
};
在
cpp
中必须对它进行初始化:
int A::s_value = 0;//
注意,这里没
有
static
的修饰!
类的静态成员是该类所有实例的共用成员,
也就是在该类的范畴内是个全局变量,
也可以理解为
是一个名为
A::s_value
的全局变量,只不过它是带
有类安全属性的;道理很简单,因为它是在程序
初始化的时候分配的,所以只分配一次,
所以就是共用的;
类的静态
成员必须初始化,道理也是一样的,因为它是在程序初始化的时候分配的,所以必须有
初
始化,
类中只是声明,
在
cpp
中才是初始化,
你可以在初始化的代码上放个断点,
< br>在程序执行
main
的第一条语句之前就会先走到那;如
果你的静态成员是个类,那么就会调用到它的构造函数;
2
.类的静态函数:
class A
{
private:
static void
func(int value);
};
实现的时候也不需要
static
的修饰,因为
static
是声明性关键字;
p>
类的静态函数是在该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员
,不需
要类的实例即可调用;实际上,它就是增加了类的访问权限的全局函数:
void A::func(int)
;
静态成员函数可以继承和覆盖
,
但无法是虚函数
;
3
.只在
cpp
内有效的全
局变量:
在
cpp
文件的全局范围内声明:
static int g_value = 0;
这个变量的含义是在该
cpp
内有效,
但是其他的
cpp
文件不能访问这个变
量;
如果有两个
cpp
文
件声明了同名的全局静态变量,那么他们实际上是独立的两个变量;
如果不使用
static
p>
声明全局变量:
int
g_value = 0;
那么将无法保证这个变量
不被别的
cpp
共享,
也无法保证一定
能被别的
cpp
共享,
因为要让多个<
/p>
cpp
共享一个全局变量,应将它声明为
extern
(外部)的;也有可能编译会报告变量被重复定义;总
之不建议这样的写法,不明确这个全局变量的用法;
如果在一个头文件中声明:
static int g_vaule = 0;
那么会为每个包含该头文件的
cpp
都创建一个全局变量,
p>
但他们都是独立的;
所以也不建议这样
的写
法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同作用域的变量;
这里顺便说一下如何声明所有
cpp
可共享的全局变量,在头文件里声明为
extern
p>
的:
extern int
g_value; //
注意,不要初始化值!
然后在其中任何一个包含该头文件的
< br>cpp
中初始化(一次)就好:
int g_value = 0; //
初始化一样不要
extern
修饰,因为
extern
也是声明性关键字;
然后所有包含该头文件的
cpp
文件都
可以用
g_value
这个名字访问相同的一个变量;
4
.只在
cpp
内有效的全局函数:
在
cpp
内声明:
static void
func();
函数的实现不需要
< br>static
修饰,那么这个函数只可在本
cpp
内使用,不会同其他
cpp
中的同名
函数引起冲突;道理和如果不使用
static
会引起的问题和第
3
点一样;不要在头文件中声明
static
的全局函数,不要在
cpp
内声明非
static
的全局函数,如果你要在多
个
cpp
中复用该函数,就把它
的声明
提到头文件里去,否则在
cpp
内部声明需要加上
static
修饰;在
C
语
言中这点由为重要!
ARM
中的
RO
、
R
W
和
ZI DATA
一直以来对于<
/p>
ARM
体系中所描述的
RO
,
RW
和
ZI
数据存在似是而非的理解,这段时间对其仔细了
解了一番,发现了一些规律,
理解了一些以前书本上有的但是不理解的东西,我想应该有不少人也有
和我同样的困惑,
因此将我的一些关于
RO
,
RW
和
ZI
的理解写出来,希望能对大家有所帮助
。
要了解
RO
,
RW
和
ZI
需要首先了解以下知识:
ARM
程序的组成
< br>此处所说的
“ARM
程序
”
p>
是指在
ARM
系统中正在执行的程序,
p>
而非保存在
ROM
中的
bin
映像
(
image
)
文件,这一点清注意区别。
一个
ARM
程序包含
3
部分:
RO
,
RW<
/p>
和
ZI
RO
是程序中的指令和常量
RW
是程序中的已初始化变量
ZI
是程序中的未初始化的变量
p>
由以上
3
点说明可以理解为:
RO
就是
readonl
y
,
RW
就
是
read/write
,
ZI
就是
zero
ARM
映像文件的组成
所谓
ARM
映像文件就是指烧录到
< br>ROM
中的
bin
文件,也成为
image
文件。以下用
Image<
/p>
文件来称
呼它。
Image
文件包含了
RO
和
RW
数据。
之所以
Image
文件不包含
ZI
数据,是因为
ZI
数据都是
0
,没必要包含,只要程序运行之前将
ZI
< br>数
据所在的区域一律清零即可。包含进去反而浪费存储空间。
Q
:为什么
Image
中必须包含
RO
和
RW
?
A
:因为
RO
中的指令和常量以及
RW
中初始化过的变量是不能像
ZI
那样
“
无中生有
”
的。
ARM
程序的执行过程
从以上两点可以知道,烧录到
ROM
中的
image
文件与实际运行时的
ARM
程序之间并不是完全一样
的。因此就有必要了解
A
RM
程序是如何从
ROM
中的
image
到达实际运行状态的。
实际上,
RO
中的指令至少应该有这样的功能:<
/p>
1.
将
RW
从
ROM
中搬到
RAM
中,因为
RW
是变量,变量不
能存在
ROM
中。
2.
将
ZI
所在的
RAM
区域全部清零,
因为
p>
ZI
区域并不在
Image
中,
所以需要程序根据编译器给出的
ZI
地址及大小来将相应得
RAM
区域清零。
ZI
中也是变量,同理:变量不能存在
ROM
p>
中
在程序运行的最初阶段,
RO
中的指令完成了这两项工作后
C
程序才能正常访问变量。否则只能运行
不含变量的代码。
说了上面的可能还是有些迷糊,
RO
,
RW
和
ZI
到底是什么,下面我将给出几个例子,最直观的来说
明
RO<
/p>
,
RW
,
ZI<
/p>
在
C
中是什么意思。
1; RO
看下面两段程序,
他们之间差了一条语句,
这条语句就是声明一个字符常量。
因此
按照我们之前说的,
他们之间应该只会在
RO
< br>数据中相差一个字节(字符常量为
1
字节)。
Prog1
:
#include
void
main(void)
{
;
}
Prog2
:
#include
const
char a = 5
;
void
main(void)
{
;
}
Prog1
编译出来后的信息如下:
=======================================
=====================
==================
==
Code
RO Data
RW Data
ZI Data
Debug
948
60
0
96
0
Grand Totals
===============
=============================================
====================
Total RO
Size(Code + RO Data)
1008
( 0.98kB)
Total RW
Size(RW Data +
ZI Data)
96
( 0.09kB)
Total ROM
Size(Code + RO Data + RW Data)
1008
( 0.98kB)
==================================================
==========
====================
Prog2
编译出来后的信息如下:
=======================================
=====================
==================
==
Code
RO Data
RW Data
ZI Data
Debug
948
61
0
96
0
Grand Totals
===============
=============================================
====================
Total
RO
Size(Code + RO Data)
1009
( 0.99kB)
Total
RW
Size(RW Data + ZI Data)
96
( 0.09kB)
Total
ROM Size(Code + RO
Data + RW Data)
1009
( 0.99kB)
==================
==========================================
< br>====================
以上两个程序编译出来后的信息可以看出:
< br>Prog1
和
Prog2
的
p>
RO
包含了
Code
和
RO Data
两类数据。他们的唯一区别就是
Prog2
的
RO Data
比
Prog1
多了
1
个字节。这正和之前的推测一致。
如果增加的是一
条指令而不是一个常量,则结果应该是
Code
数据大小有差别
。
-
-
-
-
-
-
-
-
-
上一篇:初中英语句子翻译 范文
下一篇:八下英语各个单元知识汇总