aerkate

MSP430C语言扩展(原创)

0
阅读(26684)

 

TIOBE世界编程语言排行榜2011年3月榜单

SUN推出的Java势头还是很猛的样子,但是C也是依旧坚挺,如果说考虑上他的继承者们,他们占据了接近三分之一的天下。C以其博大精深,亲近底层深受大家的喜爱,学好C还是很重要的。

上图列出了C语言、编译器、机器码之间的关系。大部分处理器的C语言都是在标准C上增加对相应处理器的特殊操作而构成的。C语言写的源程序属于文本文件,不能直接被目标CPU运行,需要经过编译器生成机器码才可以。

MSP430单片机的C语言语法与标准C语言差异很小,主要是进行了一些扩展,包括关键字扩展和函数扩展。我们可以利用这些扩展编写出效率更高、功能更强的程序,但是由于扩展的代码直接与MSP430的硬件结构相关,因此降低了可移植性。当然我们可以通过将程序分层编写的方式有效的控制一下。将通用的算法严格遵循标准C语言规范的包装成一组文件后者函数,用以保证可移植性;将于MSP430硬件相关的部分,包装成另一组文件或者函数,在移植时只需修改这一部分即可。

下面我们将简单认识一下MSP430单片机C语言和标准C语言的差异。

关于变量

C语言的国际标准中,对各变量字节数没有做严格的限定,不同的编译器可以有略微的差异。

EW430允许修改某些变量的特性。通过右键工程名打开Option选项,在General Option项可以设置浮点指针长度,在Compile Option 选项可以设置char。在变量定义表达式中增加某些关键字可以给变量赋予某些特性。

const 用于定义常量,定义的常量将会被放在ROM中,因而可以用const关键字定义一些像显示断码表这样的常量数组。

static:用于定义本地全局变量,只能在函数内使用,可以避免全局变量混乱。

volatile:用于定义挥发性变量。编译器将认为该变量的值会随时变化,对该变量的任何操作都不会被优化过程删除。

我们可以在option的C/C++ Compiler 中来设置优化的级别。优化级别越高,机器码生成越紧凑,但是编译器会在保证运行结果正确的前提下自作主张的修改代码。所以要谨慎对待。

no_init 或者__no_init:定义无需初始化的变量。

关于数学运算的一些原则

虽然MSP430的运算速度非常可观了,但是考虑到对单片机而言浮点型运算还是很慢,且RAM开销很大,会影响到功耗等原因,所以还是要尽量避免使用浮点型的运算;进行定点数运算时要防止数据溢出;对于小数也应该尽可能的考虑通过扩大再处理的方式,使用定点数的进行运算;最后就是要尽量减少乘除法,如果乘除的数值刚好是2的幂,可以采用移位的方式。

位操作和寄存器操作

MSP430的C语言中不支持为变量,但可以通过变量与掩模位之间的逻辑操作来实现

P2OUT |=0x01; //P2.0至高电平

P2OUT &= ~0x02 //P2.1至低电平

P2OUT ^= 0x04 //P2.2取反

同时在寄存器头文件中已经将BIT0~BIT7定义为0x01~0x80,上面的语句的另一种方式是:

P2OUT |=BIT0; //P2.0至高电平

P2OUT &= ~BIT1 //P2.1至低电平

P2OUT ^= BIT2 //P2.2取反

MSP430单片机内部各模块的配置、操作全部通过寄存器进行。对于我们这种初学者而言可以先不考虑寄存器的绝对地址,而是通过在问价开头包含相应头文件的方式,像操作变量那样操作寄存器。我们可以在EW430的安装文件夹中找到找到这些头文件,头文件中寄存器和标志位名称与《User Guide》内列出的名称完全一致,在使用时可以打开看一下。

IE1 |= BIT6+BIT7; //串口收、发中断控制位URXIE0和URTIE0至高电平,打开串口收发中断

大部分控制寄存器在上电复位过程中都会被自动清零,它们在初始化的时候可以用“|=”号赋值。

EW430提供的关键字与内部函数的扩展可以在使用时慢慢记忆,在此就不一一说明。

最后让我们来谈点程序风格的问题。我们写的程序不仅要被计算机读,好要被其他程序员读。一个风格清爽而严谨的程序更容易被读懂,更容易修改和排错。

变量名应该尽量使用具有说明性的名称。若名称包含多个单词,每个单词首字母大写以便区分单词。

例如:

 int  InputVoltage; //输入电压

int  Temperature; //温度

函数名也应该具有说明性,可以按照模块名_功能名的方式命名。

char LCD_Init();//LCD 初始化

void PWM_SetDuty(); //设置PWM占空比

对于变量名和函数名,一旦约定某种简写方式,以后就要保持风格不变。而当加入一个团队时,团队目前所使用的风格就是做好的风格,要保持惯用风格一致性。对于表达式而言应该尽量自然、简洁、无歧义。

还有一个能够帮助我们阅读程序的途径就是注释。通过简洁明了的点名程序的突出特征,或者阐明思路,或者提供宏观的功能解释,或者特殊之处,帮助我们理解程序。

使用// 完成一行的标注

使用/*  */ l来实现一个段落的标注

我们可以在每个函数前面注释该函数的名称、参数、参数值域、返回值、设计思路、功能、注意事项等来帮助我们阅读程序。下面给出一个程序范例用以说明

 

/****************************************************************************************************

*名    称:LCD_InsertChar()

*功    能:在LCD最右端插入一个字符

*入口参数:ch:插入的字符

*出口参数:无

*说    明:调用该函数后,LCD所有已显示的字符左移一位,新的字符插入在最右端一位,该函数可以实现滚屏动画效果,或用于在数据后面显示单位

*范    例:LCD_DisplsyDrvimsl(1234,1);

                  LCD_InsertChar(PP);

                  LCD_InsertChar(FF); 显示结果:123.4PF

****************************************************************************************************/

void LCD_InsertChar(char ch)

{

  char i;

  char * pLCD=(char*)&LCDM1;//取LCD控制器显存地址

  for(i=6;i>=1;i--) pLCD[i]=pLCD[i-1]; //已显示内容全部左移1位

  pLCD[0]=LCD_Tab[ch];           //新字符显示在屏幕最右侧

}