分类: 嵌入式
2013-09-07 21:35:30
函数头部进行注释,列出函数功能、输入参数、输出参数、返回值、调用关系等信息
按位与操作:可以实现将特定为清零,也可以提取出某数的指定位
按位或操作:可以实现将特定位的置位操作,也可以用于提取出某数的指定位
按位异或操作:可以实现将特定位的取反(与0异或保留原值,与1异或取反),也可以实现在不引入第三变量的情况下,交换量变量的内容(a=a^b,b=b^a,a=a^b)
取反操作:主要用于将操作数的某位或某些位取反,为其他操作提供数据准备
左移:操作常常用于将特定的位置1,也可用于代替乘法和除法操作,嵌入式编程中,左移操作常用作某寄存器对应位进行设置(如:# define BIT_UTXD0 (0x1<<3)),这样使程序可移植性好
volatile的本意为“暂态”和“易变的”,该说明符主要起到抑制编译器优化的作用。由于访问内部高速CACHE或寄存器的速度比访问外部RAM快得多,所以编译器一般都会做减少存取外部RAM的优化,对于一个变量,如果编译器发现复制后没有变化,编译器就可能优化代码,直接从内部高速缓存CACHE或寄存器获取数据,而不是从内存中读取。如果在这段时间里,变量被中断或外围设备输入等编译器未知的原因改变,程序可能没有获取最新的值而导致运行结果异常
如果在声明时用volatile进行修饰,遇到这个关键字声明的变量,编译器对访问该变量的代码不再进行优化,从而可以提供特殊地址的稳定访问,一般volatile限制符长用于下面几种情况说明:
1:存储器映射的硬件寄存器通常要加volatile说明,因为每次对他的读写都可能具有不同的意义
2:中断服务程序修改的供其他程序检测的变量需要加volatile
3:多任务环境下各任务间共享的标志应该加volatile进行说明
地址强制转换:在C语言中,绝对地址被当成整型数,如果把它当成一个地址来使用就需要进行地址强制转换,如定义一个整型指针int *p,然后把绝对地址0X0FA00转换成一个整型的地址值赋给这个整型指针p=(int *)0x0FA00
因此在嵌入式设计中,经常可以看到寄存器用如下方式进行定义:
# define rPCONA (*(volatile unsigned
*)0x1D20000)
中断处理程序:
标准C不包含中断服务的自动处理,许多编译器开发商在标准C上增加了对中断的支持,提供了自定义的一些关键字用于说明中断服务程序(Interrupt Service Routine ,ISR),比如常见的有_Interrupt、# program interrupt等,如果一个函数被说明为中断服务程序,编译器会自动添加中断处理所需要的现场保护盒出栈代码
在编写中断服务程序时需要满足如下要求:
1:不能向中断服务程序传递参数
2:中断服务程序没有返回值
3:中断服务程序要尽可能的短,来减少中断服务程序的处理时间,保证实时系统的性能
模块化程序设计:将系统内的任务合理的划分,将具有同一属性或相同类别的代码归为一类组成模块
嵌入式软件系统主要有两类模块:硬件驱动模块,一种特定硬件对应一个模块;系统控制功能模块
一般每个模块都是由一个.c源文件和一个.h头文件组合而成,硬件相关的模块里,源文件一般是对接口功能的封装,将硬件功能定义的定义为功能代码段,供应用程序调用,头文件是对于该模块硬件接口寄存器的地址定义和宏定义;在应用模块里,源文件用来实现控制任务,头文件用来对相应模块所用到的外部变量或函数进行声明
如果某模块提供给其他模块调用的外部函数或外部变量,则要在.h文件中用extern关键字进行声明,并在该模块的.c源文件中定义该变量
子程序调用通过寄存器R0~R3传递参数,当参数不超过4个时,可以使用寄存器R0~R3来传递参数,参数依次存放到R0~R3中,当参数超过四个时,还可以使用数据栈来进行参数传递,入栈的顺序与参数顺序相反,即最后一个参数先入栈
汇编语言与C的混合编程通常有以下几种:
1:在C程序中嵌入汇编指令
2:在汇编程序中访问C定义的全局变量
3:在C程序中调用汇编函数
4:汇编程序中调用C函数
1:在C程序中嵌入汇编指令
在此情况中,使用关键字_ _asm来标识一段汇编指令程序
如:_ _asm
{汇编语言
…….
汇编语言
}
例如:
if( )_ _asm volatile(…………….)
2:在汇编程序中访问C定义的全局变量
在此情况中,在汇编代码中使用 IMPORT 全局变量名 ,然后才能在汇编代码中把此全局变量当成立即数来使用
例如:
汇编:AREA asmfie,CODE,READONLY
C语言:#
include
EXPORT asmDouble int qvar_1=12;
IMPORT qvar_1 extern asmDouble(void);
asmDouble int main()
ldr r0,qvar_1 {printf(………..);
……
asmDouble();
……. …………..
3:在C程序中调用汇编函数
在此情况中,在C中声明函数原型,并加extern,此外在汇编中用EXPORT导出函数名并用该函数作为汇编代码段的标识(在GUN汇编中用.global来导出函数名),最后用mov PC ,lr
来返回,然后就可以在C中使用函数了
例如:AREA
asmfile,CODE,READONLY
#include
EXPORT asm_strcopy
extern void asm_strcopy(const char *src , char *dest )
asm_strcopy int main ()
loop: {…………
ldrb r4,[r0],#1
asm_strcopy(s,d);
cmp R4,#0 ………….}
beq over
strb r4,[r1],#1
b loop
over:
mov pc,lr
end
4:汇编程序中调用C函数
需要在汇编中IMPORT对应的C函数名(GUN汇编是用.extern对应的C函数名),然后将C的代码放在一个独立的C文件中编译
例如:EXPORT asmfile
int cfun(int a , int b , int c)
AREA asmfile ,CODE,READONLY {return a+b+c;}
IMPORT cfun
ENTRY
mov r0,#11
mov r1,#22
mov r2,#33
bl cfun
end
过程调用结果返回:
1:结果为一个32位的整数时,通过寄存器R0返回;结果为一个64为整数时,通过寄存器R0,R1返回
2:结果为一个浮点数时,可以通过浮点运算部件寄存器F0、D0或者S0来返回,结果为复合型的浮点数时(复数),可以通过寄存器F0~Fn或者D0~Dn来返回
3:对于更多的结果,需要通过内存来返回