C 嵌入式
时间:2009-03-08 来源:creatory
volatile关键字
使用volatile声明变量时,主要是为了防止编译器优化,多次访问同一变量时,每次都从物理地址重新加载其值
宏定义
#define MAX(a,b) ((a)>=(b)?(a):(b))
寄存器变量(频繁操作)
/*求1+2+3+...+n=?*/
int Addition(int n)
{
register int i,s=0;
for(i=1;i<=n;i++)
s=s+i;
return s;
}
内嵌汇编(优化20%的关键代码,节省运行时间)
/*做加法*/
int result
void addition(long a,long b)
{
_asm{
mov ax,a
mov bx,b
add ax,[bx]
mov result,ax
}
}
对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度;
对于UART等设备,其内部有一定容量的接收BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断。例如计算机终端在向目标机通过RS-232传递数据时,不宜设置UART只接收到一个BYTE就向CPU提中断,从而无谓浪费中断处理时间;
如果对某设备能采取DMA方式读取,就采用DMA读取,DMA读取方式在读取目标中包含的存储信息较大时效率较高,其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式,减少了CPU 对外设的干预,进一步提高了CPU与外设的并行操作程度。
活用位操作
使用C语言的位操作可以减少除法和取模的运算
/1/ /2/
int i,j; int i,j;
i=879/16; i=879>>4;
j=562%32 j=562-(562>>5<<5);
我们通常要对硬件寄存器进行位设置,譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的第低6位设置为0(开中断2),最通用的做法是:
#define INT_I2_MASK 0x0040
wTemp=inword(INT_MASK);
outword(INT_MASK,wTemp & ~INT_I2_MASK);
将该位置1(按位或)
#define INT_I2_MASK 0X0040
wTemp=inword(INT_MASK);
outword(INT_MASK,wTemp | INT_I2_MASK);
判断该位是否为1
#define INT_I2_MASK 0x0040
wTemp=inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{
/*该位为1*/
}
宏定义是C语言中实现类似函数功能而又不具函数调用和返回开销的较好方法,但宏在本质上不是函数,因而要防止宏展开后出现不可预料的结果,对宏的定义和使用要慎而处之。很遗憾,标准C至今没有包括C++中inline函数的功能,inline函数兼具无调用开销和安全的优点。
使用寄存器变量、内嵌汇编和活用位操作也是提高程序效率的有效方法。
C标准中一些预定义的宏
C标准中指定了一些预定义的宏,对于编程经常会用到。下面这个表中就是一些常常用到的预定义宏。
__DATE__
进行预处理的日期(“Mmm dd yyyy”形式的字符串文字)
__FILE__
代表当前源代码文件名的字符串文字
__LINE__
代表当前源代码中的行号的整数常量
__TIME__
源文件编译时间,格式微“hh:mm:ss”
__func__
当前所在函数名
对于__FILE__,__LINE__,__func__这样的宏,在调试程序时是很有用的,因为你可以很容易的知道程序运行到了哪个文件的那一行,是哪个函数。
下面一个例子是打印上面这些预定义的宏的。
#include
#include
void why_me();
int main()
{
printf( "The file is %s.\n", __FILE__ );
printf( "The date is %s.\n", __DATE__ );
printf( "The time is %s.\n", __TIME__ );
printf( "This is line %d.\n", __LINE__ );
printf( "This function is %s.\n", __func__ );
why_me();
return 0;
}
void why_me()
{
printf( "This function is %s\n", __func__ );
printf( "The file is %s.\n", __FILE__ );
printf( "This is line %d.\n", __LINE__ );
}
1、防止一个头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2、重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
typedef
unsigned char
boolean;
/* Boolean value type. */
typedef
unsigned long int
uint32;
/* Unsigned 32 bit value */
typedef
unsigned short
uint16;
/* Unsigned 16 bit value */
typedef
unsigned char
uint8;
/* Unsigned 8
bit value */
typedef
signed long int
int32;
/* Signed 32 bit value */
typedef
signed short
int16;
/* Signed 16 bit value */
typedef
signed char
int8;
/* Signed 8
bit value */
//下面的不建议使用
typedef
unsigned char
byte;
/* Unsigned 8
bit value type. */
typedef
unsigned short
word;
/* Unsinged 16 bit value type. */
typedef
unsigned long
dword;
/* Unsigned 32 bit value type. */
typedef
unsigned char
uint1;
/* Unsigned 8
bit value type. */
typedef
unsigned short
uint2;
/* Unsigned 16 bit value type. */
typedef
unsigned long
uint4;
/* Unsigned 32 bit value type. */
typedef
signed char
int1;
/* Signed 8
bit value type. */
typedef
signed short
int2;
/* Signed 16 bit value type. */
typedef
long int
int4;
/* Signed 32 bit value type. */
typedef
signed long
sint31;
/* Signed 32 bit value */
typedef
signed short
sint15;
/* Signed 16 bit value */
typedef
signed char
sint7;
/* Signed 8
bit value */
3.得到指定地址上的一个字节或字
#define MEM_B(x) (*((byte*)(x)))
#define MEM_W(x) (*((word*)(x)))
4.求最大值最小值
#define MAN(x,y) (((x)>(y))?(x):(y))
#define MIN(x,y) (((x)<(y))?(x):(y))
5.将一个字母转换为大写
#define UPCASE(c) (((c)>='a' && (c)<='z')?((c)-0x20):(c))
6.返回数组元素个数
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))
7.对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port)
(*((volatile byte *) (port)))
#define inpw(port)
(*((volatile word *) (port)))
#define inpdw(port)
(*((volatile dword *)(port)))
#define outp(port, val)
(*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val)
(*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
使用volatile声明变量时,主要是为了防止编译器优化,多次访问同一变量时,每次都从物理地址重新加载其值
宏定义
#define MAX(a,b) ((a)>=(b)?(a):(b))
寄存器变量(频繁操作)
/*求1+2+3+...+n=?*/
int Addition(int n)
{
register int i,s=0;
for(i=1;i<=n;i++)
s=s+i;
return s;
}
内嵌汇编(优化20%的关键代码,节省运行时间)
/*做加法*/
int result
void addition(long a,long b)
{
_asm{
mov ax,a
mov bx,b
add ax,[bx]
mov result,ax
}
}
对于程序代码,已经被烧录在FLASH或ROM中,我们可以让CPU直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将FLASH或ROM中的目标代码拷贝入RAM中后再执行以提高取指令速度;
对于UART等设备,其内部有一定容量的接收BUFFER,我们应尽量在BUFFER被占满后再向CPU提出中断。例如计算机终端在向目标机通过RS-232传递数据时,不宜设置UART只接收到一个BYTE就向CPU提中断,从而无谓浪费中断处理时间;
如果对某设备能采取DMA方式读取,就采用DMA读取,DMA读取方式在读取目标中包含的存储信息较大时效率较高,其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA方式较之中断驱动方式,减少了CPU 对外设的干预,进一步提高了CPU与外设的并行操作程度。
活用位操作
使用C语言的位操作可以减少除法和取模的运算
/1/ /2/
int i,j; int i,j;
i=879/16; i=879>>4;
j=562%32 j=562-(562>>5<<5);
我们通常要对硬件寄存器进行位设置,譬如,我们通过将AM186ER型80186处理器的中断屏蔽控制寄存器的第低6位设置为0(开中断2),最通用的做法是:
#define INT_I2_MASK 0x0040
wTemp=inword(INT_MASK);
outword(INT_MASK,wTemp & ~INT_I2_MASK);
将该位置1(按位或)
#define INT_I2_MASK 0X0040
wTemp=inword(INT_MASK);
outword(INT_MASK,wTemp | INT_I2_MASK);
判断该位是否为1
#define INT_I2_MASK 0x0040
wTemp=inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{
/*该位为1*/
}
宏定义是C语言中实现类似函数功能而又不具函数调用和返回开销的较好方法,但宏在本质上不是函数,因而要防止宏展开后出现不可预料的结果,对宏的定义和使用要慎而处之。很遗憾,标准C至今没有包括C++中inline函数的功能,inline函数兼具无调用开销和安全的优点。
使用寄存器变量、内嵌汇编和活用位操作也是提高程序效率的有效方法。
C标准中一些预定义的宏
C标准中指定了一些预定义的宏,对于编程经常会用到。下面这个表中就是一些常常用到的预定义宏。
__DATE__
进行预处理的日期(“Mmm dd yyyy”形式的字符串文字)
__FILE__
代表当前源代码文件名的字符串文字
__LINE__
代表当前源代码中的行号的整数常量
__TIME__
源文件编译时间,格式微“hh:mm:ss”
__func__
当前所在函数名
对于__FILE__,__LINE__,__func__这样的宏,在调试程序时是很有用的,因为你可以很容易的知道程序运行到了哪个文件的那一行,是哪个函数。
下面一个例子是打印上面这些预定义的宏的。
#include
#include
void why_me();
int main()
{
printf( "The file is %s.\n", __FILE__ );
printf( "The date is %s.\n", __DATE__ );
printf( "The time is %s.\n", __TIME__ );
printf( "This is line %d.\n", __LINE__ );
printf( "This function is %s.\n", __func__ );
why_me();
return 0;
}
void why_me()
{
printf( "This function is %s\n", __func__ );
printf( "The file is %s.\n", __FILE__ );
printf( "This is line %d.\n", __LINE__ );
}
1、防止一个头文件被重复包含
#ifndef COMDEF_H
#define COMDEF_H
//头文件内容
#endif
2、重新定义一些类型,防止由于各种平台和编译器的不同,而产生的类型字节数差异,方便移植。
typedef
unsigned char
boolean;
/* Boolean value type. */
typedef
unsigned long int
uint32;
/* Unsigned 32 bit value */
typedef
unsigned short
uint16;
/* Unsigned 16 bit value */
typedef
unsigned char
uint8;
/* Unsigned 8
bit value */
typedef
signed long int
int32;
/* Signed 32 bit value */
typedef
signed short
int16;
/* Signed 16 bit value */
typedef
signed char
int8;
/* Signed 8
bit value */
//下面的不建议使用
typedef
unsigned char
byte;
/* Unsigned 8
bit value type. */
typedef
unsigned short
word;
/* Unsinged 16 bit value type. */
typedef
unsigned long
dword;
/* Unsigned 32 bit value type. */
typedef
unsigned char
uint1;
/* Unsigned 8
bit value type. */
typedef
unsigned short
uint2;
/* Unsigned 16 bit value type. */
typedef
unsigned long
uint4;
/* Unsigned 32 bit value type. */
typedef
signed char
int1;
/* Signed 8
bit value type. */
typedef
signed short
int2;
/* Signed 16 bit value type. */
typedef
long int
int4;
/* Signed 32 bit value type. */
typedef
signed long
sint31;
/* Signed 32 bit value */
typedef
signed short
sint15;
/* Signed 16 bit value */
typedef
signed char
sint7;
/* Signed 8
bit value */
3.得到指定地址上的一个字节或字
#define MEM_B(x) (*((byte*)(x)))
#define MEM_W(x) (*((word*)(x)))
4.求最大值最小值
#define MAN(x,y) (((x)>(y))?(x):(y))
#define MIN(x,y) (((x)<(y))?(x):(y))
5.将一个字母转换为大写
#define UPCASE(c) (((c)>='a' && (c)<='z')?((c)-0x20):(c))
6.返回数组元素个数
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))
7.对于IO空间映射在存储空间的结构,输入输出处理
#define inp(port)
(*((volatile byte *) (port)))
#define inpw(port)
(*((volatile word *) (port)))
#define inpdw(port)
(*((volatile dword *)(port)))
#define outp(port, val)
(*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val)
(*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
相关阅读 更多 +