1.用typedef和#define定义类型:1)常用typedef声明新的类型名来代替已有的类型名,这主要是便于移植。
typedef unsigned int U32
……
U32 var=3;
2)在程序中可以看到用#define定义一个U32来代替unsingned int
以上两种类型定义方法的不同之处,在于typedef是在编译阶段处理的,而#define是在预处理阶段处理的。
2.signed int表示有符号整型,最高位符号位,剩下的31位才是数据的有效位,范围:-(2^31)~(2^31)-1;
unsigned int表示无符号整型,32位有效数据位,因此数据范围:0~(2^32)-1.
3.volatile和强制类型转换
C语言中有32个关键字,volative就是其中一个,用来修饰变量时,表示该变量的值可能被硬件更改,因此每次读取这个变量值的时候要重新从内存中读取这个变量的值,而不是使用保存在寄存器里的备份。
当操作类型不一样时,需要用到类型转换(当然,C语言内部有隐形转换规则),将其称为强制类型转换。eg:#define rBWSCON (*(volatile unsigned*)0x48000000) 访问0x48000000中的数据。
(unsigned *)0x48000000表示将0x48000000强制转换为一个地址指针,即指向内存中地址0x48000000处,准确地说是指向内存中从0x48000000开始的连续的4个字节的内存片中(0x48000000~0x48000003);然后再其前面加上*是指针运算符(间接访问运算符),表示取该内存单元中的数据。
4.位运算
#define rGPBCON (*(volatile unsigned*)0x56000010)
rGPBCON &=~(3<<10);
rGPBCON |=(1<<10);
小技巧:对硬件寄存器的访问都是采用这种“先与后或”的方式。优点是不会影响寄存器中其他位的设置(与“1”相与,值不变,与“0”相或值不变)。
5.防止文件重复包含技巧
编译器对C语言程序进行处理大致经过预处理(Preprocess)、编译(Compile)、汇编(Assemble)和链接(Linking)共4个步骤,最终才生成可执行程序。一般对源程序进行语法和词法分析之前,先要对程序进行预处理。C编译器专门提供了部分预处理指令来指示编译器如何对源程序进行预处理,预处理以#开始,单独占一行。
#ifndef _LED_H_
#define _LED_H_
extern void Led_Init();
extern void Led1_On();
extern void Led1_Off();
#endif
行用extern声明了一个外部函数,也就是说在其他文件中可以使用这个函数,即函数Led_Init()是在其他文件中定义的,本文件可能用到,因此要声明一下。
6.ARM编译器对C语言的扩展
_ _irq声明中断处理函数:void __irq Timer0_Isr(void)(两个下划线)
_ _swi声明软中断:将处理器工作模式切换到管理模式,主要为了支持操作系统的系统功能调用接口或者也可以使用软中断来实现任务的切换等。_ _swi(0x20)void ledtest().
_ _asm内嵌汇编。
_ _inline定义内联函数
7.在系统上电后,需要有一段引导程序完成对系统资源的初始化,为用户程序建立基本的运行环境。因此,启动代码主要是完成对ARM处理器的初始化,使其能够正常工作。启动代码主要做的事情:
1.建立异常中断向量表。
2.初始化各模式的堆栈。
3.初始化硬件。
4.最后跳转到主应用程序。
8.对于程序代码量很小的程序段,可以用宏的形式实现(宏,就是指在调用时展开),可以节省函数调用时的开销,减少调用时速度减慢;当函数代码量较大时,就用函数来实现。
#define Led1_On() {rGPBDAT&=(~(1<<5));}
#define Led1_Off() {rGPBDAT|=(1<<5);}
9.对寄存器的操作主要是按位与操作和按位或操作。按位与操作主要用于对某几位的清零,按位或操作主要用于对某几位的置1。
阅读(1815) | 评论(0) | 转发(1) |