关键词不能为空

当前您在: 主页 > 英语 >

arm学习笔记

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-03-03 12:58
tags:

-

2021年3月3日发(作者:duedate)


如何使用


STM32F4


DSP




我们平常所使用的


CPU


为定点


CPU


,意思是进行整点数值运算的


CPU


。当遇到形如

< p>
1.1+1.1


的浮点数


运算时,定点

< p>
CPU


就遇到大难题了。对于


32


位单片机,利用


Q


化处理能发挥他本身的性能,但是精


度和速度仍然不会提高很多。






现在设计出了一个新的


CPU


,叫做


FPU


,这个芯片专门处理浮点数的运算,这样处理器就将整点


数和浮点数分开来处理,整点数 交由定点


CPU


处理而浮点数交由


FP U


处理。我们见到过


TI


< p>
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

< p>


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


,变量在程序初始


化时被分配,直到程序退出前才被释放;也就是


static


是按照程序的生命周期来分配释放变量的,

< p>
而不是变量自己的生命周期;所以,像这样的例子:



void func()


{


int a;


static int b;


}



每一次调用该函数,变量


a


都是新的,因为它是 在进入函数体的时候被分配,退出函数体的时候


被释放,所以多个线程调用该函数,都会 拥有各自独立的变量


a


,因为它总是要被重新分配的;而变



b


不管你是否使用该函数,


在程序初始化时就被分配的了,


或者在第一次执行到它的声明的时候分


配(不同的编译器可能不同),所以多个线程调用该函数的时候,总是访问同一个变量


b


,这也是在


多线程编程中必须注意的!




static


的全部用法:



1


.类的静态成员:



class A


{


private:


static int s_value;


};




cpp


中必须对它进行初始化:



int A::s_value = 0;//


注意,这里没 有


static


的修饰!




类的静态成员是该类所有实例的共用成员,

< p>
也就是在该类的范畴内是个全局变量,


也可以理解为


是一个名为


A::s_value


的全局变量,只不过它是带 有类安全属性的;道理很简单,因为它是在程序


初始化的时候分配的,所以只分配一次, 所以就是共用的;




类的静态 成员必须初始化,道理也是一样的,因为它是在程序初始化的时候分配的,所以必须有


初 始化,


类中只是声明,



cpp


中才是初始化,


你可以在初始化的代码上放个断点,

< br>在程序执行


main


的第一条语句之前就会先走到那;如 果你的静态成员是个类,那么就会调用到它的构造函数;




2


.类的静态函数:



class A


{


private:


static void func(int value);


};



实现的时候也不需要


static


的修饰,因为


static


是声明性关键字;



类的静态函数是在该类的范畴内的全局函数,不能访问类的私有成员,只能访问类的静态成员 ,不需


要类的实例即可调用;实际上,它就是增加了类的访问权限的全局函数:


void A::func(int)





静态成员函数可以继承和覆盖


,


但无法是虚函数


;



3


.只在


cpp


内有效的全 局变量:





cpp


文件的全局范围内声明:



static int g_value = 0;



这个变量的含义是在该


cpp


内有效,


但是其他的


cpp


文件不能访问这个变 量;


如果有两个


cpp



件声明了同名的全局静态变量,那么他们实际上是独立的两个变量;




如果不使用


static


声明全局变量:



int g_value = 0;



那么将无法保证这个变量 不被别的


cpp


共享,


也无法保证一定 能被别的


cpp


共享,


因为要让多个< /p>


cpp


共享一个全局变量,应将它声明为


extern


(外部)的;也有可能编译会报告变量被重复定义;总

之不建议这样的写法,不明确这个全局变量的用法;




如果在一个头文件中声明:



static int g_vaule = 0;



那么会为每个包含该头文件的


cpp


都创建一个全局变量,


但他们都是独立的;


所以也不建议这样


的写 法,一样不明确需要怎样使用这个变量,因为只是创建了一组同名而不同作用域的变量;




这里顺便说一下如何声明所有


cpp


可共享的全局变量,在头文件里声明为


extern


的:



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

< p>
内声明非


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


程序



是指在


ARM


系统中正在执行的程序,


而非保存在


ROM


中的

bin


映像



image



文件,这一点清注意区别。



一个


ARM


程序包含


3


部分:


RO



RW< /p>



ZI


RO


是程序中的指令和常量



RW


是程序中的已初始化变量



ZI


是程序中的未初始化的变量



由以上


3


点说明可以理解为:



RO


就是


readonl y




RW


就 是


read/write




ZI


就是


zero


ARM


映像文件的组成



所谓


ARM


映像文件就是指烧录到

< br>ROM


中的


bin


文件,也成为


image


文件。以下用


Image< /p>


文件来称


呼它。



Image


文件包含了


RO



RW


数据。



之所以


Image


文件不包含


ZI

< p>
数据,是因为


ZI


数据都是


0


,没必要包含,只要程序运行之前将


ZI

< br>数


据所在的区域一律清零即可。包含进去反而浪费存储空间。


Q


:为什么


Image


中必须包含


RO



RW




A


:因为


RO


中的指令和常量以及


RW


中初始化过的变量是不能像


ZI


那样

< p>


无中生有



的。



ARM


程序的执行过程



从以上两点可以知道,烧录到


ROM


中的

< p>
image


文件与实际运行时的


ARM

< p>
程序之间并不是完全一样


的。因此就有必要了解


A RM


程序是如何从


ROM


中的


image


到达实际运行状态的。


< p>
实际上,


RO


中的指令至少应该有这样的功能:< /p>



1.



RW



ROM


中搬到


RAM


中,因为


RW


是变量,变量不 能存在


ROM


中。



2.



ZI


所在的


RAM


区域全部清零,


因为


ZI


区域并不在


Image


中,


所以需要程序根据编译器给出的


ZI


地址及大小来将相应得


RAM


区域清零。

< p>
ZI


中也是变量,同理:变量不能存在


ROM




在程序运行的最初阶段,


RO


中的指令完成了这两项工作后


C


程序才能正常访问变量。否则只能运行


不含变量的代码。



说了上面的可能还是有些迷糊,


RO



RW



ZI


到底是什么,下面我将给出几个例子,最直观的来说



RO< /p>



RW



ZI< /p>



C


中是什么意思。


1; RO


看下面两段程序,


他们之间差了一条语句,


这条语句就是声明一个字符常量。


因此 按照我们之前说的,


他们之间应该只会在


RO

< br>数据中相差一个字节(字符常量为


1


字节)。

< p>


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


=============== =============================================

< p>
====================


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


=============== =============================================

< p>
====================


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



RO


包含了


Code



RO Data


两类数据。他们的唯一区别就是

< p>
Prog2



RO Data


Prog1


多了


1


个字节。这正和之前的推测一致。



如果增加的是一 条指令而不是一个常量,则结果应该是


Code


数据大小有差别 。


-


-


-


-


-


-


-


-



本文更新与2021-03-03 12:58,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/700116.html

arm学习笔记的相关文章