C语言常用语法Word下载.docx
- 文档编号:5744521
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:18
- 大小:26.76KB
C语言常用语法Word下载.docx
《C语言常用语法Word下载.docx》由会员分享,可在线阅读,更多相关《C语言常用语法Word下载.docx(18页珍藏版)》请在冰点文库上搜索。
(5)逗号表达式(顺序表达式)
形式为
表达式1,表达式2表达式n
顺序求出表达式1,表达式2表达式n的值。
结果为表达式n的值。
(6)赋值表达式
将赋值号“=”右侧表达式的值赋值号左边的变量。
赋值表达式的值为执行赋值后被赋值的变量的值。
(7)条件表达式
逻辑表达式?
表达式1:
表达式2
逻辑表达式的若为非零,则条件表达式的值等于表达式1的值;
若逻辑表达式的值为零,则条件表达式的值等于表达式2的值。
(8)指针表达式
对指针类型的数据进行运算。
例如,p-2,p1-p2等(其中p,P1,P2均已定义为指向数组的指针变量,p1与p2指向同一数组中的元素),结果为指针类型。
以上各种表达式可以包含有关的运算符,也可以是不包含任何运算符的初等量(例如,常数是算术表达式的最简单的形式)。
4数据定义
对程序中用到的所有变量都需要进行定义。
对数据要定义其数据类型,需要时要指定其存储类别。
(1)类型标识符可用
int
short
long
unsigned
char
float
double
struct结构体名
union共用体名
enum枚举型名
用typedef定义的类型名
结构体与共同体的定义形式为
struct结构体名
{成员表列};
用typedef定义新类型名的形式为
typedef已有类型新定义类型;
如:
typedefintCOUNT;
//就是在有INT的地方都可以用COUNT代替
(2)存储类别可用
auto//一般默认
static
register
extren
(如不指定存储类别,作auto处理)
变量的定义形式为
存储类别数据类型变量表列;
例如:
staticfloata,b,c;
注意外部数据定义只能用extern或static,而不能用auto或register.
5函数定义
存储类别数据类型函数名(形参表列)
函数体
函数的存储类别只能用extern或static.函数体是用花括弧括起来的,可包括数据定义和语句.函数的定义举例如下:
staticintmax(int,inty)
{intz;
z=x>
y?
x:
y;
return(z);
}
6变量的初始化
可以在定义时对变量或数组指定初始值.
静态变量或外部变量如未初始化,系统自动使其初值为零或空.对自动变量或寄存器变量,若未初始化,则其初值为一不可预测的数据.
7语句
(1)表达式语句;
(2)函数调用语句;
(3)控制语句;
(4)复合语句;
(5)空语句.
其中控制语句包括:
(1)if(表达式)语句
或
if(表达式)语句1
else语句2
(2)while(表达式)语句
(3)do语句
while(表达式);
(4)for(表达式1;
表达式2;
表达式3)
语句
(5)switch(表达式)
{case常量表达式1:
语句1;
case常量表达式2:
语句2;
case常量表达式n:
语句n;
default;
语句n+1;
前缀case和default本身并不改变控制流程,它们只起标号作用,在执行上一个case所标志的语句后,继续顺序执行下一个case前缀所所标志的语句,除非上一个语句中最后用break语句使控制转出switch结构。
(6)break语句
(7)continue语句
(8)return语句
(9)goto语句
8预处理命令
#define宏名字符串
#define宏名(参数1,参数2……参数n)字符串
#undef宏名
#include“文件名”(或〈文件名〉)
#if常量表达式
#ifdef宏名
#ifndef宏名
#else
#endif
[2007-12-612:
55:
00|By:
xiangzi]
1
推荐
要包含一个单片机硬件的资源头文件。
各模块使用了定义在Common.h中的一些数据类型。
BIT(bit)BYTE(unsignedchar)等,具体请参见源程序。
时钟模块
在单片机软件设计中,时钟是重要资源,为了充分利用时钟资源,故设计本时钟模块。
本模块使用定时器0,在完成用户指定功能的同时,还能够自动处理一些其它模块中与时钟相关的信息。
时钟模块由声明文件Timer.h以及实现文件Timer.c组成。
用户应该在Config.h中定义宏TIMER_RELOAD来设定定时器0的重装载初值。
推荐的定时器0的中断时间大于1毫秒。
在程序的初始化阶段调用时钟模块的初始化函数InitTimerModule()之后,就可以使用时钟模块所以支持的各种功能。
具体描述如下:
延时:
当用户需要进行一定时间的延时时,可以通过调用Delay()来进行,参数为时钟中断的次数。
如时钟中断周期为1ms,想进行100ms的延时,则可以调用Delay(100)。
注意:
如果延时的绝对时间小于时钟中断的周期,则不能够用本方法做到延时。
定时:
当程序中需要使用定时功能时,如等待某外部事件,如果在一定时间内发生则继续执行,如果在这段时间内发生,则认为出现错误,转向错误处理机制。
在此推荐一种编程模式,但用户可以用自己认为更合理的方式处理此类问题。
这里简单说明一下关于阻塞式函数及非阻塞式函数。
简单说,阻塞式函数就是当检测完成条件,如果不能够完成则等待,如:
voidCheckSomething()
{
//gbitSuccessFlagisaglobalvariable
while(gbitSuccessFlag==FALSE)
{
//donothingbutwaiting
}
可以看到,当bitSuccessFlag没有被设置为TRUE时,函数保持等待状态不返回,这样就是阻塞式的函数。
另外一种情况:
BITCheckSomething()
if(gbitSuccessFlag==TRUE)
//…
returnTRUE;
returnFALSE;
在这里,如果所检测的事件有没有完成,函数进行检测之后,立刻返回,通过返回值报告完成情况,如果没有完成,则等待调用者分配再次执行的机会。
这样的函数就是非阻塞函数。
在应用定时功能时,首先要将检测函数定义成非阻塞函数。
如上面的第二个版本的CheckSomething。
然后下面模式:
BITbitDone=FALSE;
ResetClock();
//cleartimerinterrupttimescounter
while(GetClock()<
MAX_WAITINGTIME)
if(CheckSomething()==TRUE)
bitDone=TRUE;
break;
if(bitDone==FALSE)
//processtimeout
或者简单写成:
MAX_WAITINGTIME&
&
(bitDone=CheckSomething));
if(bitDone==FLASE)
{
//…
软件看门狗:
实现具有局限性的看门狗功能。
在程序中合适的地方加入对软件看门狗的复位函数ResetWatchDog(),在Config.h中加入宏TIMER_WATCHDOGTIMEOUT。
当程序运行时,如果在发生TIMER_WATCHDOGTIMEOUT次时钟中断之内没有复位软件看门狗,则系统复位。
如果没有加入TIMER_WATCHDOGTIMEOUT宏,程序中的ResetWatchDog没有任何用处,不用删除。
如果系统不能实现时钟中断,则软件看门狗也同时失去功能。
目前版本的的时钟模块的复位功能并不是完全复位,主要表现在当复位之后,系统将不再响应任何中断。
所以软件看门狗只是一个程序的调试功能,不应该将它用于正式工作的程序,此时应该使用硬件看门狗。
用户自定义任务:
如果想在时钟中断内执行一些耗时较短的任务,可以定义回调函数OnTimerInterrupt。
函数原形为:
voidOnTimerInterrupt();
如果想在发生时钟中断时执行一些功能,而这些功能又耗时相对较长,不合适放在中断响应函数内部,则可以在程序中的主循环中的任意地方添加:
ImpTimerService(),同时提供原形为voidOnTimerEvent()的回调函数。
具体的程序如下所示:
voidmain()
Initialize();
while(TRUE)
//…working
ImpTimerService();
voidOnTimerEvent()
//dosometask
对通讯模块提供支持:
如通讯中的各种超时等,见通讯模块中的详细说明。
对键盘扫描模块提供支持:
可以自动调用键盘扫描模块,见键盘扫描模块中的详细说明。
对程序调试提供支持:
在程序开发过程中,有时为了判断程序是不是在工作,常用利用单片机系统的某一空闲引脚通过一个限流电阻接一个发光二极管,在程序中间隔固定时间交替控制发光管的明暗。
实现这个功能只要在Config.h文件中定义TIMER_FLASHLED宏,如:
#defineTIMER_FLASHLED P1_0
则当时钟中断发生256次之后,改变发光管的状态。
通讯模块
串口资源做为单片机与外界通信的常用手段,通讯模块提供了完全缓冲的串口通讯底层机制,适用于长度不大的数据包的发送及接收。
如果处理关键数据,需要用户自己提供纠错协议。
通讯模块由声明文件SComm.h及实现文件SComm.c组成。
初始化:
调用函数InitSCommModule()来初始化通讯模块:
voidInitSCommModule(BYTEbyTimerReload,BITbitTurbo)
参数说明:
byTimerReload:
定时器1的重装载初始值。
bitTurob:
当此参数为TRUE时,串行通讯在定时器1的溢出速率基础上加倍。
为FALSE时,串行通讯速率为定时器1的溢出速率。
缓冲区:
模块使用了由宏SCOMM_SENDBUFSIZE、SCOMM_RECEBUFSIZE及SCOMM_PKGBUFSIZE所指定长度的三个缓冲区,分别为发送、接收及数据包(用于处理接收到的数据)缓冲区(如果没有使用异步接收功能,则不需要使用数据包缓冲区)。
在缺省时,这三个宏都被定义为10,但用户可以自已按照系统的RAM资源占用情况在Config.h中重定义缓冲区的大小。
需要注意的是,如果缓冲的长度不够,当发送或接收长数据包的时候可能会发生问题,关于数据缓冲区的最小值的设置可以参考下面的说明。
注意:
需要尽快取出接收缓冲区中的数据,否则当缓冲区满之后,新的数据将被简单的丢掉。
字节级服务函数:
在Config.h文件中定义了宏SCOMM_DriverInterface(如:
#defineSCOMM_DriverInterface),则可以使用字节级服务函数,即通讯模块的底层函数。
共有两个函数可以使用:
voidSendByte(BYTEbyData);
发送一个字节,如果当前缓冲区满,则等待。
参数byData为要发送的数据。
BYTEReceByte();
接收一个字节,如果当前缓冲区中没有数据,则此函数阻塞,直到接收到数据为止。
接收到数据通过返回值返回。
可以通过调用IsSendBufEmpty()IsSendBufFull()IsReceBufEmpty()IsReceBufFull() 宏来判断缓冲区的空或满,以防系统阻塞。
不推荐直接使用这一级的服务函数,应该使用高层次上的服务函数或者在这一级服务函数的基础上构造自己的通讯函数。
数据包级服务函数:
在Config.h文件中定义宏SCOMM_PackageInterface(如:
#defineSCOMM_PackageInterface)则可以使用数据包级服务函数。
voidSendPackage(BYTE*pbyData,BYTEbyLen);
发送数据包,参数pbyData为将要发送的数据包缓冲区(数组)的指针,byLen为将要发送的数据包的长度。
当没有定义SCOMM_DriverInterface时,数据被完全缓冲。
即不能够发送长度超过发送缓冲区长度的数据包。
当定义了SCOMM_DriverInterface时,采用单字节发送,这时不限制需要发送的数据的长度。
BYTERecePackage(BYTE*pbyData,BYTEbyLen);
接收数据包,参数pbyData为存放将要接收的数据的缓冲区,byLen为缓冲区长度。
返回值为接收到的字节数,当模块的接收缓冲区为空时,函数非阻塞,立即返回,返回值为零。
同步发送接收服务函数:
比如在一个串行总线多机通讯系统中,主机需要定时循检各从机的状态,往往是发一个包含从机地址及指令的数据包给从机,之后等待一定的时间,从机需要在这段时间之内给主机一个应答,如果没有这个应答,则认为从机工作状态出错,转去进行相应的处理。
在这个模型里,主机不能够不进行等待而给另一台从机发送指令,也不能够不管从机在很久没有应答的情况下继续等待。
还有一种情况,比如当使用485总线进行通信时,如果是两条通讯线则系统只能工作在半双工模式下,总线在同一时间内只能工作在发送或接收,为了防止发送和接收相互干扰,这时的通讯常常需要使用同步发送和接收。
当在Config.h文件中定义宏SCOMM_SyncInterface后,则可以使用通讯模块提供同步发送接收函数:
发送数据包,参数pbyData为将要改善的数据包的缓冲区指针,byLen为将要发送的数据包的长度。
这个函数可以保证等待一个完整的数据包完全发送出去之后,它才返回,在这段时间内,它会阻塞运行。
BYTESyncRecePackage(BYTE*pbyBuf,BYTEbyBufLen,WORDwTimeout,BYTEbyParam);
接收数据包。
返回值为接收到的数据包长度。
参数pbyBuf为将要接收数据包的缓冲区的指针,byBufLen为提供的缓冲区的长度,wTimeout为通信超时值,如果在发生了由wTimeout所指定次数的时钟中断而还没有接收到或没有接收到完整的数据包时,函数返回零,最后一个参数byParam的含义见后面的解释。
异步发送接收服务函数:
在一个简单的系统或多机通讯系统中的从机上,一般情况下不需要复杂的停等的工作模式,而且往往单片机需要对硬件进行控制和检测,不允许长时间的停下来检测通讯,但又要求当需要通讯时需要尽快的反应速度,这时就需要使用异步发送和接收服务函数。
使用异步发送和接收服务函数需要在Config.h文件中定义SCOMM_AsyncInterface宏。
同样提供两个服务函数:
这里的函数的接口与同步发送和接收的服务函数相同。
关于这里的细节,见后面对同步和异步服务函数的说明。
voidAsyncRecePackage(BYTEbyParam);
接收数据包,参数byParam的意义见后面的描述。
使用异步通讯需要用户定义一个回调函数,原型如下:
voidOnRecePackage(BYTE*pbyData,BYTEbyBufLen);
当异步接收服务函数接收到数据包之后,调用OnRecePackage回调函数,在pbyData指定的缓冲区中存放数据包,byBufLen为数据包的长度。
在Config.h文件中定义宏SCOMM_TIMEOUT可以设定异步接收的超时值,当开始接收数据包,但没有收完数据而发生了SCOMM_TIMEOUT次时钟中断后,认为接收超时,将已接收到的数据删除。
同步和异步通讯服务函数:
有些情况下,比如一个通讯系统中,由一台计算机通过串口控制主机,主机通过串口连接很多从机,主机的串口采用分时复用,在这样的模型中,主机和控制计算机之间的通讯可以使用,异步通讯方式,而主机与从机可以使用同步通讯方式。
而同步和异步的发送函数接口是相同的,在这样的情况下,发送都是同步的。
在这样的模型中,当使用不同的接收函数之前,需要注意清除接收缓冲区中的内容,通讯模块提供函数:
ClearReceBuffer来做到这一点,此函数原型如下:
voidClearReceBuffer();
通讯过程中,数据包往往是有固定的格式的,这种格式需要根据用户所使用的协议的不同而不同。
同步和异步接收服务函数支持从接收到的数据中识别出一定格式的数据包。
举例说明:
目前使用的协议决定数据包的格式为固定的包头0xff,固定的长度4个字节。
其它的细节在这里不重要,所以忽略掉。
为了能够使用用SyncRecePackage或AsyncRecePackage函数从接收到的数据中识别出如上格式的数据包,有两种方法:
第一种办法是在Config.h文件中定义宏SCOMM_SimplePackageFormat,说明数据包为一种简单格式,比如上面的协议。
之后还要定义两个宏分别用来识别数据包头和数据包尾,两个宏分别是:
IsPackageHeader(x)和IsPackageTailer(x,y,z)
接收函数(SyncRecePackage和AsyncRecePackage)在没有开始接收数据包(准确的说是还没有从接收到的数据包中找到包头的时候),会对接收到的每一个字节的数据调用IsPackageHeader宏,将相应的数据作为参数,如果IsPackageHeader宏的结果为TRUE,则认为找到了数据包头,否则继续对下一个字节进行判断。
上面的协议对应的IsPackageHeader宏可以写为:
#defineIsPackageHeader(x) ((x)==0xff)
当接收到包头之后,接收函数会对接下来的每一个字节数据调用IsPackagTailer宏来判断是不是已经接收完数据包,三个参数分别为:
当前判断的数据。
y:
从包头开始到当前被判断的数据止的计数值,即当前已经接收到的字节数。
z:
用户在调用SyncRecePackage或AsyncRecePackage时指定的byParam参数。
与IsPackageHeader相似,如果宏IsPackageTailer的运算结果为TRUE,则认为接收到完整的数据包,则调用相应的回调函数(对于异步接收函数)或返回(对于同步接收函数)。
如果运算结果为FALSE则继续判断下一个字节的数据。
上面的协议对应的IsPackageTailer宏可以写为:
#defineIsPackageTailer(x,y,z) ((y)>
=(z))
当然,用户也可以将IsPackageHeader和IsPackageTailer定义成为函数,通过BIT类型的返回值来向调用者提供与相应宏相同的信息。
另一种办法需要在Config.h文件中定义宏SCOMM_ComplexPackageFormat。
(需要注意的是,不能够同时定义SCOMM_SimplePackageFormat和SCOMM_ComplexPackageFormat宏,否则会造成严重的不可预见性错误。
这时需要提供回调函数QueryPackageFormat,原形如下:
BYTEQueryPackageFormat(BYTEbyData,BYTEbyCount,BYTEbyParam);
函数中三个参数的含义与使用简单数据包格式时判断数据包尾的宏的参数相同。
函数通过返回值来通知作为调用者的接收函数对接收到的数据如何处理,但目前这种方法仅为需要处理复杂数据包格式时的一种可选方法,但不推荐。
用户如果想使用这种方法可以自己更改接收函数中相应的
#ifdefSCOM_ComplexPackageFormat
#endif//SCOMM_ComplexPackageFormat
预编译指令之间的内容。
例如指定QueryPackageFormat的返回值的含义:
0:
继续找数据包头或继续找数据包尾。
1:
找到数据包头。
2:
找到数据包尾。
3:
数据包出错,需要抛弃。
然后更改源代码来实现上面的协议。
当用户需要使用字符串的时候,可以利用简单的包装函数将字符串转换为字节数组。
所以没有必要提供专用的字符串处理函数。
键盘扫描模块
键盘扫描模块有两种工作方式,一种为自动的由时钟模块调用,另一种是由程序员自行调用。
1)由时钟模块自动调用的方式
将时钟模块实现文件(Timer.h)及键盘扫描模块的实现文件(KBScan。
c)包含进工程,在Config.h文件中添加TIMER_KBSCANDELAY宏。
时钟模块自动对时钟中断进行计数,当达到TIMER_KBSCANDELAY宏所定义的值后,自动调用键盘扫描模块中的函数KBScanProcess()进行键盘扫描,也就是说,这个宏的值可以决定按键消抖动的时间。
用户应该提供两个回调函数OnKBScan()及onKeysPressed()。
在函数OnKBScan中进行键盘扫描,并返回扫描码。
扫描码的类型缺省为BYTE,当键盘规模较大时,BYTE不能
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 常用 语法